From 4c4a17ed0c458acbdc44d0c7ddeba6eb5f502bd0 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Fri, 11 Jul 2025 18:53:15 +0200 Subject: [PATCH] cli/templates: init apply disk --- pkgs/clan-cli/clan_cli/templates/__init__.py | 5 ++ pkgs/clan-cli/clan_cli/templates/apply.py | 15 ++++ .../clan-cli/clan_cli/templates/apply_disk.py | 78 +++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 pkgs/clan-cli/clan_cli/templates/apply.py create mode 100644 pkgs/clan-cli/clan_cli/templates/apply_disk.py diff --git a/pkgs/clan-cli/clan_cli/templates/__init__.py b/pkgs/clan-cli/clan_cli/templates/__init__.py index 1696b625f..8f0f175dc 100644 --- a/pkgs/clan-cli/clan_cli/templates/__init__.py +++ b/pkgs/clan-cli/clan_cli/templates/__init__.py @@ -1,6 +1,7 @@ # !/usr/bin/env python3 import argparse +from .apply import register_apply_parser from .list import register_list_parser @@ -13,4 +14,8 @@ def register_parser(parser: argparse.ArgumentParser) -> None: required=True, ) list_parser = subparser.add_parser("list", help="List avilable templates") + apply_parser = subparser.add_parser( + "apply", help="Apply a template of the specified type" + ) register_list_parser(list_parser) + register_apply_parser(apply_parser) diff --git a/pkgs/clan-cli/clan_cli/templates/apply.py b/pkgs/clan-cli/clan_cli/templates/apply.py new file mode 100644 index 000000000..d5113853c --- /dev/null +++ b/pkgs/clan-cli/clan_cli/templates/apply.py @@ -0,0 +1,15 @@ +import argparse + +from .apply_disk import register_apply_disk_template_parser + + +def register_apply_parser(parser: argparse.ArgumentParser) -> None: + subparser = parser.add_subparsers( + title="template_type", + description="the template type to apply", + help="the template type to apply", + required=True, + ) + disk_parser = subparser.add_parser("disk", help="Apply a disk template") + + register_apply_disk_template_parser(disk_parser) diff --git a/pkgs/clan-cli/clan_cli/templates/apply_disk.py b/pkgs/clan-cli/clan_cli/templates/apply_disk.py new file mode 100644 index 000000000..c460ea64d --- /dev/null +++ b/pkgs/clan-cli/clan_cli/templates/apply_disk.py @@ -0,0 +1,78 @@ +import argparse +import logging +from collections.abc import Sequence +from typing import Any + +from clan_lib.api.disk import set_machine_disk_schema +from clan_lib.machines.machines import Machine + +log = logging.getLogger(__name__) + + +class AppendSetAction(argparse.Action): + def __init__(self, option_strings: str, dest: str, **kwargs: Any) -> None: + super().__init__(option_strings, dest, **kwargs) + + def __call__( + self, + parser: argparse.ArgumentParser, + namespace: argparse.Namespace, + values: str | Sequence[str] | None, + option_string: str | None = None, + ) -> None: + lst = getattr(namespace, self.dest) + assert isinstance(values, list), "values must be a list" + lst.append((values[0], values[1])) + + +def apply_command(args: argparse.Namespace) -> None: + """Apply a disk template to a machine.""" + set_tuples: list[tuple[str, str]] = args.set + + placeholders = dict(set_tuples) + + set_machine_disk_schema( + Machine(args.to_machine, args.flake), + args.template, + placeholders, + force=args.force, + check_hw=not args.skip_hardware_check, + ) + log.info(f"Applied disk template '{args.template}' to machine '{args.to_machine}' ") + + +def register_apply_disk_template_parser(parser: argparse.ArgumentParser) -> None: + parser.add_argument( + "--to-machine", + type=str, + required=True, + help="The machine to apply the template to", + ) + parser.add_argument( + "--template", + type=str, + required=True, + help="The name of the disk template to apply", + ) + parser.add_argument( + "--set", + help="Set a placeholder in the template to a value", + nargs=2, + metavar=("placeholder", "value"), + action=AppendSetAction, + default=[], + ) + parser.add_argument( + "--force", + help="Force apply the template even if the machine already has a disk schema", + action="store_true", + default=False, + ) + parser.add_argument( + "--skip-hardware-check", + help="Disables hardware checking. By default this command checks that the facter.json report exists and validates provided options", + action="store_true", + default=False, + ) + + parser.set_defaults(func=apply_command)