Added state directory.

This commit is contained in:
Luis Hebendanz 2023-10-13 19:56:10 +02:00
parent fa5f39f226
commit 711c70d1f0
10 changed files with 74 additions and 35 deletions

View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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)

View File

@ -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")

View File

@ -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))

View File

@ -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()

View File

@ -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)

View File

@ -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 (