Merge pull request 'add apply "machine" as an alias to clan machines create' (#5005) from apply into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5005
This commit is contained in:
@@ -198,7 +198,7 @@ This subcommand provides an interface to templates provided by clan.
|
|||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
$ clan templates list
|
$ clan templates list
|
||||||
List all the machines managed by Clan.
|
List all available templates
|
||||||
|
|
||||||
Usage differs based on the template type
|
Usage differs based on the template type
|
||||||
|
|
||||||
@@ -227,6 +227,16 @@ Disk templates
|
|||||||
|
|
||||||
Real world example
|
Real world example
|
||||||
$ clan templates apply disk single-disk jon --set mainDisk "/dev/disk/by-id/nvme-WD_PC_SN740_SDDQNQD-512G-1201_232557804368"
|
$ clan templates apply disk single-disk jon --set mainDisk "/dev/disk/by-id/nvme-WD_PC_SN740_SDDQNQD-512G-1201_232557804368"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Machine templates
|
||||||
|
|
||||||
|
$ clan templates apply machine [TEMPLATE] [MACHINE_NAME]
|
||||||
|
Will create a new machine [MACHINE_NAME] from the specified [TEMPLATE]
|
||||||
|
|
||||||
|
Real world example
|
||||||
|
$ clan templates apply machine flash-installer my-installer
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
formatter_class=argparse.RawTextHelpFormatter,
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
|
|||||||
@@ -303,6 +303,27 @@ def complete_templates_clan(
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def complete_templates_machine(
|
||||||
|
_prefix: str,
|
||||||
|
parsed_args: argparse.Namespace,
|
||||||
|
**_kwargs: Any,
|
||||||
|
) -> Iterable[str]:
|
||||||
|
"""Provides completion functionality for machine templates"""
|
||||||
|
flake = (
|
||||||
|
clan_dir_result
|
||||||
|
if (clan_dir_result := clan_dir(getattr(parsed_args, "flake", None)))
|
||||||
|
is not None
|
||||||
|
else "."
|
||||||
|
)
|
||||||
|
|
||||||
|
list_all_templates = list_templates(Flake(flake))
|
||||||
|
machine_template_list = list_all_templates.builtins.get("machine")
|
||||||
|
if machine_template_list:
|
||||||
|
machine_templates = list(machine_template_list)
|
||||||
|
return dict.fromkeys(machine_templates, "machine")
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
def complete_vars_for_machine(
|
def complete_vars_for_machine(
|
||||||
_prefix: str,
|
_prefix: str,
|
||||||
parsed_args: argparse.Namespace,
|
parsed_args: argparse.Namespace,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from .apply_disk import register_apply_disk_template_parser
|
from .apply_disk import register_apply_disk_template_parser
|
||||||
|
from .apply_machine import register_apply_machine_template_parser
|
||||||
|
|
||||||
|
|
||||||
def register_apply_parser(parser: argparse.ArgumentParser) -> None:
|
def register_apply_parser(parser: argparse.ArgumentParser) -> None:
|
||||||
@@ -11,5 +12,7 @@ def register_apply_parser(parser: argparse.ArgumentParser) -> None:
|
|||||||
required=True,
|
required=True,
|
||||||
)
|
)
|
||||||
disk_parser = subparser.add_parser("disk", help="Apply a disk template")
|
disk_parser = subparser.add_parser("disk", help="Apply a disk template")
|
||||||
|
machine_parser = subparser.add_parser("machine", help="Apply a machine template")
|
||||||
|
|
||||||
register_apply_disk_template_parser(disk_parser)
|
register_apply_disk_template_parser(disk_parser)
|
||||||
|
register_apply_machine_template_parser(machine_parser)
|
||||||
|
|||||||
42
pkgs/clan-cli/clan_cli/templates/apply_machine.py
Normal file
42
pkgs/clan-cli/clan_cli/templates/apply_machine.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from clan_lib.nix_models.clan import InventoryMachine
|
||||||
|
from clan_lib.nix_models.clan import InventoryMachineDeploy as MachineDeploy
|
||||||
|
|
||||||
|
from clan_cli.machines.create import CreateOptions, create_machine
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def apply_command(args: argparse.Namespace) -> None:
|
||||||
|
"""Apply a machine template - actually an alias for machines create --template."""
|
||||||
|
# Create machine using the create_machine API directly
|
||||||
|
machine = InventoryMachine(
|
||||||
|
name=args.machine,
|
||||||
|
tags=[],
|
||||||
|
deploy=MachineDeploy(targetHost=None),
|
||||||
|
)
|
||||||
|
|
||||||
|
opts = CreateOptions(
|
||||||
|
clan_dir=args.flake,
|
||||||
|
machine=machine,
|
||||||
|
template=args.template,
|
||||||
|
)
|
||||||
|
|
||||||
|
create_machine(opts)
|
||||||
|
|
||||||
|
|
||||||
|
def register_apply_machine_template_parser(parser: argparse.ArgumentParser) -> None:
|
||||||
|
parser.add_argument(
|
||||||
|
"template",
|
||||||
|
type=str,
|
||||||
|
help="The name of the machine template to apply",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"machine",
|
||||||
|
type=str,
|
||||||
|
help="The name of the machine to create from the template",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.set_defaults(func=apply_command)
|
||||||
79
pkgs/clan-cli/clan_cli/templates/apply_test.py
Normal file
79
pkgs/clan-cli/clan_cli/templates/apply_test.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from clan_lib.errors import ClanError
|
||||||
|
from clan_lib.flake import Flake
|
||||||
|
from clan_lib.machines.machines import Machine
|
||||||
|
from clan_lib.templates.disk import set_machine_disk_schema
|
||||||
|
|
||||||
|
from clan_cli.tests.fixtures_flakes import FlakeForTest
|
||||||
|
from clan_cli.tests.helpers import cli
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.with_core
|
||||||
|
def test_templates_apply_machine_and_disk(
|
||||||
|
test_flake_with_core: FlakeForTest,
|
||||||
|
) -> None:
|
||||||
|
"""Test both machine template creation and disk template application."""
|
||||||
|
flake_path = str(test_flake_with_core.path)
|
||||||
|
|
||||||
|
cli.run(
|
||||||
|
[
|
||||||
|
"templates",
|
||||||
|
"apply",
|
||||||
|
"machine",
|
||||||
|
"new-machine",
|
||||||
|
"test-apply-machine",
|
||||||
|
"--flake",
|
||||||
|
flake_path,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Verify machine was created
|
||||||
|
machine_dir = test_flake_with_core.path / "machines" / "test-apply-machine"
|
||||||
|
assert machine_dir.exists(), "Machine directory should be created"
|
||||||
|
assert (machine_dir / "configuration.nix").exists(), (
|
||||||
|
"Configuration file should exist"
|
||||||
|
)
|
||||||
|
|
||||||
|
facter_content = {
|
||||||
|
"disks": [
|
||||||
|
{
|
||||||
|
"name": "test-disk",
|
||||||
|
"path": "/dev/sda",
|
||||||
|
"size": 107374182400,
|
||||||
|
"type": "disk",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
facter_path = machine_dir / "facter.json"
|
||||||
|
facter_path.write_text(json.dumps(facter_content, indent=2))
|
||||||
|
|
||||||
|
machine = Machine(name="test-apply-machine", flake=Flake(flake_path))
|
||||||
|
set_machine_disk_schema(
|
||||||
|
machine,
|
||||||
|
"single-disk",
|
||||||
|
{"mainDisk": "/dev/sda"},
|
||||||
|
force=False,
|
||||||
|
check_hw=False, # Skip hardware validation for test
|
||||||
|
)
|
||||||
|
|
||||||
|
# Verify disk template was applied by checking that disko.nix exists or was updated
|
||||||
|
disko_file = machine_dir / "disko.nix"
|
||||||
|
assert disko_file.exists(), "Disko configuration should be created"
|
||||||
|
|
||||||
|
# Verify error handling - try to create duplicate machine
|
||||||
|
# Since apply machine now uses machines create, it raises ClanError for duplicates
|
||||||
|
with pytest.raises(ClanError, match="already exists"):
|
||||||
|
cli.run(
|
||||||
|
[
|
||||||
|
"templates",
|
||||||
|
"apply",
|
||||||
|
"machine",
|
||||||
|
"new-machine",
|
||||||
|
"test-apply-machine", # Same name as existing
|
||||||
|
"--flake",
|
||||||
|
flake_path,
|
||||||
|
]
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user