nix machine / user configurations
1#!/usr/bin/env nu 2 3use std "path add" 4use std/log 5 6path add /nix/var/nix/profiles/default/bin 7 8cd $env.NH_FLAKE 9 10# load webhook secrets 11rage -d -i ./ssh_key ./secrets/deployWebhook.age | from toml | load-env 12 13def webhook [title: string, content: string, exit_code?: number, ping?: bool = false] { 14 let type = if $exit_code == null { "⌛" } else if $exit_code == 0 { "✔️" } else { "❌" } 15 let msg = { 16 content: (if $ping { "hey <@853064602904166430>!" } else { "" }), 17 embeds: [{ 18 description: $content, 19 title: $"($type) /($title)/", 20 footer: { 21 text: $"(date now) \((sys host | get hostname)\)", 22 } 23 }] 24 } 25 26 if $exit_code == 0 or $exit_code == null { 27 log info $content 28 } else { 29 log error $content 30 } 31 http post --content-type application/json $"https://discord.com/api/webhooks/($env.WEBHOOK_ID)/($env.WEBHOOK_TOKEN)" $msg 32} 33 34def upload-paste []: any -> string { 35 let paste_url = http post -H ["user-agent" "gaze.systems terra deploy"] --content-type multipart/form-data "https://0x0.st" {file: ($in | to text | into binary), secret: true} 36 return $paste_url 37} 38 39def time-block [block]: nothing -> record { 40 let start = date now 41 let result = do $block 42 let end = date now 43 return {result: $result, elapsed: ($end - $start)} 44} 45 46let hosts = { 47 wolumonde: { 48 type: "nixos", 49 user: "root", 50 addr: "23.88.101.188", 51 }, 52 "dusk@devel.mobi": { 53 type: "home", 54 user: "dusk", 55 addr: "devel.mobi", 56 }, 57} 58 59def deploy [hostname: string] { 60 log info $"start deploy host ($hostname)" 61 let hooktitle = $"/($hostname)/deploy" 62 let hostcfg = $hosts | get $hostname 63 64 webhook $hooktitle $"=== deploy for ($hostname): started ===\n\n(sys disks | to text)\n\n(sys mem | to text)" 65 66 def run_step [action: string, block]: nothing -> bool { 67 webhook $"($hooktitle)/($action)" $"=== ($action) ($hostname) started ===" 68 let result = time-block { do $block | tee -e {print -r} | tee {print -r} | complete } 69 let failed = $result.result.exit_code != 0 70 webhook $"($hooktitle)/($action)" $"=== ($action) ($hostname) is done ===\n\ntook ($result.elapsed)\n\nlog: ($result.result | upload-paste)" $result.result.exit_code $failed 71 return $failed 72 } 73 74 let result_dir = mktemp -d | path join "result" 75 let build_cmd = { 76 match $hostcfg.type { 77 "nixos" => {nh os build --no-nom -H $hostname -o $result_dir -- -L --show-trace} 78 "home" => {nh home build --no-nom -c $hostname -o $result_dir -- -L --show-trace} 79 } 80 } 81 if (run_step "build" $build_cmd) { 82 return 83 } 84 let result_link = readlink $result_dir 85 86 let target = $"($hostcfg.user)@($hostcfg.addr)" 87 let copy_cmd = {nix copy --to $"ssh://($target)" $result_link} 88 if (run_step "copy to" $copy_cmd) { 89 return 90 } 91 92 let activate_cmd = { 93 let cmd = match $hostcfg.type { 94 "nixos" => $"sudo '($result_link)/bin/switch-to-configuration' 'switch'", 95 "home" => $"($result_link)/activate", 96 } 97 ssh $target $cmd 98 } 99 if (run_step "activate" $activate_cmd) { 100 return 101 } 102 103 webhook $hooktitle $"=== deploy for ($hostname): finished ===" 0 true 104} 105 106def update-inputs []: list<string> -> bool { 107 let inputsText = $in | str join ", " 108 let stashed = try { 109 let stash_result = git stash | complete 110 $stash_result.stdout | str contains "Saved working directory" 111 } catch { 112 false 113 } 114 log info $"trying to update inputs ($inputsText)" 115 let result = nix run .#nvfetcher -- -f $"\(($in | str join '|')\)" | complete 116 let is_ok = ($result.stdout | str contains "Changes:") 117 if $is_ok { 118 let changes_content = $result.stdout | lines | skip until {|line| $line | str contains "Changes:"} | skip 1 | str join "\n" 119 webhook $"/inputs" $"=== updated inputs ===\n\n($changes_content)" $result.exit_code 120 } 121 if $is_ok { 122 # try committing flake updates 123 try { 124 git add _sources 125 git commit -m "chore(nix): update inputs [skip ci]" 126 } 127 } else { 128 try { 129 git restore . 130 } 131 } 132 if $stashed { 133 try { 134 git stash pop 135 } 136 } 137 $is_ok 138} 139 140def main [hostname: string = "wolumonde", --only-deploy (-d)] { 141 webhook "deploy" "=== started deploying ===" 142 143 mut inputs_updated = false 144 if $only_deploy == false { 145 $inputs_updated = ["blog" "limbusart" "nsid-tracker" "tangled"] | update-inputs 146 try { 147 log info "trying to update dns records" 148 nix run ".#dns" -- push 149 } catch { |err| 150 webhook "dns" $"=== error pushing dns ===\n\n($err.msg | to text)" 1 151 } 152 } 153 154 if $hostname == "all" { 155 $hosts | columns | each {|host| deploy $host} 156 } else { 157 deploy $hostname 158 } 159 160 if $inputs_updated { 161 try { git push } 162 } 163}