%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2004-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% %CopyrightEnd% %% %%%------------------------------------------------------------------- %%% File : loose_node.erl %%% Author : Rickard Green <rickard.s.green@ericsson.com> %%% Description : Creation of nodes which are not supervised by %%% the test_server. Currently needed by init_SUITE %%% and heart_SUITE (until the test_server can %%% handle node restart). %%% %%% Created : 22 Sep 2004 by Rickard Green <rickard.s.green@ericsson.com> %%%------------------------------------------------------------------- -module(loose_node). -author('rickard.s.green@ericsson.com'). %% %% Exports %% -export([start/3, start/2, stop/1]). %% %% Internal exports %% -export([loose_node_started/1]). %% %% Exported functions for internal use. %% %% %% Defines %% -define(L2A, list_to_atom). -define(A2L, atom_to_list). -define(I2L, integer_to_list). %% %% Exported functions. %% stop(Node) when is_atom(Node) -> rpc:cast(Node, erlang, halt, []), io:format("Stopped loose node ~p~n", [Node]), ok. start(Name, Args) -> start(Name, Args, -1). start(Name, Args, TimeOut) when is_atom(Name) -> start(atom_to_list(Name), Args, TimeOut); start(Name, Args, TimeOut) when is_list(Name), is_list(Args), is_integer(TimeOut) -> Parent = self(), Ref = make_ref(), Starter = fun () -> Erl = case init:get_argument(progname) of {ok,[[Prog]]} -> Prog; _ -> "erl" end, RegName = until_success(fun () -> {A, B, C} = now(), Reg = ?L2A(?A2L(?MODULE) ++ "-" ++ ?I2L(A) ++ "-" ++ ?I2L(B) ++ "-" ++ ?I2L(C)), true = register(Reg, self()), Reg end), NameCmd = case net_kernel:longnames() of true -> " -name " ++ Name; false -> " -sname " ++ Name end, Cookie = " -setcookie " ++ atom_to_list(auth:get_cookie()), Pa = " -pa " ++ filename:dirname(code:which(?MODULE)), ThisNode = node(), NodeStarted = " -run " ++ atom_to_list(?MODULE) ++ " loose_node_started " ++ atom_to_list(RegName) ++ " " ++ atom_to_list(ThisNode) ++ " " ++ integer_to_list(TimeOut), CrashDump = " -env ERL_CRASH_DUMP" ++ " erl_crash.dump.loose_node." ++ Name, Cmd = Erl ++ " -detached" ++ NameCmd ++ Cookie ++ Pa ++ NodeStarted ++ CrashDump ++ " " ++ Args, io:format("Trying to start loose node...~n" " --> ~p~n", [Cmd]), Res = case open_port({spawn, Cmd}, []) of P when is_port(P) -> receive {loose_node_started, Node, {RegName, ThisNode}} -> io:format("Loose node ~p started.~n", [Node]), {ok, Node} after 10000 -> io:format("Start of loose node ~p " "timed out.", [Name]), {error, timeout} end; _ -> io:format("Start of loose node ~p failed.", [Name]), {error, open_port_failed} end, Parent ! {Ref, Res} end, spawn_opt(Starter, [link, {priority, max}]), receive {Ref, Result} -> Result end. %% %% Exported functions for internal use. %% loose_node_started([Name, Node, TimeOutSecs]) when is_list(Name), is_list(Node), is_list(TimeOutSecs) -> spawn_opt(fun () -> process_flag(trap_exit, true), Proc = {list_to_atom(Name), list_to_atom(Node)}, Timeout = case catch list_to_integer(TimeOutSecs) of I when is_integer(I), I >= 0 -> I*1000; _ -> infinity end, wait_until(fun () -> is_alive() end), Proc ! {loose_node_started, node(), Proc}, receive after Timeout -> timeout end, erlang:halt("Loose node timeout") end, [{priority, max}]), ok. %% %% Internal functions. %% until_success(Fun) -> case catch Fun() of {'EXIT', _} -> until_success(Fun); Res -> Res end. wait_until(Fun) -> case Fun() of true -> true; _ -> receive after 100 -> wait_until(Fun) end end.