I want to simplify my config, what I had before was:
{ config, ... }:
let mosquittoUsername = "10_24_0_1";
in {
sops.secrets = {
mosquittoPassword = { };
postgresqlGoskPassword = { };
};
services.gosk = { enable = true; };
services.gosk.processors = rec {
readMqtt = {
command = "read mqtt";
publishTo = 6300;
configFile = config.sops.templates.readMqtt.path;
};
writeDatabaseMapped = {
command = "write database mapped";
subscribeTo = [ readMqtt.publishTo ];
configFile = config.sops.templates.writeDatabaseMapped.path;
after = [ "container@postgresql-15-test.service" ];
};
};
sops.templates = {
readMqtt = {
content = ''
---
username: "${mosquittoUsername}"
password: "${config.sops.placeholder.mosquittoPassword}"
url: "mqtt://10.24.0.1:1883"
interval: "10s"
buffer_size: 1000
example_required_file: "${./extraFiles/test.bin}"
'';
};
writeDatabaseMapped = {
content = ''
---
url: "postgres://gosk:${config.sops.placeholder.postgresqlGoskPassword}@192.168.100.2:5432/gosk?sslmode=disable&application_name=gosk_writer_postgresql"
batch_flush_length: 100
batch_flush_interval: 1m
buffer_size: 100
number_of_workers: 1
timeout: 10s
'';
};
};
}
and the definition of the gosk service:
{ config, lib, pkgs, utils, ... }:
with lib;
let
cfg = config.services.gosk;
# Escape as required by: https://www.freedesktop.org/software/systemd/man/systemd.unit.html
escapeUnitName = name:
lib.concatMapStrings (s: if lib.isList s then "-" else s)
(builtins.split "[^a-zA-Z0-9_.\\-]+" name);
in {
options.services.gosk = {
enable = mkEnableOption "Go Signal K service";
package = lib.mkPackageOption pkgs "gosk" { };
processors = mkOption {
type = types.attrsOf (types.submodule {
options = {
enable = mkOption {
type = types.bool;
default = true;
description = "Whether or not to enable this command.";
};
command = mkOption {
type = types.separatedString " ";
default = "";
example = "write database mapped";
description = "Command to add to this gosk command.";
};
subscribeTo = mkOption {
type = with types; listOf port;
default = [ ];
example = [ 6000 6001 ];
description = "Ports to subscribe to.";
};
publishTo = mkOption {
type = with types; nullOr port;
default = null;
example = 6000;
description =
"Port to publish to, if null then this process will not publish.";
};
configFile = mkOption {
type = with types; nullOr path;
default = null;
example = ./gosk.yaml;
description =
"Configuration file in YAML format for this gosk command.";
};
after = mkOption {
type = types.listOf utils.systemdUtils.lib.unitNameType;
default = [ ];
example = [ "postgresql" ];
description = "Systemd services to wait for";
};
extraArgs = mkOption {
type = with types; listOf str;
default = [ ];
example = ''
[ "--pmport" "127.0.0.1:9203" ]
'';
description = "Extra arguments for the gosk processor.";
};
};
});
default = { };
example = literalExpression ''
{
"map ais" = {
command = "map";
subscribeTo = [ 6001 ];
publishTo = 6101;
configFile = ./gosk.yaml;
};
}
'';
description = "gosk commands to run.";
};
};
config = mkIf cfg.enable {
systemd.services = mapAttrs' (name: c:
nameValuePair "gosk-${escapeUnitName name}" (mkMerge [{
inherit (c) enable;
description = "gosk ${name}";
wantedBy = [ "multi-user.target" ];
inherit (c) after;
serviceConfig = {
ExecStart = toString ([ "${pkgs.gosk}/bin/gosk" ]
++ lib.optional (c.command != "") c.command ++ [
(concatMapStringsSep " " (url: "-s tcp://127.0.0.1:${url}")
c.subscribeTo)
] ++ lib.optional (isString c.publishURL)
"-p tcp://127.0.0.1:${c.publishTo}"
++ lib.optional (c.configFile != null)
"--config \${CREDENTIALS_DIRECTORY}/gosk.yaml" ++ c.extraArgs);
Restart = "always";
LoadCredential =
if c.configFile != null then "gosk.yaml:${c.configFile}" else "";
DynamicUser = "yes";
};
}])) cfg.processors;
# sops.templates = mapAttrs' (name: c:
# ) cfg.processors;
};
meta.maintainers = with maintainers; [ munnik ];
}
I want to join the content of the config file in the service definition so that it becomes more readable. And I don’t have to specifiy a separte sops.templates
section. Something like this:
{ config, ... }:
let mosquittoUsername = "10_24_0_1";
in {
sops.secrets = {
mosquittoPassword = { };
postgresqlGoskPassword = { };
};
services.gosk = { enable = true; };
services.gosk.processors = rec {
readMqtt = {
arguments = "read mqtt";
publishTo = 6300;
config = ''
---
username: "${mosquittoUsername}"
password: "${config.sops.placeholder.mosquittoPassword}"
url: "mqtt://10.24.0.1:1883"
interval: "10s"
buffer_size: 1000
example_required_file: "${./extraFiles/test.bin}"
'';
};
writeDatabaseMapped = {
arguments = "write database mapped";
subscribeTo = [ readMqtt.publishTo ];
config = ''
---
url: "postgres://gosk:${config.sops.placeholder.postgresqlGoskPassword}@192.168.100.2:5432/gosk?sslmode=disable&application_name=gosk_writer_postgresql"
batch_flush_length: 100
batch_flush_interval: 1m
buffer_size: 100
number_of_workers: 1
timeout: 10s
'';
after = [ "container@postgresql-15-test.service" ];
};
};
}
Therefore, I modified gosk service definition to:
{ config, lib, pkgs, utils, ... }:
with lib;
let
cfg = config.services.gosk;
# Escape as required by: https://www.freedesktop.org/software/systemd/man/systemd.unit.html
goskUnitName = name:
"gosk-" + lib.concatMapStrings (s: if lib.isList s then "-" else s)
(builtins.split "[^a-zA-Z0-9_.\\-]+" name);
in {
options.services.gosk = {
enable = mkEnableOption "Go Signal K service";
package = lib.mkPackageOption pkgs "gosk" { };
processors = mkOption {
type = types.attrsOf (types.submodule {
options = {
enable = mkOption {
type = types.bool;
default = true;
description = "Whether or not to enable this service.";
};
arguments = mkOption {
type = types.separatedString " ";
default = "";
example = "write database mapped";
description = "Arguments to add to this gosk service.";
};
subscribeTo = mkOption {
type = with types; listOf port;
default = [ ];
example = [ 6000 6001 ];
description = "Ports to subscribe to.";
};
publishTo = mkOption {
type = with types; nullOr port;
default = null;
example = 6000;
description =
"Port to publish to, if null then this process will not publish.";
};
config = mkOption {
type = with types; nullOr str;
default = null;
example = ''
---
name: "AIS"
protocol: "nmea0183"
url: "file:///dev/ttyUSBCom0" # verified
baudRate: 38400
dataBits: 8
stopBits: 1
parity: "N"
'';
description = "Configuration in YAML format for this gosk service.";
};
after = mkOption {
type = types.listOf utils.systemdUtils.lib.unitNameType;
default = [ ];
example = [ "postgresql" ];
description = "Systemd services to wait for";
};
extraArgs = mkOption {
type = with types; listOf str;
default = [ ];
example = ''
[ "--pmport" "127.0.0.1:9203" ]
'';
description = "Extra arguments for the gosk processor.";
};
};
});
default = { };
example = literalExpression ''
{
"map ais" = {
arguments = "map";
subscribeTo = [ 6001 ];
publishTo = 6101;
config = \'\'
---
name: "AIS"
protocol: "nmea0183"
url: "file:///dev/ttyUSBCom0" # verified
baudRate: 38400
dataBits: 8
stopBits: 1
parity: "N"
\'\';
};
}
'';
description = "gosk services to run.";
};
};
config = mkIf cfg.enable rec {
sops.templates = mapAttrs' (name: c:
nameValuePair (goskUnitName name) (mkMerge [{ content = c.config; }]))
cfg.processors;
systemd.services = mapAttrs' (name: c:
nameValuePair (goskUnitName name) (mkMerge [{
inherit (c) enable;
inherit (c) after;
description = "gosk ${name}";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = toString ([ "${pkgs.gosk}/bin/gosk" ]
++ lib.optional (c.arguments != "") c.arguments ++ [
(concatMapStringsSep " "
(port: "-s tcp://127.0.0.1:${toString port}") c.subscribeTo)
] ++ lib.optional (isInt c.publishTo)
"-p tcp://127.0.0.1:${toString c.publishTo}"
++ lib.optional (c.config != null)
"--config \${CREDENTIALS_DIRECTORY}/config.yaml" ++ c.extraArgs);
Restart = "always";
LoadCredential = if c.config != null then
"config.yaml:${sops.templates.${goskUnitName name}.path}"
else
"";
DynamicUser = "yes";
};
}])) cfg.processors;
};
meta.maintainers = with maintainers; [ munnik ];
}
But this results in an error:
error: attribute 'path' missing
at /nix/store/b643glfy3wal6pwz7rwk8r7h56qn0bjj-source/modules/nixos/services/gosk.nix:122:28:
121| LoadCredential = if c.config != null then
122| "config.yaml:${sops.templates.${goskUnitName name}.path}"
| ^
123| else
I tried several ways to write this but I can’t get it working. How do I refer to the sops file?