make machine class now a dataclass

This commit is contained in:
Jörg Thalheim
2024-07-02 14:06:31 +02:00
parent cc583dd79e
commit b4698528ef
23 changed files with 125 additions and 128 deletions

View File

@@ -1,10 +1,11 @@
import json
import logging
from dataclasses import dataclass, field
from pathlib import Path
from tempfile import NamedTemporaryFile
from typing import Any
from clan_cli.clan_uri import ClanURI, FlakeId
from clan_cli.clan_uri import FlakeId
from ..cmd import run_no_stdout
from ..errors import ClanError
@@ -14,63 +15,41 @@ from ..ssh import Host, parse_deployment_address
log = logging.getLogger(__name__)
@dataclass
class Machine:
name: str
flake: FlakeId
nix_options: list[str]
eval_cache: dict[str, str]
build_cache: dict[str, Path]
_flake_path: Path | None
_deployment_info: None | dict
nix_options: list[str] = field(default_factory=list)
cached_deployment: None | dict = None
def __init__(
self,
name: str,
flake: Path | str,
deployment_info: dict | None = None,
nix_options: list[str] = [],
) -> None:
"""
Creates a Machine
@name: the name of the machine
@clan_dir: the directory of the clan, optional, if not set it will be determined from the current working directory
@machine_json: can be optionally used to skip evaluation of the machine, location of the json file with machine data
"""
uri = ClanURI.from_str(str(flake), name)
self.flake_id = uri.flake_id
self.name: str = uri.machine_name
self.eval_cache: dict[str, str] = {}
self.build_cache: dict[str, Path] = {}
self._flake_path: Path | None = None
self._deployment_info: None | dict = deployment_info
self.nix_options = nix_options
_eval_cache: dict[str, str] = field(default_factory=dict)
_build_cache: dict[str, Path] = field(default_factory=dict)
def flush_caches(self) -> None:
self._deployment_info = None
self._flake_path = None
self.build_cache.clear()
self.eval_cache.clear()
self.cached_deployment = None
self._build_cache.clear()
self._eval_cache.clear()
def __str__(self) -> str:
return f"Machine(name={self.name}, flake={self.flake_id})"
return f"Machine(name={self.name}, flake={self.flake})"
def __repr__(self) -> str:
return str(self)
@property
def deployment_info(self) -> dict:
if self._deployment_info is not None:
return self._deployment_info
self._deployment_info = json.loads(
def deployment(self) -> dict:
if self.cached_deployment is not None:
return self.cached_deployment
deployment = json.loads(
self.build_nix("config.system.clan.deployment.file").read_text()
)
return self._deployment_info
self.cached_deployment = deployment
return deployment
@property
def target_host_address(self) -> str:
# deploymentAddress is deprecated.
val = self.deployment_info.get("targetHost") or self.deployment_info.get(
val = self.deployment.get("targetHost") or self.deployment.get(
"deploymentAddress"
)
if val is None:
@@ -80,40 +59,34 @@ class Machine:
@target_host_address.setter
def target_host_address(self, value: str) -> None:
self.deployment_info["targetHost"] = value
self.deployment["targetHost"] = value
@property
def secret_facts_module(self) -> str:
return self.deployment_info["facts"]["secretModule"]
return self.deployment["facts"]["secretModule"]
@property
def public_facts_module(self) -> str:
return self.deployment_info["facts"]["publicModule"]
return self.deployment["facts"]["publicModule"]
@property
def facts_data(self) -> dict[str, dict[str, Any]]:
if self.deployment_info["facts"]["services"]:
return self.deployment_info["facts"]["services"]
if self.deployment["facts"]["services"]:
return self.deployment["facts"]["services"]
return {}
@property
def secrets_upload_directory(self) -> str:
return self.deployment_info["facts"]["secretUploadDirectory"]
return self.deployment["facts"]["secretUploadDirectory"]
@property
def flake_dir(self) -> Path:
if self._flake_path:
return self._flake_path
if self.flake_id.is_local():
self._flake_path = self.flake_id.path
elif self.flake_id.is_remote():
self._flake_path = Path(nix_metadata(self.flake_id.url)["path"])
if self.flake.is_local():
return self.flake.path
elif self.flake.is_remote():
return Path(nix_metadata(self.flake.url)["path"])
else:
raise ClanError(f"Unsupported flake url: {self.flake_id}")
assert self._flake_path is not None
return self._flake_path
raise ClanError(f"Unsupported flake url: {self.flake}")
@property
def target_host(self) -> Host:
@@ -127,7 +100,7 @@ class Machine:
The host where the machine is built and deployed from.
Can be the same as the target host.
"""
build_host = self.deployment_info.get("buildHost")
build_host = self.deployment.get("buildHost")
if build_host is None:
return self.target_host
# enable ssh agent forwarding to allow the build host to access the target host
@@ -230,12 +203,12 @@ class Machine:
eval a nix attribute of the machine
@attr: the attribute to get
"""
if attr in self.eval_cache and not refresh and extra_config is None:
return self.eval_cache[attr]
if attr in self._eval_cache and not refresh and extra_config is None:
return self._eval_cache[attr]
output = self.nix("eval", attr, extra_config, impure, nix_options)
if isinstance(output, str):
self.eval_cache[attr] = output
self._eval_cache[attr] = output
return output
else:
raise ClanError("eval_nix returned not a string")
@@ -253,12 +226,12 @@ class Machine:
@attr: the attribute to get
"""
if attr in self.build_cache and not refresh and extra_config is None:
return self.build_cache[attr]
if attr in self._build_cache and not refresh and extra_config is None:
return self._build_cache[attr]
output = self.nix("build", attr, extra_config, impure, nix_options)
if isinstance(output, Path):
self.build_cache[attr] = output
self._build_cache[attr] = output
return output
else:
raise ClanError("build_nix returned not a Path")