tangled
alpha
login
or
join now
pyrox.dev
/
nixpkgs
0
fork
atom
lol
0
fork
atom
overview
issues
pulls
pipelines
nixos/glance: allow specifying secret settings
gepbird.tngl.sh
11 months ago
27d160b6
5e5402ec
verified
This commit was signed with the committer's
known signature
.
gepbird.tngl.sh
SSH Key Fingerprint:
SHA256:MP2UpIRtJpbFFqyucP431H/FPCfn58UhEUTro4lXtRs=
+98
-13
2 changed files
expand all
collapse all
unified
split
nixos
modules
services
web-apps
glance.nix
tests
glance.nix
+56
-7
nixos/modules/services/web-apps/glance.nix
reviewed
···
8
8
cfg = config.services.glance;
9
9
10
10
inherit (lib)
11
11
+
catAttrs
12
12
+
concatMapStrings
13
13
+
getExe
11
14
mkEnableOption
12
12
-
mkPackageOption
13
13
-
mkOption
14
15
mkIf
15
15
-
getExe
16
16
+
mkOption
17
17
+
mkPackageOption
16
18
types
19
19
+
;
20
20
+
21
21
+
inherit (builtins)
22
22
+
concatLists
23
23
+
isAttrs
24
24
+
isList
25
25
+
attrNames
26
26
+
getAttr
17
27
;
18
28
19
29
settingsFormat = pkgs.formats.yaml { };
30
30
+
settingsFile = settingsFormat.generate "glance.yaml" cfg.settings;
31
31
+
mergedSettingsFile = "/run/glance/glance.yaml";
20
32
in
21
33
{
22
34
options.services.glance = {
···
69
81
{ type = "calendar"; }
70
82
{
71
83
type = "weather";
72
72
-
location = "Nivelles, Belgium";
84
84
+
location = {
85
85
+
_secret = "/var/lib/secrets/glance/location";
86
86
+
};
73
87
}
74
88
];
75
89
}
···
84
98
Configuration written to a yaml file that is read by glance. See
85
99
<https://github.com/glanceapp/glance/blob/main/docs/configuration.md>
86
100
for more.
101
101
+
102
102
+
Settings containing secret data should be set to an
103
103
+
attribute set containing the attribute
104
104
+
<literal>_secret</literal> - a string pointing to a file
105
105
+
containing the value the option should be set to. See the
106
106
+
example in `services.glance.settings.pages` at the weather widget
107
107
+
with a location secret to get a better picture of this.
87
108
'';
88
109
};
89
110
···
102
123
description = "Glance feed dashboard server";
103
124
wantedBy = [ "multi-user.target" ];
104
125
after = [ "network.target" ];
126
126
+
path = [ pkgs.replace-secret ];
105
127
106
128
serviceConfig = {
107
107
-
ExecStart =
129
129
+
ExecStartPre =
108
130
let
109
109
-
glance-yaml = settingsFormat.generate "glance.yaml" cfg.settings;
131
131
+
findSecrets =
132
132
+
data:
133
133
+
if isAttrs data then
134
134
+
if data ? _secret then
135
135
+
[ data ]
136
136
+
else
137
137
+
concatLists (map (attr: findSecrets (getAttr attr data)) (attrNames data))
138
138
+
else if isList data then
139
139
+
concatLists (map findSecrets data)
140
140
+
else
141
141
+
[ ];
142
142
+
secretPaths = catAttrs "_secret" (findSecrets cfg.settings);
143
143
+
mkSecretReplacement = secretPath: ''
144
144
+
replace-secret ${
145
145
+
lib.escapeShellArgs [
146
146
+
"_secret: ${secretPath}"
147
147
+
secretPath
148
148
+
mergedSettingsFile
149
149
+
]
150
150
+
}
151
151
+
'';
152
152
+
secretReplacements = concatMapStrings mkSecretReplacement secretPaths;
110
153
in
111
111
-
"${getExe cfg.package} --config ${glance-yaml}";
154
154
+
# Use "+" to run as root because the secrets may not be accessible to glance
155
155
+
"+"
156
156
+
+ pkgs.writeShellScript "glance-start-pre" ''
157
157
+
install -m 600 -o $USER ${settingsFile} ${mergedSettingsFile}
158
158
+
${secretReplacements}
159
159
+
'';
160
160
+
ExecStart = "${getExe cfg.package} --config ${mergedSettingsFile}";
112
161
WorkingDirectory = "/var/lib/glance";
113
162
StateDirectory = "glance";
114
163
RuntimeDirectory = "glance";
+42
-6
nixos/tests/glance.nix
reviewed
···
5
5
6
6
nodes = {
7
7
machine_default =
8
8
-
{ pkgs, ... }:
8
8
+
{ ... }:
9
9
{
10
10
services.glance = {
11
11
enable = true;
12
12
};
13
13
};
14
14
15
15
-
machine_custom_port =
15
15
+
machine_configured =
16
16
{ pkgs, ... }:
17
17
+
let
18
18
+
# Do not use this in production. This will make the secret world-readable
19
19
+
# in the Nix store
20
20
+
secrets.glance-location.path = builtins.toString (
21
21
+
pkgs.writeText "location-secret" "Nivelles, Belgium"
22
22
+
);
23
23
+
in
17
24
{
18
25
services.glance = {
19
26
enable = true;
20
20
-
settings.server.port = 5678;
27
27
+
settings = {
28
28
+
server.port = 5678;
29
29
+
pages = [
30
30
+
{
31
31
+
name = "Home";
32
32
+
columns = [
33
33
+
{
34
34
+
size = "full";
35
35
+
widgets = [
36
36
+
{ type = "calendar"; }
37
37
+
{
38
38
+
type = "weather";
39
39
+
location = {
40
40
+
_secret = secrets.glance-location.path;
41
41
+
};
42
42
+
}
43
43
+
];
44
44
+
}
45
45
+
];
46
46
+
}
47
47
+
];
48
48
+
};
21
49
};
22
50
};
23
51
};
···
25
53
extraPythonPackages =
26
54
p: with p; [
27
55
beautifulsoup4
56
56
+
pyyaml
57
57
+
types-pyyaml
28
58
types-beautifulsoup4
29
59
];
30
60
31
61
testScript = ''
32
62
from bs4 import BeautifulSoup
63
63
+
import yaml
33
64
34
65
machine_default.start()
35
66
machine_default.wait_for_unit("glance.service")
36
67
machine_default.wait_for_open_port(8080)
37
68
38
38
-
machine_custom_port.start()
39
39
-
machine_custom_port.wait_for_unit("glance.service")
40
40
-
machine_custom_port.wait_for_open_port(5678)
69
69
+
machine_configured.start()
70
70
+
machine_configured.wait_for_unit("glance.service")
71
71
+
machine_configured.wait_for_open_port(5678)
41
72
42
73
soup = BeautifulSoup(machine_default.succeed("curl http://localhost:8080"))
43
74
expected_version = "v${config.nodes.machine_default.services.glance.package.version}"
44
75
assert any(a.text == expected_version for a in soup.select(".footer a"))
76
76
+
77
77
+
yaml_contents = machine_configured.succeed("cat /run/glance/glance.yaml")
78
78
+
yaml_parsed = yaml.load(yaml_contents, Loader=yaml.FullLoader)
79
79
+
location = yaml_parsed["pages"][0]["columns"][0]["widgets"][1]["location"]
80
80
+
assert location == "Nivelles, Belgium"
45
81
'';
46
82
47
83
meta.maintainers = [ lib.maintainers.drupol ];