From 711c70d1f075ed989422b276168c4543f5cbbd59 Mon Sep 17 00:00:00 2001 From: Qubasa Date: Fri, 13 Oct 2023 19:56:10 +0200 Subject: [PATCH] Added state directory. --- pkgs/clan-cli/clan_cli/async_cmd.py | 22 +++++++++++++++++-- pkgs/clan-cli/clan_cli/flake/create.py | 20 +++++------------ pkgs/clan-cli/clan_cli/machines/create.py | 17 ++++++++++++-- pkgs/clan-cli/clan_cli/vms/inspect.py | 4 ++-- pkgs/clan-cli/clan_cli/webui/api_inputs.py | 6 +++-- pkgs/clan-cli/clan_cli/webui/routers/flake.py | 14 ++++++------ .../clan_cli/webui/routers/machines.py | 3 ++- pkgs/clan-cli/clan_cli/webui/routers/vms.py | 9 ++++++-- pkgs/clan-cli/tests/temporary_dir.py | 11 ++++++++-- pkgs/clan-cli/tests/test_vms_api_create.py | 3 ++- 10 files changed, 74 insertions(+), 35 deletions(-) diff --git a/pkgs/clan-cli/clan_cli/async_cmd.py b/pkgs/clan-cli/clan_cli/async_cmd.py index 77e477a6..b3aa72b1 100644 --- a/pkgs/clan-cli/clan_cli/async_cmd.py +++ b/pkgs/clan-cli/clan_cli/async_cmd.py @@ -2,7 +2,7 @@ import asyncio import logging import shlex from pathlib import Path -from typing import NamedTuple, Optional +from typing import Any, Callable, Coroutine, Dict, NamedTuple, Optional from .errors import ClanError @@ -36,10 +36,28 @@ async def run(cmd: list[str], cwd: Optional[Path] = None) -> CmdOut: raise ClanError( f""" command: {shlex.join(cmd)} +working directory: {cwd_res} exit code: {proc.returncode} -command output: +stderr: {stderr.decode("utf-8")} +stdout: +{stdout.decode("utf-8")} """ ) return CmdOut(stdout.decode("utf-8"), stderr.decode("utf-8"), cwd=cwd) + + +def runforcli(func: Callable[..., Coroutine[Any, Any, Dict[str, CmdOut]]], *args: Any) -> None: + try: + res = asyncio.run(func(*args)) + + for i in res.items(): + name, out = i + if out.stderr: + print(f"{name}: {out.stderr}", end="") + if out.stdout: + print(f"{name}: {out.stdout}", end="") + except ClanError as e: + print(e) + exit(1) \ No newline at end of file diff --git a/pkgs/clan-cli/clan_cli/flake/create.py b/pkgs/clan-cli/clan_cli/flake/create.py index c6625962..07e5a52e 100644 --- a/pkgs/clan-cli/clan_cli/flake/create.py +++ b/pkgs/clan-cli/clan_cli/flake/create.py @@ -1,14 +1,12 @@ # !/usr/bin/env python3 import argparse -import asyncio from pathlib import Path from typing import Dict from pydantic import AnyUrl from pydantic.tools import parse_obj_as -from ..async_cmd import CmdOut, run -from ..errors import ClanError +from ..async_cmd import CmdOut, run, runforcli from ..nix import nix_command, nix_shell DEFAULT_URL: AnyUrl = parse_obj_as(AnyUrl, "git+https://git.clan.lol/clan/clan-core#new-clan") @@ -33,6 +31,10 @@ async def create_flake(directory: Path, url: AnyUrl) -> Dict[str, CmdOut]: out = await run(command, directory) response["git init"] = out + command = nix_shell(["git"], ["git", "add", "."]) + out = await run(command, directory) + response["git add"] = out + command = nix_shell(["git"], ["git", "config", "user.name", "clan-tool"]) out = await run(command, directory) response["git config"] = out @@ -49,18 +51,8 @@ async def create_flake(directory: Path, url: AnyUrl) -> Dict[str, CmdOut]: def create_flake_command(args: argparse.Namespace) -> None: - try: - res = asyncio.run(create_flake(args.directory, DEFAULT_URL)) + runforcli(create_flake, args.directory, DEFAULT_URL) - for i in res.items(): - name, out = i - if out.stderr: - print(f"{name}: {out.stderr}", end="") - if out.stdout: - print(f"{name}: {out.stdout}", end="") - except ClanError as e: - print(e) - exit(1) # takes a (sub)parser and configures it diff --git a/pkgs/clan-cli/clan_cli/machines/create.py b/pkgs/clan-cli/clan_cli/machines/create.py index 54b70705..b8c7ea9b 100644 --- a/pkgs/clan-cli/clan_cli/machines/create.py +++ b/pkgs/clan-cli/clan_cli/machines/create.py @@ -1,18 +1,31 @@ import argparse +import logging +from typing import Dict +from ..async_cmd import CmdOut, run, runforcli +from ..nix import nix_shell from .folders import machine_folder +log = logging.getLogger(__name__) -def create_machine(name: str) -> None: +async def create_machine(name: str) -> Dict[str, CmdOut]: folder = machine_folder(name) folder.mkdir(parents=True, exist_ok=True) + # create empty settings.json file inside the folder with open(folder / "settings.json", "w") as f: f.write("{}") + response = {} + out = await run(nix_shell(["git"], ["git", "add", str(folder)])) + response["git add"] = out + out = await run(nix_shell(["git"], ["git", "commit", "-m", f"Added machine {name}", str(folder)])) + response["git commit"] = out + + return response def create_command(args: argparse.Namespace) -> None: - create_machine(args.host) + runforcli(create_machine, args.host) def register_create_parser(parser: argparse.ArgumentParser) -> None: diff --git a/pkgs/clan-cli/clan_cli/vms/inspect.py b/pkgs/clan-cli/clan_cli/vms/inspect.py index cd922518..417dd718 100644 --- a/pkgs/clan-cli/clan_cli/vms/inspect.py +++ b/pkgs/clan-cli/clan_cli/vms/inspect.py @@ -27,8 +27,8 @@ async def inspect_vm(flake_url: AnyUrl | Path, flake_attr: str) -> VmConfig: f'{flake_url}#clanInternals.machines."{system}"."{flake_attr}".config.system.clan.vm.config' ] ) - stdout, stderr = await run(cmd) - data = json.loads(stdout) + out = await run(cmd) + data = json.loads(out.stdout) return VmConfig(flake_url=flake_url, flake_attr=flake_attr, **data) diff --git a/pkgs/clan-cli/clan_cli/webui/api_inputs.py b/pkgs/clan-cli/clan_cli/webui/api_inputs.py index 23f5ef96..b22432f8 100644 --- a/pkgs/clan-cli/clan_cli/webui/api_inputs.py +++ b/pkgs/clan-cli/clan_cli/webui/api_inputs.py @@ -1,5 +1,7 @@ +# mypy: ignore-errors import logging from pathlib import Path +from typing import Any from pydantic import AnyUrl, BaseModel, validator @@ -28,7 +30,7 @@ class ClanDataPath(BaseModel): dest: Path @validator("dest") - def check_data_path(cls, v: Path) -> Path: + def check_data_path(cls: Any, v: Path) -> Path: # type: ignore return validate_path(clan_data_dir(), v) @@ -36,7 +38,7 @@ class ClanFlakePath(BaseModel): dest: Path @validator("dest") - def check_dest(cls, v: Path) -> Path: + def check_dest(cls: Any, v: Path) -> Path: # type: ignore return validate_path(clan_flake_dir(), v) diff --git a/pkgs/clan-cli/clan_cli/webui/routers/flake.py b/pkgs/clan-cli/clan_cli/webui/routers/flake.py index 8a4fb59f..6eedf363 100644 --- a/pkgs/clan-cli/clan_cli/webui/routers/flake.py +++ b/pkgs/clan-cli/clan_cli/webui/routers/flake.py @@ -6,15 +6,15 @@ from typing import Annotated from fastapi import APIRouter, Body, HTTPException, status from pydantic import AnyUrl +from clan_cli.webui.api_inputs import ( + FlakeCreateInput, +) from clan_cli.webui.api_outputs import ( FlakeAction, FlakeAttrResponse, FlakeCreateResponse, FlakeResponse, ) -from clan_cli.webui.api_inputs import ( - FlakeCreateInput, -) from ...async_cmd import run from ...flake import create @@ -25,11 +25,11 @@ router = APIRouter() # TODO: Check for directory traversal async def get_attrs(url: AnyUrl | Path) -> list[str]: cmd = nix_flake_show(url) - stdout, stderr = await run(cmd) + out = await run(cmd) data: dict[str, dict] = {} try: - data = json.loads(stdout) + data = json.loads(out.stdout) except JSONDecodeError: raise HTTPException(status_code=422, detail="Could not load flake.") @@ -57,8 +57,8 @@ async def inspect_flake( # Extract the flake from the given URL # We do this by running 'nix flake prefetch {url} --json' cmd = nix_command(["flake", "prefetch", str(url), "--json", "--refresh"]) - stdout, stderr = await run(cmd) - data: dict[str, str] = json.loads(stdout) + out = await run(cmd) + data: dict[str, str] = json.loads(out.stdout) if data.get("storePath") is None: raise HTTPException(status_code=500, detail="Could not load flake") diff --git a/pkgs/clan-cli/clan_cli/webui/routers/machines.py b/pkgs/clan-cli/clan_cli/webui/routers/machines.py index 340b702b..656f991c 100644 --- a/pkgs/clan-cli/clan_cli/webui/routers/machines.py +++ b/pkgs/clan-cli/clan_cli/webui/routers/machines.py @@ -37,7 +37,8 @@ async def list_machines() -> MachinesResponse: @router.post("/api/machines", status_code=201) async def create_machine(machine: Annotated[MachineCreate, Body()]) -> MachineResponse: - _create_machine(machine.name) + out = await _create_machine(machine.name) + log.debug(out) return MachineResponse(machine=Machine(name=machine.name, status=Status.UNKNOWN)) diff --git a/pkgs/clan-cli/clan_cli/webui/routers/vms.py b/pkgs/clan-cli/clan_cli/webui/routers/vms.py index d208f41f..414ed39d 100644 --- a/pkgs/clan-cli/clan_cli/webui/routers/vms.py +++ b/pkgs/clan-cli/clan_cli/webui/routers/vms.py @@ -1,4 +1,5 @@ import logging +from pathlib import Path from typing import Annotated, Iterator from uuid import UUID @@ -6,13 +7,17 @@ from fastapi import APIRouter, Body, status from fastapi.exceptions import HTTPException from fastapi.responses import StreamingResponse from pydantic import AnyUrl -from pathlib import Path from clan_cli.webui.routers.flake import get_attrs from ...task_manager import get_task from ...vms import create, inspect -from ..api_outputs import VmConfig, VmCreateResponse, VmInspectResponse, VmStatusResponse +from ..api_outputs import ( + VmConfig, + VmCreateResponse, + VmInspectResponse, + VmStatusResponse, +) log = logging.getLogger(__name__) router = APIRouter() diff --git a/pkgs/clan-cli/tests/temporary_dir.py b/pkgs/clan-cli/tests/temporary_dir.py index 91310f90..c8e31edc 100644 --- a/pkgs/clan-cli/tests/temporary_dir.py +++ b/pkgs/clan-cli/tests/temporary_dir.py @@ -1,3 +1,4 @@ +import os import tempfile from pathlib import Path from typing import Iterator @@ -7,5 +8,11 @@ import pytest @pytest.fixture def temporary_dir() -> Iterator[Path]: - with tempfile.TemporaryDirectory(prefix="pytest-") as dirpath: - yield Path(dirpath) + if os.getenv("TEST_KEEP_TEMPORARY_DIR"): + temp_dir = tempfile.mkdtemp(prefix="pytest-") + path = Path(temp_dir) + yield path + print("=========> Keeping temporary directory: ", path) + else: + with tempfile.TemporaryDirectory(prefix="pytest-") as dirpath: + yield Path(dirpath) diff --git a/pkgs/clan-cli/tests/test_vms_api_create.py b/pkgs/clan-cli/tests/test_vms_api_create.py index 5ff0fe0a..ef9a40ab 100644 --- a/pkgs/clan-cli/tests/test_vms_api_create.py +++ b/pkgs/clan-cli/tests/test_vms_api_create.py @@ -74,8 +74,9 @@ def generic_create_vm_test(api: TestClient, flake: Path, vm: str) -> None: print(line.decode("utf-8")) print("=========END LOGS==========") assert response.status_code == 200, "Failed to get vm logs" - + print("Get /api/vms/{uuid}/status") response = api.get(f"/api/vms/{uuid}/status") + print("Finished Get /api/vms/{uuid}/status") assert response.status_code == 200, "Failed to get vm status" data = response.json() assert (