ALPHA: wire is a tool to deploy nixos systems wire.althaea.zone/
at rollback-hacking 224 lines 7.0 kB view raw
1# SPDX-License-Identifier: AGPL-3.0-or-later 2# Copyright 2024-2025 wire Contributors 3 4{ 5 lib, 6 name, 7 ... 8}: 9let 10 inherit (lib) types; 11in 12{ 13 imports = 14 let 15 inherit (lib) mkAliasOptionModule; 16 in 17 [ 18 (mkAliasOptionModule [ "deployment" "targetHost" ] [ "deployment" "target" "hosts" ]) 19 (mkAliasOptionModule [ "deployment" "targetUser" ] [ "deployment" "target" "user" ]) 20 (mkAliasOptionModule [ "deployment" "targetPort" ] [ "deployment" "target" "port" ]) 21 ]; 22 23 options.deployment = { 24 target = lib.mkOption { 25 type = types.submodule { 26 imports = [ 27 (lib.mkAliasOptionModule [ "host" ] [ "hosts" ]) 28 ]; 29 options = { 30 hosts = lib.mkOption { 31 type = types.coercedTo types.str lib.singleton (types.listOf types.str); 32 description = "IPs or hostnames to attempt to connect to. They are tried in order."; 33 default = lib.singleton name; 34 apply = lib.unique; 35 }; 36 user = lib.mkOption { 37 type = types.str; 38 description = "User to use for SSH. The user must be atleast `wheel` and must use an SSH key or similar 39 non-interactive login method. More information can be found at https://wire.althaea.zone/guides/non-root-user"; 40 default = "root"; 41 }; 42 port = lib.mkOption { 43 type = types.int; 44 default = 22; 45 description = "SSH port to use."; 46 }; 47 }; 48 }; 49 description = "Describes the target for this node"; 50 default = { }; 51 }; 52 53 rollback = lib.mkOption { 54 type = types.bool; 55 default = true; 56 description = "Attempt to rollback this node if it cannot be contacted after activation."; 57 }; 58 59 buildOnTarget = lib.mkOption { 60 type = types.bool; 61 default = false; 62 description = "Whether to build the system on the target host or not."; 63 }; 64 65 allowLocalDeployment = lib.mkOption { 66 type = types.bool; 67 default = true; 68 description = "Whether to allow or deny this node being applied to localhost when the host's hostname matches the 69 node's name."; 70 }; 71 72 tags = lib.mkOption { 73 type = types.listOf types.str; 74 default = [ ]; 75 description = "Tags for node."; 76 example = [ 77 "arm" 78 "cloud" 79 ]; 80 }; 81 82 privilegeEscalationCommand = lib.mkOption { 83 type = types.listOf types.str; 84 description = "Command to elevate."; 85 default = [ 86 "sudo" 87 "--" 88 ]; 89 }; 90 91 replaceUnknownProfiles = lib.mkOption { 92 type = types.bool; 93 description = "No-op, colmena compatibility"; 94 default = true; 95 }; 96 97 sshOptions = lib.mkOption { 98 type = types.listOf types.str; 99 description = "No-op, colmena compatibility"; 100 default = [ ]; 101 }; 102 103 _keys = lib.mkOption { 104 internal = true; 105 readOnly = true; 106 }; 107 108 _hostPlatform = lib.mkOption { 109 internal = true; 110 readOnly = true; 111 }; 112 113 keys = lib.mkOption { 114 type = types.attrsOf ( 115 types.submodule ( 116 { 117 name, 118 config, 119 ... 120 }: 121 { 122 imports = 123 let 124 inherit (lib) mkAliasOptionModule; 125 in 126 [ 127 (mkAliasOptionModule [ "keyFile" ] [ "source" ]) 128 (mkAliasOptionModule [ "keyCommand" ] [ "source" ]) 129 (mkAliasOptionModule [ "text" ] [ "source" ]) 130 ]; 131 options = { 132 name = lib.mkOption { 133 type = types.str; 134 default = name; 135 description = "Filename of the secret."; 136 }; 137 destDir = lib.mkOption { 138 type = types.path; 139 default = "/run/keys/"; 140 description = "Destination directory for the secret. Change this to something other than `/run/keys/` for keys to persist past reboots."; 141 }; 142 path = lib.mkOption { 143 internal = true; 144 type = types.path; 145 default = 146 if lib.hasSuffix "/" config.destDir then 147 "${config.destDir}${config.name}" 148 else 149 "${config.destDir}/${config.name}"; 150 description = "Path that the key is deployed to."; 151 }; 152 service = lib.mkOption { 153 internal = true; 154 type = types.str; 155 default = "${config.name}-key.service"; 156 description = "Name of the systemd service that represents this key."; 157 }; 158 group = lib.mkOption { 159 type = types.str; 160 default = "root"; 161 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."; 162 }; 163 user = lib.mkOption { 164 type = types.str; 165 default = "root"; 166 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."; 167 }; 168 permissions = lib.mkOption { 169 type = types.str; 170 default = "0600"; 171 description = "Unix Octal permissions, in string format, for the key."; 172 }; 173 source = lib.mkOption { 174 type = types.oneOf [ 175 types.str 176 types.path 177 (types.listOf types.str) 178 ]; 179 description = "Source of the key. Either a path to a file, a literal string, or a command to generate the key."; 180 }; 181 uploadAt = lib.mkOption { 182 type = types.enum [ 183 "pre-activation" 184 "post-activation" 185 ]; 186 default = "pre-activation"; 187 description = "When to upload the key. Either `pre-activation` or `post-activation`."; 188 }; 189 environment = lib.mkOption { 190 type = types.attrsOf types.str; 191 default = { }; 192 description = "Key-Value environment variables to use when creating the key if the key source is a command."; 193 }; 194 }; 195 } 196 ) 197 ); 198 description = "Secrets to be deployed to the node."; 199 default = { }; 200 example = { 201 "wireless.env" = { 202 source = [ 203 "gpg" 204 "--decrypt" 205 "secrets/wireless.env.gpg" 206 ]; 207 destDir = "/etc/keys/"; 208 }; 209 210 "arbfile.txt" = { 211 source = ./arbfile.txt; 212 destDir = "/etc/arbs/"; 213 }; 214 215 "arberfile.txt" = { 216 source = '' 217 Hello World 218 ''; 219 destDir = "/etc/arbs/"; 220 }; 221 }; 222 }; 223 }; 224}