summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGuido Günther <agx@sigxcpu.org>2015-09-19 14:03:02 +0200
committerGuido Günther <agx@sigxcpu.org>2015-09-19 14:12:09 +0200
commit4500b9a982f0e0803318d604a993ded16820dcd3 (patch)
tree3f70382fb23f0094b7da5afa7d2f22b67a7d3216 /src
Initial commit
Diffstat (limited to 'src')
-rw-r--r--src/simplec.app.src16
-rwxr-xr-xsrc/simplec.erl10
-rw-r--r--src/simplec_app.erl21
-rw-r--r--src/simplec_hostsfile.erl164
-rw-r--r--src/simplec_sup.erl67
-rw-r--r--src/simplec_vms.erl191
6 files changed, 469 insertions, 0 deletions
diff --git a/src/simplec.app.src b/src/simplec.app.src
new file mode 100644
index 0000000..943f1e9
--- /dev/null
+++ b/src/simplec.app.src
@@ -0,0 +1,16 @@
+%%-*- mode: erlang -*-
+
+{application, simplec,
+ [
+ {description, ""},
+ {vsn, "1"},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib
+ ]},
+ {mod, { simplec_app, []}},
+ {env, [{uri, "qemu:///system"},
+ {dir, "priv"}
+ ]}
+ ]}.
diff --git a/src/simplec.erl b/src/simplec.erl
new file mode 100755
index 0000000..7550349
--- /dev/null
+++ b/src/simplec.erl
@@ -0,0 +1,10 @@
+%% -*- erlang -*-
+
+-module(simplec).
+-export([start/0, stop/0]).
+
+start() ->
+ application:start(simplec).
+
+stop() ->
+ applictation:stop(simplec).
diff --git a/src/simplec_app.erl b/src/simplec_app.erl
new file mode 100644
index 0000000..5936dd0
--- /dev/null
+++ b/src/simplec_app.erl
@@ -0,0 +1,21 @@
+-module(simplec_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+-include("simplec.hrl").
+
+%% ===================================================================
+%% Application callbacks
+%% ===================================================================
+
+start(_StartType, _StartArgs) ->
+ {ok, Uri} = application:get_env(simplec, uri),
+ {ok, Dir} = application:get_env(simplec, dir),
+ C = #config{url=Uri, dir=Dir},
+ simplec_sup:start_link(C).
+
+stop(_State) ->
+ ok.
diff --git a/src/simplec_hostsfile.erl b/src/simplec_hostsfile.erl
new file mode 100644
index 0000000..fba64af
--- /dev/null
+++ b/src/simplec_hostsfile.erl
@@ -0,0 +1,164 @@
+%%%-------------------------------------------------------------------
+%%% @author Guido <agx@bogon.m.sigxcpu.org>
+%%% @copyright (C) 2015, Guido Günther
+%%% @doc
+%%%
+%%% @end
+%%% Created : 30 Aug 2015 by Guido <agx@bogon.m.sigxcpu.org>
+%%%-------------------------------------------------------------------
+-module(simplec_hostsfile).
+
+-behaviour(gen_server).
+
+-include("simplec.hrl").
+
+%% API
+-export([start_link/1,
+ write/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-define(SERVER, ?MODULE).
+
+-record(state, {config}).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+
+%%--------------------------------------------------------------------
+%% @doc
+%% Starts the server
+%%
+%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
+%% @end
+%%--------------------------------------------------------------------
+start_link(Config) ->
+ gen_server:start_link({local, ?SERVER}, ?MODULE, Config, []).
+
+
+%%--------------------------------------------------------------------
+%% @doc
+%% Writes out the hosts
+%% @end
+%%--------------------------------------------------------------------
+write(Hosts) ->
+ gen_server:cast(simplec_hostsfile, {hosts, Hosts}).
+
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Initializes the server
+%%
+%% @spec init(Args) -> {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%% @end
+%%--------------------------------------------------------------------
+init(Config) ->
+ State = #state{config=Config},
+ % Make sure the file exists
+ write_hostsfile(State, {hosts, []}),
+ {ok, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling call messages
+%%
+%% @spec handle_call(Request, From, State) ->
+%% {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling cast messages
+%%
+%% @spec handle_cast(Msg, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_cast({hosts, Hosts}, State) ->
+ write_hostsfile(State, {hosts, Hosts}),
+ {noreply, State}.
+
+
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling all non call/cast messages
+%%
+%% @spec handle_info(Info, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% This function is called by a gen_server when it is about to
+%% terminate. It should be the opposite of Module:init/1 and do any
+%% necessary cleaning up. When it returns, the gen_server terminates
+%% with Reason. The return value is ignored.
+%%
+%% @spec terminate(Reason, State) -> void()
+%% @end
+%%--------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Convert process state when code is changed
+%%
+%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
+%% @end
+%%--------------------------------------------------------------------
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+
+
+write_line(Host, Addr) ->
+ write_line(Host, Addr, []).
+
+write_line(_Host, [], Aggr) ->
+ Aggr;
+write_line(Host, [H|T], Aggr) ->
+ write_line(Host, T, [io_lib:format("~s ~s~n",[H,Host])|Aggr]).
+
+
+write_hostsfile(#state{config=Config}, {hosts, Hosts}) ->
+ File = filename:join(Config#config.dir,
+ "libvirt-" ++ http_uri:encode(Config#config.url) ++ ".hosts"),
+ TmpFile = File ++ [".tmp"],
+ Data = [ write_line(Host, Addrs) || {Host, Addrs} <- Hosts ],
+ file:write_file(TmpFile, Data),
+ file:rename(TmpFile, File).
diff --git a/src/simplec_sup.erl b/src/simplec_sup.erl
new file mode 100644
index 0000000..f4bc3fa
--- /dev/null
+++ b/src/simplec_sup.erl
@@ -0,0 +1,67 @@
+%%%-------------------------------------------------------------------
+%%% @author Guido <agx@bogon.m.sigxcpu.org>
+%%% @copyright (C) 2015, Guido Günther
+%%% @doc
+%%%
+%%% @end
+%%% Created : 15 Sep 2015 by Guido <agx@sigxcpu.org>
+%%%-------------------------------------------------------------------
+-module(simplec_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/1]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+%% Helper macro for declaring children of supervisor
+-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
+-define(CHILD_WITH_ARGS(I, Type, Args), {I, {I, start_link, [Args]}, permanent, 5000, Type, [I]}).
+
+%%%===================================================================
+%%% API functions
+%%%===================================================================
+
+%%--------------------------------------------------------------------
+%% @doc
+%% Starts the supervisor
+%%
+%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
+%% @end
+%%--------------------------------------------------------------------
+start_link(Config) ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, Config).
+
+%%%===================================================================
+%%% Supervisor callbacks
+%%%===================================================================
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Whenever a supervisor is started using supervisor:start_link/[2,3],
+%% this function is called by the new process to find out about
+%% restart strategy, maximum restart frequency and child
+%% specifications.
+%%
+%% @spec init(Args) -> {ok, {SupFlags, [ChildSpec]}} |
+%% ignore |
+%% {error, Reason}
+%% @end
+%%--------------------------------------------------------------------
+init(Config) ->
+ RestartStrategy = one_for_one,
+ MaxRestarts = 1000,
+ MaxSecondsBetweenRestarts = 3600,
+
+ SupFlags = {RestartStrategy, MaxRestarts, MaxSecondsBetweenRestarts},
+ Childs = [?CHILD_WITH_ARGS(simplec_vms, worker, Config),
+ ?CHILD_WITH_ARGS(simplec_hostsfile, worker, Config)],
+ {ok, {SupFlags, Childs}}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
diff --git a/src/simplec_vms.erl b/src/simplec_vms.erl
new file mode 100644
index 0000000..1d3e076
--- /dev/null
+++ b/src/simplec_vms.erl
@@ -0,0 +1,191 @@
+%%%-------------------------------------------------------------------
+%%% @author Guido <agx@bogon.m.sigxcpu.org>
+%%% @copyright (C) 2015, Guido Günther
+%%% @doc
+%%%
+%%% @end
+%%% Created : 2 Sep 2015 by Guido <agx@bogon.m.sigxcpu.org>
+%%%-------------------------------------------------------------------
+-module(simplec_vms).
+
+-behaviour(gen_server).
+
+-include("simplec.hrl").
+
+%% API
+-export([start_link/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-define(SERVER, ?MODULE).
+-define(QUERY_INTERVAL, 2000).
+
+-record(state, {url, verxref, cur}).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+
+%%--------------------------------------------------------------------
+%% @doc
+%% Starts the server
+%%
+%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
+%% @end
+%%--------------------------------------------------------------------
+start_link(Args) ->
+ gen_server:start_link({local, ?SERVER}, ?MODULE, Args, []).
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Initializes the server
+%%
+%% @spec init(Args) -> {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%% @end
+%%--------------------------------------------------------------------
+init(Config) ->
+ Url = Config#config.url,
+ io:format("Monitoring ~s~n~n", [Url]),
+ {ok, Ref} = verx_client:start(),
+ {ok, [1]} = verx:auth_polkit(Ref),
+ ok = verx:connect_open(Ref, [Url, 0]),
+ {ok, #state{url=Url, verxref=Ref}, ?QUERY_INTERVAL}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling call messages
+%%
+%% @spec handle_call(Request, From, State) ->
+%% {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_call(Request, _From, State) ->
+ io:format("Call ~s~n~n", [Request]),
+ Reply = ok,
+ {reply, Reply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling cast messages
+%%
+%% @spec handle_cast(Msg, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_cast(Msg, State) ->
+ io:format("Msg ~s~n~n", [Msg]),
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling all non call/cast messages
+%%
+%% @spec handle_info(Info, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_info(timeout, State) ->
+ {ok, Res} = get_addresses(State#state.verxref),
+ case Res == State#state.cur of
+ false -> print_addresses(Res),
+ simplec_hostsfile:write(Res);
+ true -> true
+ end,
+ {noreply, State#state{cur=Res}, ?QUERY_INTERVAL};
+handle_info(Info, State) ->
+ io:format("Info ~s~n~n", [Info]),
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% This function is called by a gen_server when it is about to
+%% terminate. It should be the opposite of Module:init/1 and do any
+%% necessary cleaning up. When it returns, the gen_server terminates
+%% with Reason. The return value is ignored.
+%%
+%% @spec terminate(Reason, State) -> void()
+%% @end
+%%--------------------------------------------------------------------
+terminate(_Reason, State) ->
+ io:format("Terminating"),
+ ok = verx:connect_close(State#state.verxref),
+ ok = verx_client:stop(State#state.verxref),
+ ok.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Convert process state when code is changed
+%%
+%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
+%% @end
+%%--------------------------------------------------------------------
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+
+filter_addresses(Addrs) ->
+ [ begin
+ {_Iface, _Mac, [{_Type, Addr, _Netmask}]} = A,
+ Addr
+ end || A <- Addrs ].
+
+
+addresses(Ref, Domain) ->
+ {ok, [Addrs]} = verx:domain_interface_addresses(Ref, [Domain, 0, 0]),
+ Addrs.
+
+
+domains(Ref, IDs) ->
+ [ begin
+ {ok, [Domain]} = verx:domain_lookup_by_id(Ref, [N]),
+ Domain
+ end || N <- IDs ].
+
+
+print_addr({Name, Adresses}) ->
+ io:format("~20s: ", [Name]),
+ [ io:format("~s ", [A]) || A <- Adresses ],
+ io:format("~n").
+
+
+print_addresses(Res) ->
+ [ print_addr(R) || R <- Res ],
+ io:format("~n").
+
+
+get_addresses(Ref) ->
+ {ok, [NumRun]} = verx:connect_num_of_domains(Ref),
+ {ok, [Running]} = verx:connect_list_domains(Ref, [NumRun]),
+
+ Domains = domains(Ref, Running),
+ Res = [ begin
+ {Name, _, _} = D,
+ Addrs = addresses(Ref, D),
+ {Name, filter_addresses(Addrs)}
+ end || D <- Domains ],
+ {ok, Res}.