aboutsummaryrefslogtreecommitdiffstats
path: root/priv/templates/install_upgrade_escript.dtl
diff options
context:
space:
mode:
Diffstat (limited to 'priv/templates/install_upgrade_escript.dtl')
-rw-r--r--priv/templates/install_upgrade_escript.dtl106
1 files changed, 106 insertions, 0 deletions
diff --git a/priv/templates/install_upgrade_escript.dtl b/priv/templates/install_upgrade_escript.dtl
new file mode 100644
index 0000000..7c331aa
--- /dev/null
+++ b/priv/templates/install_upgrade_escript.dtl
@@ -0,0 +1,106 @@
+#!/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, 60000).
+-define(INFO(Fmt,Args), io:format(Fmt,Args)).
+
+%% Upgrades, to a new tar.gz release
+main([RelName, NodeName, Cookie, VersionArg]) ->
+ TargetNode = start_distribution(NodeName, 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)
+ 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, Cookie) ->
+ MyNode = make_script_node(NodeName),
+ {ok, _Pid} = net_kernel:start([MyNode, longnames]),
+ 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])).