ALPHA: wire is a tool to deploy nixos systems
wire.althaea.zone/
1{
2 lib,
3 name,
4 config,
5 ...
6}:
7let
8 inherit (lib) types;
9in
10{
11 imports =
12 let
13 inherit (lib) mkAliasOptionModule;
14 in
15 [
16 (mkAliasOptionModule [ "deployment" "targetHost" ] [ "deployment" "target" "hosts" ])
17 (mkAliasOptionModule [ "deployment" "targetUser" ] [ "deployment" "target" "user" ])
18 (mkAliasOptionModule [ "deployment" "targetPort" ] [ "deployment" "target" "port" ])
19 ];
20
21 options.deployment = {
22 target = lib.mkOption {
23 type = types.submodule {
24 imports = [
25 (lib.mkAliasOptionModule [ "host" ] [ "hosts" ])
26 ];
27 options = {
28 hosts = lib.mkOption {
29 type = types.coercedTo types.str lib.singleton (types.listOf types.str);
30 description = "IPs or hostnames to attempt to connect to. They are tried in order.";
31 default = lib.singleton name;
32 apply = lib.unique;
33 };
34 user = lib.mkOption {
35 type = types.str;
36 description = "User to use for ssh.";
37 default = "root";
38 };
39 port = lib.mkOption {
40 type = types.int;
41 default = 22;
42 description = "SSH port to use.";
43 };
44 };
45 };
46 description = "Describes the target for this node";
47 default = { };
48 };
49
50 buildOnTarget = lib.mkOption {
51 type = types.bool;
52 default = false;
53 description = "Whether to build the system on the target host or not.";
54 };
55
56 allowLocalDeployment = lib.mkOption {
57 type = types.bool;
58 default = true;
59 description = "Whether to allow or deny this node being applied to localhost when the host's hostname matches the
60 node's name.";
61 };
62
63 tags = lib.mkOption {
64 type = types.listOf types.str;
65 default = [ ];
66 description = "Tags for node.";
67 example = [
68 "arm"
69 "cloud"
70 ];
71 };
72
73 _keys = lib.mkOption {
74 internal = true;
75 readOnly = true;
76 };
77
78 _hostPlatform = lib.mkOption {
79 internal = true;
80 readOnly = true;
81 };
82
83 keys = lib.mkOption {
84 type = types.attrsOf (
85 types.submodule (
86 {
87 name,
88 config,
89 ...
90 }:
91 {
92 imports =
93 let
94 inherit (lib) mkAliasOptionModule;
95 in
96 [
97 (mkAliasOptionModule [ "keyFile" ] [ "source" ])
98 (mkAliasOptionModule [ "keyCommand" ] [ "source" ])
99 (mkAliasOptionModule [ "text" ] [ "source" ])
100 ];
101 options = {
102 name = lib.mkOption {
103 type = types.str;
104 default = name;
105 description = "Filename of the secret.";
106 };
107 destDir = lib.mkOption {
108 type = types.path;
109 default = "/run/keys/";
110 description = "Destination directory for the secret. Change this to something other than `/run/keys/` for keys to persist past reboots.";
111 };
112 path = lib.mkOption {
113 internal = true;
114 type = types.path;
115 default = "${config.destDir}/${config.name}";
116 };
117 group = lib.mkOption {
118 type = types.str;
119 default = "root";
120 description = "Group to own the key. If this group does not exist this will silently fail and the key will be owned by gid 0.";
121 };
122 user = lib.mkOption {
123 type = types.str;
124 default = "root";
125 description = "User to own the key. If this user does not exist this will silently fail and the key will be owned by uid 0.";
126 };
127 permissions = lib.mkOption {
128 type = types.str;
129 default = "0600";
130 description = "Unix Octal permissions, in string format, for the key.";
131 };
132 source = lib.mkOption {
133 type = types.oneOf [
134 types.str
135 types.path
136 (types.listOf types.str)
137 ];
138 description = "Source of the key. Either a path to a file, a literal string, or a command to generate the key.";
139 };
140 uploadAt = lib.mkOption {
141 type = types.enum [
142 "pre-activation"
143 "post-activation"
144 ];
145 default = "pre-activation";
146 description = "When to upload the key. Either `pre-activation` or `post-activation`.";
147 };
148 environment = lib.mkOption {
149 type = types.attrsOf types.str;
150 default = { };
151 description = "Key-Value environment variables to use when creating the key if the key source is a command.";
152 };
153 };
154 }
155 )
156 );
157 description = "Secrets to be deployed to the node.";
158 default = { };
159 example = {
160 "wireless.env" = {
161 source = [
162 "gpg"
163 "--decrypt"
164 "secrets/wireless.env.gpg"
165 ];
166 destDir = "/etc/keys/";
167 };
168
169 "arbfile.txt" = {
170 source = ./arbfile.txt;
171 destDir = "/etc/arbs/";
172 };
173
174 "arberfile.txt" = {
175 source = ''
176 Hello World
177 '';
178 destDir = "/etc/arbs/";
179 };
180 };
181 };
182 };
183
184 config = {
185 deployment = {
186 _keys = lib.mapAttrsToList (
187 _: value:
188 value
189 // {
190 source = {
191 # Attach type to internally tag serde enum
192 t = builtins.replaceStrings [ "path" "string" "list" ] [ "Path" "String" "Command" ] (
193 builtins.typeOf value.source
194 );
195 c = value.source;
196 };
197 }
198 ) config.deployment.keys;
199
200 _hostPlatform = config.nixpkgs.hostPlatform.system;
201 };
202 };
203}