diff options
author | Guido Günther <agx@sigxcpu.org> | 2015-09-19 14:03:02 +0200 |
---|---|---|
committer | Guido Günther <agx@sigxcpu.org> | 2015-09-19 14:12:09 +0200 |
commit | 4500b9a982f0e0803318d604a993ded16820dcd3 (patch) | |
tree | 3f70382fb23f0094b7da5afa7d2f22b67a7d3216 /src |
Initial commit
Diffstat (limited to 'src')
-rw-r--r-- | src/simplec.app.src | 16 | ||||
-rwxr-xr-x | src/simplec.erl | 10 | ||||
-rw-r--r-- | src/simplec_app.erl | 21 | ||||
-rw-r--r-- | src/simplec_hostsfile.erl | 164 | ||||
-rw-r--r-- | src/simplec_sup.erl | 67 | ||||
-rw-r--r-- | src/simplec_vms.erl | 191 |
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}. |