Reformat with nixfmt
This commit is contained in:
parent
3aab6ab23a
commit
8441081b6b
11 changed files with 837 additions and 674 deletions
10
default.nix
10
default.nix
|
|
@ -1,6 +1,4 @@
|
|||
(import
|
||||
(fetchTarball {
|
||||
url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz";
|
||||
sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2";
|
||||
})
|
||||
{ src = ./.; }).defaultNix
|
||||
(import (fetchTarball {
|
||||
url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz";
|
||||
sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2";
|
||||
}) { src = ./.; }).defaultNix
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
{ lib, pkgs, ... }: {
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
config = {
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
|
||||
|
|
@ -56,28 +57,28 @@
|
|||
};
|
||||
};
|
||||
|
||||
systemd.services =
|
||||
lib.listToAttrs
|
||||
(lib.flip lib.genList 10 (ix:
|
||||
lib.nameValuePair "service-${toString ix}"
|
||||
{
|
||||
enable = true;
|
||||
description = "service-${toString ix}";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [
|
||||
"network-online.target"
|
||||
];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
wantedBy = [ "system-manager.target" ];
|
||||
requiredBy = lib.mkIf (ix > 5) [ "service-0.service" ];
|
||||
script = ''
|
||||
sleep ${if ix > 5 then "2" else "1"}
|
||||
'';
|
||||
})
|
||||
);
|
||||
systemd.services = lib.listToAttrs (
|
||||
lib.flip lib.genList 10 (
|
||||
ix:
|
||||
lib.nameValuePair "service-${toString ix}" {
|
||||
enable = true;
|
||||
description = "service-${toString ix}";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [
|
||||
"network-online.target"
|
||||
];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
wantedBy = [ "system-manager.target" ];
|
||||
requiredBy = lib.mkIf (ix > 5) [ "service-0.service" ];
|
||||
script = ''
|
||||
sleep ${if ix > 5 then "2" else "1"}
|
||||
'';
|
||||
}
|
||||
)
|
||||
);
|
||||
systemd.tmpfiles.rules = [ "D /var/tmp/system-manager 0755 root root -" ];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
406
flake.nix
406
flake.nix
|
|
@ -39,15 +39,16 @@
|
|||
};
|
||||
|
||||
outputs =
|
||||
{ self
|
||||
, nixpkgs
|
||||
, flake-utils
|
||||
, rust-overlay
|
||||
, crane
|
||||
, devshell
|
||||
, treefmt-nix
|
||||
, pre-commit-hooks
|
||||
, ...
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
rust-overlay,
|
||||
crane,
|
||||
devshell,
|
||||
treefmt-nix,
|
||||
pre-commit-hooks,
|
||||
...
|
||||
}@inputs:
|
||||
{
|
||||
lib = import ./nix/lib.nix {
|
||||
|
|
@ -60,201 +61,228 @@
|
|||
modules = [ ./examples/example.nix ];
|
||||
};
|
||||
}
|
||||
//
|
||||
(flake-utils.lib.eachSystem
|
||||
// (flake-utils.lib.eachSystem
|
||||
[
|
||||
flake-utils.lib.system.x86_64-linux
|
||||
flake-utils.lib.system.aarch64-linux
|
||||
]
|
||||
(system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [ (import rust-overlay) devshell.overlays.default ];
|
||||
};
|
||||
# TODO Pin the version for release
|
||||
rust = pkgs.rust-bin.stable.latest;
|
||||
(
|
||||
system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [
|
||||
(import rust-overlay)
|
||||
devshell.overlays.default
|
||||
];
|
||||
};
|
||||
# TODO Pin the version for release
|
||||
rust = pkgs.rust-bin.stable.latest;
|
||||
|
||||
craneLib = (crane.mkLib pkgs).overrideToolchain rust.default;
|
||||
craneLib = (crane.mkLib pkgs).overrideToolchain rust.default;
|
||||
|
||||
# Common derivation arguments used for all builds
|
||||
commonArgs = { dbus, pkg-config }: {
|
||||
src = craneLib.cleanCargoSource ./.;
|
||||
buildInputs = [
|
||||
dbus
|
||||
];
|
||||
nativeBuildInputs = [
|
||||
pkg-config
|
||||
];
|
||||
# https://github.com/ipetkov/crane/issues/385
|
||||
doNotLinkInheritedArtifacts = true;
|
||||
};
|
||||
|
||||
# Build only the cargo dependencies
|
||||
cargoArtifacts = { dbus, pkg-config }:
|
||||
craneLib.buildDepsOnly ((commonArgs { inherit dbus pkg-config; }) // {
|
||||
pname = "system-manager";
|
||||
});
|
||||
|
||||
system-manager-unwrapped =
|
||||
{ dbus
|
||||
, pkg-config
|
||||
}:
|
||||
craneLib.buildPackage ((commonArgs { inherit dbus pkg-config; }) // {
|
||||
pname = "system-manager";
|
||||
cargoArtifacts = cargoArtifacts { inherit dbus pkg-config; };
|
||||
});
|
||||
|
||||
system-manager =
|
||||
{ dbus
|
||||
, makeBinaryWrapper
|
||||
, nix
|
||||
, pkg-config
|
||||
, runCommand
|
||||
}:
|
||||
let
|
||||
unwrapped = system-manager-unwrapped { inherit dbus pkg-config; };
|
||||
in
|
||||
runCommand "system-manager"
|
||||
# Common derivation arguments used for all builds
|
||||
commonArgs =
|
||||
{ dbus, pkg-config }:
|
||||
{
|
||||
nativeBuildInputs = [ makeBinaryWrapper ];
|
||||
}
|
||||
''
|
||||
makeWrapper \
|
||||
${unwrapped}/bin/system-manager \
|
||||
$out/bin/system-manager \
|
||||
--prefix PATH : ${nixpkgs.lib.makeBinPath [ nix ]}
|
||||
'';
|
||||
src = craneLib.cleanCargoSource ./.;
|
||||
buildInputs = [
|
||||
dbus
|
||||
];
|
||||
nativeBuildInputs = [
|
||||
pkg-config
|
||||
];
|
||||
# https://github.com/ipetkov/crane/issues/385
|
||||
doNotLinkInheritedArtifacts = true;
|
||||
};
|
||||
|
||||
system-manager-clippy =
|
||||
{ dbus
|
||||
, pkg-config
|
||||
}:
|
||||
craneLib.cargoClippy ((commonArgs { inherit dbus pkg-config; }) // {
|
||||
cargoArtifacts = cargoArtifacts { inherit dbus pkg-config; };
|
||||
cargoClippyExtraArgs = "--all-targets -- --deny warnings";
|
||||
});
|
||||
# Build only the cargo dependencies
|
||||
cargoArtifacts =
|
||||
{ dbus, pkg-config }:
|
||||
craneLib.buildDepsOnly (
|
||||
(commonArgs { inherit dbus pkg-config; })
|
||||
// {
|
||||
pname = "system-manager";
|
||||
}
|
||||
);
|
||||
|
||||
system-manager-test =
|
||||
{ dbus
|
||||
, pkg-config
|
||||
}:
|
||||
craneLib.cargoTest ((commonArgs { inherit dbus pkg-config; }) // {
|
||||
cargoArtifacts = cargoArtifacts { inherit dbus pkg-config; };
|
||||
});
|
||||
system-manager-unwrapped =
|
||||
{
|
||||
dbus,
|
||||
pkg-config,
|
||||
}:
|
||||
craneLib.buildPackage (
|
||||
(commonArgs { inherit dbus pkg-config; })
|
||||
// {
|
||||
pname = "system-manager";
|
||||
cargoArtifacts = cargoArtifacts { inherit dbus pkg-config; };
|
||||
}
|
||||
);
|
||||
|
||||
# treefmt-nix configuration
|
||||
treefmt.config = {
|
||||
projectRootFile = "flake.nix";
|
||||
programs = {
|
||||
nixfmt.enable = true;
|
||||
rustfmt = {
|
||||
enable = true;
|
||||
package = rust.rustfmt;
|
||||
system-manager =
|
||||
{
|
||||
dbus,
|
||||
makeBinaryWrapper,
|
||||
nix,
|
||||
pkg-config,
|
||||
runCommand,
|
||||
}:
|
||||
let
|
||||
unwrapped = system-manager-unwrapped { inherit dbus pkg-config; };
|
||||
in
|
||||
runCommand "system-manager"
|
||||
{
|
||||
nativeBuildInputs = [ makeBinaryWrapper ];
|
||||
}
|
||||
''
|
||||
makeWrapper \
|
||||
${unwrapped}/bin/system-manager \
|
||||
$out/bin/system-manager \
|
||||
--prefix PATH : ${nixpkgs.lib.makeBinPath [ nix ]}
|
||||
'';
|
||||
|
||||
system-manager-clippy =
|
||||
{
|
||||
dbus,
|
||||
pkg-config,
|
||||
}:
|
||||
craneLib.cargoClippy (
|
||||
(commonArgs { inherit dbus pkg-config; })
|
||||
// {
|
||||
cargoArtifacts = cargoArtifacts { inherit dbus pkg-config; };
|
||||
cargoClippyExtraArgs = "--all-targets -- --deny warnings";
|
||||
}
|
||||
);
|
||||
|
||||
system-manager-test =
|
||||
{
|
||||
dbus,
|
||||
pkg-config,
|
||||
}:
|
||||
craneLib.cargoTest (
|
||||
(commonArgs { inherit dbus pkg-config; })
|
||||
// {
|
||||
cargoArtifacts = cargoArtifacts { inherit dbus pkg-config; };
|
||||
}
|
||||
);
|
||||
|
||||
# treefmt-nix configuration
|
||||
treefmt.config = {
|
||||
projectRootFile = "flake.nix";
|
||||
programs = {
|
||||
nixfmt.enable = true;
|
||||
rustfmt = {
|
||||
enable = true;
|
||||
package = rust.rustfmt;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
packages = {
|
||||
# The unwrapped version takes nix from the PATH, it will fail if nix
|
||||
# cannot be found.
|
||||
# The wrapped version has a reference to the nix store path, so nix is
|
||||
# part of its runtime closure.
|
||||
system-manager-unwrapped = pkgs.callPackage system-manager-unwrapped { };
|
||||
system-manager = pkgs.callPackage system-manager { };
|
||||
in
|
||||
{
|
||||
packages = {
|
||||
# The unwrapped version takes nix from the PATH, it will fail if nix
|
||||
# cannot be found.
|
||||
# The wrapped version has a reference to the nix store path, so nix is
|
||||
# part of its runtime closure.
|
||||
system-manager-unwrapped = pkgs.callPackage system-manager-unwrapped { };
|
||||
system-manager = pkgs.callPackage system-manager { };
|
||||
|
||||
system-manager-clippy = pkgs.callPackage system-manager-clippy { };
|
||||
system-manager-test = pkgs.callPackage system-manager-test { };
|
||||
system-manager-clippy = pkgs.callPackage system-manager-clippy { };
|
||||
system-manager-test = pkgs.callPackage system-manager-test { };
|
||||
|
||||
default = self.packages.${system}.system-manager;
|
||||
};
|
||||
|
||||
devShells.default =
|
||||
let
|
||||
llvm = pkgs.llvmPackages_latest;
|
||||
in
|
||||
pkgs.devshell.mkShell {
|
||||
packages = with pkgs; [
|
||||
llvm.clang
|
||||
pkg-config
|
||||
(rust.default.override {
|
||||
extensions = [ "rust-src" ];
|
||||
})
|
||||
(treefmt-nix.lib.mkWrapper pkgs treefmt.config)
|
||||
];
|
||||
env = [
|
||||
{
|
||||
name = "PKG_CONFIG_PATH";
|
||||
value = pkgs.lib.makeSearchPath "lib/pkgconfig" [
|
||||
pkgs.dbus.dev
|
||||
pkgs.systemdMinimal.dev
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "LIBCLANG_PATH";
|
||||
value = "${llvm.libclang}/lib";
|
||||
}
|
||||
{
|
||||
# for rust-analyzer
|
||||
name = "RUST_SRC_PATH";
|
||||
value = "${rust.rust-src}";
|
||||
}
|
||||
{
|
||||
name = "RUST_BACKTRACE";
|
||||
value = "1";
|
||||
}
|
||||
{
|
||||
name = "RUSTFLAGS";
|
||||
value =
|
||||
let
|
||||
getLib = pkg: "${pkgs.lib.getLib pkg}/lib";
|
||||
in
|
||||
pkgs.lib.concatStringsSep " " [
|
||||
"-L${getLib pkgs.systemdMinimal} -lsystemd"
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "DEVSHELL_NO_MOTD";
|
||||
value = "1";
|
||||
}
|
||||
];
|
||||
devshell.startup.pre-commit.text = (pre-commit-hooks.lib.${system}.run {
|
||||
src = ./.;
|
||||
hooks = {
|
||||
check-format = {
|
||||
enable = true;
|
||||
entry = "treefmt --fail-on-change";
|
||||
};
|
||||
cargo-clippy = {
|
||||
enable = true;
|
||||
description = "Lint Rust code.";
|
||||
entry = "cargo-clippy --workspace -- -D warnings";
|
||||
files = "\\.rs$";
|
||||
pass_filenames = false;
|
||||
};
|
||||
};
|
||||
}).shellHook;
|
||||
default = self.packages.${system}.system-manager;
|
||||
};
|
||||
|
||||
checks =
|
||||
let
|
||||
# The Aarch64 VM tests seem to hang on garnix, we disable them for now
|
||||
enableVmTests = system != flake-utils.lib.system.aarch64-linux;
|
||||
in
|
||||
{
|
||||
inherit (self.packages.${system})
|
||||
# Build the crate as part of `nix flake check` for convenience
|
||||
system-manager
|
||||
system-manager-clippy
|
||||
system-manager-test;
|
||||
} //
|
||||
pkgs.lib.optionalAttrs enableVmTests (import ./test/nix/modules {
|
||||
inherit system;
|
||||
inherit (pkgs) lib;
|
||||
inherit (inputs) nix-vm-test;
|
||||
system-manager = self;
|
||||
});
|
||||
})
|
||||
devShells.default =
|
||||
let
|
||||
llvm = pkgs.llvmPackages_latest;
|
||||
in
|
||||
pkgs.devshell.mkShell {
|
||||
packages = with pkgs; [
|
||||
llvm.clang
|
||||
pkg-config
|
||||
(rust.default.override {
|
||||
extensions = [ "rust-src" ];
|
||||
})
|
||||
(treefmt-nix.lib.mkWrapper pkgs treefmt.config)
|
||||
];
|
||||
env = [
|
||||
{
|
||||
name = "PKG_CONFIG_PATH";
|
||||
value = pkgs.lib.makeSearchPath "lib/pkgconfig" [
|
||||
pkgs.dbus.dev
|
||||
pkgs.systemdMinimal.dev
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "LIBCLANG_PATH";
|
||||
value = "${llvm.libclang}/lib";
|
||||
}
|
||||
{
|
||||
# for rust-analyzer
|
||||
name = "RUST_SRC_PATH";
|
||||
value = "${rust.rust-src}";
|
||||
}
|
||||
{
|
||||
name = "RUST_BACKTRACE";
|
||||
value = "1";
|
||||
}
|
||||
{
|
||||
name = "RUSTFLAGS";
|
||||
value =
|
||||
let
|
||||
getLib = pkg: "${pkgs.lib.getLib pkg}/lib";
|
||||
in
|
||||
pkgs.lib.concatStringsSep " " [
|
||||
"-L${getLib pkgs.systemdMinimal} -lsystemd"
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "DEVSHELL_NO_MOTD";
|
||||
value = "1";
|
||||
}
|
||||
];
|
||||
devshell.startup.pre-commit.text =
|
||||
(pre-commit-hooks.lib.${system}.run {
|
||||
src = ./.;
|
||||
hooks = {
|
||||
check-format = {
|
||||
enable = true;
|
||||
entry = "treefmt --fail-on-change";
|
||||
};
|
||||
cargo-clippy = {
|
||||
enable = true;
|
||||
description = "Lint Rust code.";
|
||||
entry = "cargo-clippy --workspace -- -D warnings";
|
||||
files = "\\.rs$";
|
||||
pass_filenames = false;
|
||||
};
|
||||
};
|
||||
}).shellHook;
|
||||
};
|
||||
|
||||
checks =
|
||||
let
|
||||
# The Aarch64 VM tests seem to hang on garnix, we disable them for now
|
||||
enableVmTests = system != flake-utils.lib.system.aarch64-linux;
|
||||
in
|
||||
{
|
||||
inherit (self.packages.${system})
|
||||
# Build the crate as part of `nix flake check` for convenience
|
||||
system-manager
|
||||
system-manager-clippy
|
||||
system-manager-test
|
||||
;
|
||||
}
|
||||
// pkgs.lib.optionalAttrs enableVmTests (
|
||||
import ./test/nix/modules {
|
||||
inherit system;
|
||||
inherit (pkgs) lib;
|
||||
inherit (inputs) nix-vm-test;
|
||||
system-manager = self;
|
||||
}
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
108
nix/lib.nix
108
nix/lib.nix
|
|
@ -1,7 +1,7 @@
|
|||
{ nixpkgs # The nixpkgs flake
|
||||
, self # The system-manager flake
|
||||
, nixos # The path to the nixos dir from nixpkgs
|
||||
,
|
||||
{
|
||||
nixpkgs, # The nixpkgs flake
|
||||
self, # The system-manager flake
|
||||
nixos, # The path to the nixos dir from nixpkgs
|
||||
}:
|
||||
let
|
||||
inherit (nixpkgs) lib;
|
||||
|
|
@ -11,45 +11,64 @@ in
|
|||
# reporting in module-system errors.
|
||||
# Usage example:
|
||||
# { _file = "${printAttrPos (builtins.unsafeGetAttrPos "a" { a = null; })}: inline module"; }
|
||||
printAttrPos = { file, line, column }: "${file}:${toString line}:${toString column}";
|
||||
printAttrPos =
|
||||
{
|
||||
file,
|
||||
line,
|
||||
column,
|
||||
}:
|
||||
"${file}:${toString line}:${toString column}";
|
||||
|
||||
makeSystemConfig =
|
||||
{ modules
|
||||
, extraSpecialArgs ? { }
|
||||
{
|
||||
modules,
|
||||
extraSpecialArgs ? { },
|
||||
}:
|
||||
let
|
||||
# Module that sets additional module arguments
|
||||
extraArgsModule = { lib, config, pkgs, ... }: {
|
||||
_file = "${self.lib.printAttrPos (builtins.unsafeGetAttrPos "a" { a = null; })}: inline module";
|
||||
_module.args = {
|
||||
pkgs = nixpkgs.legacyPackages.${config.nixpkgs.hostPlatform};
|
||||
utils = import "${nixos}/lib/utils.nix" {
|
||||
inherit lib config pkgs;
|
||||
extraArgsModule =
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
_file = "${self.lib.printAttrPos (builtins.unsafeGetAttrPos "a" { a = null; })}: inline module";
|
||||
_module.args = {
|
||||
pkgs = nixpkgs.legacyPackages.${config.nixpkgs.hostPlatform};
|
||||
utils = import "${nixos}/lib/utils.nix" {
|
||||
inherit lib config pkgs;
|
||||
};
|
||||
# Pass the wrapped system-manager binary down
|
||||
inherit (self.packages.${config.nixpkgs.hostPlatform}) system-manager;
|
||||
};
|
||||
# Pass the wrapped system-manager binary down
|
||||
inherit (self.packages.${config.nixpkgs.hostPlatform}) system-manager;
|
||||
};
|
||||
};
|
||||
|
||||
config = (lib.evalModules {
|
||||
specialArgs = { nixosModulesPath = "${nixos}/modules"; } // extraSpecialArgs;
|
||||
modules = [
|
||||
extraArgsModule
|
||||
./modules
|
||||
] ++ modules;
|
||||
}).config;
|
||||
config =
|
||||
(lib.evalModules {
|
||||
specialArgs = {
|
||||
nixosModulesPath = "${nixos}/modules";
|
||||
} // extraSpecialArgs;
|
||||
modules = [
|
||||
extraArgsModule
|
||||
./modules
|
||||
] ++ modules;
|
||||
}).config;
|
||||
|
||||
# Get the system as it was defined in the modules.
|
||||
system = config.nixpkgs.hostPlatform;
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
|
||||
returnIfNoAssertions = drv:
|
||||
returnIfNoAssertions =
|
||||
drv:
|
||||
let
|
||||
failedAssertions = map (x: x.message) (lib.filter (x: !x.assertion) config.assertions);
|
||||
in
|
||||
if failedAssertions != [ ]
|
||||
then throw "\nFailed assertions:\n${lib.concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}"
|
||||
else lib.showWarnings config.warnings drv;
|
||||
if failedAssertions != [ ] then
|
||||
throw "\nFailed assertions:\n${lib.concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}"
|
||||
else
|
||||
lib.showWarnings config.warnings drv;
|
||||
|
||||
servicesPath = pkgs.writeTextFile {
|
||||
name = "services";
|
||||
|
|
@ -72,45 +91,50 @@ in
|
|||
|
||||
toplevel =
|
||||
let
|
||||
scripts = lib.mapAttrsToList
|
||||
(_: script: linkFarmBinEntryFromDrv script)
|
||||
config.build.scripts;
|
||||
scripts = lib.mapAttrsToList (_: script: linkFarmBinEntryFromDrv script) config.build.scripts;
|
||||
|
||||
entries = [
|
||||
(linkFarmEntryFromDrv servicesPath)
|
||||
(linkFarmEntryFromDrv etcPath)
|
||||
] ++ scripts;
|
||||
|
||||
addPassthru = drv: drv.overrideAttrs (prevAttrs: {
|
||||
passthru = (prevAttrs.passthru or { }) // {
|
||||
inherit config;
|
||||
};
|
||||
});
|
||||
addPassthru =
|
||||
drv:
|
||||
drv.overrideAttrs (prevAttrs: {
|
||||
passthru = (prevAttrs.passthru or { }) // {
|
||||
inherit config;
|
||||
};
|
||||
});
|
||||
in
|
||||
addPassthru (pkgs.linkFarm "system-manager" entries);
|
||||
in
|
||||
returnIfNoAssertions toplevel;
|
||||
|
||||
mkTestPreamble =
|
||||
{ node
|
||||
, profile
|
||||
, action
|
||||
}: ''
|
||||
{
|
||||
node,
|
||||
profile,
|
||||
action,
|
||||
}:
|
||||
''
|
||||
${node}.succeed("${profile}/bin/${action} 2>&1 | tee /tmp/output.log")
|
||||
${node}.succeed("! grep -F 'ERROR' /tmp/output.log")
|
||||
'';
|
||||
|
||||
activateProfileSnippet = { node, profile }:
|
||||
activateProfileSnippet =
|
||||
{ node, profile }:
|
||||
self.lib.mkTestPreamble {
|
||||
inherit node profile;
|
||||
action = "activate";
|
||||
};
|
||||
deactivateProfileSnippet = { node, profile }:
|
||||
deactivateProfileSnippet =
|
||||
{ node, profile }:
|
||||
self.lib.mkTestPreamble {
|
||||
inherit node profile;
|
||||
action = "deactivate";
|
||||
};
|
||||
prepopulateProfileSnippet = { node, profile }:
|
||||
prepopulateProfileSnippet =
|
||||
{ node, profile }:
|
||||
self.lib.mkTestPreamble {
|
||||
inherit node profile;
|
||||
action = "prepopulate";
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
{ lib
|
||||
, config
|
||||
, pkgs
|
||||
, system-manager
|
||||
, ...
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
pkgs,
|
||||
system-manager,
|
||||
...
|
||||
}:
|
||||
{
|
||||
imports = [
|
||||
|
|
@ -31,7 +32,12 @@
|
|||
type = types.listOf types.unspecified;
|
||||
internal = true;
|
||||
default = [ ];
|
||||
example = [{ assertion = false; message = "you can't enable this for that reason"; }];
|
||||
example = [
|
||||
{
|
||||
assertion = false;
|
||||
message = "you can't enable this for that reason";
|
||||
}
|
||||
];
|
||||
description = lib.mdDoc ''
|
||||
This option allows modules to express conditions that must
|
||||
hold for the evaluation of the system configuration to
|
||||
|
|
@ -95,20 +101,27 @@
|
|||
allowAnyDistro = lib.mkEnableOption "the usage of system-manager on untested distributions";
|
||||
|
||||
preActivationAssertions = lib.mkOption {
|
||||
type = with lib.types; attrsOf (submodule ({ name, ... }: {
|
||||
options = {
|
||||
enable = lib.mkEnableOption "the assertion";
|
||||
type =
|
||||
with lib.types;
|
||||
attrsOf (
|
||||
submodule (
|
||||
{ name, ... }:
|
||||
{
|
||||
options = {
|
||||
enable = lib.mkEnableOption "the assertion";
|
||||
|
||||
name = lib.mkOption {
|
||||
type = types.str;
|
||||
default = name;
|
||||
};
|
||||
name = lib.mkOption {
|
||||
type = types.str;
|
||||
default = name;
|
||||
};
|
||||
|
||||
script = lib.mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
}));
|
||||
script = lib.mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
|
|
@ -140,17 +153,22 @@
|
|||
system-manager.preActivationAssertions = {
|
||||
osVersion =
|
||||
let
|
||||
supportedIds = [ "nixos" "ubuntu" ];
|
||||
supportedIds = [
|
||||
"nixos"
|
||||
"ubuntu"
|
||||
];
|
||||
in
|
||||
{
|
||||
enable = !config.system-manager.allowAnyDistro;
|
||||
script = ''
|
||||
source /etc/os-release
|
||||
${lib.concatStringsSep "\n" (lib.flip map supportedIds (supportedId: ''
|
||||
if [ $ID = "${supportedId}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
''))}
|
||||
${lib.concatStringsSep "\n" (
|
||||
lib.flip map supportedIds (supportedId: ''
|
||||
if [ $ID = "${supportedId}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
'')
|
||||
)}
|
||||
echo "This OS is not currently supported."
|
||||
echo "Supported OSs are: ${lib.concatStringsSep ", " supportedIds}"
|
||||
exit 1
|
||||
|
|
@ -184,27 +202,27 @@
|
|||
|
||||
preActivationAssertionScript =
|
||||
let
|
||||
mkAssertion = { name, script, ... }: ''
|
||||
# ${name}
|
||||
mkAssertion =
|
||||
{ name, script, ... }:
|
||||
''
|
||||
# ${name}
|
||||
|
||||
echo -e "Evaluating pre-activation assertion ${name}...\n"
|
||||
(
|
||||
set +e
|
||||
${script}
|
||||
)
|
||||
assertion_result=$?
|
||||
|
||||
if [ $assertion_result -ne 0 ]; then
|
||||
failed_assertions+=${name}
|
||||
fi
|
||||
'';
|
||||
|
||||
mkAssertions = assertions:
|
||||
lib.concatStringsSep "\n" (
|
||||
lib.mapAttrsToList (name: mkAssertion) (
|
||||
lib.filterAttrs (name: cfg: cfg.enable)
|
||||
assertions
|
||||
echo -e "Evaluating pre-activation assertion ${name}...\n"
|
||||
(
|
||||
set +e
|
||||
${script}
|
||||
)
|
||||
assertion_result=$?
|
||||
|
||||
if [ $assertion_result -ne 0 ]; then
|
||||
failed_assertions+=${name}
|
||||
fi
|
||||
'';
|
||||
|
||||
mkAssertions =
|
||||
assertions:
|
||||
lib.concatStringsSep "\n" (
|
||||
lib.mapAttrsToList (name: mkAssertion) (lib.filterAttrs (name: cfg: cfg.enable) assertions)
|
||||
);
|
||||
in
|
||||
pkgs.writeShellScript "preActivationAssertions" ''
|
||||
|
|
@ -230,43 +248,40 @@
|
|||
# TODO: handle globbing
|
||||
etc =
|
||||
let
|
||||
addToStore = name: file: pkgs.runCommandLocal "${name}-etc-link" { } ''
|
||||
mkdir -p "$out/$(dirname "${file.target}")"
|
||||
ln -s "${file.source}" "$out/${file.target}"
|
||||
addToStore =
|
||||
name: file:
|
||||
pkgs.runCommandLocal "${name}-etc-link" { } ''
|
||||
mkdir -p "$out/$(dirname "${file.target}")"
|
||||
ln -s "${file.source}" "$out/${file.target}"
|
||||
|
||||
if [ "${file.mode}" != symlink ]; then
|
||||
echo "${file.mode}" > "$out/${file.target}.mode"
|
||||
echo "${file.user}" > "$out/${file.target}.uid"
|
||||
echo "${file.group}" > "$out/${file.target}.gid"
|
||||
fi
|
||||
'';
|
||||
if [ "${file.mode}" != symlink ]; then
|
||||
echo "${file.mode}" > "$out/${file.target}.mode"
|
||||
echo "${file.user}" > "$out/${file.target}.uid"
|
||||
echo "${file.group}" > "$out/${file.target}.gid"
|
||||
fi
|
||||
'';
|
||||
|
||||
filteredEntries = lib.filterAttrs
|
||||
(_name: etcFile: etcFile.enable)
|
||||
config.environment.etc;
|
||||
filteredEntries = lib.filterAttrs (_name: etcFile: etcFile.enable) config.environment.etc;
|
||||
|
||||
srcDrvs = lib.mapAttrs addToStore filteredEntries;
|
||||
|
||||
entries = lib.mapAttrs
|
||||
(name: file: file // { source = "${srcDrvs.${name}}"; })
|
||||
filteredEntries;
|
||||
entries = lib.mapAttrs (name: file: file // { source = "${srcDrvs.${name}}"; }) filteredEntries;
|
||||
|
||||
staticEnv = pkgs.buildEnv {
|
||||
name = "etc-static-env";
|
||||
paths = lib.attrValues srcDrvs;
|
||||
};
|
||||
in
|
||||
{ inherit entries staticEnv; };
|
||||
{
|
||||
inherit entries staticEnv;
|
||||
};
|
||||
|
||||
services =
|
||||
lib.mapAttrs'
|
||||
(unitName: unit:
|
||||
lib.nameValuePair unitName {
|
||||
storePath =
|
||||
''${unit.unit}/${unitName}'';
|
||||
})
|
||||
(lib.filterAttrs (_: unit: unit.enable)
|
||||
config.systemd.units);
|
||||
services = lib.mapAttrs' (
|
||||
unitName: unit:
|
||||
lib.nameValuePair unitName {
|
||||
storePath = ''${unit.unit}/${unitName}'';
|
||||
}
|
||||
) (lib.filterAttrs (_: unit: unit.enable) config.systemd.units);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
{ lib, config, pkgs, ... }:
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
options.environment = {
|
||||
|
|
@ -24,10 +29,9 @@
|
|||
];
|
||||
|
||||
etc = {
|
||||
"profile.d/system-manager-path.sh".source =
|
||||
pkgs.writeText "system-manager-path.sh" ''
|
||||
export PATH=${pathDir}/bin/:''${PATH}
|
||||
'';
|
||||
"profile.d/system-manager-path.sh".source = pkgs.writeText "system-manager-path.sh" ''
|
||||
export PATH=${pathDir}/bin/:''${PATH}
|
||||
'';
|
||||
|
||||
# TODO: figure out how to properly add fish support. We could start by
|
||||
# looking at what NixOS and HM do to set up the fish env.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
{ lib
|
||||
, pkgs
|
||||
, ...
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
options = {
|
||||
|
|
@ -18,99 +19,108 @@
|
|||
Set of files that have to be linked in {file}`/etc`.
|
||||
'';
|
||||
|
||||
type = lib.types.attrsOf (lib.types.submodule (
|
||||
{ name, config, options, ... }:
|
||||
{
|
||||
options = {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule (
|
||||
{
|
||||
name,
|
||||
config,
|
||||
options,
|
||||
...
|
||||
}:
|
||||
{
|
||||
options = {
|
||||
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = lib.mdDoc ''
|
||||
Whether this /etc file should be generated. This
|
||||
option allows specific /etc files to be disabled.
|
||||
'';
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = lib.mdDoc ''
|
||||
Whether this /etc file should be generated. This
|
||||
option allows specific /etc files to be disabled.
|
||||
'';
|
||||
};
|
||||
|
||||
target = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = lib.mdDoc ''
|
||||
Name of symlink (relative to
|
||||
{file}`/etc`). Defaults to the attribute
|
||||
name.
|
||||
'';
|
||||
};
|
||||
|
||||
text = lib.mkOption {
|
||||
default = null;
|
||||
type = lib.types.nullOr lib.types.lines;
|
||||
description = lib.mdDoc "Text of the file.";
|
||||
};
|
||||
|
||||
source = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = lib.mdDoc "Path of the source file.";
|
||||
};
|
||||
|
||||
mode = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "symlink";
|
||||
example = "0600";
|
||||
description = lib.mdDoc ''
|
||||
If set to something else than `symlink`,
|
||||
the file is copied instead of symlinked, with the given
|
||||
file mode.
|
||||
'';
|
||||
};
|
||||
|
||||
uid = lib.mkOption {
|
||||
default = 0;
|
||||
type = lib.types.int;
|
||||
description = lib.mdDoc ''
|
||||
UID of created file. Only takes effect when the file is
|
||||
copied (that is, the mode is not 'symlink').
|
||||
'';
|
||||
};
|
||||
|
||||
gid = lib.mkOption {
|
||||
default = 0;
|
||||
type = lib.types.int;
|
||||
description = lib.mdDoc ''
|
||||
GID of created file. Only takes effect when the file is
|
||||
copied (that is, the mode is not 'symlink').
|
||||
'';
|
||||
};
|
||||
|
||||
user = lib.mkOption {
|
||||
default = "+${toString config.uid}";
|
||||
type = lib.types.str;
|
||||
description = lib.mdDoc ''
|
||||
User name of created file.
|
||||
Only takes effect when the file is copied (that is, the mode is not 'symlink').
|
||||
Changing this option takes precedence over `uid`.
|
||||
'';
|
||||
};
|
||||
|
||||
group = lib.mkOption {
|
||||
default = "+${toString config.gid}";
|
||||
type = lib.types.str;
|
||||
description = lib.mdDoc ''
|
||||
Group name of created file.
|
||||
Only takes effect when the file is copied (that is, the mode is not 'symlink').
|
||||
Changing this option takes precedence over `gid`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
target = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = lib.mdDoc ''
|
||||
Name of symlink (relative to
|
||||
{file}`/etc`). Defaults to the attribute
|
||||
name.
|
||||
'';
|
||||
config = {
|
||||
target = lib.mkDefault name;
|
||||
source = lib.mkIf (config.text != null) (
|
||||
let
|
||||
name' = "etc-" + baseNameOf name;
|
||||
in
|
||||
lib.mkDerivedConfig options.text (pkgs.writeText name')
|
||||
);
|
||||
};
|
||||
|
||||
text = lib.mkOption {
|
||||
default = null;
|
||||
type = lib.types.nullOr lib.types.lines;
|
||||
description = lib.mdDoc "Text of the file.";
|
||||
};
|
||||
|
||||
source = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = lib.mdDoc "Path of the source file.";
|
||||
};
|
||||
|
||||
mode = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "symlink";
|
||||
example = "0600";
|
||||
description = lib.mdDoc ''
|
||||
If set to something else than `symlink`,
|
||||
the file is copied instead of symlinked, with the given
|
||||
file mode.
|
||||
'';
|
||||
};
|
||||
|
||||
uid = lib.mkOption {
|
||||
default = 0;
|
||||
type = lib.types.int;
|
||||
description = lib.mdDoc ''
|
||||
UID of created file. Only takes effect when the file is
|
||||
copied (that is, the mode is not 'symlink').
|
||||
'';
|
||||
};
|
||||
|
||||
gid = lib.mkOption {
|
||||
default = 0;
|
||||
type = lib.types.int;
|
||||
description = lib.mdDoc ''
|
||||
GID of created file. Only takes effect when the file is
|
||||
copied (that is, the mode is not 'symlink').
|
||||
'';
|
||||
};
|
||||
|
||||
user = lib.mkOption {
|
||||
default = "+${toString config.uid}";
|
||||
type = lib.types.str;
|
||||
description = lib.mdDoc ''
|
||||
User name of created file.
|
||||
Only takes effect when the file is copied (that is, the mode is not 'symlink').
|
||||
Changing this option takes precedence over `uid`.
|
||||
'';
|
||||
};
|
||||
|
||||
group = lib.mkOption {
|
||||
default = "+${toString config.gid}";
|
||||
type = lib.types.str;
|
||||
description = lib.mdDoc ''
|
||||
Group name of created file.
|
||||
Only takes effect when the file is copied (that is, the mode is not 'symlink').
|
||||
Changing this option takes precedence over `gid`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
target = lib.mkDefault name;
|
||||
source = lib.mkIf (config.text != null) (
|
||||
let name' = "etc-" + baseNameOf name;
|
||||
in lib.mkDerivedConfig options.text (pkgs.writeText name')
|
||||
);
|
||||
};
|
||||
}
|
||||
));
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
{ lib
|
||||
, config
|
||||
, pkgs
|
||||
, utils
|
||||
, ...
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
pkgs,
|
||||
utils,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
|
|
@ -19,14 +20,28 @@ in
|
|||
# We could consider copying the systemd lib from NixOS and removing the bits
|
||||
# that are not relevant to us, like this option.
|
||||
package = lib.mkOption {
|
||||
type = lib.types.oneOf [ lib.types.str lib.types.path lib.types.package ];
|
||||
type = lib.types.oneOf [
|
||||
lib.types.str
|
||||
lib.types.path
|
||||
lib.types.package
|
||||
];
|
||||
default = pkgs.systemdMinimal;
|
||||
};
|
||||
|
||||
globalEnvironment = lib.mkOption {
|
||||
type = with lib.types; attrsOf (nullOr (oneOf [ str path package ]));
|
||||
type =
|
||||
with lib.types;
|
||||
attrsOf (
|
||||
nullOr (oneOf [
|
||||
str
|
||||
path
|
||||
package
|
||||
])
|
||||
);
|
||||
default = { };
|
||||
example = { TZ = "CET"; };
|
||||
example = {
|
||||
TZ = "CET";
|
||||
};
|
||||
description = lib.mdDoc ''
|
||||
Environment variables passed to *all* systemd units.
|
||||
'';
|
||||
|
|
@ -104,7 +119,9 @@ in
|
|||
generators = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.path;
|
||||
default = { };
|
||||
example = { systemd-gpt-auto-generator = "/dev/null"; };
|
||||
example = {
|
||||
systemd-gpt-auto-generator = "/dev/null";
|
||||
};
|
||||
description = lib.mdDoc ''
|
||||
Definition of systemd generators.
|
||||
For each `NAME = VALUE` pair of the attrSet, a link is generated from
|
||||
|
|
@ -129,14 +146,10 @@ in
|
|||
wantedBy = [ "default.target" ];
|
||||
};
|
||||
|
||||
timers =
|
||||
lib.mapAttrs
|
||||
(name: service:
|
||||
{
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig.OnCalendar = service.startAt;
|
||||
})
|
||||
(lib.filterAttrs (name: service: service.enable && service.startAt != [ ]) cfg.services);
|
||||
timers = lib.mapAttrs (name: service: {
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig.OnCalendar = service.startAt;
|
||||
}) (lib.filterAttrs (name: service: service.enable && service.startAt != [ ]) cfg.services);
|
||||
|
||||
units =
|
||||
lib.mapAttrs' (n: v: lib.nameValuePair "${n}.path" (systemd-lib.pathToUnit v)) cfg.paths
|
||||
|
|
@ -145,16 +158,24 @@ in
|
|||
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.socket" (systemd-lib.socketToUnit v)) cfg.sockets
|
||||
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.target" (systemd-lib.targetToUnit v)) cfg.targets
|
||||
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.timer" (systemd-lib.timerToUnit v)) cfg.timers
|
||||
// lib.listToAttrs (map
|
||||
(v:
|
||||
let n = utils.escapeSystemdPath v.where;
|
||||
in lib.nameValuePair "${n}.mount" (systemd-lib.mountToUnit v))
|
||||
cfg.mounts)
|
||||
// lib.listToAttrs (map
|
||||
(v:
|
||||
let n = utils.escapeSystemdPath v.where;
|
||||
in lib.nameValuePair "${n}.automount" (systemd-lib.automountToUnit v))
|
||||
cfg.automounts);
|
||||
// lib.listToAttrs (
|
||||
map (
|
||||
v:
|
||||
let
|
||||
n = utils.escapeSystemdPath v.where;
|
||||
in
|
||||
lib.nameValuePair "${n}.mount" (systemd-lib.mountToUnit v)
|
||||
) cfg.mounts
|
||||
)
|
||||
// lib.listToAttrs (
|
||||
map (
|
||||
v:
|
||||
let
|
||||
n = utils.escapeSystemdPath v.where;
|
||||
in
|
||||
lib.nameValuePair "${n}.automount" (systemd-lib.automountToUnit v)
|
||||
) cfg.automounts
|
||||
);
|
||||
};
|
||||
|
||||
environment.etc =
|
||||
|
|
@ -164,49 +185,59 @@ in
|
|||
enabledUnits = lib.filterAttrs (_: unit: unit.enable) cfg.units;
|
||||
in
|
||||
{
|
||||
"systemd/system".source = pkgs.runCommand "system-manager-units"
|
||||
{
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
}
|
||||
''
|
||||
mkdir -p $out
|
||||
"systemd/system".source =
|
||||
pkgs.runCommand "system-manager-units"
|
||||
{
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
}
|
||||
''
|
||||
mkdir -p $out
|
||||
|
||||
for i in ${toString (lib.mapAttrsToList (n: v: v.unit) enabledUnits)}; do
|
||||
fn=$(basename $i/*)
|
||||
if [ -e $out/$fn ]; then
|
||||
if [ "$(readlink -f $i/$fn)" = /dev/null ]; then
|
||||
ln -sfn /dev/null $out/$fn
|
||||
for i in ${toString (lib.mapAttrsToList (n: v: v.unit) enabledUnits)}; do
|
||||
fn=$(basename $i/*)
|
||||
if [ -e $out/$fn ]; then
|
||||
if [ "$(readlink -f $i/$fn)" = /dev/null ]; then
|
||||
ln -sfn /dev/null $out/$fn
|
||||
else
|
||||
${
|
||||
if allowCollisions then
|
||||
''
|
||||
mkdir -p $out/$fn.d
|
||||
ln -s $i/$fn $out/$fn.d/overrides.conf
|
||||
''
|
||||
else
|
||||
''
|
||||
echo "Found multiple derivations configuring $fn!"
|
||||
exit 1
|
||||
''
|
||||
}
|
||||
fi
|
||||
else
|
||||
${if allowCollisions then ''
|
||||
mkdir -p $out/$fn.d
|
||||
ln -s $i/$fn $out/$fn.d/overrides.conf
|
||||
'' else ''
|
||||
echo "Found multiple derivations configuring $fn!"
|
||||
exit 1
|
||||
''}
|
||||
ln -fs $i/$fn $out/
|
||||
fi
|
||||
else
|
||||
ln -fs $i/$fn $out/
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
${lib.concatStrings (
|
||||
lib.mapAttrsToList (name: unit:
|
||||
lib.concatMapStrings (name2: ''
|
||||
mkdir -p $out/'${name2}.wants'
|
||||
ln -sfn '../${name}' $out/'${name2}.wants'/
|
||||
'') (unit.wantedBy or [])
|
||||
) enabledUnits)}
|
||||
${lib.concatStrings (
|
||||
lib.mapAttrsToList (
|
||||
name: unit:
|
||||
lib.concatMapStrings (name2: ''
|
||||
mkdir -p $out/'${name2}.wants'
|
||||
ln -sfn '../${name}' $out/'${name2}.wants'/
|
||||
'') (unit.wantedBy or [ ])
|
||||
) enabledUnits
|
||||
)}
|
||||
|
||||
${lib.concatStrings (
|
||||
lib.mapAttrsToList (name: unit:
|
||||
lib.concatMapStrings (name2: ''
|
||||
mkdir -p $out/'${name2}.requires'
|
||||
ln -sfn '../${name}' $out/'${name2}.requires'/
|
||||
'') (unit.requiredBy or [])
|
||||
) enabledUnits)}
|
||||
'';
|
||||
${lib.concatStrings (
|
||||
lib.mapAttrsToList (
|
||||
name: unit:
|
||||
lib.concatMapStrings (name2: ''
|
||||
mkdir -p $out/'${name2}.requires'
|
||||
ln -sfn '../${name}' $out/'${name2}.requires'/
|
||||
'') (unit.requiredBy or [ ])
|
||||
) enabledUnits
|
||||
)}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,21 @@
|
|||
{ nixosModulesPath
|
||||
, lib
|
||||
, ...
|
||||
{
|
||||
nixosModulesPath,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
imports = [
|
||||
./nginx.nix
|
||||
] ++
|
||||
# List of imported NixOS modules
|
||||
# TODO: how will we manage this in the long term?
|
||||
map (path: nixosModulesPath + path) [
|
||||
"/misc/meta.nix"
|
||||
"/security/acme/"
|
||||
"/services/web-servers/nginx/"
|
||||
];
|
||||
|
||||
imports =
|
||||
[
|
||||
./nginx.nix
|
||||
]
|
||||
++
|
||||
# List of imported NixOS modules
|
||||
# TODO: how will we manage this in the long term?
|
||||
map (path: nixosModulesPath + path) [
|
||||
"/misc/meta.nix"
|
||||
"/security/acme/"
|
||||
"/services/web-servers/nginx/"
|
||||
];
|
||||
|
||||
options =
|
||||
# We need to ignore a bunch of options that are used in NixOS modules but
|
||||
|
|
|
|||
|
|
@ -5,4 +5,3 @@ let
|
|||
};
|
||||
in
|
||||
(import compat { src = ./.; }).shellNix.default
|
||||
|
||||
|
|
|
|||
|
|
@ -1,42 +1,55 @@
|
|||
{ lib
|
||||
, system-manager
|
||||
, system
|
||||
, nix-vm-test
|
||||
{
|
||||
lib,
|
||||
system-manager,
|
||||
system,
|
||||
nix-vm-test,
|
||||
}:
|
||||
|
||||
let
|
||||
forEachUbuntuImage =
|
||||
name:
|
||||
{ modules
|
||||
, testScriptFunction
|
||||
, extraPathsToRegister ? [ ]
|
||||
, projectTest ? test: test.sandboxed
|
||||
{
|
||||
modules,
|
||||
testScriptFunction,
|
||||
extraPathsToRegister ? [ ],
|
||||
projectTest ? test: test.sandboxed,
|
||||
}:
|
||||
let
|
||||
ubuntu = nix-vm-test.lib.${system}.ubuntu;
|
||||
in
|
||||
lib.listToAttrs (lib.flip map (lib.attrNames ubuntu.images)
|
||||
(imageVersion:
|
||||
let
|
||||
toplevel = (system-manager.lib.makeSystemConfig {
|
||||
modules = modules ++ [
|
||||
({ lib, pkgs, ... }: {
|
||||
options.hostPkgs = lib.mkOption { type = lib.types.raw; readOnly = true; };
|
||||
config.hostPkgs = pkgs;
|
||||
})
|
||||
];
|
||||
});
|
||||
inherit (toplevel.config) hostPkgs;
|
||||
in
|
||||
lib.nameValuePair "ubuntu-${imageVersion}-${name}"
|
||||
(projectTest
|
||||
(ubuntu.${imageVersion} {
|
||||
testScript = testScriptFunction { inherit toplevel hostPkgs; };
|
||||
extraPathsToRegister = extraPathsToRegister ++ [
|
||||
toplevel
|
||||
];
|
||||
sharedDirs = { };
|
||||
}))
|
||||
lib.listToAttrs (
|
||||
lib.flip map (lib.attrNames ubuntu.images) (
|
||||
imageVersion:
|
||||
let
|
||||
toplevel = (
|
||||
system-manager.lib.makeSystemConfig {
|
||||
modules = modules ++ [
|
||||
(
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
options.hostPkgs = lib.mkOption {
|
||||
type = lib.types.raw;
|
||||
readOnly = true;
|
||||
};
|
||||
config.hostPkgs = pkgs;
|
||||
}
|
||||
)
|
||||
];
|
||||
}
|
||||
);
|
||||
inherit (toplevel.config) hostPkgs;
|
||||
in
|
||||
lib.nameValuePair "ubuntu-${imageVersion}-${name}" (
|
||||
projectTest (
|
||||
ubuntu.${imageVersion} {
|
||||
testScript = testScriptFunction { inherit toplevel hostPkgs; };
|
||||
extraPathsToRegister = extraPathsToRegister ++ [
|
||||
toplevel
|
||||
];
|
||||
sharedDirs = { };
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
@ -44,90 +57,100 @@ let
|
|||
# and one that cannot.
|
||||
# The id parameter is a string that can be used to force reloading the services
|
||||
# between two configs by changing their contents.
|
||||
testModule = id: { lib, pkgs, ... }: {
|
||||
systemd.services = {
|
||||
has-reload = {
|
||||
enable = true;
|
||||
description = "service-reload";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecReload = ''
|
||||
${lib.getBin pkgs.coreutils}/bin/true
|
||||
testModule =
|
||||
id:
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
systemd.services = {
|
||||
has-reload = {
|
||||
enable = true;
|
||||
description = "service-reload";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecReload = ''
|
||||
${lib.getBin pkgs.coreutils}/bin/true
|
||||
'';
|
||||
};
|
||||
wantedBy = [ "system-manager.target" ];
|
||||
script = ''
|
||||
echo "I can be reloaded (id: ${id})"
|
||||
'';
|
||||
};
|
||||
has-no-reload = {
|
||||
enable = true;
|
||||
description = "service-no-reload";
|
||||
serviceConfig.Type = "simple";
|
||||
wantedBy = [ "system-manager.target" ];
|
||||
script = ''
|
||||
while true; do
|
||||
echo "I cannot be reloaded (id: ${id})"
|
||||
done
|
||||
'';
|
||||
};
|
||||
wantedBy = [ "system-manager.target" ];
|
||||
script = ''
|
||||
echo "I can be reloaded (id: ${id})"
|
||||
'';
|
||||
};
|
||||
has-no-reload = {
|
||||
enable = true;
|
||||
description = "service-no-reload";
|
||||
serviceConfig.Type = "simple";
|
||||
wantedBy = [ "system-manager.target" ];
|
||||
script = ''
|
||||
while true; do
|
||||
echo "I cannot be reloaded (id: ${id})"
|
||||
done
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
newConfig = system-manager.lib.makeSystemConfig {
|
||||
modules = [
|
||||
(testModule "new")
|
||||
({ lib, pkgs, ... }: {
|
||||
config = {
|
||||
nixpkgs.hostPlatform = system;
|
||||
(
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
config = {
|
||||
nixpkgs.hostPlatform = system;
|
||||
|
||||
services.nginx.enable = false;
|
||||
services.nginx.enable = false;
|
||||
|
||||
environment = {
|
||||
etc = {
|
||||
foo_new = {
|
||||
text = ''
|
||||
This is just a test!
|
||||
environment = {
|
||||
etc = {
|
||||
foo_new = {
|
||||
text = ''
|
||||
This is just a test!
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
systemPackages = [
|
||||
pkgs.fish
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services = {
|
||||
new-service = {
|
||||
enable = true;
|
||||
description = "new-service";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecReload = "${lib.getBin pkgs.coreutils}/bin/true";
|
||||
};
|
||||
wantedBy = [
|
||||
"system-manager.target"
|
||||
"default.target"
|
||||
];
|
||||
script = ''
|
||||
sleep 2
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
systemPackages = [
|
||||
pkgs.fish
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services = {
|
||||
new-service = {
|
||||
enable = true;
|
||||
description = "new-service";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecReload = "${lib.getBin pkgs.coreutils}/bin/true";
|
||||
};
|
||||
wantedBy = [ "system-manager.target" "default.target" ];
|
||||
script = ''
|
||||
sleep 2
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
})
|
||||
}
|
||||
)
|
||||
];
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
forEachUbuntuImage "example"
|
||||
{
|
||||
modules = [
|
||||
(testModule "old")
|
||||
../../../examples/example.nix
|
||||
];
|
||||
extraPathsToRegister = [ newConfig ];
|
||||
testScriptFunction = { toplevel, ... }: ''
|
||||
forEachUbuntuImage "example" {
|
||||
modules = [
|
||||
(testModule "old")
|
||||
../../../examples/example.nix
|
||||
];
|
||||
extraPathsToRegister = [ newConfig ];
|
||||
testScriptFunction =
|
||||
{ toplevel, ... }:
|
||||
''
|
||||
# Start all machines in parallel
|
||||
start_all()
|
||||
|
||||
|
|
@ -138,7 +161,10 @@ forEachUbuntuImage "example"
|
|||
vm.succeed("grep -F 'Error while creating file in /etc: Unmanaged path already exists in filesystem, please remove it and run system-manager again: /etc/foo_test' /tmp/output.log")
|
||||
vm.succeed("rm /etc/foo_test")
|
||||
|
||||
${system-manager.lib.activateProfileSnippet { node = "vm"; profile = toplevel; }}
|
||||
${system-manager.lib.activateProfileSnippet {
|
||||
node = "vm";
|
||||
profile = toplevel;
|
||||
}}
|
||||
vm.wait_for_unit("system-manager.target")
|
||||
|
||||
vm.succeed("systemctl status service-9.service")
|
||||
|
|
@ -150,7 +176,10 @@ forEachUbuntuImage "example"
|
|||
|
||||
vm.succeed("test -d /var/tmp/system-manager")
|
||||
|
||||
${system-manager.lib.activateProfileSnippet { node = "vm"; profile = newConfig; }}
|
||||
${system-manager.lib.activateProfileSnippet {
|
||||
node = "vm";
|
||||
profile = newConfig;
|
||||
}}
|
||||
vm.succeed("systemctl status new-service.service")
|
||||
vm.fail("systemctl status service-9.service")
|
||||
vm.fail("test -f /etc/a/nested/example/foo3")
|
||||
|
|
@ -177,89 +206,111 @@ forEachUbuntuImage "example"
|
|||
vm.fail("test -f /etc/baz/bar/foo2")
|
||||
vm.succeed("test -f /etc/foo_new")
|
||||
|
||||
${system-manager.lib.deactivateProfileSnippet { node = "vm"; profile = newConfig; }}
|
||||
${system-manager.lib.deactivateProfileSnippet {
|
||||
node = "vm";
|
||||
profile = newConfig;
|
||||
}}
|
||||
vm.fail("systemctl status new-service.service")
|
||||
vm.fail("test -f /etc/foo_new")
|
||||
#vm.fail("test -f /var/tmp/system-manager/foo1")
|
||||
'';
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
forEachUbuntuImage "prepopulate" {
|
||||
modules = [
|
||||
(testModule "old")
|
||||
../../../examples/example.nix
|
||||
];
|
||||
extraPathsToRegister = [ newConfig ];
|
||||
testScriptFunction =
|
||||
{ toplevel, ... }:
|
||||
''
|
||||
# Start all machines in parallel
|
||||
start_all()
|
||||
|
||||
vm.wait_for_unit("default.target")
|
||||
|
||||
${system-manager.lib.prepopulateProfileSnippet {
|
||||
node = "vm";
|
||||
profile = toplevel;
|
||||
}}
|
||||
vm.systemctl("daemon-reload")
|
||||
|
||||
# Simulate a reboot, to check that the services defined with
|
||||
# system-manager start correctly after a reboot.
|
||||
# TODO: can we find an easy way to really reboot the VM and not
|
||||
# loose the root FS state?
|
||||
vm.systemctl("isolate rescue.target")
|
||||
# We need to send a return character to dismiss the rescue-mode prompt
|
||||
vm.send_key("ret")
|
||||
vm.systemctl("isolate default.target")
|
||||
vm.wait_for_unit("system-manager.target")
|
||||
|
||||
vm.succeed("systemctl status service-9.service")
|
||||
vm.succeed("test -f /etc/baz/bar/foo2")
|
||||
vm.succeed("test -f /etc/a/nested/example/foo3")
|
||||
vm.succeed("test -f /etc/foo.conf")
|
||||
vm.succeed("grep -F 'launch_the_rockets = true' /etc/foo.conf")
|
||||
vm.fail("grep -F 'launch_the_rockets = false' /etc/foo.conf")
|
||||
|
||||
${system-manager.lib.activateProfileSnippet {
|
||||
node = "vm";
|
||||
profile = newConfig;
|
||||
}}
|
||||
vm.succeed("systemctl status new-service.service")
|
||||
vm.fail("systemctl status service-9.service")
|
||||
vm.fail("test -f /etc/a/nested/example/foo3")
|
||||
vm.fail("test -f /etc/baz/bar/foo2")
|
||||
vm.succeed("test -f /etc/foo_new")
|
||||
|
||||
${system-manager.lib.deactivateProfileSnippet {
|
||||
node = "vm";
|
||||
profile = newConfig;
|
||||
}}
|
||||
vm.fail("systemctl status new-service.service")
|
||||
vm.fail("test -f /etc/foo_new")
|
||||
'';
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
forEachUbuntuImage "prepopulate" {
|
||||
modules = [
|
||||
(testModule "old")
|
||||
../../../examples/example.nix
|
||||
];
|
||||
extraPathsToRegister = [ newConfig ];
|
||||
testScriptFunction = { toplevel, ... }: ''
|
||||
# Start all machines in parallel
|
||||
start_all()
|
||||
forEachUbuntuImage "system-path" {
|
||||
modules = [
|
||||
(testModule "old")
|
||||
../../../examples/example.nix
|
||||
];
|
||||
extraPathsToRegister = [ newConfig ];
|
||||
testScriptFunction =
|
||||
{ toplevel, hostPkgs, ... }:
|
||||
''
|
||||
# Start all machines in parallel
|
||||
start_all()
|
||||
vm.wait_for_unit("default.target")
|
||||
|
||||
vm.wait_for_unit("default.target")
|
||||
vm.fail("bash --login -c '$(which rg)'")
|
||||
vm.fail("bash --login -c '$(which fd)'")
|
||||
|
||||
${system-manager.lib.prepopulateProfileSnippet { node = "vm"; profile = toplevel; }}
|
||||
vm.systemctl("daemon-reload")
|
||||
${system-manager.lib.activateProfileSnippet {
|
||||
node = "vm";
|
||||
profile = toplevel;
|
||||
}}
|
||||
|
||||
# Simulate a reboot, to check that the services defined with
|
||||
# system-manager start correctly after a reboot.
|
||||
# TODO: can we find an easy way to really reboot the VM and not
|
||||
# loose the root FS state?
|
||||
vm.systemctl("isolate rescue.target")
|
||||
# We need to send a return character to dismiss the rescue-mode prompt
|
||||
vm.send_key("ret")
|
||||
vm.systemctl("isolate default.target")
|
||||
vm.wait_for_unit("system-manager.target")
|
||||
vm.wait_for_unit("system-manager.target")
|
||||
vm.wait_for_unit("system-manager-path.service")
|
||||
|
||||
vm.succeed("systemctl status service-9.service")
|
||||
vm.succeed("test -f /etc/baz/bar/foo2")
|
||||
vm.succeed("test -f /etc/a/nested/example/foo3")
|
||||
vm.succeed("test -f /etc/foo.conf")
|
||||
vm.succeed("grep -F 'launch_the_rockets = true' /etc/foo.conf")
|
||||
vm.fail("grep -F 'launch_the_rockets = false' /etc/foo.conf")
|
||||
#vm.fail("bash --login -c '$(which fish)'")
|
||||
vm.succeed("bash --login -c 'realpath $(which rg) | grep -F ${hostPkgs.ripgrep}/bin/rg'")
|
||||
vm.succeed("bash --login -c 'realpath $(which fd) | grep -F ${hostPkgs.fd}/bin/fd'")
|
||||
|
||||
${system-manager.lib.activateProfileSnippet { node = "vm"; profile = newConfig; }}
|
||||
vm.succeed("systemctl status new-service.service")
|
||||
vm.fail("systemctl status service-9.service")
|
||||
vm.fail("test -f /etc/a/nested/example/foo3")
|
||||
vm.fail("test -f /etc/baz/bar/foo2")
|
||||
vm.succeed("test -f /etc/foo_new")
|
||||
${system-manager.lib.activateProfileSnippet {
|
||||
node = "vm";
|
||||
profile = newConfig;
|
||||
}}
|
||||
|
||||
${system-manager.lib.deactivateProfileSnippet { node = "vm"; profile = newConfig; }}
|
||||
vm.fail("systemctl status new-service.service")
|
||||
vm.fail("test -f /etc/foo_new")
|
||||
'';
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
forEachUbuntuImage "system-path" {
|
||||
modules = [
|
||||
(testModule "old")
|
||||
../../../examples/example.nix
|
||||
];
|
||||
extraPathsToRegister = [ newConfig ];
|
||||
testScriptFunction = { toplevel, hostPkgs, ... }: ''
|
||||
# Start all machines in parallel
|
||||
start_all()
|
||||
vm.wait_for_unit("default.target")
|
||||
|
||||
vm.fail("bash --login -c '$(which rg)'")
|
||||
vm.fail("bash --login -c '$(which fd)'")
|
||||
|
||||
${system-manager.lib.activateProfileSnippet { node = "vm"; profile = toplevel; }}
|
||||
|
||||
vm.wait_for_unit("system-manager.target")
|
||||
vm.wait_for_unit("system-manager-path.service")
|
||||
|
||||
#vm.fail("bash --login -c '$(which fish)'")
|
||||
vm.succeed("bash --login -c 'realpath $(which rg) | grep -F ${hostPkgs.ripgrep}/bin/rg'")
|
||||
vm.succeed("bash --login -c 'realpath $(which fd) | grep -F ${hostPkgs.fd}/bin/fd'")
|
||||
|
||||
${system-manager.lib.activateProfileSnippet { node = "vm"; profile = newConfig; }}
|
||||
|
||||
vm.fail("bash --login -c '$(which rg)'")
|
||||
vm.fail("bash --login -c '$(which fd)'")
|
||||
vm.succeed("bash --login -c 'realpath $(which fish) | grep -F ${hostPkgs.fish}/bin/fish'")
|
||||
'';
|
||||
}
|
||||
vm.fail("bash --login -c '$(which rg)'")
|
||||
vm.fail("bash --login -c '$(which fd)'")
|
||||
vm.succeed("bash --login -c 'realpath $(which fish) | grep -F ${hostPkgs.fish}/bin/fish'")
|
||||
'';
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue