diff options
| author | Kj Tsanaktsidis <kjtsanaktsidis@groq.com> | 2025-09-07 15:39:01 +1000 |
|---|---|---|
| committer | Kj Tsanaktsidis <kjtsanaktsidis@groq.com> | 2025-09-07 15:39:01 +1000 |
| commit | 6ad580f49e7412eb428b45b4fa03039f17fb5c8e (patch) | |
| tree | 6e49c1dab1ccf2738fba2d1084a02d8b5b04ae19 | |
| parent | 7c4275017db7b31da2bd9299c83e28ead981b5ed (diff) | |
script it
| -rw-r--r-- | flake.nix | 38 | ||||
| -rw-r--r-- | kj-laptop01/configuration.nix | 2 | ||||
| -rw-r--r-- | nixos-update.rb | 127 |
3 files changed, 138 insertions, 29 deletions
@@ -49,38 +49,20 @@ let pkgs = nixpkgs-stable.legacyPackages.${system}; - install-script = pkgs.writers.writeRubyBin "install" { - libraries = []; - } /* ruby */ '' - require 'tmpdir' - require 'open3' - require 'json' - require 'fileutils' + nixos-update = pkgs.writers.writeRubyBin "nixos-update" { + libraries = [ pkgs.rubyPackages.tty-command ]; + runtimeInputs = [ + pkgs.sops + pkgs.nixos-anywhere + pkgs.nixos-rebuild + ]; + } (builtins.readFile ./nixos-update.rb); - system_flake = ARGV[0] - ENV['SOPS_AGE_KEY_FILE'] ||= File.expand_path("~/.config/sops/age/keys.txt") - sops_exe = "${pkgs.sops}/bin/sops" - nixos_anywhere_exe = "${pkgs.nixos-anywhere}/bin/nixos-anywhere" - - secret_data_raw, status = Open3.capture2(sops_exe, "decrypt", "--output-type", "json", "#{system_flake}/secrets.yaml") - raise "Failed to decrypt secrets.yaml" unless status.success? - secret_data = JSON.parse(secret_data_raw) - - Dir.mktmpdir("secrets") do |secret_dir| - FileUtils.mkdir_p(File.join(secret_dir, 'copy_dir/etc/ssh')) - File.write(File.join(secret_dir, 'copy_dir/etc/ssh/ssh_host_ed25519_key'), secret_data["ssh_host_key_ed25519"]) - File.write(File.join(secret_dir, 'luks_passphrase'), secret_data["luks_passphrase"]) - - system nixos_anywhere_exe, "--disk-encryption-keys", File.join(secret_dir, 'luks_passphrase'), - "--extra-files", File.join(secret_dir, 'copy_dir'), "--flake", ".##{system_flake}", *ARGV[1..-1], - exception: true - end - ''; in { - install = { + nixos-update = { type = "app"; - program = "${install-script}/bin/install"; + program = "${nixos-update}/bin/nixos-update"; }; }); }; diff --git a/kj-laptop01/configuration.nix b/kj-laptop01/configuration.nix index 2ad9ebd..ae4c54d 100644 --- a/kj-laptop01/configuration.nix +++ b/kj-laptop01/configuration.nix @@ -40,7 +40,7 @@ isNormalUser = true; description = "KJ Tsanaktsidis"; group = "kjtsanaktsidis"; - extraGroups = [ "wheel" ]; + extraGroups = [ "wheel" "networkmanager" ]; hashedPasswordFile = config.sops.secrets.kj_hashed_password.path; openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAC/BtvW1c1RbBI8eeGo7oOH2y9byBaxWVDHsErgaE+s kjtsanaktsidis@KJMacbookGroq.local" diff --git a/nixos-update.rb b/nixos-update.rb new file mode 100644 index 0000000..b6f3607 --- /dev/null +++ b/nixos-update.rb @@ -0,0 +1,127 @@ +#!/usr/bin/env ruby + +require 'tmpdir' +require 'json' +require 'fileutils' +require 'tty-command' +require 'etc' +require 'optparse' + +class NixOSUpdater + def initialize + @options = parse_options + @system_flake = ARGV[0] + @target_host = ARGV[1] + + validate_args! + + ENV['SOPS_AGE_KEY_FILE'] ||= File.expand_path('~/.config/sops/age/keys.txt') + end + + def run + if @options[:install] + perform_install + else + perform_update + end + end + + private + + def parse_options + options = {} + + OptionParser.new do |opts| + opts.banner = 'Usage: nixos-update.rb [--install] --system-def <def> --target <target>' + + opts.on('--install', 'Perform initial installation with nixos-anywhere') do + options[:install] = true + end + + opts.on('-h', '--help', 'Show this help message') do + puts opts + exit + end + + opts.on('--system-def', 'what system configuration to install') do |defn| + @system_def = defn + end + + opts.on('--target', 'what user@host to install to') do |target| + @target = target + end + + opts.on('--build-on', 'what user@host to build on') do |build_on| + @build_on = build_on + end + end.parse! + + options + end + + def validate_args! + if @system_def.nil? + warn 'Error: --system-def argument is required' + exit 1 + end + + @target = "#{Etc.getlogin}@#{@system_def}" if @target.nil? + @build_on = @target if @build_on.nil? && RUBY_PLATFORM !~ /linux/ + end + + def decrypt_secrets + cmd = TTY::Command.new(printer: :null) + result = cmd.run(sops_exe, 'decrypt', '--output-type', 'json', "#{@system_flake}/secrets.yaml") + JSON.parse(result.out) + end + + def perform_install + puts "### Performing initial installation of #{@system_flake} to #{@target_host} ###" + + secrets = decrypt_secrets + + Dir.mktmpdir('secrets') do |dir| + FileUtils.mkdir_p("#{dir}/copy_dir/etc/ssh") + File.write("#{dir}/copy_dir/etc/ssh/ssh_host_ed25519_key", secrets['ssh_host_key_ed25519']) + File.write("#{dir}/luks_passphrase", secrets['luks_passphrase']) + + cmd_args = [ + 'nixos-anywhere', + '--disk-encryption-keys', "#{dir}/luks_passphrase", "#{dir}/luks_passphrase", + '--extra-files', "#{dir}/copy_dir", + '--flake', ".##{@system_flake}" + ] + + cmd_args << '--build-on-remote' if RUBY_PLATFORM !~ /linux/ + cmd_args << @target_host + + # Execute nixos-anywhere + cmd = TTY::Command.new + cmd.run(*cmd_args) + end + end + + def perform_update + puts "### Updating #{@system_flake} configuration on #{@target_host} ###" + + cmd_args = [ + 'nixos-rebuild-ng', + 'switch', + '--flake', ".##{@system_flake}", + '--sudo', '--ask-sudo-passowrd' + ] + + if @target_host + cmd_args << '--target-host' << @target_host + cmd_args << '--use-remote-sudo' + end + + cmd_args << '--build-on' << @build_on if @build_on + + cmd = TTY::Command.new + cmd.run(*cmd_args) + end +end + +# Run the updater +NixOSUpdater.new.run |
