aboutsummaryrefslogtreecommitdiffstats
path: root/priv
diff options
context:
space:
mode:
Diffstat (limited to 'priv')
-rw-r--r--priv/files/install_upgrade_escript106
-rw-r--r--priv/files/nodetool137
-rw-r--r--priv/files/sys_config9
3 files changed, 252 insertions, 0 deletions
diff --git a/priv/files/install_upgrade_escript b/priv/files/install_upgrade_escript
new file mode 100644
index 0000000..6dcddb3
--- /dev/null
+++ b/priv/files/install_upgrade_escript
@@ -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])).
diff --git a/priv/files/nodetool b/priv/files/nodetool
new file mode 100644
index 0000000..c98e544
--- /dev/null
+++ b/priv/files/nodetool
@@ -0,0 +1,137 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ft=erlang ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% nodetool: Helper Script for interacting with live nodes
+%%
+%% -------------------------------------------------------------------
+
+main(Args) ->
+ ok = start_epmd(),
+ %% Extract the args
+ {RestArgs, TargetNode} = process_args(Args, [], undefined),
+
+ %% See if the node is currently running -- if it's not, we'll bail
+ case {net_kernel:hidden_connect_node(TargetNode), net_adm:ping(TargetNode)} of
+ {true, pong} ->
+ ok;
+ {_, pang} ->
+ io:format(\"Node ~p not responding to pings.\n\", [TargetNode]),
+ halt(1)
+ end,
+
+ case RestArgs of
+ [\"ping\"] ->
+ %% If we got this far, the node already responsed to a ping, so just dump
+ %% a \"pong\"
+ io:format(\"pong\n\");
+ [\"stop\"] ->
+ io:format(\"~p\n\", [rpc:call(TargetNode, init, stop, [], 60000)]);
+ [\"restart\"] ->
+ io:format(\"~p\n\", [rpc:call(TargetNode, init, restart, [], 60000)]);
+ [\"reboot\"] ->
+ io:format(\"~p\n\", [rpc:call(TargetNode, init, reboot, [], 60000)]);
+ [\"rpc\", Module, Function | RpcArgs] ->
+ case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
+ [RpcArgs], 60000) of
+ ok ->
+ ok;
+ {badrpc, Reason} ->
+ io:format(\"RPC to ~p failed: ~p\n\", [TargetNode, Reason]),
+ halt(1);
+ _ ->
+ halt(1)
+ end;
+ [\"rpcterms\", Module, Function, ArgsAsString] ->
+ case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
+ consult(ArgsAsString), 60000) of
+ {badrpc, Reason} ->
+ io:format(\"RPC to ~p failed: ~p\n\", [TargetNode, Reason]),
+ halt(1);
+ Other ->
+ io:format(\"~p\n\", [Other])
+ end;
+ Other ->
+ io:format(\"Other: ~p\n\", [Other]),
+ io:format(\"Usage: nodetool {ping|stop|restart|reboot}\n\")
+ end,
+ net_kernel:stop().
+
+process_args([], Acc, TargetNode) ->
+ {lists:reverse(Acc), TargetNode};
+process_args([\"-setcookie\", Cookie | Rest], Acc, TargetNode) ->
+ erlang:set_cookie(node(), list_to_atom(Cookie)),
+ process_args(Rest, Acc, TargetNode);
+process_args([\"-name\", TargetName | Rest], Acc, _) ->
+ ThisNode = append_node_suffix(TargetName, \"_maint_\"),
+ {ok, _} = net_kernel:start([ThisNode, longnames]),
+ process_args(Rest, Acc, nodename(TargetName));
+process_args([\"-sname\", TargetName | Rest], Acc, _) ->
+ ThisNode = append_node_suffix(TargetName, \"_maint_\"),
+ {ok, _} = net_kernel:start([ThisNode, shortnames]),
+ process_args(Rest, Acc, nodename(TargetName));
+process_args([Arg | Rest], Acc, Opts) ->
+ process_args(Rest, [Arg | Acc], Opts).
+
+
+start_epmd() ->
+ [] = os:cmd(epmd_path() ++ \" -daemon\"),
+ ok.
+
+epmd_path() ->
+ ErtsBinDir = filename:dirname(escript:script_name()),
+ Name = \"epmd\",
+ case os:find_executable(Name, ErtsBinDir) of
+ false ->
+ case os:find_executable(Name) of
+ false ->
+ io:format(\"Could not find epmd.~n\"),
+ halt(1);
+ GlobalEpmd ->
+ GlobalEpmd
+ end;
+ Epmd ->
+ Epmd
+ end.
+
+
+nodename(Name) ->
+ case string:tokens(Name, \"@\") of
+ [_Node, _Host] ->
+ list_to_atom(Name);
+ [Node] ->
+ [_, Host] = string:tokens(atom_to_list(node()), \"@\"),
+ list_to_atom(lists:concat([Node, \"@\", Host]))
+ end.
+
+append_node_suffix(Name, Suffix) ->
+ case string:tokens(Name, \"@\") of
+ [Node, Host] ->
+ list_to_atom(lists:concat([Node, Suffix, os:getpid(), \"@\", Host]));
+ [Node] ->
+ list_to_atom(lists:concat([Node, Suffix, os:getpid()]))
+ end.
+
+%%
+%% Given a string or binary, parse it into a list of terms, ala file:consult/0
+%%
+consult(Str) when is_list(Str) ->
+ consult([], Str, []);
+consult(Bin) when is_binary(Bin)->
+ consult([], binary_to_list(Bin), []).
+
+consult(Cont, Str, Acc) ->
+ case erl_scan:tokens(Cont, Str, 0) of
+ {done, Result, Remaining} ->
+ case Result of
+ {ok, Tokens, _} ->
+ {ok, Term} = erl_parse:parse_term(Tokens),
+ consult([], Remaining, [Term | Acc]);
+ {eof, _Other} ->
+ lists:reverse(Acc);
+ {error, Info, _} ->
+ {error, Info}
+ end;
+ {more, Cont1} ->
+ consult(Cont1, eof, Acc)
+ end.
diff --git a/priv/files/sys_config b/priv/files/sys_config
new file mode 100644
index 0000000..eda2e75
--- /dev/null
+++ b/priv/files/sys_config
@@ -0,0 +1,9 @@
+%% Thanks to Ulf Wiger at Ericcson for these comments:
+%%
+%% This file is identified via the erl command line option -config File.
+%% Note that File should have no extension, e.g.
+%% erl -config .../sys (if this file is called sys.config)
+%%
+%% In this file, you can redefine application environment variables.
+%% This way, you don't have to modify the .app files of e.g. OTP applications.
+[].