From 62e636cfe75cdc10a4c30da9c68a6eb6401f8ac9 Mon Sep 17 00:00:00 2001 From: Luna Mendes Date: Mon, 11 Jun 2018 04:24:16 -0300 Subject: [PATCH] add many stuff owo --- config/config.example.exs | 31 +++++++++++++++ config/config.exs | 27 ++++++++++++- lib/adapters/adapter.ex | 7 ++++ lib/adapters/elixire.ex | 31 +++++++++++++++ lib/adapters/ping.ex | 22 +++++++++++ lib/manager.ex | 80 +++++++++++++++++++++++++++++++++++++++ lib/supervisor.ex | 9 ++++- mix.exs | 1 + mix.lock | 3 ++ 9 files changed, 208 insertions(+), 3 deletions(-) create mode 100644 config/config.example.exs create mode 100644 lib/adapters/adapter.ex create mode 100644 lib/adapters/elixire.ex create mode 100644 lib/adapters/ping.ex create mode 100644 lib/manager.ex diff --git a/config/config.example.exs b/config/config.example.exs new file mode 100644 index 0000000..6603a02 --- /dev/null +++ b/config/config.example.exs @@ -0,0 +1,31 @@ +use Mix.Config + +config :elstat, + # where will elstat (backend and frontend) + # be served + port: 8069, + + # which services will be managed by elstat? + # this follows a service spec + # the example here is for elixire + services: [ + %{ + id: :elixire, + description: "elixi.re", + adapter: Elstat.Adapter.Elixire, + adapter_opts: %{ + base_url: "https://elixi.re", + }, + # every 10 seconds + poll: 10, + }, + %{ + id: :genserver, + description: "genserver, elixire main server", + adapter: Elstat.Adapter.Ping, + adapter_opts: %{ + address: "192.168.1.1", + }, + poll: 15, + }, + ] diff --git a/config/config.exs b/config/config.exs index eecbc65..fec8873 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,4 +1,29 @@ use Mix.Config config :elstat, - port: 8069 + port: 8069, + + # which services will be managed by elstat? + # this follows a service spec + # the example here is for elixire + services: [ + %{ + id: :elixire, + human_id: "elixi.re", + adapter: Elstat.Adapter.Elixire, + adapter_opts: %{ + base_url: "https://elixi.re", + }, + # every 10 seconds + poll: 10, + }, + %{ + id: :genserver, + human_id: "genserver, elixire main server", + adapter: Elstat.Adapter.Ping, + adapter_opts: %{ + address: "192.168.1.1", + }, + poll: 15, + }, + ] diff --git a/lib/adapters/adapter.ex b/lib/adapters/adapter.ex new file mode 100644 index 0000000..d7e3764 --- /dev/null +++ b/lib/adapters/adapter.ex @@ -0,0 +1,7 @@ +defmodule Elstat.Adapter do + @type adapter_check_res :: {:ok, any()} | {:error, any()} + + @type adp_args :: Map.t + + @callback check(adp_args) :: adapter_check_res +end diff --git a/lib/adapters/elixire.ex b/lib/adapters/elixire.ex new file mode 100644 index 0000000..c227d0c --- /dev/null +++ b/lib/adapters/elixire.ex @@ -0,0 +1,31 @@ +defmodule Elstat.Adapter.Elixire do + @behaviour Elstat.Adapter + + use GenServer + require Logger + + def start_link(service_opts) do + GenServer.start_link(__MODULE__, service_opts, []) + end + + def init(service_opts) do + Logger.info("Elixire adapter started with #{inspect service_opts}") + {:ok, %{}} + end + + def check(args) do + addr = args.base_url + + req_start = :erlang.monotonic_time(:millisecond) + resp = HTTPoison.get!("#{addr}/api/hello") + req_end = :erlang.monotonic_time(:millisecond) + + delta = req_end - req_start + + {:ok, {:map, %{ + status: resp.status_code == 200, + latency: {:millisecond, delta}, + }}} + end + +end diff --git a/lib/adapters/ping.ex b/lib/adapters/ping.ex new file mode 100644 index 0000000..12d53e0 --- /dev/null +++ b/lib/adapters/ping.ex @@ -0,0 +1,22 @@ +defmodule Elstat.Adapter.Ping do + @behaviour Elstat.Adapter + + use GenServer + require Logger + + def start_link(service_opts) do + GenServer.start_link(__MODULE__, service_opts, []) + end + + def init(service_opts) do + Logger.info("Ping started with #{inspect service_opts}") + {:ok, %{}} + end + + def check(args) do + {cmd_output, _} = System.cmd("ping", ["-c", "1", args.address]) + alive? = not Regex.match?(~r/100(\.0)?% packet loss/, cmd_output) + {:ok, {:bool, alive?}} + end + +end diff --git a/lib/manager.ex b/lib/manager.ex new file mode 100644 index 0000000..736802a --- /dev/null +++ b/lib/manager.ex @@ -0,0 +1,80 @@ +defmodule Elstat.Error.Service do + defexception message: "default message" +end + +defmodule Elstat.ServiceWorker do + require Logger + + def start_link(service) do + Logger.info "spawning worker for #{inspect service.id}" + + worker_pid = spawn(fn -> + worker_func(service) + end) + + {:ok, worker_pid} + end + + def worker_func(service) do + adapter = service.adapter + + result = adapter.check(service.adapter_opts) + Logger.info "result from #{inspect adapter} #{inspect service.id}: #{inspect result}" + + man_pid = :global.whereis_name Elstat.Manager + send man_pid, {:service_info, {service.id, result}} + + Process.sleep(service.poll * 1000) + worker_func(service) + end +end + +defmodule Elstat.Manager do + @moduledoc """ + Elstat's service manager. + """ + use GenServer + require Logger + + def start_link(opts) do + GenServer.start_link(__MODULE__, :ok, [name: {:global, Elstat.Manager}] ++ opts) + end + + def build_services() do + services = Application.fetch_env!(:elstat, :services) + + workers = services + |> Enum.map(fn service -> + service_id = service.id + + # each service worker will enter an infinite loop + # polling the service (via an adapter) and giving + # information back to the manager, so it can + # process and show those via its API. + %{ + id: service_id, + start: {Elstat.ServiceWorker, :start_link, [service]} + } + end) + + # spawn the managere alongside service workers + [ Elstat.Manager | workers] + end + + # server callbacks + def init(:ok) do + services = Application.fetch_env!(:elstat, :services) + + # TODO : send data to db + + {:ok, %{ + services: services, + }} + end + + def handle_info({:service_info, data}, state) do + Logger.debug "got service data! #{inspect data}" + {:noreply, state} + end + +end diff --git a/lib/supervisor.ex b/lib/supervisor.ex index 922f850..3541c04 100644 --- a/lib/supervisor.ex +++ b/lib/supervisor.ex @@ -9,13 +9,18 @@ defmodule Elstat.Supervisor do def init(:ok) do Logger.info "starting sup" - children = [ + base_children = [ %{ id: Elstat.Cowboy, start: {Elstat.Cowboy, :start_link, []}, - } + }, + {Sqlitex.Server, ['elstat.db', [name: Sqlitex.Server]]} ] + service_children = Elstat.Manager.build_services() + + children = service_children ++ base_children + Logger.debug "final children #{inspect children}" Supervisor.init(children, strategy: :one_for_one) end diff --git a/mix.exs b/mix.exs index a537adc..749aa2d 100644 --- a/mix.exs +++ b/mix.exs @@ -23,6 +23,7 @@ defmodule Elstat.MixProject do defp deps do [ {:httpoison, "~> 1.1.1"}, + {:sqlitex, "~> 1.4.2"}, {:cowboy, "~> 2.4.0"} ] end diff --git a/mix.lock b/mix.lock index cbf2422..d290bb7 100644 --- a/mix.lock +++ b/mix.lock @@ -2,6 +2,8 @@ "certifi": {:hex, :certifi, "2.3.1", "d0f424232390bf47d82da8478022301c561cf6445b5b5fb6a84d49a9e76d2639", [:rebar3], [{:parse_trans, "3.2.0", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, "cowboy": {:hex, :cowboy, "2.4.0", "f1b72fabe9c8a5fc64ac5ac85fb65474d64733d1df52a26fad5d4ba3d9f70a9f", [:rebar3], [{:cowlib, "~> 2.3.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.5.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"}, "cowlib": {:hex, :cowlib, "2.3.0", "bbd58ef537904e4f7c1dd62e6aa8bc831c8183ce4efa9bd1150164fe15be4caa", [:rebar3], [], "hexpm"}, + "decimal": {:hex, :decimal, "1.5.0", "b0433a36d0e2430e3d50291b1c65f53c37d56f83665b43d79963684865beab68", [:mix], [], "hexpm"}, + "esqlite": {:hex, :esqlite, "0.2.4", "3a8a352c190afe2d6b828b252a6fbff65b5cc1124647f38b15bdab3bf6fd4b3e", [:rebar3], [], "hexpm"}, "hackney": {:hex, :hackney, "1.12.1", "8bf2d0e11e722e533903fe126e14d6e7e94d9b7983ced595b75f532e04b7fdc7", [:rebar3], [{:certifi, "2.3.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, "httpoison": {:hex, :httpoison, "1.1.1", "96ed7ab79f78a31081bb523eefec205fd2900a02cda6dbc2300e7a1226219566", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "idna": {:hex, :idna, "5.1.1", "cbc3b2fa1645113267cc59c760bafa64b2ea0334635ef06dbac8801e42f7279c", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, @@ -9,6 +11,7 @@ "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"}, "parse_trans": {:hex, :parse_trans, "3.2.0", "2adfa4daf80c14dc36f522cf190eb5c4ee3e28008fc6394397c16f62a26258c2", [:rebar3], [], "hexpm"}, "ranch": {:hex, :ranch, "1.5.0", "f04166f456790fee2ac1aa05a02745cc75783c2bfb26d39faf6aefc9a3d3a58a", [:rebar3], [], "hexpm"}, + "sqlitex": {:hex, :sqlitex, "1.4.2", "b18f2b53cefbc9cca0bd17d51386f9caa7cf341144cb314e5cd9fd2a1f9b0845", [:mix], [{:decimal, "~> 1.1", [hex: :decimal, repo: "hexpm", optional: false]}, {:esqlite, "~> 0.2.4", [hex: :esqlite, repo: "hexpm", optional: false]}], "hexpm"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.3.1", "a1f612a7b512638634a603c8f401892afbf99b8ce93a45041f8aaca99cadb85e", [:rebar3], [], "hexpm"}, }