From 750b6aec59818ec79a8df860e334cc42a6a7f11f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Wed, 29 May 2024 11:10:14 +0200 Subject: [PATCH] flash: make configuration more explicit Injecting nixos configuration and potentially overriding settings a user made and can cause surprises. In most cases, users want to just make these option part of their NixOS configuration and by having the rest in the command line we make it more explicit what other configuration is being applied. --- docs/site/getting-started/installer.md | 15 +++- pkgs/clan-cli/clan_cli/flash.py | 112 ++++--------------------- 2 files changed, 30 insertions(+), 97 deletions(-) diff --git a/docs/site/getting-started/installer.md b/docs/site/getting-started/installer.md index 30ffb1a6..c7a6c5e7 100644 --- a/docs/site/getting-started/installer.md +++ b/docs/site/getting-started/installer.md @@ -42,13 +42,22 @@ sudo umount /dev/sdb1 === "**Linux OS**" ### Step 2. Flash Custom Installer - Using clan flash enables the inclusion of ssh public keys and disables ssh password authentication. - It also includes the language and keymap currently used into the installer image. + Using clan flash enables the inclusion of ssh public keys. + It also allows to set language and keymap currently in the installer image. ```bash - clan flash --flake git+https://git.clan.lol/clan/clan-core flash-installer --disk main /dev/sd + clan flash --flake git+https://git.clan.lol/clan/clan-core \ + --ssh-pubkey $HOME/.ssh/id_ed25519.pub \ + --keymap en \ + --language en \ + --disk main /dev/sd \ + flash-installer ``` + The `--ssh-pubkey`, `--language` and `--keymap` are optional. + Replace `$HOME/.ssh/id_ed25519.pub` with a path to your SSH public key. + If you do not have an ssh key yet, you can generate one with `ssh-keygen -t ed25519` command. + !!! Danger "Specifying the wrong device can lead to unrecoverable data loss." The `clan flash` utility will erase the disk. Make sure to specify the correct device diff --git a/pkgs/clan-cli/clan_cli/flash.py b/pkgs/clan-cli/clan_cli/flash.py index 7cec0f67..91d4df49 100644 --- a/pkgs/clan-cli/clan_cli/flash.py +++ b/pkgs/clan-cli/clan_cli/flash.py @@ -3,7 +3,6 @@ import importlib import json import logging import os -import re import shutil import textwrap from collections.abc import Sequence @@ -21,63 +20,6 @@ from .nix import nix_shell log = logging.getLogger(__name__) -def list_available_ssh_keys(ssh_dir: Path = Path("~/.ssh").expanduser()) -> list[Path]: - """ - Function to list all available SSH public keys in the default .ssh directory. - Returns a list of paths to available public key files. - """ - public_key_patterns = ["*.pub"] - available_keys: list[Path] = [] - - # Check for public key files - for pattern in public_key_patterns: - for key_path in ssh_dir.glob(pattern): - if key_path.is_file(): - available_keys.append(key_path) - - return available_keys - - -def read_public_key_contents(public_keys: list[Path]) -> list[str]: - """ - Function to read and return the contents of available SSH public keys. - Returns a list containing the contents of each public key. - """ - public_key_contents = [] - - for key_path in public_keys: - try: - with open(key_path.expanduser()) as key_file: - public_key_contents.append(key_file.read().strip()) - except FileNotFoundError: - log.error(f"Public key file not found: {key_path}") - - return public_key_contents - - -def get_keymap_and_locale() -> dict[str, str]: - locale = "en_US.UTF-8" - keymap = "en" - - # Execute the `localectl status` command - result = run(["localectl", "status"]) - - if result.returncode == 0: - output = result.stdout - - # Extract the Keymap (X11 Layout) - keymap_match = re.search(r"X11 Layout:\s+(.*)", output) - if keymap_match: - keymap = keymap_match.group(1) - - # Extract the System Locale (LANG only) - locale_match = re.search(r"System Locale:\s+LANG=(.*)", output) - if locale_match: - locale = locale_match.group(1) - - return {"keymap": keymap, "locale": locale} - - def flash_machine( machine: Machine, *, @@ -184,10 +126,10 @@ def flash_command(args: argparse.Namespace) -> None: confirm=not args.yes, debug=args.debug, mode=args.mode, - language=args.lang, + language=args.language, keymap=args.keymap, write_efi_boot_entries=args.write_efi_boot_entries, - nix_options=args.options, + nix_options=args.option, ) machine = Machine(opts.machine, flake=opts.flake) @@ -201,40 +143,22 @@ def flash_command(args: argparse.Namespace) -> None: if ask != "y": return - root_keys = read_public_key_contents(opts.ssh_keys_path) - if opts.confirm and not root_keys: - msg = "Should we add your SSH public keys to the root user? [y/N] " - ask = input(msg) - if ask == "y": - pubkeys = list_available_ssh_keys() - root_keys.extend(read_public_key_contents(pubkeys)) - else: - raise ClanError( - "No SSH public keys provided. Use --ssh-pubkey to add keys." - ) - elif not opts.confirm and not root_keys: - pubkeys = list_available_ssh_keys() - root_keys.extend(read_public_key_contents(pubkeys)) - # If ssh-pubkeys set, we don't need to ask for confirmation - elif opts.confirm and root_keys: - pass - elif not opts.confirm and root_keys: - pass - else: - raise ClanError("Invalid state") - - localectl = get_keymap_and_locale() - extra_config = { - "users": { + extra_config: dict[str, Any] = {} + if opts.ssh_keys_path: + root_keys = [] + for key_path in opts.ssh_keys_path: + try: + root_keys.append(key_path.read_text()) + except OSError as e: + raise ClanError(f"Cannot read SSH public key file: {key_path}: {e}") + extra_config["users"] = { "users": {"root": {"openssh": {"authorizedKeys": {"keys": root_keys}}}} - }, - "console": { - "keyMap": opts.keymap if opts.keymap else localectl["keymap"], - }, - "i18n": { - "defaultLocale": opts.language if opts.language else localectl["locale"], - }, - } + } + if opts.keymap: + extra_config["console"] = {"keyMap": opts.keymap} + + if opts.language: + extra_config["i18n"] = {"defaultLocale": opts.language} flash_machine( machine, @@ -286,7 +210,7 @@ def register_parser(parser: argparse.ArgumentParser) -> None: help="ssh pubkey file to add to the root user. Can be used multiple times", ) parser.add_argument( - "--lang", + "--language", type=str, help="system language", )