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