diff --git a/README.md b/README.md index dea7211..bc6ed11 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# System Stats Daemon +# Systant An Elixir application that runs as a systemd daemon to: 1. Publish system stats to MQTT every 30 seconds @@ -9,10 +9,10 @@ An Elixir application that runs as a systemd daemon to: Edit `config/config.exs` to configure MQTT connection: ```elixir -config :system_stats_daemon, SystemStatsDaemon.MqttClient, +config :systant, Systant.MqttClient, host: "localhost", port: 1883, - client_id: "system_stats_daemon", + client_id: "systant", username: nil, password: nil, stats_topic: "system/stats", @@ -35,24 +35,24 @@ mix run --no-halt # Production release MIX_ENV=prod mix release -_build/prod/rel/system_stats_daemon/bin/system_stats_daemon start +_build/prod/rel/systant/bin/systant start ``` ## Systemd Installation 1. Build production release 2. Copy binary to `/usr/local/bin/` -3. Copy `system_stats_daemon.service` to `/etc/systemd/system/` +3. Copy `systant.service` to `/etc/systemd/system/` 4. Enable and start: ```bash -sudo systemctl enable system_stats_daemon -sudo systemctl start system_stats_daemon +sudo systemctl enable systant +sudo systemctl start systant ``` ## Features -- Publishes "Hello world" stats every 30 seconds to `system/stats` topic +- Publishes "Hello from systant" stats every 30 seconds to `system/stats` topic - Listens on `system/commands` topic and logs received messages - Configurable MQTT connection settings - Runs as systemd daemon with auto-restart diff --git a/config/config.exs b/config/config.exs index ea54911..e0b812f 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,9 +1,9 @@ import Config -config :system_stats_daemon, SystemStatsDaemon.MqttClient, +config :systant, Systant.MqttClient, host: "mqtt.home", port: 1883, - client_id: "system_stats_daemon", + client_id: "systant", username: "mqtt", password: "pleasework", stats_topic: "system/stats", diff --git a/lib/system_stats_daemon.ex b/lib/systant.ex similarity index 52% rename from lib/system_stats_daemon.ex rename to lib/systant.ex index d026f5d..1023347 100644 --- a/lib/system_stats_daemon.ex +++ b/lib/systant.ex @@ -1,6 +1,6 @@ -defmodule SystemStatsDaemon do +defmodule Systant do @moduledoc """ - Documentation for `SystemStatsDaemon`. + Documentation for `Systant`. """ @doc """ @@ -8,7 +8,7 @@ defmodule SystemStatsDaemon do ## Examples - iex> SystemStatsDaemon.hello() + iex> Systant.hello() :world """ diff --git a/lib/system_stats_daemon/application.ex b/lib/systant/application.ex similarity index 69% rename from lib/system_stats_daemon/application.ex rename to lib/systant/application.ex index cd99cf2..f320546 100644 --- a/lib/system_stats_daemon/application.ex +++ b/lib/systant/application.ex @@ -1,4 +1,4 @@ -defmodule SystemStatsDaemon.Application do +defmodule Systant.Application do # See https://hexdocs.pm/elixir/Application.html # for more information on OTP Applications @moduledoc false @@ -8,12 +8,12 @@ defmodule SystemStatsDaemon.Application do @impl true def start(_type, _args) do children = [ - {SystemStatsDaemon.MqttClient, []} + {Systant.MqttClient, []} ] # See https://hexdocs.pm/elixir/Supervisor.html # for other strategies and supported options - opts = [strategy: :one_for_one, name: SystemStatsDaemon.Supervisor] + opts = [strategy: :one_for_one, name: Systant.Supervisor] Supervisor.start_link(children, opts) end end diff --git a/lib/system_stats_daemon/mqtt_client.ex b/lib/systant/mqtt_client.ex similarity index 92% rename from lib/system_stats_daemon/mqtt_client.ex rename to lib/systant/mqtt_client.ex index 7a66d67..9c832e3 100644 --- a/lib/system_stats_daemon/mqtt_client.ex +++ b/lib/systant/mqtt_client.ex @@ -1,4 +1,4 @@ -defmodule SystemStatsDaemon.MqttClient do +defmodule Systant.MqttClient do use GenServer require Logger @@ -11,7 +11,7 @@ defmodule SystemStatsDaemon.MqttClient do end def init(_opts) do - config = Application.get_env(:system_stats_daemon, __MODULE__) + config = Application.get_env(:systant, __MODULE__) Logger.info("Starting MQTT client with config: #{inspect(config)}") # Use a unique client ID to avoid conflicts @@ -32,7 +32,7 @@ defmodule SystemStatsDaemon.MqttClient do # Send immediate hello message hello_msg = %{ - message: "Hello - system_stats_daemon started", + message: "Hello - systant started", timestamp: DateTime.utc_now() |> DateTime.to_iso8601(), hostname: get_hostname() } @@ -64,7 +64,7 @@ defmodule SystemStatsDaemon.MqttClient do defp publish_stats(config, client_id) do stats = %{ - message: "Hello from system_stats_daemon", + message: "Hello from systant", timestamp: DateTime.utc_now() |> DateTime.to_iso8601(), hostname: get_hostname() } diff --git a/mix.exs b/mix.exs index 8b8be29..3a0f432 100644 --- a/mix.exs +++ b/mix.exs @@ -3,7 +3,7 @@ defmodule SystemStatsDaemon.MixProject do def project do [ - app: :system_stats_daemon, + app: :systant, version: "0.1.0", elixir: "~> 1.18", start_permanent: Mix.env() == :prod, @@ -16,7 +16,7 @@ defmodule SystemStatsDaemon.MixProject do def application do [ extra_applications: [:logger], - mod: {SystemStatsDaemon.Application, []} + mod: {Systant.Application, []} ] end @@ -30,7 +30,7 @@ defmodule SystemStatsDaemon.MixProject do defp releases do [ - system_stats_daemon: [ + systant: [ include_executables_for: [:unix], applications: [runtime_tools: :permanent] ] diff --git a/nixos-module.nix b/nixos-module.nix index d6bdf98..cf9d08b 100644 --- a/nixos-module.nix +++ b/nixos-module.nix @@ -3,15 +3,15 @@ with lib; let - cfg = config.services.system-stats-daemon; + cfg = config.services.systant; in { - options.services.system-stats-daemon = { - enable = mkEnableOption "System Stats MQTT Daemon"; + options.services.systant = { + enable = mkEnableOption "Systant MQTT Daemon"; package = mkOption { type = types.package; - description = "The system-stats-daemon package to use"; + description = "The systant package to use"; }; mqttHost = mkOption { @@ -58,8 +58,8 @@ in }; config = mkIf cfg.enable { - systemd.services.system-stats-daemon = { - description = "System Stats MQTT Daemon"; + systemd.services.systant = { + description = "Systant MQTT Daemon"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; @@ -77,13 +77,13 @@ in Type = "exec"; User = "root"; Group = "root"; - ExecStart = "${cfg.package}/bin/system_stats_daemon start"; - ExecStop = "${cfg.package}/bin/system_stats_daemon stop"; + ExecStart = "${cfg.package}/bin/systant start"; + ExecStop = "${cfg.package}/bin/systant stop"; Restart = "always"; RestartSec = 5; StandardOutput = "journal"; StandardError = "journal"; - SyslogIdentifier = "system_stats_daemon"; + SyslogIdentifier = "systant"; WorkingDirectory = "${cfg.package}"; # Security settings diff --git a/systant.nix b/systant.nix new file mode 100644 index 0000000..3b3d81c --- /dev/null +++ b/systant.nix @@ -0,0 +1,59 @@ +{ lib +, stdenv +, fetchgit +, elixir +, erlang +, rebar3 +, git +}: + +stdenv.mkDerivation rec { + pname = "systant"; + version = "0.1.0"; + + src = fetchgit { + url = "https://git.ryanpandya.com/ryan/systant.git"; + rev = "9d8306a64b7893ea0d25e2b08f470541fb4db7c8"; + sha256 = lib.fakeSha256; # Replace with actual hash after first build attempt + }; + + nativeBuildInputs = [ + elixir + erlang + rebar3 + git + ]; + + buildPhase = '' + runHook preBuild + + export MIX_ENV=prod + export MIX_HOME=$TMPDIR/mix + export HEX_HOME=$TMPDIR/hex + export REBAR_CACHE_DIR=$TMPDIR/rebar3 + + mix local.hex --force + mix local.rebar --force + mix deps.get --only=prod + mix release + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out + cp -r _build/prod/rel/systant/* $out/ + + runHook postInstall + ''; + + meta = with lib; { + description = "Systant - System stats MQTT daemon for monitoring system metrics"; + homepage = "https://git.ryanpandya.com/ryan/systant"; + license = licenses.mit; # Update if different + maintainers = [ ]; # Add your maintainer info if desired + platforms = platforms.linux; + }; +} \ No newline at end of file diff --git a/system_stats_daemon.service b/systant.service similarity index 61% rename from system_stats_daemon.service rename to systant.service index 5a2df27..c41a143 100644 --- a/system_stats_daemon.service +++ b/systant.service @@ -1,19 +1,19 @@ [Unit] -Description=System Stats MQTT Daemon +Description=Systant MQTT Daemon After=network.target [Service] Type=exec User=root Group=root -ExecStart=/opt/system_stats_daemon/bin/system_stats_daemon start -ExecStop=/opt/system_stats_daemon/bin/system_stats_daemon stop +ExecStart=/opt/systant/bin/systant start +ExecStop=/opt/systant/bin/systant stop Restart=always RestartSec=5 StandardOutput=journal StandardError=journal -SyslogIdentifier=system_stats_daemon -WorkingDirectory=/opt/system_stats_daemon +SyslogIdentifier=systant +WorkingDirectory=/opt/systant # Security settings - still apply restrictions where possible NoNewPrivileges=true diff --git a/test/systant_test.exs b/test/systant_test.exs new file mode 100644 index 0000000..a31bd82 --- /dev/null +++ b/test/systant_test.exs @@ -0,0 +1,8 @@ +defmodule SystantTest do + use ExUnit.Case + doctest Systant + + test "greets the world" do + assert Systant.hello() == :world + end +end diff --git a/test/system_stats_daemon_test.exs b/test/system_stats_daemon_test.exs deleted file mode 100644 index f67ef9d..0000000 --- a/test/system_stats_daemon_test.exs +++ /dev/null @@ -1,8 +0,0 @@ -defmodule SystemStatsDaemonTest do - use ExUnit.Case - doctest SystemStatsDaemon - - test "greets the world" do - assert SystemStatsDaemon.hello() == :world - end -end