mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-02-12 15:14:13 +00:00
Merge pull request #243995 from nikstur/systemd-sysupdate
This commit is contained in:
commit
96f7ceb7b9
@ -34,6 +34,7 @@
|
||||
|
||||
- [ebusd](https://ebusd.eu), a daemon for handling communication with eBUS devices connected to a 2-wire bus system (“energy bus” used by numerous heating systems). Available as [services.ebusd](#opt-services.ebusd.enable).
|
||||
|
||||
- [systemd-sysupdate](https://www.freedesktop.org/software/systemd/man/systemd-sysupdate.html), atomically updates the host OS, container images, portable service images or other sources. Available as [systemd.sysupdate](opt-systemd.sysupdate).
|
||||
|
||||
## Backward Incompatibilities {#sec-release-23.11-incompatibilities}
|
||||
|
||||
|
@ -1398,6 +1398,7 @@
|
||||
./system/boot/systemd/oomd.nix
|
||||
./system/boot/systemd/repart.nix
|
||||
./system/boot/systemd/shutdown.nix
|
||||
./system/boot/systemd/sysupdate.nix
|
||||
./system/boot/systemd/tmpfiles.nix
|
||||
./system/boot/systemd/user.nix
|
||||
./system/boot/systemd/userdbd.nix
|
||||
|
142
nixos/modules/system/boot/systemd/sysupdate.nix
Normal file
142
nixos/modules/system/boot/systemd/sysupdate.nix
Normal file
@ -0,0 +1,142 @@
|
||||
{ config, lib, pkgs, utils, ... }:
|
||||
|
||||
let
|
||||
cfg = config.systemd.sysupdate;
|
||||
|
||||
format = pkgs.formats.ini { };
|
||||
|
||||
listOfDefinitions = lib.mapAttrsToList
|
||||
(name: format.generate "${name}.conf")
|
||||
(lib.filterAttrs (k: _: !(lib.hasPrefix "_" k)) cfg.transfers);
|
||||
|
||||
definitionsDirectory = pkgs.runCommand "sysupdate.d" { } ''
|
||||
mkdir -p $out
|
||||
${(lib.concatStringsSep "\n"
|
||||
(map (pkg: "cp ${pkg} $out/${pkg.name}") listOfDefinitions)
|
||||
)}
|
||||
'';
|
||||
in
|
||||
{
|
||||
options.systemd.sysupdate = {
|
||||
|
||||
enable = lib.mkEnableOption (lib.mdDoc "systemd-sysupdate") // {
|
||||
description = lib.mdDoc ''
|
||||
Atomically update the host OS, container images, portable service
|
||||
images or other sources.
|
||||
|
||||
If enabled, updates are triggered in regular intervals via a
|
||||
`systemd.timer` unit.
|
||||
|
||||
Please see
|
||||
<https://www.freedesktop.org/software/systemd/man/systemd-sysupdate.html>
|
||||
for more details.
|
||||
'';
|
||||
};
|
||||
|
||||
timerConfig = utils.systemdUtils.unitOptions.timerOptions.options.timerConfig // {
|
||||
default = { };
|
||||
description = lib.mdDoc ''
|
||||
The timer configuration for performing the update.
|
||||
|
||||
By default, the upstream configuration is used:
|
||||
<https://github.com/systemd/systemd/blob/main/units/systemd-sysupdate.timer>
|
||||
'';
|
||||
};
|
||||
|
||||
reboot = {
|
||||
enable = lib.mkEnableOption (lib.mdDoc "automatically rebooting after an update") // {
|
||||
description = lib.mdDoc ''
|
||||
Whether to automatically reboot after an update.
|
||||
|
||||
If set to `true`, the system will automatically reboot via a
|
||||
`systemd.timer` unit but only after a new version was installed.
|
||||
|
||||
This uses a unit completely separate from the one performing the
|
||||
update because it is typically advisable to download updates
|
||||
regularly while the system is up, but delay reboots until the
|
||||
appropriate time (i.e. typically at night).
|
||||
|
||||
Set this to `false` if you do not want to reboot after an update. This
|
||||
is useful when you update a container image or another source where
|
||||
rebooting is not necessary in order to finalize the update.
|
||||
'';
|
||||
};
|
||||
|
||||
timerConfig = utils.systemdUtils.unitOptions.timerOptions.options.timerConfig // {
|
||||
default = { };
|
||||
description = lib.mdDoc ''
|
||||
The timer configuration for rebooting after an update.
|
||||
|
||||
By default, the upstream configuration is used:
|
||||
<https://github.com/systemd/systemd/blob/main/units/systemd-sysupdate-reboot.timer>
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
transfers = lib.mkOption {
|
||||
type = with lib.types; attrsOf format.type;
|
||||
default = { };
|
||||
example = {
|
||||
"10-uki.conf" = {
|
||||
Transfer = {
|
||||
ProtectVersion = "%A";
|
||||
};
|
||||
|
||||
Source = {
|
||||
Type = "url-file";
|
||||
Path = "https://download.example.com/";
|
||||
MatchPattern = "nixos_@v.efi.xz";
|
||||
};
|
||||
|
||||
Target = {
|
||||
Type = "regular-file";
|
||||
Path = "/EFI/Linux";
|
||||
PathRelativeTo = "boot";
|
||||
MatchPattern = ''
|
||||
nixos_@v+@l-@d.efi"; \
|
||||
nixos_@v+@l.efi \
|
||||
nixos_@v.efi
|
||||
'';
|
||||
Mode = "0444";
|
||||
TriesLeft = 3;
|
||||
TriesDone = 0;
|
||||
InstancesMax = 2;
|
||||
};
|
||||
};
|
||||
};
|
||||
description = lib.mdDoc ''
|
||||
Specify transfers as a set of the names of the transfer files as the
|
||||
key and the configuration as its value. The configuration can use all
|
||||
upstream options. See
|
||||
<https://www.freedesktop.org/software/systemd/man/sysupdate.d.html>
|
||||
for all available options.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
|
||||
systemd.additionalUpstreamSystemUnits = [
|
||||
"systemd-sysupdate.service"
|
||||
"systemd-sysupdate.timer"
|
||||
"systemd-sysupdate-reboot.service"
|
||||
"systemd-sysupdate-reboot.timer"
|
||||
];
|
||||
|
||||
systemd.timers = {
|
||||
"systemd-sysupdate" = {
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = cfg.timerConfig;
|
||||
};
|
||||
"systemd-sysupdate-reboot" = lib.mkIf cfg.reboot.enable {
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = cfg.reboot.timerConfig;
|
||||
};
|
||||
};
|
||||
|
||||
environment.etc."sysupdate.d".source = definitionsDirectory;
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ nikstur ];
|
||||
}
|
@ -772,6 +772,7 @@ in {
|
||||
systemd-portabled = handleTest ./systemd-portabled.nix {};
|
||||
systemd-repart = handleTest ./systemd-repart.nix {};
|
||||
systemd-shutdown = handleTest ./systemd-shutdown.nix {};
|
||||
systemd-sysupdate = runTest ./systemd-sysupdate.nix;
|
||||
systemd-timesyncd = handleTest ./systemd-timesyncd.nix {};
|
||||
systemd-user-tmpfiles-rules = handleTest ./systemd-user-tmpfiles-rules.nix {};
|
||||
systemd-misc = handleTest ./systemd-misc.nix {};
|
||||
|
21
nixos/tests/common/gpg-keyring.nix
Normal file
21
nixos/tests/common/gpg-keyring.nix
Normal file
@ -0,0 +1,21 @@
|
||||
{ pkgs, ... }:
|
||||
|
||||
pkgs.runCommand "gpg-keyring" { nativeBuildInputs = [ pkgs.gnupg ]; } ''
|
||||
mkdir -p $out
|
||||
export GNUPGHOME=$out
|
||||
cat > foo <<EOF
|
||||
%echo Generating a basic OpenPGP key
|
||||
%no-protection
|
||||
Key-Type: EdDSA
|
||||
Key-Curve: ed25519
|
||||
Name-Real: Bob Foobar
|
||||
Name-Email: bob@foo.bar
|
||||
Expire-Date: 0
|
||||
# Do a commit here, so that we can later print "done"
|
||||
%commit
|
||||
%echo done
|
||||
EOF
|
||||
gpg --batch --generate-key foo
|
||||
rm $out/S.gpg-agent $out/S.gpg-agent.*
|
||||
gpg --export bob@foo.bar -a > $out/pubkey.gpg
|
||||
''
|
@ -1,26 +1,6 @@
|
||||
import ./make-test-python.nix ({pkgs, lib, ...}:
|
||||
let
|
||||
gpgKeyring = (pkgs.runCommand "gpg-keyring" { buildInputs = [ pkgs.gnupg ]; } ''
|
||||
mkdir -p $out
|
||||
export GNUPGHOME=$out
|
||||
cat > foo <<EOF
|
||||
%echo Generating a basic OpenPGP key
|
||||
%no-protection
|
||||
Key-Type: DSA
|
||||
Key-Length: 1024
|
||||
Subkey-Type: ELG-E
|
||||
Subkey-Length: 1024
|
||||
Name-Real: Bob Foobar
|
||||
Name-Email: bob@foo.bar
|
||||
Expire-Date: 0
|
||||
# Do a commit here, so that we can later print "done"
|
||||
%commit
|
||||
%echo done
|
||||
EOF
|
||||
gpg --batch --generate-key foo
|
||||
rm $out/S.gpg-agent $out/S.gpg-agent.*
|
||||
gpg --export bob@foo.bar -a > $out/pubkey.gpg
|
||||
'');
|
||||
gpgKeyring = import ./common/gpg-keyring.nix { inherit pkgs; };
|
||||
|
||||
nspawnImages = (pkgs.runCommand "localhost" { buildInputs = [ pkgs.coreutils pkgs.gnupg ]; } ''
|
||||
mkdir -p $out
|
||||
|
66
nixos/tests/systemd-sysupdate.nix
Normal file
66
nixos/tests/systemd-sysupdate.nix
Normal file
@ -0,0 +1,66 @@
|
||||
# Tests downloading a signed update aritfact from a server to a target machine.
|
||||
# This test does not rely on the `systemd.timer` units provided by the
|
||||
# `systemd-sysupdate` module but triggers the `systemd-sysupdate` service
|
||||
# manually to make the test more robust.
|
||||
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
gpgKeyring = import ./common/gpg-keyring.nix { inherit pkgs; };
|
||||
in
|
||||
{
|
||||
name = "systemd-sysupdate";
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ nikstur ];
|
||||
|
||||
nodes = {
|
||||
server = { pkgs, ... }: {
|
||||
networking.firewall.enable = false;
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts."server" = {
|
||||
root = pkgs.runCommand "sysupdate-artifacts" { buildInputs = [ pkgs.gnupg ]; } ''
|
||||
mkdir -p $out
|
||||
cd $out
|
||||
|
||||
echo "nixos" > nixos_1.efi
|
||||
sha256sum nixos_1.efi > SHA256SUMS
|
||||
|
||||
export GNUPGHOME="$(mktemp -d)"
|
||||
cp -R ${gpgKeyring}/* $GNUPGHOME
|
||||
|
||||
gpg --batch --sign --detach-sign --output SHA256SUMS.gpg SHA256SUMS
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
target = {
|
||||
systemd.sysupdate = {
|
||||
enable = true;
|
||||
transfers = {
|
||||
"uki" = {
|
||||
Source = {
|
||||
Type = "url-file";
|
||||
Path = "http://server/";
|
||||
MatchPattern = "nixos_@v.efi";
|
||||
};
|
||||
Target = {
|
||||
Path = "/boot/EFI/Linux";
|
||||
MatchPattern = "nixos_@v.efi";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
environment.etc."systemd/import-pubring.gpg".source = "${gpgKeyring}/pubkey.gpg";
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
server.wait_for_unit("nginx.service")
|
||||
|
||||
target.succeed("systemctl start systemd-sysupdate")
|
||||
assert "nixos" in target.wait_until_succeeds("cat /boot/EFI/Linux/nixos_1.efi", timeout=5)
|
||||
'';
|
||||
}
|
Loading…
Reference in New Issue
Block a user