%% -*- 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.