aboutsummaryrefslogblamecommitdiffstats
path: root/priv/templates/install_upgrade_escript
blob: 0910c387135adee13e6172f4a06166a8aa3d7c7d (plain) (tree)
1
2
3
4
5
6
7
8
9




                                                                    
                         

                                             
                                            

                                                                       

























                                                                                                                  

                                                                        




                                                       

                                                                                                                  


                                                                      
                                                                


                                                                  
                                                                



                                                               
                                                                            

                                                              
                                                                                 

                                                                      
                                                                                                

                                                  
                                                                                    




                                   
                             





                                                                                         
                                                                                        



                                                                                   
                                                    




                                              


                                                                                                 











                                                                                                      



                                                                                


                                                        







                                                                            
                                             
                                                       
                                                
 
                                                    
                                        
                                                                        






                                                    
                                                                          






                                                              

                                                                             








                                   
#!/usr/bin/env escript
%%! -noshell -noinput
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ft=erlang ts=4 sw=4 et

-define(TIMEOUT, 300000).
-define(INFO(Fmt,Args), io:format(Fmt,Args)).

%% Unpack or upgrade to a new tar.gz release
main(["unpack", RelName, NameTypeArg, NodeName, Cookie, VersionArg]) ->
    TargetNode = start_distribution(NodeName, NameTypeArg, Cookie),
    WhichReleases = which_releases(TargetNode),
    Version = parse_version(VersionArg),
    case proplists:get_value(Version, WhichReleases) of
        undefined ->
            %% not installed, so unpack tarball:
            ?INFO("Release ~s not found, attempting to unpack releases/~s/~s.tar.gz~n",[Version,Version,RelName]),
            ReleasePackage = Version ++ "/" ++ RelName,
            case rpc:call(TargetNode, release_handler, unpack_release,
                          [ReleasePackage], ?TIMEOUT) of
                {ok, Vsn} ->
                    ?INFO("Unpacked successfully: ~p~n", [Vsn]);
                {error, UnpackReason} ->
                    print_existing_versions(TargetNode),
                    ?INFO("Unpack failed: ~p~n",[UnpackReason]),
                    erlang:halt(2)
            end;
        old ->
            %% no need to unpack, has been installed previously
            ?INFO("Release ~s is marked old, switching to it.~n",[Version]);
        unpacked ->
            ?INFO("Release ~s is already unpacked, now installing.~n",[Version]);
        current ->
            ?INFO("Release ~s is already installed and current. Making permanent.~n",[Version]);
        permanent ->
            ?INFO("Release ~s is already installed, and set permanent.~n",[Version])
    end;
main(["install", RelName, NameTypeArg, NodeName, Cookie, VersionArg]) ->
    TargetNode = start_distribution(NodeName, NameTypeArg, Cookie),
    WhichReleases = which_releases(TargetNode),
    Version = parse_version(VersionArg),
    case proplists:get_value(Version, WhichReleases) of
        undefined ->
            %% not installed, so unpack tarball:
            ?INFO("Release ~s not found, attempting to unpack releases/~s/~s.tar.gz~n",[Version,Version,RelName]),
            ReleasePackage = Version ++ "/" ++ RelName,
            case rpc:call(TargetNode, release_handler, unpack_release,
                          [ReleasePackage], ?TIMEOUT) of
                {ok, Vsn} ->
                    ?INFO("Unpacked successfully: ~p~n", [Vsn]),
                    install_and_permafy(TargetNode, RelName, Vsn);
                {error, UnpackReason} ->
                    print_existing_versions(TargetNode),
                    ?INFO("Unpack failed: ~p~n",[UnpackReason]),
                    erlang:halt(2)
            end;
        old ->
            %% no need to unpack, has been installed previously
            ?INFO("Release ~s is marked old, switching to it.~n",[Version]),
            install_and_permafy(TargetNode, RelName, Version);
        unpacked ->
            ?INFO("Release ~s is already unpacked, now installing.~n",[Version]),
            install_and_permafy(TargetNode, RelName, Version);
        current -> %% installed and in-use, just needs to be permanent
            ?INFO("Release ~s is already installed and current. Making permanent.~n",[Version]),
            permafy(TargetNode, RelName, Version);
        permanent ->
            ?INFO("Release ~s is already installed, and set permanent.~n",[Version])
    end;
main(_) ->
    erlang:halt(1).

parse_version(V) when is_list(V) ->
    hd(string:tokens(V,"/")).

install_and_permafy(TargetNode, RelName, Vsn) ->
    case rpc:call(TargetNode, release_handler, check_install_release, [Vsn], ?TIMEOUT) of
        {ok, _OtherVsn, _Desc} ->
            ok;
        {error, Reason} ->
            ?INFO("ERROR: release_handler:check_install_release failed: ~p~n",[Reason]),
            erlang:halt(3)
    end,
    case rpc:call(TargetNode, release_handler, install_release, [Vsn], ?TIMEOUT) of
        {ok, _, _} ->
            ?INFO("Installed Release: ~s~n", [Vsn]),
            permafy(TargetNode, RelName, Vsn),
            ok;
        {error, {no_such_release, Vsn}} ->
            VerList =
                iolist_to_binary(
                    [io_lib:format("* ~s\t~s~n",[V,S]) ||  {V,S} <- which_releases(TargetNode)]),
            ?INFO("Installed versions:~n~s", [VerList]),
            ?INFO("ERROR: Unable to revert to '~s' - not installed.~n", [Vsn]),
            erlang:halt(2);
        %% as described in http://erlang.org/doc/man/appup.html, when performing a relup
        %% with soft purge:
        %%      If the value is soft_purge, release_handler:install_release/1
        %%      returns {error,{old_processes,Mod}}
        {error, {old_processes, Mod}} ->
            ?INFO("ERROR: unable to install '~s' - old processes still running code from module ~p~n",
                [Vsn, Mod]),
            erlang:halt(3);
        {error, Reason1} ->
            ?INFO("ERROR: release_handler:install_release failed: ~p~n",[Reason1]),
            erlang:halt(4)
    end.

permafy(TargetNode, RelName, Vsn) ->
    ok = rpc:call(TargetNode, release_handler, make_permanent, [Vsn], ?TIMEOUT),
    file:copy(filename:join(["bin", RelName++"-"++Vsn]),
              filename:join(["bin", RelName])),
    ?INFO("Made release permanent: ~p~n", [Vsn]),
    ok.

which_releases(TargetNode) ->
    R = rpc:call(TargetNode, release_handler, which_releases, [], ?TIMEOUT),
    [ {V, S} ||  {_,V,_, S} <- R ].

print_existing_versions(TargetNode) ->
    VerList = iolist_to_binary([
            io_lib:format("* ~s\t~s~n",[V,S])
            ||  {V,S} <- which_releases(TargetNode) ]),
    ?INFO("Installed versions:~n~s", [VerList]).

start_distribution(NodeName, NameTypeArg, Cookie) ->
    MyNode = make_script_node(NodeName),
    {ok, _Pid} = net_kernel:start([MyNode, get_name_type(NameTypeArg)]),
    erlang:set_cookie(node(), list_to_atom(Cookie)),
    TargetNode = list_to_atom(NodeName),
    case {net_kernel:connect_node(TargetNode),
          net_adm:ping(TargetNode)} of
        {true, pong} ->
            ok;
        {_, pang} ->
            io:format("Node ~p not responding to pings.\n", [TargetNode]),
            erlang:halt(1)
    end,
    {ok, Cwd} = file:get_cwd(),
    ok = rpc:call(TargetNode, file, set_cwd, [Cwd], ?TIMEOUT),
    TargetNode.

make_script_node(Node) ->
    [Name, Host] = string:tokens(Node, "@"),
    list_to_atom(lists:concat([Name, "_upgrader_", os:getpid(), "@", Host])).

%% get name type from arg
get_name_type(NameTypeArg) ->
	case NameTypeArg of
		"-sname" ->
			shortnames;
		_ ->
			longnames
	end.