A hermetic remote rebuild is when Nixinate sends a specific Nix binary to the remote first, then uses it when activating a system closure, rather than using the Nix that is already on the remote. This is defaulted to false for the time being, as the bandwidth usage can be high. This allows users to avoid the need to bootstrap the remote first by enabling flakes on the remote Nix binary.
108 lines
4.8 KiB
Nix
108 lines
4.8 KiB
Nix
{
|
||
description = "Nixinate your systems 🕶️";
|
||
inputs = {
|
||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||
};
|
||
outputs = { self, nixpkgs, ... }@inputs:
|
||
let
|
||
version = builtins.substring 0 8 self.lastModifiedDate;
|
||
supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ];
|
||
forSystems = systems: f:
|
||
nixpkgs.lib.genAttrs systems
|
||
(system: f system nixpkgs.legacyPackages.${system});
|
||
forAllSystems = forSystems supportedSystems;
|
||
nixpkgsFor = forAllSystems (system: pkgs: import nixpkgs { inherit system; overlays = [ self.overlay ]; });
|
||
in rec
|
||
{
|
||
herculesCI.ciSystems = [ "x86_64-linux" ];
|
||
overlay = final: prev: {
|
||
nixinate = {
|
||
nix = prev.pkgs.writeShellScriptBin "nix"
|
||
''${final.nixVersions.unstable}/bin/nix --experimental-features "nix-command flakes" "$@"'';
|
||
nixos-rebuild = prev.nixos-rebuild.override { inherit (final) nix; };
|
||
};
|
||
generateApps = flake:
|
||
let
|
||
machines = builtins.attrNames flake.nixosConfigurations;
|
||
validMachines = final.lib.remove "" (final.lib.forEach machines (x: final.lib.optionalString (flake.nixosConfigurations."${x}"._module.args ? nixinate) "${x}" ));
|
||
mkDeployScript = { machine, dryRun }: let
|
||
inherit (builtins) abort;
|
||
inherit (final.lib) getExe;
|
||
nix = "${getExe final.nix}";
|
||
nixos-rebuild = "${getExe final.nixos-rebuild}";
|
||
openssh = "${getExe final.openssh}";
|
||
|
||
n = flake.nixosConfigurations.${machine}._module.args.nixinate;
|
||
hermetic = n.hermetic or false;
|
||
user = n.sshUser or "root";
|
||
host = n.host;
|
||
where = n.buildOn or "remote";
|
||
remote = if where == "remote" then true else if where == "local" then false else abort "_module.args.nixinate.buildOn is not set to a valid value of 'local' or 'remote'";
|
||
switch = if dryRun then "dry-activate" else "switch";
|
||
script =
|
||
''
|
||
set -e
|
||
echo "🚀 Deploying nixosConfigurations.${machine} from ${flake}"
|
||
echo "👤 SSH User: ${user}"
|
||
echo "🌐 SSH Host: ${host}"
|
||
'' + (if remote then ''
|
||
echo "🚀 Sending flake to ${machine} via nix copy:"
|
||
( set -x; ${nix} copy ${flake} --to ssh://${user}@${host} )
|
||
'' + (if hermetic then ''
|
||
echo "🤞 Activating configuration hermetically on ${machine} via ssh:"
|
||
( set -x; ${nix} build ${nixos-rebuild} --no-link --store ssh://${user}@${host} )
|
||
( set -x; ${openssh} -t ${user}@${host} 'sudo ${nixos-rebuild} ${switch} --flake ${flake}#${machine}' )
|
||
'' else ''
|
||
echo "🤞 Activating configuration non-hermetically on ${machine} via ssh:"
|
||
( set -x; ${openssh} -t ${user}@${host} 'sudo nixos-rebuild ${switch} --flake ${flake}#${machine}' )
|
||
'')
|
||
else ''
|
||
echo "🔨 Building system closure locally, copying it to remote store and activating it:"
|
||
( set -x; NIX_SSHOPTS="-t" ${nixos-rebuild} ${switch} --flake ${flake}#${machine} --target-host ${user}@${host} --use-remote-sudo )
|
||
'');
|
||
in final.writeScript "deploy-${machine}.sh" script;
|
||
in
|
||
{
|
||
nixinate =
|
||
(
|
||
nixpkgs.lib.genAttrs
|
||
validMachines
|
||
(x:
|
||
{
|
||
type = "app";
|
||
program = toString (mkDeployScript {
|
||
machine = x;
|
||
dryRun = false;
|
||
});
|
||
}
|
||
)
|
||
// nixpkgs.lib.genAttrs
|
||
(map (a: a + "-dry-run") validMachines)
|
||
(x:
|
||
{
|
||
type = "app";
|
||
program = toString (mkDeployScript {
|
||
machine = nixpkgs.lib.removeSuffix "-dry-run" x;
|
||
dryRun = true;
|
||
});
|
||
}
|
||
)
|
||
);
|
||
};
|
||
};
|
||
nixinate = forAllSystems (system: pkgs: nixpkgsFor.${system}.generateApps);
|
||
checks = forAllSystems (system: pkgs:
|
||
let
|
||
vmTests = import ./tests {
|
||
makeTest = (import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; }).makeTest;
|
||
inherit inputs; pkgs = nixpkgsFor.${system};
|
||
};
|
||
in
|
||
pkgs.lib.optionalAttrs pkgs.stdenv.isLinux vmTests # vmTests can only be ran on Linux, so append them only if on Linux.
|
||
//
|
||
{
|
||
# Other checks here...
|
||
}
|
||
);
|
||
};
|
||
}
|