You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

182 lines
6.3 KiB

14 years ago
14 years ago
  1. #!/usr/bin/env escript
  2. %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
  3. %% ex: ft=erlang ts=4 sw=4 et
  4. %% -------------------------------------------------------------------
  5. %%
  6. %% nodetool: Helper Script for interacting with live nodes
  7. %%
  8. %% -------------------------------------------------------------------
  9. main(Args) ->
  10. ok = start_epmd(),
  11. %% Extract the args
  12. {RestArgs, TargetNode} = process_args(Args, [], undefined),
  13. %% any commands that don't need a running node
  14. case RestArgs of
  15. ["chkconfig", File] ->
  16. case file:consult(File) of
  17. {ok, _} ->
  18. io:format("ok\n"),
  19. halt(0);
  20. {error, {Line, Mod, Term}} ->
  21. io:format(standard_error, ["Error on line ",
  22. file:format_error({Line, Mod, Term}), "\n"], []),
  23. halt(1);
  24. {error, R} ->
  25. io:format(standard_error, ["Error reading config file: ",
  26. file:format_error(R), "\n"], []),
  27. halt(1)
  28. end;
  29. _ ->
  30. ok
  31. end,
  32. %% See if the node is currently running -- if it's not, we'll bail
  33. case {net_kernel:hidden_connect_node(TargetNode),
  34. net_adm:ping(TargetNode)} of
  35. {true, pong} ->
  36. ok;
  37. {false,pong} ->
  38. io:format("Failed to connect to node ~p .\n", [TargetNode]),
  39. halt(1);
  40. {_, pang} ->
  41. io:format("Node ~p not responding to pings.\n", [TargetNode]),
  42. halt(1)
  43. end,
  44. case RestArgs of
  45. ["getpid"] ->
  46. io:format("~p\n",
  47. [list_to_integer(rpc:call(TargetNode, os, getpid, []))]);
  48. ["ping"] ->
  49. %% If we got this far, the node already responsed to a
  50. %% ping, so just dump a "pong"
  51. io:format("pong\n");
  52. ["stop"] ->
  53. io:format("~p\n", [rpc:call(TargetNode, init, stop, [], 60000)]);
  54. ["restart"] ->
  55. io:format("~p\n", [rpc:call(TargetNode, init, restart, [], 60000)]);
  56. ["reboot"] ->
  57. io:format("~p\n", [rpc:call(TargetNode, init, reboot, [], 60000)]);
  58. ["rpc", Module, Function | RpcArgs] ->
  59. case rpc:call(TargetNode,
  60. list_to_atom(Module),
  61. list_to_atom(Function),
  62. [RpcArgs], 60000) of
  63. ok ->
  64. ok;
  65. {badrpc, Reason} ->
  66. io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
  67. halt(1);
  68. _ ->
  69. halt(1)
  70. end;
  71. ["rpc_infinity", Module, Function | RpcArgs] ->
  72. case rpc:call(TargetNode,
  73. list_to_atom(Module),
  74. list_to_atom(Function),
  75. [RpcArgs], infinity) of
  76. ok ->
  77. ok;
  78. {badrpc, Reason} ->
  79. io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
  80. halt(1);
  81. _ ->
  82. halt(1)
  83. end;
  84. ["rpcterms", Module, Function, ArgsAsString] ->
  85. case rpc:call(TargetNode,
  86. list_to_atom(Module),
  87. list_to_atom(Function),
  88. consult(ArgsAsString), 60000) of
  89. {badrpc, Reason} ->
  90. io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
  91. halt(1);
  92. Other ->
  93. io:format("~p\n", [Other])
  94. end;
  95. Other ->
  96. io:format("Other: ~p\n", [Other]),
  97. io:format("Usage: nodetool {chkconfig|getpid|ping|stop|restart|reboot|rpc|rpc_infinity|rpcterms}\n")
  98. end,
  99. net_kernel:stop().
  100. process_args([], Acc, TargetNode) ->
  101. {lists:reverse(Acc), TargetNode};
  102. process_args(["-setcookie", Cookie | Rest], Acc, TargetNode) ->
  103. erlang:set_cookie(node(), list_to_atom(Cookie)),
  104. process_args(Rest, Acc, TargetNode);
  105. process_args(["-name", TargetName | Rest], Acc, _) ->
  106. ThisNode = append_node_suffix(TargetName, "_maint_"),
  107. {ok, _} = net_kernel:start([ThisNode, longnames]),
  108. process_args(Rest, Acc, nodename(TargetName));
  109. process_args(["-sname", TargetName | Rest], Acc, _) ->
  110. ThisNode = append_node_suffix(TargetName, "_maint_"),
  111. {ok, _} = net_kernel:start([ThisNode, shortnames]),
  112. process_args(Rest, Acc, nodename(TargetName));
  113. process_args([Arg | Rest], Acc, Opts) ->
  114. process_args(Rest, [Arg | Acc], Opts).
  115. start_epmd() ->
  116. [] = os:cmd(epmd_path() ++ " -daemon"),
  117. ok.
  118. epmd_path() ->
  119. ErtsBinDir = filename:dirname(escript:script_name()),
  120. Name = "epmd",
  121. case os:find_executable(Name, ErtsBinDir) of
  122. false ->
  123. case os:find_executable(Name) of
  124. false ->
  125. io:format("Could not find epmd.~n"),
  126. halt(1);
  127. GlobalEpmd ->
  128. GlobalEpmd
  129. end;
  130. Epmd ->
  131. Epmd
  132. end.
  133. nodename(Name) ->
  134. case string:tokens(Name, "@") of
  135. [_Node, _Host] ->
  136. list_to_atom(Name);
  137. [Node] ->
  138. [_, Host] = string:tokens(atom_to_list(node()), "@"),
  139. list_to_atom(lists:concat([Node, "@", Host]))
  140. end.
  141. append_node_suffix(Name, Suffix) ->
  142. case string:tokens(Name, "@") of
  143. [Node, Host] ->
  144. list_to_atom(lists:concat([Node, Suffix, os:getpid(), "@", Host]));
  145. [Node] ->
  146. list_to_atom(lists:concat([Node, Suffix, os:getpid()]))
  147. end.
  148. %%
  149. %% Given a string or binary, parse it into a list of terms, ala file:consult/0
  150. %%
  151. consult(Str) when is_list(Str) ->
  152. consult([], Str, []);
  153. consult(Bin) when is_binary(Bin)->
  154. consult([], binary_to_list(Bin), []).
  155. consult(Cont, Str, Acc) ->
  156. case erl_scan:tokens(Cont, Str, 0) of
  157. {done, Result, Remaining} ->
  158. case Result of
  159. {ok, Tokens, _} ->
  160. {ok, Term} = erl_parse:parse_term(Tokens),
  161. consult([], Remaining, [Term | Acc]);
  162. {eof, _Other} ->
  163. lists:reverse(Acc);
  164. {error, Info, _} ->
  165. {error, Info}
  166. end;
  167. {more, Cont1} ->
  168. consult(Cont1, eof, Acc)
  169. end.