diff --git a/data/eval-machines.nix b/data/eval-machines.nix index 20f465e..369754f 100644 --- a/data/eval-machines.nix +++ b/data/eval-machines.nix @@ -5,18 +5,21 @@ let network = import networkExpr; nwPkgs = network.network.pkgs or { }; lib = network.network.lib or nwPkgs.lib or (import ); - evalConfig = network.network.evalConfig or ((nwPkgs.path or ) - + "/nixos/lib/eval-config.nix"); - runCommand = - network.network.runCommand or nwPkgs.runCommand or (import - { }).runCommand; + evalConfig = + network.network.evalConfig or ((nwPkgs.path or ) + "/nixos/lib/eval-config.nix"); + runCommand = network.network.runCommand or nwPkgs.runCommand or (import { }).runCommand; in with lib; let defaults = network.defaults or { }; - modules = { machineName, nodes, check }: + modules = + { + machineName, + nodes, + check, + }: [ # Get the configuration of this machine from each network # expression, attaching _file attributes so the NixOS module @@ -25,47 +28,53 @@ let defaults - ({ lib, ... }: { - key = "deploy-stuff"; - imports = [ ./options.nix ]; - # Make documentation builds deterministic, even with our - # tempdir module imports. - documentation.nixos.extraModuleSources = [ ../. ]; - # Provide a default hostname and deployment target equal - # to the attribute name of the machine in the model. - networking.hostName = lib.mkDefault machineName; - deployment.targetHost = lib.mkDefault machineName; - - # If network.pkgs is set, mkDefault nixpkgs.pkgs - nixpkgs.pkgs = lib.mkIf (nwPkgs != { }) (lib.mkDefault nwPkgs); - - # Avoid the deprecated evalConfig arguments by - # setting them here instead. - _module = { - args = { - name = machineName; - inherit nodes; + ( + { lib, ... }: + { + key = "deploy-stuff"; + imports = [ ./options.nix ]; + # Make documentation builds deterministic, even with our + # tempdir module imports. + documentation.nixos.extraModuleSources = [ ../. ]; + # Provide a default hostname and deployment target equal + # to the attribute name of the machine in the model. + networking.hostName = lib.mkDefault machineName; + deployment.targetHost = lib.mkDefault machineName; + + # If network.pkgs is set, mkDefault nixpkgs.pkgs + nixpkgs.pkgs = lib.mkIf (nwPkgs != { }) (lib.mkDefault nwPkgs); + + # Avoid the deprecated evalConfig arguments by + # setting them here instead. + _module = { + args = { + name = machineName; + inherit nodes; + }; + inherit check; }; - inherit check; - }; - }) - ] ++ optional (network ? _file) { inherit (network) _file; }; - - machineNames = attrNames (removeAttrs network [ - "network" - "defaults" - "resources" - "require" - "_file" - ]); + } + ) + ] + ++ optional (network ? _file) { inherit (network) _file; }; + + machineNames = attrNames ( + removeAttrs network [ + "network" + "defaults" + "resources" + "require" + "_file" + ] + ); in rec { # Unchecked configuration of all machines. # Using unchecked config evaluation allows each machine to access other machines # configuration without recursing as full evaluation is prevented - uncheckedNodes = listToAttrs (map - (machineName: { + uncheckedNodes = listToAttrs ( + map (machineName: { name = machineName; value = import evalConfig { # Force decide system in module system @@ -76,12 +85,12 @@ rec { nodes = uncheckedNodes; }; }; - }) - machineNames); + }) machineNames + ); # Compute the definitions of the machines. - nodes = listToAttrs (map - (machineName: { + nodes = listToAttrs ( + map (machineName: { name = machineName; value = import evalConfig { # Force decide system in module system @@ -92,8 +101,8 @@ rec { nodes = uncheckedNodes; }; }; - }) - machineNames); + }) machineNames + ); deploymentInfoModule = { deployment = { @@ -105,27 +114,37 @@ rec { # Phase 1: evaluate only the deployment attributes. info = - let network' = network; - in rec { - - machines = flip mapAttrs nodes (n: v': - let v = scrubOptionValue v'; - in { + let + network' = network; + in + rec { + + machines = flip mapAttrs nodes ( + n: v': + let + v = scrubOptionValue v'; + in + { inherit (v.config.deployment) - targetHost targetPort targetUser secrets preDeployChecks healthChecks buildOnly - substituteOnDestination tags; + targetHost + targetPort + targetUser + secrets + preDeployChecks + healthChecks + buildOnly + substituteOnDestination + tags + ; name = n; - nixosRelease = v.config.system.nixos.release or (removeSuffix - v.config.system.nixos.version.suffix - v.config.system.nixos.version); - nixConfig = mapAttrs - (n: v: - if builtins.isString v then - v - else - throw "nix option '${n}' must have a string typed value") - (network'.network.nixConfig or { }); - }); + nixosRelease = + v.config.system.nixos.release + or (removeSuffix v.config.system.nixos.version.suffix v.config.system.nixos.version); + nixConfig = mapAttrs ( + n: v: if builtins.isString v then v else throw "nix option '${n}' must have a string typed value" + ) (network'.network.nixConfig or { }); + } + ); machineList = map (key: getAttr key machines) (attrNames machines); network = network'.network or { }; @@ -141,25 +160,39 @@ rec { }; # Phase 2: build complete machine configurations. - machines = { argsFile, buildTargets ? null }: + machines = + { + argsFile, + buildTargets ? null, + }: let fileArgs = builtins.fromJSON (builtins.readFile argsFile); nodes' = filterAttrs (n: _v: elem n fileArgs.Names) nodes; in - runCommand "morph" { preferLocalBuild = true; } - (if buildTargets == null then '' - mkdir -p $out - ${toString (mapAttrsToList (nodeName: nodeDef: '' - ln -s ${nodeDef.config.system.build.toplevel} $out/${nodeName} - '') nodes')} - '' else '' - mkdir -p $out - ${toString (mapAttrsToList (nodeName: nodeDef: '' - mkdir -p $out/${nodeName} - ${toString (mapAttrsToList (buildName: buildFn: '' - ln -s ${buildFn nodeDef} $out/${nodeName}/${buildName} - '') buildTargets)} - '') nodes')} - ''); + runCommand "morph" { preferLocalBuild = true; } ( + if buildTargets == null then + '' + mkdir -p $out + ${toString ( + mapAttrsToList (nodeName: nodeDef: '' + ln -s ${nodeDef.config.system.build.toplevel} $out/${nodeName} + '') nodes' + )} + '' + else + '' + mkdir -p $out + ${toString ( + mapAttrsToList (nodeName: nodeDef: '' + mkdir -p $out/${nodeName} + ${toString ( + mapAttrsToList (buildName: buildFn: '' + ln -s ${buildFn nodeDef} $out/${nodeName}/${buildName} + '') buildTargets + )} + '') nodes' + )} + '' + ); } diff --git a/data/options.nix b/data/options.nix index fa72d4c..ee448d3 100644 --- a/data/options.nix +++ b/data/options.nix @@ -1,4 +1,9 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: with lib; with lib.types; @@ -50,8 +55,7 @@ let action = mkOption { default = [ ]; type = listOf str; - description = - "Action to perform on remote host after uploading secret."; + description = "Action to perform on remote host after uploading secret."; }; mkDirs = mkOption { @@ -66,7 +70,10 @@ let uploadAt = mkOption { default = "pre-activation"; - type = enum [ "pre-activation" "post-activation" ]; + type = enum [ + "pre-activation" + "post-activation" + ]; description = '' When to upload the secret. @@ -268,7 +275,9 @@ in # all derived dependencies. config.system.extraDependencies = let - cmds = concatMap (h: h.cmd) (config.deployment.preDeployChecks.cmd ++ config.deployment.healthChecks.cmd); + cmds = concatMap (h: h.cmd) ( + config.deployment.preDeployChecks.cmd ++ config.deployment.healthChecks.cmd + ); in [ (pkgs.writeText "healthcheck-commands.txt" (concatStringsSep "\n" cmds)) ]; } diff --git a/default.nix b/default.nix index 8a767c1..18f4db7 100644 --- a/default.nix +++ b/default.nix @@ -1,4 +1,8 @@ -{ nixpkgs ? import ./nixpkgs.nix, pkgs ? import nixpkgs { }, version ? "dev" }: +{ + nixpkgs ? import ./nixpkgs.nix, + pkgs ? import nixpkgs { }, + version ? "dev", +}: pkgs.buildGoModule rec { name = "morph-unstable-${version}"; @@ -6,8 +10,10 @@ pkgs.buildGoModule rec { src = pkgs.nix-gitignore.gitignoreSource [ ] ./.; - ldflags = - [ "-X main.version=${version}" "-X main.assetRoot=${placeholder "lib"}" ]; + ldflags = [ + "-X main.version=${version}" + "-X main.assetRoot=${placeholder "lib"}" + ]; vendorHash = "sha256-zQlMtbXgrH83zrcIoOuFhb2tYCeQ1pz4UQUvRIsLMCE=="; @@ -16,7 +22,10 @@ pkgs.buildGoModule rec { cp -v ./data/*.nix $lib ''; - outputs = [ "out" "lib" ]; + outputs = [ + "out" + "lib" + ]; meta = { homepage = "https://github.com/DBCDK/morph"; diff --git a/examples/healthchecks.nix b/examples/healthchecks.nix index 871b814..4c13352 100644 --- a/examples/healthchecks.nix +++ b/examples/healthchecks.nix @@ -1,5 +1,7 @@ -let pkgs = import (import ../nixpkgs.nix) { }; -in { +let + pkgs = import (import ../nixpkgs.nix) { }; +in +{ network = { inherit pkgs; description = "health check demo hosts"; @@ -24,10 +26,16 @@ in { deployment = { healthChecks = { - cmd = [{ - cmd = [ "true" "one argument" "another argument" ]; - description = "Testing that 'true' works."; - }]; + cmd = [ + { + cmd = [ + "true" + "one argument" + "another argument" + ]; + description = "Testing that 'true' works."; + } + ]; http = [ { @@ -40,8 +48,7 @@ in { { scheme = "https"; port = 443; - host = - "some-other-host.example.com"; # defaults to the hostname of the host if unset + host = "some-other-host.example.com"; # defaults to the hostname of the host if unset path = "/health"; description = "Check whether $imaginaryService is running."; } diff --git a/examples/secrets.nix b/examples/secrets.nix index d96e01a..27c4eea 100644 --- a/examples/secrets.nix +++ b/examples/secrets.nix @@ -1,5 +1,7 @@ -let pkgs = import (import ../nixpkgs.nix) { }; -in { +let + pkgs = import (import ../nixpkgs.nix) { }; +in +{ network = { inherit pkgs; description = "webserver with secrets"; @@ -14,7 +16,12 @@ in { owner.user = "nginx"; owner.group = "root"; permissions = "0400"; # this is the default - action = [ "sudo" "systemctl" "reload" "nginx.service" ]; + action = [ + "sudo" + "systemctl" + "reload" + "nginx.service" + ]; }; }; }; diff --git a/examples/simple.nix b/examples/simple.nix index 7324e13..7d82623 100644 --- a/examples/simple.nix +++ b/examples/simple.nix @@ -1,9 +1,16 @@ -let pkgs = import (import ../nixpkgs.nix) { }; -in { +let + pkgs = import (import ../nixpkgs.nix) { }; +in +{ network = { inherit pkgs; description = "simple hosts"; - ordering = { tags = [ "db" "web" ]; }; + ordering = { + tags = [ + "db" + "web" + ]; + }; }; "web01" = _: { diff --git a/flake.nix b/flake.nix index d56ac59..cae086a 100644 --- a/flake.nix +++ b/flake.nix @@ -4,7 +4,9 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; - flake-utils = { url = "github:numtide/flake-utils"; }; + flake-utils = { + url = "github:numtide/flake-utils"; + }; pre-commit-hooks = { url = "github:cachix/pre-commit-hooks.nix"; @@ -18,8 +20,16 @@ }; }; - outputs = { self, pre-commit-hooks, nixpkgs, flake-utils, treefmt-nix }: - flake-utils.lib.eachDefaultSystem (system: + outputs = + { + self, + pre-commit-hooks, + nixpkgs, + flake-utils, + treefmt-nix, + }: + flake-utils.lib.eachDefaultSystem ( + system: let # Current Version of Morph # TODO: this sucks... @@ -43,15 +53,20 @@ let # some treefmt formatters are not supported in pre-commit-hooks we # filter them out for now. - toFilter = [ "yamlfmt" ]; + toFilter = [ + "yamlfmt" + "nixfmt" + ]; filterFn = n: _v: (!builtins.elem n toFilter); - treefmtFormatters = - pkgs.lib.mapAttrs (_n: v: { inherit (v) enable; }) - (pkgs.lib.filterAttrs filterFn (import ./treefmt.nix).programs); + treefmtFormatters = pkgs.lib.mapAttrs (_n: v: { inherit (v) enable; }) ( + pkgs.lib.filterAttrs filterFn (import ./treefmt.nix).programs + ); in pre-commit-hooks.lib.${system}.run { src = ./.; - hooks = treefmtFormatters; + hooks = treefmtFormatters // { + nixfmt-rfc-style.enable = true; + }; }; }; @@ -81,7 +96,10 @@ cp -v ./data/*.nix $lib ''; - outputs = [ "out" "lib" ]; + outputs = [ + "out" + "lib" + ]; meta = { homepage = "https://github.com/DBCDK/morph"; @@ -90,5 +108,6 @@ }; }; }; - }); + } + ); } diff --git a/healthchecks/healthchecks.go b/healthchecks/healthchecks.go index 836f6ef..5fb7e1c 100644 --- a/healthchecks/healthchecks.go +++ b/healthchecks/healthchecks.go @@ -44,7 +44,7 @@ func PerformChecks(sshContext *ssh.SSHContext, checkName string, host Host, heal for !done { select { case <-doneChan: - fmt.Fprintln(os.Stderr, checkName + " OK") + fmt.Fprintln(os.Stderr, checkName+" OK") done = true case <-timeoutChan: fmt.Fprintf(os.Stderr, "Timeout: Gave up waiting for %s to complete after %d seconds\n", checkName, timeout) diff --git a/nixos/tests/integration_tests.nix b/nixos/tests/integration_tests.nix index 69d211d..eff3f26 100644 --- a/nixos/tests/integration_tests.nix +++ b/nixos/tests/integration_tests.nix @@ -1,6 +1,5 @@ { nixosTest, packages, ... }: - nixosTest { name = "morph-deployment-test"; nodes = @@ -19,9 +18,7 @@ nixosTest { inherit services boot; environment.systemPackages = [ packages.morph ]; }; - target = _: { - inherit services boot; - }; + target = _: { inherit services boot; }; }; testScript = '' start_all() diff --git a/nixpkgs.nix b/nixpkgs.nix index 364108e..e3d708d 100644 --- a/nixpkgs.nix +++ b/nixpkgs.nix @@ -1,3 +1,2 @@ # Intentionally impure for CI against nixos-unstable -builtins.fetchTarball - "https://github.com/NixOS/nixpkgs/archive/nixos-unstable.tar.gz" +builtins.fetchTarball "https://github.com/NixOS/nixpkgs/archive/nixos-unstable.tar.gz" diff --git a/shell.nix b/shell.nix index 6d9f379..8d96f74 100644 --- a/shell.nix +++ b/shell.nix @@ -1,5 +1,10 @@ -{ nixpkgs ? import ./nixpkgs.nix, pkgs ? import nixpkgs { } }: +{ + nixpkgs ? import ./nixpkgs.nix, + pkgs ? import nixpkgs { }, +}: -let morph = pkgs.callPackage ./default.nix { }; +let + morph = pkgs.callPackage ./default.nix { }; -in pkgs.mkShell { inputsFrom = [ morph ]; } +in +pkgs.mkShell { inputsFrom = [ morph ]; } diff --git a/treefmt.nix b/treefmt.nix index e4f1216..c83fb16 100644 --- a/treefmt.nix +++ b/treefmt.nix @@ -1,9 +1,8 @@ { projectRootFile = "flake.nix"; programs = { - nixpkgs-fmt.enable = true; # nix formatter + nixfmt.enable = true; # nix formatter statix.enable = true; # nix static analysis - deadnix.enable = true; # find dead nix code shellcheck.enable = true; # bash/shell taplo.enable = true; # toml yamlfmt.enable = true; # yaml @@ -11,9 +10,14 @@ }; settings = { formatter = { - nixpkgs-fmt.includes = [ "*.nix" "./data/*" ]; - statix.includes = [ "*.nix" "./data/*" ]; - deadnix.includes = [ "*.nix" "./data/*" ]; + nixfmt.includes = [ + "*.nix" + "./data/*" + ]; + statix.includes = [ + "*.nix" + "./data/*" + ]; }; }; }