nodetool 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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. -mode(compile).
  10. main(Args) ->
  11. ok = start_epmd(),
  12. %% Extract the args
  13. {RestArgs, TargetNode} = process_args(Args, [], undefined),
  14. %% process_args() has side-effects (e.g. when processing "-name"),
  15. %% so take care of app-starting business first.
  16. [application:start(App) || App <- [crypto, public_key, ssl]],
  17. %% any commands that don't need a running node
  18. case RestArgs of
  19. ["chkconfig", File] ->
  20. case file:consult(File) of
  21. {ok, Terms} ->
  22. case validate(Terms) of
  23. ok ->
  24. io:format("ok\n"),
  25. halt(0);
  26. {error, Problems} ->
  27. lists:foreach(fun print_issue/1, Problems),
  28. %% halt(1) if any problems were errors
  29. halt(case [x || {error, _} <- Problems] of
  30. [] -> 0;
  31. _ -> 1
  32. end)
  33. end;
  34. {error, {Line, Mod, Term}} ->
  35. io:format(standard_error, ["Error on line ", file:format_error({Line, Mod, Term}), "\n"], []),
  36. halt(1);
  37. {error, R} ->
  38. io:format(standard_error, ["Error reading config file: ", file:format_error(R), "\n"], []),
  39. halt(1)
  40. end;
  41. _ ->
  42. ok
  43. end,
  44. %% See if the node is currently running -- if it's not, we'll bail
  45. case {net_kernel:hidden_connect_node(TargetNode), net_adm:ping(TargetNode)} of
  46. {true, pong} ->
  47. ok;
  48. {false,pong} ->
  49. io:format("Failed to connect to node ~p .\n", [TargetNode]),
  50. halt(1);
  51. {_, pang} ->
  52. io:format("Node ~p not responding to pings.\n", [TargetNode]),
  53. halt(1)
  54. end,
  55. case RestArgs of
  56. ["getpid"] ->
  57. io:format("~p\n", [list_to_integer(rpc:call(TargetNode, os, getpid, []))]);
  58. ["ping"] ->
  59. %% If we got this far, the node already responsed to a ping, so just dump
  60. %% a "pong"
  61. io:format("pong\n");
  62. ["stop"] ->
  63. io:format("~p\n", [rpc:call(TargetNode, init, stop, [], 60000)]);
  64. ["restart"] ->
  65. io:format("~p\n", [rpc:call(TargetNode, init, restart, [], 60000)]);
  66. ["reboot"] ->
  67. io:format("~p\n", [rpc:call(TargetNode, init, reboot, [], 60000)]);
  68. ["rpc", Module, Function | RpcArgs] ->
  69. case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
  70. [RpcArgs], 60000) of
  71. ok ->
  72. ok;
  73. {badrpc, Reason} ->
  74. io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
  75. halt(1);
  76. _ ->
  77. halt(1)
  78. end;
  79. ["rpc_infinity", Module, Function | RpcArgs] ->
  80. case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function), [RpcArgs], infinity) of
  81. ok ->
  82. ok;
  83. {badrpc, Reason} ->
  84. io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
  85. halt(1);
  86. _ ->
  87. halt(1)
  88. end;
  89. ["rpcterms", Module, Function, ArgsAsString] ->
  90. case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
  91. consult(ArgsAsString), 60000) of
  92. {badrpc, Reason} ->
  93. io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
  94. halt(1);
  95. Other ->
  96. io:format("~p\n", [Other])
  97. end;
  98. Other ->
  99. io:format("Other: ~p\n", [Other]),
  100. io:format("Usage: nodetool {chkconfig|getpid|ping|stop|restart|reboot|rpc|rpc_infinity|rpcterms}\n")
  101. end,
  102. net_kernel:stop().
  103. process_args([], Acc, TargetNode) ->
  104. {lists:reverse(Acc), TargetNode};
  105. process_args(["-setcookie", Cookie | Rest], Acc, TargetNode) ->
  106. erlang:set_cookie(node(), list_to_atom(Cookie)),
  107. process_args(Rest, Acc, TargetNode);
  108. process_args(["-name", TargetName | Rest], Acc, _) ->
  109. ThisNode = append_node_suffix(TargetName, "_maint_"),
  110. {ok, _} = net_kernel:start([ThisNode, longnames]),
  111. process_args(Rest, Acc, nodename(TargetName));
  112. process_args(["-sname", TargetName | Rest], Acc, _) ->
  113. ThisNode = append_node_suffix(TargetName, "_maint_"),
  114. {ok, _} = net_kernel:start([ThisNode, shortnames]),
  115. process_args(Rest, Acc, nodename(TargetName));
  116. process_args([Arg | Rest], Acc, Opts) ->
  117. process_args(Rest, [Arg | Acc], Opts).
  118. start_epmd() ->
  119. [] = os:cmd(epmd_path() ++ " -daemon"),
  120. ok.
  121. epmd_path() ->
  122. ErtsBinDir = filename:dirname(escript:script_name()),
  123. Name = "epmd",
  124. case os:find_executable(Name, ErtsBinDir) of
  125. false ->
  126. case os:find_executable(Name) of
  127. false ->
  128. io:format("Could not find epmd.~n"),
  129. halt(1);
  130. GlobalEpmd ->
  131. GlobalEpmd
  132. end;
  133. Epmd ->
  134. Epmd
  135. end.
  136. nodename(Name) ->
  137. case string:tokens(Name, "@") of
  138. [_Node, _Host] ->
  139. list_to_atom(Name);
  140. [Node] ->
  141. [_, Host] = string:tokens(atom_to_list(node()), "@"),
  142. list_to_atom(lists:concat([Node, "@", Host]))
  143. end.
  144. append_node_suffix(Name, Suffix) ->
  145. case string:tokens(Name, "@") of
  146. [Node, Host] ->
  147. list_to_atom(lists:concat([Node, Suffix, os:getpid(), "@", Host]));
  148. [Node] ->
  149. list_to_atom(lists:concat([Node, Suffix, os:getpid()]))
  150. end.
  151. %%
  152. %% Given a string or binary, parse it into a list of terms, ala file:consult/0
  153. %%
  154. consult(Str) when is_list(Str) ->
  155. consult([], Str, []);
  156. consult(Bin) when is_binary(Bin)->
  157. consult([], binary_to_list(Bin), []).
  158. consult(Cont, Str, Acc) ->
  159. case erl_scan:tokens(Cont, Str, 0) of
  160. {done, Result, Remaining} ->
  161. case Result of
  162. {ok, Tokens, _} ->
  163. {ok, Term} = erl_parse:parse_term(Tokens),
  164. consult([], Remaining, [Term | Acc]);
  165. {eof, _Other} ->
  166. lists:reverse(Acc);
  167. {error, Info, _} ->
  168. {error, Info}
  169. end;
  170. {more, Cont1} ->
  171. consult(Cont1, eof, Acc)
  172. end.
  173. %%
  174. %% Validation functions for checking the emqttd.config
  175. %%
  176. validate([Terms]) ->
  177. Results = [ValidateFun(Terms) || ValidateFun <- get_validation_funs()],
  178. Failures = [Res || Res <- Results, Res /= true],
  179. case Failures of
  180. [] ->
  181. ok;
  182. _ ->
  183. {error, Failures}
  184. end.
  185. %% Some initial and basic checks for the app.config file
  186. get_validation_funs() ->
  187. [ ].
  188. print_issue({warning, Warning}) ->
  189. io:format(standard_error, "Warning in emqttd.config: ~s~n", [Warning]);
  190. print_issue({error, Error}) ->
  191. io:format(standard_error, "Error in emqttd.config: ~s~n", [Error]).