nixos/systemd-boot-builder: warn instead of aborting when an old gen's secrets fail
After removing or renaming a file in boot.initrd.secrets, older generations' append scripts start failing. Aborting on that blocks deploying the new configuration, so only treat a failure as fatal when it belongs to the configuration being switched to.
This commit is contained in:
@@ -140,23 +140,30 @@ class SystemIdentifier(NamedTuple):
|
||||
@dataclass
|
||||
class BootFile:
|
||||
system_identifier: SystemIdentifier
|
||||
current: bool
|
||||
path: Path
|
||||
writer: WriteBootFile
|
||||
|
||||
@staticmethod
|
||||
def from_source(system_identifier: SystemIdentifier, source: Path) -> "BootFile":
|
||||
def from_source(
|
||||
system_identifier: SystemIdentifier, current: bool, source: Path
|
||||
) -> "BootFile":
|
||||
return BootFile(
|
||||
system_identifier=system_identifier,
|
||||
current=current,
|
||||
path=boot_path(source),
|
||||
writer=CopyWriter(source=source),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def from_initrd(
|
||||
system_identifier: SystemIdentifier, source: Path, initrd_secrets: Path | None
|
||||
system_identifier: SystemIdentifier,
|
||||
current: bool,
|
||||
source: Path,
|
||||
initrd_secrets: Path | None,
|
||||
) -> "BootFile":
|
||||
if initrd_secrets is None:
|
||||
return BootFile.from_source(system_identifier, source)
|
||||
return BootFile.from_source(system_identifier, current, source)
|
||||
else:
|
||||
# We're trying to calculate a canonical path unique to
|
||||
# this initrd and secret-appender. The boot_path is the
|
||||
@@ -173,6 +180,7 @@ class BootFile:
|
||||
combined_hash = hashlib.sha256(combined.encode("utf-8")).hexdigest()
|
||||
return BootFile(
|
||||
system_identifier=system_identifier,
|
||||
current=current,
|
||||
path=NIXOS_DIR / f"{combined_hash}-initrd.efi",
|
||||
writer=InitrdWithSecretsWriter(
|
||||
source=source, initrd_secrets=initrd_secrets
|
||||
@@ -181,7 +189,7 @@ class BootFile:
|
||||
|
||||
@staticmethod
|
||||
def from_entry(
|
||||
system_identifier: SystemIdentifier, contents: bytes
|
||||
system_identifier: SystemIdentifier, current: bool, contents: bytes
|
||||
) -> tuple["BootFile", str]:
|
||||
contents_hash = hashlib.sha256(contents).hexdigest()
|
||||
path_prefix = f"nixos-{contents_hash}"
|
||||
@@ -199,6 +207,7 @@ class BootFile:
|
||||
return (
|
||||
BootFile(
|
||||
system_identifier=system_identifier,
|
||||
current=current,
|
||||
path=path,
|
||||
writer=ContentsWriter(contents=contents),
|
||||
),
|
||||
@@ -336,19 +345,23 @@ def boot_file(
|
||||
specialisation: str | None,
|
||||
machine_id: str | None,
|
||||
bootspec: BootSpec,
|
||||
current: bool,
|
||||
) -> tuple[BootFileList, str]:
|
||||
system_identifier = SystemIdentifier(profile, generation, specialisation)
|
||||
if specialisation:
|
||||
bootspec = bootspec.specialisations[specialisation]
|
||||
kernel = BootFile.from_source(system_identifier, bootspec.kernel)
|
||||
kernel = BootFile.from_source(system_identifier, current, bootspec.kernel)
|
||||
initrd = BootFile.from_initrd(
|
||||
system_identifier,
|
||||
current,
|
||||
bootspec.initrd,
|
||||
Path(bootspec.initrdSecrets) if bootspec.initrdSecrets is not None else None,
|
||||
)
|
||||
devicetree = None
|
||||
if bootspec.devicetree is not None:
|
||||
devicetree = BootFile.from_source(system_identifier, bootspec.devicetree)
|
||||
devicetree = BootFile.from_source(
|
||||
system_identifier, current, bootspec.devicetree
|
||||
)
|
||||
|
||||
kernel_params = " ".join([f"init={bootspec.init}"] + bootspec.kernelParams)
|
||||
build_time = int(system_dir(profile, generation, specialisation).stat().st_ctime)
|
||||
@@ -371,7 +384,9 @@ def boot_file(
|
||||
f"sort-key {bootspec.sortKey}",
|
||||
]
|
||||
contents = "\n".join(filter(None, boot_entry))
|
||||
entry, bootctl_id = BootFile.from_entry(system_identifier, contents.encode("utf-8"))
|
||||
entry, bootctl_id = BootFile.from_entry(
|
||||
system_identifier, current, contents.encode("utf-8")
|
||||
)
|
||||
return (list(filter(None, [kernel, initrd, devicetree, entry])), bootctl_id)
|
||||
|
||||
|
||||
@@ -520,7 +535,9 @@ def install_bootloader(args: argparse.Namespace) -> None:
|
||||
for gen in gens:
|
||||
bootspec = get_bootspec(gen.profile, gen.generation)
|
||||
is_default = Path(bootspec.init).parent == default_config
|
||||
new_boot_files, new_bootctl_id = boot_file(*gen, machine_id, bootspec)
|
||||
new_boot_files, new_bootctl_id = boot_file(
|
||||
*gen, machine_id, bootspec, current=is_default
|
||||
)
|
||||
boot_files.extend(new_boot_files)
|
||||
if is_default:
|
||||
default_entry_id = new_bootctl_id
|
||||
@@ -532,6 +549,7 @@ def install_bootloader(args: argparse.Namespace) -> None:
|
||||
specialisation_name,
|
||||
machine_id,
|
||||
bootspec,
|
||||
current=is_default,
|
||||
)
|
||||
boot_files.extend(new_boot_files)
|
||||
if is_default:
|
||||
@@ -599,7 +617,22 @@ def garbage_collect(gc_roots: BootFileList) -> None:
|
||||
def write_boot_files(boot_files: BootFileList) -> None:
|
||||
for boot_file in boot_files:
|
||||
boot_path = BOOT_MOUNT_POINT / boot_file.path
|
||||
boot_file.writer.write_boot_file(boot_path)
|
||||
try:
|
||||
boot_file.writer.write_boot_file(boot_path)
|
||||
except subprocess.CalledProcessError:
|
||||
if boot_file.current:
|
||||
print("failed to create initrd secrets!", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
print(
|
||||
"warning: failed to create initrd secrets for generation "
|
||||
f"{boot_file.system_identifier.generation}, an older generation",
|
||||
file=sys.stderr,
|
||||
)
|
||||
print(
|
||||
"note: this is normal after having removed "
|
||||
"or renamed a file in `boot.initrd.secrets`",
|
||||
file=sys.stderr,
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
||||
Reference in New Issue
Block a user