at 21.11-pre 4.6 kB view raw
1pkgs: with pkgs.lib; 2 3rec { 4 5 # Copy configuration files to avoid having the entire sources in the system closure 6 copyFile = filePath: pkgs.runCommandNoCC (builtins.unsafeDiscardStringContext (builtins.baseNameOf filePath)) {} '' 7 cp ${filePath} $out 8 ''; 9 10 # Check whenever fileSystem is needed for boot. NOTE: Make sure 11 # pathsNeededForBoot is closed under the parent relationship, i.e. if /a/b/c 12 # is in the list, put /a and /a/b in as well. 13 pathsNeededForBoot = [ "/" "/nix" "/nix/store" "/var" "/var/log" "/var/lib" "/etc" ]; 14 fsNeededForBoot = fs: fs.neededForBoot || elem fs.mountPoint pathsNeededForBoot; 15 16 # Check whenever `b` depends on `a` as a fileSystem 17 fsBefore = a: b: a.mountPoint == b.device 18 || hasPrefix "${a.mountPoint}${optionalString (!(hasSuffix "/" a.mountPoint)) "/"}" b.mountPoint; 19 20 # Escape a path according to the systemd rules, e.g. /dev/xyzzy 21 # becomes dev-xyzzy. FIXME: slow. 22 escapeSystemdPath = s: 23 replaceChars ["/" "-" " "] ["-" "\\x2d" "\\x20"] 24 (removePrefix "/" s); 25 26 # Returns a system path for a given shell package 27 toShellPath = shell: 28 if types.shellPackage.check shell then 29 "/run/current-system/sw${shell.shellPath}" 30 else if types.package.check shell then 31 throw "${shell} is not a shell package" 32 else 33 shell; 34 35 /* Recurse into a list or an attrset, searching for attrs named like 36 the value of the "attr" parameter, and return an attrset where the 37 names are the corresponding jq path where the attrs were found and 38 the values are the values of the attrs. 39 40 Example: 41 recursiveGetAttrWithJqPrefix { 42 example = [ 43 { 44 irrelevant = "not interesting"; 45 } 46 { 47 ignored = "ignored attr"; 48 relevant = { 49 secret = { 50 _secret = "/path/to/secret"; 51 }; 52 }; 53 } 54 ]; 55 } "_secret" -> { ".example[1].relevant.secret" = "/path/to/secret"; } 56 */ 57 recursiveGetAttrWithJqPrefix = item: attr: 58 let 59 recurse = prefix: item: 60 if item ? ${attr} then 61 nameValuePair prefix item.${attr} 62 else if isAttrs item then 63 map (name: recurse (prefix + "." + name) item.${name}) (attrNames item) 64 else if isList item then 65 imap0 (index: item: recurse (prefix + "[${toString index}]") item) item 66 else 67 []; 68 in listToAttrs (flatten (recurse "" item)); 69 70 /* Takes an attrset and a file path and generates a bash snippet that 71 outputs a JSON file at the file path with all instances of 72 73 { _secret = "/path/to/secret" } 74 75 in the attrset replaced with the contents of the file 76 "/path/to/secret" in the output JSON. 77 78 When a configuration option accepts an attrset that is finally 79 converted to JSON, this makes it possible to let the user define 80 arbitrary secret values. 81 82 Example: 83 If the file "/path/to/secret" contains the string 84 "topsecretpassword1234", 85 86 genJqSecretsReplacementSnippet { 87 example = [ 88 { 89 irrelevant = "not interesting"; 90 } 91 { 92 ignored = "ignored attr"; 93 relevant = { 94 secret = { 95 _secret = "/path/to/secret"; 96 }; 97 }; 98 } 99 ]; 100 } "/path/to/output.json" 101 102 would generate a snippet that, when run, outputs the following 103 JSON file at "/path/to/output.json": 104 105 { 106 "example": [ 107 { 108 "irrelevant": "not interesting" 109 }, 110 { 111 "ignored": "ignored attr", 112 "relevant": { 113 "secret": "topsecretpassword1234" 114 } 115 } 116 ] 117 } 118 */ 119 genJqSecretsReplacementSnippet = genJqSecretsReplacementSnippet' "_secret"; 120 121 # Like genJqSecretsReplacementSnippet, but allows the name of the 122 # attr which identifies the secret to be changed. 123 genJqSecretsReplacementSnippet' = attr: set: output: 124 let 125 secrets = recursiveGetAttrWithJqPrefix set attr; 126 in '' 127 if [[ -h '${output}' ]]; then 128 rm '${output}' 129 fi 130 '' 131 + concatStringsSep 132 "\n" 133 (imap1 (index: name: "export secret${toString index}=$(<'${secrets.${name}}')") 134 (attrNames secrets)) 135 + "\n" 136 + "${pkgs.jq}/bin/jq >'${output}' '" 137 + concatStringsSep 138 " | " 139 (imap1 (index: name: ''${name} = $ENV.secret${toString index}'') 140 (attrNames secrets)) 141 + '' 142 ' <<'EOF' 143 ${builtins.toJSON set} 144 EOF 145 ''; 146}