Merge pull request #249211 from oddlama/feat-influxdb-provision

nixos/influxdb2: automatic initial setup and nixos tests

Nick Cao 2dadab48 fea0315e

Changed files
+157 -7
nixos
modules
services
databases
tests
pkgs
servers
nosql
influxdb2
+117 -7
nixos/modules/services/databases/influxdb2.nix
···
{ config, lib, pkgs, ... }:
-
with lib;
-
let
format = pkgs.formats.json { };
cfg = config.services.influxdb2;
configFile = format.generate "config.json" cfg.settings;
···
description = lib.mdDoc ''configuration options for influxdb2, see <https://docs.influxdata.com/influxdb/v2.0/reference/config-options> for details.'';
type = format.type;
};
};
};
config = mkIf cfg.enable {
-
assertions = [{
-
assertion = !(builtins.hasAttr "bolt-path" cfg.settings) && !(builtins.hasAttr "engine-path" cfg.settings);
-
message = "services.influxdb2.config: bolt-path and engine-path should not be set as they are managed by systemd";
-
}];
systemd.services.influxdb2 = {
description = "InfluxDB is an open-source, distributed, time series database";
···
LimitNOFILE = 65536;
KillMode = "control-group";
Restart = "on-failure";
};
};
users.extraUsers.influxdb2 = {
···
users.extraGroups.influxdb2 = {};
};
-
meta.maintainers = with lib.maintainers; [ nickcao ];
}
···
{ config, lib, pkgs, ... }:
+
let
+
inherit
+
(lib)
+
escapeShellArg
+
hasAttr
+
literalExpression
+
mkEnableOption
+
mkIf
+
mkOption
+
types
+
;
format = pkgs.formats.json { };
cfg = config.services.influxdb2;
configFile = format.generate "config.json" cfg.settings;
···
description = lib.mdDoc ''configuration options for influxdb2, see <https://docs.influxdata.com/influxdb/v2.0/reference/config-options> for details.'';
type = format.type;
};
+
+
provision = {
+
enable = mkEnableOption "initial database setup and provisioning";
+
+
initialSetup = {
+
organization = mkOption {
+
type = types.str;
+
example = "main";
+
description = "Primary organization name";
+
};
+
+
bucket = mkOption {
+
type = types.str;
+
example = "example";
+
description = "Primary bucket name";
+
};
+
+
username = mkOption {
+
type = types.str;
+
default = "admin";
+
description = "Primary username";
+
};
+
+
retention = mkOption {
+
type = types.str;
+
default = "0";
+
description = ''
+
The duration for which the bucket will retain data (0 is infinite).
+
Accepted units are `ns` (nanoseconds), `us` or `µs` (microseconds), `ms` (milliseconds),
+
`s` (seconds), `m` (minutes), `h` (hours), `d` (days) and `w` (weeks).
+
'';
+
};
+
+
passwordFile = mkOption {
+
type = types.path;
+
description = "Password for primary user. Don't use a file from the nix store!";
+
};
+
+
tokenFile = mkOption {
+
type = types.path;
+
description = "API Token to set for the admin user. Don't use a file from the nix store!";
+
};
+
};
+
};
};
};
config = mkIf cfg.enable {
+
assertions = [
+
{
+
assertion = !(hasAttr "bolt-path" cfg.settings) && !(hasAttr "engine-path" cfg.settings);
+
message = "services.influxdb2.config: bolt-path and engine-path should not be set as they are managed by systemd";
+
}
+
];
systemd.services.influxdb2 = {
description = "InfluxDB is an open-source, distributed, time series database";
···
LimitNOFILE = 65536;
KillMode = "control-group";
Restart = "on-failure";
+
LoadCredential = [
+
"admin-password:${cfg.provision.initialSetup.passwordFile}"
+
"admin-token:${cfg.provision.initialSetup.tokenFile}"
+
];
};
+
+
path = [pkgs.influxdb2-cli];
+
+
# Mark if this is the first startup so postStart can do the initial setup
+
preStart = mkIf cfg.provision.enable ''
+
if ! test -e "$STATE_DIRECTORY/influxd.bolt"; then
+
touch "$STATE_DIRECTORY/.first_startup"
+
fi
+
'';
+
+
postStart = let
+
initCfg = cfg.provision.initialSetup;
+
in mkIf cfg.provision.enable (
+
''
+
set -euo pipefail
+
export INFLUX_HOST="http://"${escapeShellArg (cfg.settings.http-bind-address or "localhost:8086")}
+
+
# Wait for the influxdb server to come online
+
count=0
+
while ! influx ping &>/dev/null; do
+
if [ "$count" -eq 300 ]; then
+
echo "Tried for 30 seconds, giving up..."
+
exit 1
+
fi
+
+
if ! kill -0 "$MAINPID"; then
+
echo "Main server died, giving up..."
+
exit 1
+
fi
+
+
sleep 0.1
+
count=$((count++))
+
done
+
+
# Do the initial database setup. Pass /dev/null as configs-path to
+
# avoid saving the token as the active config.
+
if test -e "$STATE_DIRECTORY/.first_startup"; then
+
influx setup \
+
--configs-path /dev/null \
+
--org ${escapeShellArg initCfg.organization} \
+
--bucket ${escapeShellArg initCfg.bucket} \
+
--username ${escapeShellArg initCfg.username} \
+
--password "$(< "$CREDENTIALS_DIRECTORY/admin-password")" \
+
--token "$(< "$CREDENTIALS_DIRECTORY/admin-token")" \
+
--retention ${escapeShellArg initCfg.retention} \
+
--force >/dev/null
+
+
rm -f "$STATE_DIRECTORY/.first_startup"
+
fi
+
''
+
);
};
users.extraUsers.influxdb2 = {
···
users.extraGroups.influxdb2 = {};
};
+
meta.maintainers = with lib.maintainers; [ nickcao oddlama ];
}
+1
nixos/tests/all-tests.nix
···
iftop = handleTest ./iftop.nix {};
incron = handleTest ./incron.nix {};
influxdb = handleTest ./influxdb.nix {};
initrd-network-openvpn = handleTest ./initrd-network-openvpn {};
initrd-network-ssh = handleTest ./initrd-network-ssh {};
initrd-luks-empty-passphrase = handleTest ./initrd-luks-empty-passphrase.nix {};
···
iftop = handleTest ./iftop.nix {};
incron = handleTest ./incron.nix {};
influxdb = handleTest ./influxdb.nix {};
+
influxdb2 = handleTest ./influxdb2.nix {};
initrd-network-openvpn = handleTest ./initrd-network-openvpn {};
initrd-network-ssh = handleTest ./initrd-network-ssh {};
initrd-luks-empty-passphrase = handleTest ./initrd-luks-empty-passphrase.nix {};
+36
nixos/tests/influxdb2.nix
···
···
+
import ./make-test-python.nix ({ pkgs, ...} : {
+
name = "influxdb2";
+
meta = with pkgs.lib.maintainers; {
+
maintainers = [ offline ];
+
};
+
+
nodes.machine = { lib, ... }: {
+
environment.systemPackages = [ pkgs.influxdb2-cli ];
+
services.influxdb2.enable = true;
+
services.influxdb2.provision = {
+
enable = true;
+
initialSetup = {
+
organization = "default";
+
bucket = "default";
+
passwordFile = pkgs.writeText "admin-pw" "ExAmPl3PA55W0rD";
+
tokenFile = pkgs.writeText "admin-token" "verysecureadmintoken";
+
};
+
};
+
};
+
+
testScript = { nodes, ... }:
+
let
+
tokenArg = "--token verysecureadmintoken";
+
in ''
+
machine.wait_for_unit("influxdb2.service")
+
+
machine.fail("curl --fail -X POST 'http://localhost:8086/api/v2/signin' -u admin:wrongpassword")
+
machine.succeed("curl --fail -X POST 'http://localhost:8086/api/v2/signin' -u admin:ExAmPl3PA55W0rD")
+
+
out = machine.succeed("influx org list ${tokenArg}")
+
assert "default" in out
+
+
out = machine.succeed("influx bucket list ${tokenArg} --org default")
+
assert "default" in out
+
'';
+
})
+3
pkgs/servers/nosql/influxdb2/default.nix
···
, rustPlatform
, stdenv
, libiconv
}:
let
···
tags = [ "assets" ];
ldflags = [ "-X main.commit=v${version}" "-X main.version=${version}" ];
meta = with lib; {
description = "An open-source distributed time series database";
···
, rustPlatform
, stdenv
, libiconv
+
, nixosTests
}:
let
···
tags = [ "assets" ];
ldflags = [ "-X main.commit=v${version}" "-X main.version=${version}" ];
+
+
passthru.tests = { inherit (nixosTests) influxdb2; };
meta = with lib; {
description = "An open-source distributed time series database";