Skip to content

Commit 66d74f9

Browse files
committed
Initial darwin-multi agent
1 parent 9a031b7 commit 66d74f9

2 files changed

Lines changed: 192 additions & 0 deletions

File tree

flake.nix

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,31 @@
194194
};
195195
};
196196

197+
darwinModules.multi-agent-service =
198+
{ lib, pkgs, ...}:
199+
{
200+
_file = "${toString ./flake.nix}#darwinModules.multi-agent-service";
201+
imports = [
202+
agentFromFlakeModule_multi
203+
./internal/nix/nix-darwin/multi.nix
204+
];
205+
206+
# This module replaces what's provided by nix-darwin
207+
disabledModules = [ "services/hercules-ci-agent" ];
208+
209+
options = let inherit (lib) types mkOption; in
210+
{
211+
services.hercules-ci-agents =
212+
mkOption {
213+
type = types.attrsOf (
214+
types.submoduleWith {
215+
modules = [{ config.settings.labels.module = "darwin-multi-service"; }];
216+
}
217+
);
218+
};
219+
};
220+
};
221+
197222
# A nix-darwin module with more defaults set for machines that serve as agents
198223
darwinModules.agent-profile =
199224
{ lib, pkgs, ... }:

internal/nix/nix-darwin/multi.nix

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# Module similar to (flake).agent-service or the NixOS-bundled module, but
2+
# supports running multiple instance of the agent, each with their own files,
3+
# user, etc.
4+
5+
systemArgs@{ pkgs, config, lib, ... }:
6+
let
7+
inherit (lib) mkIf mkDefault types mkOption;
8+
inherit (lib.strings) match;
9+
topConfig = config;
10+
literalDocBook = lib.literalDocBook or lib.literalExample;
11+
literalExpression = lib.literalExpression or lib.literalExample;
12+
13+
submodule = { config, options, name, ... }:
14+
let
15+
inherit (import ../settings.nix { inherit pkgs lib; }) format makeSettingsOptions;
16+
configFile = format.generate "hercules-ci-agent${suffix}.json" config.settings;
17+
command = "${config.package}/bin/hercules-ci-agent --config ${configFile}";
18+
testCommand = "${command} --test-configuration";
19+
suffix = if name == "" then "" else "-${name}";
20+
user = topConfig.users.users.${config.user};
21+
in
22+
{
23+
options = {
24+
systemConfig = lib.mkOption {
25+
internal = true;
26+
type = types.unspecified; # A function from module arguments to config.
27+
};
28+
package = mkOption {
29+
description = ''
30+
Package containing the bin/hercules-ci-agent executable.
31+
'';
32+
type = types.package;
33+
default = pkgs.hercules-ci-agent;
34+
defaultText = literalExpression "pkgs.hercules-ci-agent";
35+
};
36+
user = mkOption {
37+
type = types.str;
38+
default = "_hercules-ci-agent";
39+
};
40+
group = mkOption {
41+
type = types.str;
42+
default = "_hercules-ci-agent";
43+
};
44+
logFile = mkOption {
45+
type = types.str;
46+
default = "/var/log/hci-agent${suffix}.log";
47+
};
48+
baseDirectory = mkOption {
49+
type = types.str;
50+
default = "/var/lib/hercules-ci-agent${if name == "" then "" else "/${name}"}"; # Almost a `suffix` logic, but yield subdir
51+
};
52+
} // makeSettingsOptions { cfg = config; opt = options; };
53+
config = let cfg = config; in
54+
{
55+
settings = {
56+
_module.args = {
57+
packageOption = options.package;
58+
inherit pkgs;
59+
};
60+
baseDirectory = cfg.baseDirectory;
61+
nixUserIsTrusted = true;
62+
labels =
63+
let
64+
mkIfNotNull = x: mkIf (x != null) x;
65+
in
66+
{
67+
darwin.label = topConfig.system.darwinLabel;
68+
darwin.revision = topConfig.system.darwinRevision;
69+
darwin.version = topConfig.system.darwinVersion;
70+
darwin.nix.daemon = topConfig.nix.useDaemon;
71+
darwin.nix.sandbox = topConfig.nix.settings.sandbox;
72+
};
73+
};
74+
systemConfig = { config, ... }: {
75+
launchd.daemons."hci-agent${suffix}" = {
76+
script = "exec ${command}";
77+
78+
path = [ config.nix.package ];
79+
environment = {
80+
NIX_SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
81+
};
82+
83+
serviceConfig.KeepAlive = true;
84+
serviceConfig.RunAtLoad = true;
85+
serviceConfig.StandardErrorPath = cfg.logFile;
86+
serviceConfig.StandardOutPath = cfg.logFile;
87+
serviceConfig.GroupName = cfg.user;
88+
serviceConfig.UserName = cfg.group;
89+
serviceConfig.WorkingDirectory = cfg.baseDirectory;
90+
serviceConfig.WatchPaths = [
91+
cfg.settings.staticSecretsDirectory
92+
];
93+
};
94+
95+
nix.settings.trusted-users = [ cfg.user ];
96+
97+
system.activationScripts.preActivation.text = ''
98+
touch '${cfg.logFile}'
99+
chown ${toString user.uid}:${toString user.gid} '${cfg.logFile}'
100+
if ! test -d ${cfg.baseDirectory}; then
101+
mkdir -p ${cfg.baseDirectory}
102+
chown ${toString user.uid}:${toString user.gid} ${cfg.baseDirectory}
103+
fi
104+
'';
105+
};
106+
};
107+
};
108+
109+
mergeSub =
110+
f: lib.mkMerge (map (sub: f (sub.systemConfig systemArgs)) (lib.attrValues config.services.hercules-ci-agents));
111+
in
112+
{
113+
options = {
114+
services.hercules-ci-agents = lib.mkOption {
115+
type = types.attrsOf (types.submoduleWith {
116+
modules = [ submodule ];
117+
});
118+
default = { };
119+
description = ''
120+
Multiple instances of hercules-ci-agent can be specified.
121+
122+
If you specify an instance named `""`, it will behave just as the `services.hercules-ci-agent` options did.
123+
- User: `hercules-ci-agent`
124+
- Default base directory: `/var/lib/hercules-ci-agent`
125+
126+
Otherwise:
127+
- User: `hercules-ci-agent` (on darwin we use same username)
128+
- Default base directory: `/var/lib/hercules-ci-agent-''${name}`
129+
'';
130+
};
131+
};
132+
133+
config = lib.mkMerge [
134+
{
135+
nix = mergeSub (c: c.nix);
136+
launchd = mergeSub (c: c.launchd);
137+
system = mergeSub (c: c.system);
138+
}
139+
{
140+
nix.extraOptions = lib.mkIf (config.services.hercules-ci-agents != { }) ''
141+
# A store path that was missing at first may well have finished building,
142+
# even shortly after the previous lookup. This *also* applies to the daemon.
143+
narinfo-cache-negative-ttl = 0
144+
'';
145+
146+
users.knownGroups = [ "hercules-ci-agent" "_hercules-ci-agent" ];
147+
users.knownUsers = [ "hercules-ci-agent" "_hercules-ci-agent" ];
148+
149+
users.users._hercules-ci-agent = {
150+
uid = mkDefault 399;
151+
gid = mkDefault config.users.groups._hercules-ci-agent.gid;
152+
home = mkDefault "/var/lib/hercules-ci-agent";
153+
name = "_hercules-ci-agent";
154+
createHome = true;
155+
shell = "/bin/bash";
156+
description = "System user for the Hercules CI Agent";
157+
};
158+
users.groups._hercules-ci-agent = {
159+
gid = mkDefault 32001;
160+
name = "_hercules-ci-agent";
161+
description = "System group for the Hercules CI Agent";
162+
};
163+
}
164+
];
165+
166+
meta.maintainers = [ ];
167+
}

0 commit comments

Comments
 (0)