Permalink
Browse files

Monitor virtual machines using a supervisor

  • Loading branch information...
msantos committed Apr 3, 2011
1 parent ca6848d commit 9b4dd51d66c9238b7ee664b28611ceaabef768a5
Showing with 247 additions and 180 deletions.
  1. +2 −0 ebin/evum.app
  2. +13 −5 src/evm.erl
  3. +13 −171 src/evum.erl
  4. +5 −2 src/evum_ctl.erl
  5. +4 −2 src/evum_mcons.erl
  6. +210 −0 src/evum_srv.erl
View
@@ -4,6 +4,8 @@
{vsn, "0.01"},
{modules, [
evum,
+ evum_srv,
+ evum_sup,
evum_mcons,
evum_ctl,
evum_switch,
View
@@ -45,7 +45,7 @@
args(Dist) ->
- evum:make_args(evm_cfg:dist(args, Dist)).
+ evum_srv:make_args(evm_cfg:dist(args, Dist)).
create(Arg) when is_list(Arg) ->
Label = proplists:get_value(label, Arg, ?LABEL),
@@ -58,6 +58,7 @@ create(Arg) when is_list(Arg) ->
wait_prompt(),
+ mount_proc(Ref),
start_net(Ref, Location),
{ok, Ref}.
@@ -78,20 +79,27 @@ wait_prompt() ->
end.
start_evum() ->
- case lists:member(evum_ctl, erlang:registered()) of
- true ->
+ evum_sup:start_link(),
+ Path = evum_ctl:socket(),
+ case file:read_file_info(Path) of
+ {ok, _} ->
ok;
- false ->
+ {error, enoent} ->
+ error_logger:info_report([{starting, switch}]),
{ok,Switch} = evum_switch:start(),
evum_ctl:start(Switch)
end.
start_vm(Label, Image, Dist) ->
Arg = evm_cfg:dist(args, Dist),
Cow = Image ++ ".cow-" ++ Label ++ "," ++ Image,
- {ok,Ref} = evum:start(Arg ++ [{ubd, Cow}]),
+ Pid = self(),
+ {ok,Ref} = supervisor:start_child(evum_sup, [Pid, Arg ++ [{ubd, Cow}]]),
{ok,Ref}.
+mount_proc(Ref) ->
+ evum:send(Ref, <<"mount -t proc /proc /proc">>).
+
start_net(_Ref, undefined) ->
ok;
start_net(Ref, Location) ->
View
@@ -1,4 +1,4 @@
-%% Copyright (c) 2010, Michael Santos <michael.santos@gmail.com>
+%% Copyright (c) 2010-2011, Michael Santos <michael.santos@gmail.com>
%% All rights reserved.
%%
%% Redistribution and use in source and binary forms, with or without
@@ -29,27 +29,13 @@
%% ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
%% POSSIBILITY OF SUCH DAMAGE.
-module(evum).
--behaviour(gen_server).
--include("evum.hrl").
-include_lib("kernel/include/inet.hrl").
--define(SERVER, ?MODULE).
--define(PROGNAME, "priv/linux").
-
-export([ping/2, sniff/1, ifconfig/2]).
--export([start/0, start/1, start/2, stop/1]).
+-export([start/0, start/1, start/2, stop/1, start_link/2]).
-export([send/2, send/3, puts/2, system/2, reboot/1]).
--export([umid/1, make_args/1, defaults/0]).
--export([start_link/2]).
--export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- terminate/2, code_change/3]).
-
--record(state, {
- cons,
- pid,
- port
-}).
+-export([defaults/0]).
-define(DEFAULT_BOOT_OPTIONS, [
net,
@@ -67,6 +53,7 @@ ifconfig(Ref, {IP, Netmask, Default}) when is_pid(Ref) ->
send(Ref, "ifconfig eth0 " ++ IP ++ " netmask " ++ Netmask),
send(Ref, "route add default gw " ++ Default).
+
ping(Ref, Hostname) when is_pid(Ref), is_list(Hostname) ->
Addr = case inet_res:gethostbyname(Hostname) of
{ok, #hostent{h_addr_list = [IP|_IPs]}} -> IP;
@@ -76,21 +63,26 @@ ping(Ref, Hostname) when is_pid(Ref), is_list(Hostname) ->
ping(Ref, {A,B,C,D} = IP) when is_pid(Ref), is_integer(A), is_integer(B), is_integer(C), is_integer(D) ->
send(Ref, "ping -w 5 -c 1 " ++ inet_parse:ntoa(IP)).
+
sniff(Ref) when is_pid(Ref) ->
send(Ref, "tcpdump -s 0 -w /tmp/sniff.out -i eth0 > /dev/null 2>&1 &").
defaults() -> ?DEFAULT_BOOT_OPTIONS.
+
start() ->
Pid = self(),
- start_link(Pid, defaults()).
+ start(Pid, defaults()).
start(Options) ->
- start_link(self(), Options).
-start(Pid, Options) when is_pid(Pid), is_list(Options) ->
+ start(self(), Options).
+start(Pid, Options) ->
start_link(Pid, Options).
-stop(Ref) when is_pid(Ref) ->
+start_link(Pid, Options) when is_pid(Pid), is_list(Options) ->
+ evum_srv:start_link(Pid, Options).
+
+stop(Ref) ->
gen_server:call(Ref, stop).
reboot(Ref) when is_pid(Ref) ->
@@ -116,153 +108,3 @@ send(Ref, Data, Timeout) when is_pid(Ref), ( is_list(Data) orelse is_binary(Data
puts(Ref, Data) when is_pid(Ref), ( is_list(Data) orelse is_binary(Data) ) ->
gen_server:call(Ref, {send, Data}, infinity).
-
-start_link(Pid, Options) ->
- {ok, Ref} = gen_server:start_link(?MODULE, [Pid, Options], []),
- boot(Ref, Options),
- {ok,Ref}.
-
-init([Pid, Options]) ->
- process_flag(trap_exit, true),
- UmlId = umid(Pid),
-
- Args = case proplists:get_value(net, Options, false) of
- false -> Options;
- true ->
- [Dev] = packet:default_interface(),
- {ok,[{hwaddr, HW}]} = inet:ifget(Dev, [hwaddr]),
- MAC = lists:flatten(string:join([ io_lib:format("~.16B", [N]) || N <- HW ], ":")),
- [{eth, 0, ?UML_DIR ++ "/evum.ctl", MAC}] ++ Options
- end,
- Cmd = make_args([
- {umid, UmlId},
- {uml_dir, ?UML_DIR}
- ] ++ Args),
- Port = open_port({spawn, Cmd}, [
- {line, 2048},
- binary,
- stderr_to_stdout,
- exit_status
- ]),
- {ok, Cons} = evum_mcons:open(?UML_DIR ++ "/" ++ UmlId ++ "/mconsole"),
- {ok, #state{
- cons = Cons,
- pid = Pid,
- port = Port
- }}.
-
-
-handle_call({send, Data}, {Pid,_}, #state{pid = Pid, port = Port} = State) ->
- Reply = case erlang:port_command(Port, Data) of
- true -> ok;
- Error -> Error
- end,
- {reply, Reply, State};
-
-handle_call({system, Command}, {Pid,_}, #state{pid = Pid, cons = Cons} = State) ->
- Reply = evum_mcons:send(Cons, Command),
- {reply, Reply, State};
-handle_call(stop, {Pid,_}, #state{pid = Pid} = State) ->
- {stop, normal, ok, State}.
-
-handle_cast(_Msg, State) ->
- {noreply, State}.
-
-terminate(_Reason, #state{cons = Cons, port = Port}) ->
- ok = evum_mcons:send(Cons, <<"halt">>),
- error_logger:info_report([{terminate, closed}]),
- evum_mcons:close(Cons),
- try erlang:port_close(Port) of
- true -> ok
- catch
- _:_ -> ok
- end.
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-
-%%--------------------------------------------------------------------
-%%% Port communication
-%%--------------------------------------------------------------------
-handle_info({Port, {data, {Eol, Data}}}, #state{port = Port, pid = Pid} = State) when Eol == eol; Eol == noeol ->
- Pid ! Data,
- {noreply, State};
-
-handle_info({Port, {exit_status, Status}}, #state{port = Port} = State) when Status > 128 ->
- {stop, {port_terminated, Status-128}, State};
-handle_info({Port, {exit_status, Status}}, #state{port = Port} = State) ->
- {stop, {port_terminated, Status}, #state{port = Port} = State};
-handle_info({'EXIT', Port, Reason}, #state{port = Port} = State) ->
- {stop, {shutdown, Reason}, State};
-
-% WTF
-handle_info(Info, State) ->
- error_logger:error_report([{wtf, Info}]),
- {noreply, State}.
-
-
-%%--------------------------------------------------------------------
-%%% Boot up
-%%--------------------------------------------------------------------
-boot(Ref, _Options) ->
- send(Ref, <<"mount -t proc /proc /proc">>),
- ok.
-
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
-make_args(PL) ->
- proplists:get_value(progname, PL, ?PROGNAME) ++ " " ++
- string:join([ get_switch(N) || N <- PL ], " ").
-
-get_switch({con, Arg}) -> "con=" ++ Arg;
-get_switch({con, Dev, Arg}) -> "con" ++ integer_to_list(Dev) ++ "=" ++ Arg;
-
-get_switch({disk, Dev, Image}) -> Dev ++ "=" ++ Image;
-get_switch({disk, Dev, Image, Cow}) -> Dev ++ "=" ++ Cow ++ "," ++ Image;
-
-% eth[0-9]+=daemon,ethernet_address,type,control_socket,data_socket
-% eth0=daemon,,unix,/var/run/uml-utilities/uml_switch.ctl
-get_switch({eth, Dev, Path}) -> get_switch({eth, Dev, Path, ""});
-get_switch({eth, Dev, Path, MAC}) ->
- "eth" ++ integer_to_list(Dev) ++ "=daemon," ++ MAC ++ ",unix," ++ Path;
-
-get_switch({init, Arg}) -> "init=" ++ Arg;
-
-get_switch({initrd, Arg}) -> "initrd=" ++ Arg;
-
-get_switch({mem, Arg}) when is_integer(Arg) -> "mem=" ++ integer_to_list(Arg) ++ "M";
-get_switch({mem, Arg}) when is_list(Arg) -> "mem=" ++ Arg;
-
-get_switch(net) -> "";
-get_switch({net, _}) -> "";
-
-get_switch({root, Arg}) -> "root=" ++ Arg;
-get_switch({rootflags, Arg}) -> "rootflags=" ++ Arg;
-get_switch({rootfstype, Arg}) -> "rootfstype=" ++ Arg;
-
-get_switch({ssl, Arg}) -> "ssl=" ++ Arg;
-get_switch({ssl, Dev, Arg}) -> "ssl" ++ integer_to_list(Dev) ++ "=" ++ Arg;
-
-get_switch({ubd, Arg}) -> "ubda=" ++ Arg;
-get_switch({ubd, Dev, Arg}) -> "ubd" ++ Dev ++ "=" ++ Arg;
-
-get_switch({umid, Arg}) -> "umid=" ++ Arg;
-
-get_switch({uml_dir, Arg}) -> "uml_dir=" ++ Arg;
-
-get_switch({verbose, true}) -> "";
-get_switch({verbose, false}) -> "quiet";
-
-get_switch({write, true}) -> "rw";
-
-get_switch(Arg) ->
- error_logger:warning_report([{ignored, Arg}]),
- "".
-
-
-umid(Pid) when is_pid(Pid) ->
- {match,[A,B,C]} = re:run(pid_to_list(Pid), "<(\\d+)\.(\\d+)\.(\\d+)>", [{capture, [1,2,3], list}]),
- "pid-" ++ os:getpid() ++ "-" ++ A ++ "-" ++ B ++ "-" ++ C.
-
-
View
@@ -34,7 +34,7 @@
-include("procket.hrl").
-include("evum.hrl").
--export([start/1, start/2, stop/1]).
+-export([start/1, start/2, stop/1, socket/0]).
-export([data/3]).
-export([start_link/2]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -69,9 +69,12 @@ data(Ref, Socket, Data) ->
start_link(Pid, Switch) when is_pid(Pid), is_pid(Switch) ->
gen_server:start_link(?MODULE, [Pid, Switch], []).
+socket() ->
+ ?UML_DIR ++ "/evum.ctl".
+
init([Pid, Switch]) ->
process_flag(trap_exit, true),
- Path = ?UML_DIR ++ "/evum.ctl",
+ Path = socket(),
{ok, Socket} = procket:socket(?PF_LOCAL, ?SOCK_STREAM, 0),
ok = procket:setsockopt(Socket, ?SOL_SOCKET, ?SO_REUSEADDR, <<1:32/native>>),
View
@@ -102,8 +102,10 @@ help(Socket) ->
send(Socket, Command) when is_list(Command) ->
send(Socket, list_to_binary(Command));
send(#socket{} = Socket, Command) when is_binary(Command) ->
- ok = write(Socket, cmd(Command)),
- recv(Socket).
+ case write(Socket, cmd(Command)) of
+ ok -> recv(Socket);
+ Error -> Error
+ end.
recv(Socket) ->
Oops, something went wrong.

0 comments on commit 9b4dd51

Please sign in to comment.