Merge pull request 'api/schema: get schema without having a machine' (#478) from DavHau-dave into main
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
]}"
|
]}"
|
||||||
ROOT=$(git rev-parse --show-toplevel)
|
ROOT=$(git rev-parse --show-toplevel)
|
||||||
cd "$ROOT/pkgs/clan-cli"
|
cd "$ROOT/pkgs/clan-cli"
|
||||||
nix develop "$ROOT#clan-cli" -c bash -c 'TMPDIR=/tmp python -m pytest -m impure -s ./tests'
|
nix develop "$ROOT#clan-cli" -c bash -c "TMPDIR=/tmp python -m pytest -m impure -s ./tests $@"
|
||||||
'';
|
'';
|
||||||
|
|
||||||
runMockApi = pkgs.writeShellScriptBin "run-mock-api" ''
|
runMockApi = pkgs.writeShellScriptBin "run-mock-api" ''
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
{ self, lib, ... }: {
|
{ inputs, ... }: {
|
||||||
flake.clanModules = {
|
flake.clanModules = {
|
||||||
diskLayouts = lib.mapAttrs'
|
diskLayouts = {
|
||||||
(name: _: lib.nameValuePair (lib.removeSuffix ".nix" name) {
|
|
||||||
imports = [
|
imports = [
|
||||||
self.inputs.disko.nixosModules.disko
|
./diskLayouts.nix
|
||||||
./diskLayouts/${name}
|
inputs.disko.nixosModules.default
|
||||||
];
|
];
|
||||||
})
|
};
|
||||||
(builtins.readDir ./diskLayouts);
|
|
||||||
deltachat = ./deltachat.nix;
|
deltachat = ./deltachat.nix;
|
||||||
xfce = ./xfce.nix;
|
xfce = ./xfce.nix;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
@@ -10,7 +9,6 @@ from fastapi import HTTPException
|
|||||||
|
|
||||||
from clan_cli.dirs import (
|
from clan_cli.dirs import (
|
||||||
machine_settings_file,
|
machine_settings_file,
|
||||||
nixpkgs_source,
|
|
||||||
specific_flake_dir,
|
specific_flake_dir,
|
||||||
specific_machine_dir,
|
specific_machine_dir,
|
||||||
)
|
)
|
||||||
@@ -91,51 +89,3 @@ def set_config_for_machine(
|
|||||||
|
|
||||||
if repo_dir is not None:
|
if repo_dir is not None:
|
||||||
commit_file(settings_path, repo_dir)
|
commit_file(settings_path, repo_dir)
|
||||||
|
|
||||||
|
|
||||||
def schema_for_machine(
|
|
||||||
flake_name: FlakeName, machine_name: str, config: Optional[dict] = None
|
|
||||||
) -> dict:
|
|
||||||
flake = specific_flake_dir(flake_name)
|
|
||||||
# use nix eval to lib.evalModules .#nixosConfigurations.<machine_name>.options.clan
|
|
||||||
with NamedTemporaryFile(mode="w", dir=flake) as clan_machine_settings_file:
|
|
||||||
env = os.environ.copy()
|
|
||||||
inject_config_flags = []
|
|
||||||
if config is not None:
|
|
||||||
json.dump(config, clan_machine_settings_file, indent=2)
|
|
||||||
clan_machine_settings_file.seek(0)
|
|
||||||
env["CLAN_MACHINE_SETTINGS_FILE"] = clan_machine_settings_file.name
|
|
||||||
inject_config_flags = [
|
|
||||||
"--impure", # needed to access CLAN_MACHINE_SETTINGS_FILE
|
|
||||||
]
|
|
||||||
proc = subprocess.run(
|
|
||||||
nix_eval(
|
|
||||||
flags=inject_config_flags
|
|
||||||
+ [
|
|
||||||
"--impure",
|
|
||||||
"--show-trace",
|
|
||||||
"--expr",
|
|
||||||
f"""
|
|
||||||
let
|
|
||||||
flake = builtins.getFlake (toString {flake});
|
|
||||||
lib = import {nixpkgs_source()}/lib;
|
|
||||||
options = flake.nixosConfigurations.{machine_name}.options;
|
|
||||||
clanOptions = options.clan;
|
|
||||||
jsonschemaLib = import {Path(__file__).parent / "jsonschema"} {{ inherit lib; }};
|
|
||||||
jsonschema = jsonschemaLib.parseOptions clanOptions;
|
|
||||||
in
|
|
||||||
jsonschema
|
|
||||||
""",
|
|
||||||
],
|
|
||||||
),
|
|
||||||
capture_output=True,
|
|
||||||
text=True,
|
|
||||||
cwd=flake,
|
|
||||||
env=env,
|
|
||||||
)
|
|
||||||
if proc.returncode != 0:
|
|
||||||
print(proc.stderr, file=sys.stderr)
|
|
||||||
raise Exception(
|
|
||||||
f"Failed to read schema for machine {machine_name}:\n{proc.stderr}"
|
|
||||||
)
|
|
||||||
return json.loads(proc.stdout)
|
|
||||||
|
|||||||
79
pkgs/clan-cli/clan_cli/config/schema.py
Normal file
79
pkgs/clan-cli/clan_cli/config/schema.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from tempfile import NamedTemporaryFile
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from clan_cli.dirs import (
|
||||||
|
nixpkgs_source,
|
||||||
|
specific_flake_dir,
|
||||||
|
)
|
||||||
|
from clan_cli.nix import nix_eval
|
||||||
|
|
||||||
|
from ..types import FlakeName
|
||||||
|
|
||||||
|
|
||||||
|
def machine_schema(
|
||||||
|
flake_name: FlakeName,
|
||||||
|
config: dict,
|
||||||
|
clan_imports: Optional[list[str]] = None,
|
||||||
|
) -> dict:
|
||||||
|
flake = specific_flake_dir(flake_name)
|
||||||
|
# use nix eval to lib.evalModules .#nixosConfigurations.<machine_name>.options.clan
|
||||||
|
with NamedTemporaryFile(mode="w", dir=flake) as clan_machine_settings_file:
|
||||||
|
env = os.environ.copy()
|
||||||
|
inject_config_flags = []
|
||||||
|
if clan_imports is not None:
|
||||||
|
config["clanImports"] = clan_imports
|
||||||
|
json.dump(config, clan_machine_settings_file, indent=2)
|
||||||
|
clan_machine_settings_file.seek(0)
|
||||||
|
env["CLAN_MACHINE_SETTINGS_FILE"] = clan_machine_settings_file.name
|
||||||
|
inject_config_flags = [
|
||||||
|
"--impure", # needed to access CLAN_MACHINE_SETTINGS_FILE
|
||||||
|
]
|
||||||
|
proc = subprocess.run(
|
||||||
|
nix_eval(
|
||||||
|
flags=inject_config_flags
|
||||||
|
+ [
|
||||||
|
"--impure",
|
||||||
|
"--show-trace",
|
||||||
|
"--expr",
|
||||||
|
f"""
|
||||||
|
let
|
||||||
|
system = builtins.currentSystem;
|
||||||
|
flake = builtins.getFlake (toString {flake});
|
||||||
|
clan-core = flake.inputs.clan-core;
|
||||||
|
nixpkgsSrc = flake.inputs.nixpkgs or {nixpkgs_source()};
|
||||||
|
lib = import (nixpkgsSrc + /lib);
|
||||||
|
pkgs = import nixpkgsSrc {{ inherit system; }};
|
||||||
|
config = lib.importJSON (builtins.getEnv "CLAN_MACHINE_SETTINGS_FILE");
|
||||||
|
fakeMachine = pkgs.nixos {{
|
||||||
|
imports =
|
||||||
|
[
|
||||||
|
clan-core.nixosModules.clanCore
|
||||||
|
# potentially the config might affect submodule options,
|
||||||
|
# therefore we need to import it
|
||||||
|
config
|
||||||
|
]
|
||||||
|
# add all clan modules specified via clanImports
|
||||||
|
++ (map (name: clan-core.clanModules.${{name}}) config.clanImports or []);
|
||||||
|
}};
|
||||||
|
clanOptions = fakeMachine.options.clan;
|
||||||
|
jsonschemaLib = import {Path(__file__).parent / "jsonschema"} {{ inherit lib; }};
|
||||||
|
jsonschema = jsonschemaLib.parseOptions clanOptions;
|
||||||
|
in
|
||||||
|
jsonschema
|
||||||
|
""",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
cwd=flake,
|
||||||
|
env=env,
|
||||||
|
)
|
||||||
|
if proc.returncode != 0:
|
||||||
|
print(proc.stderr, file=sys.stderr)
|
||||||
|
raise Exception(f"Failed to read schema:\n{proc.stderr}")
|
||||||
|
return json.loads(proc.stdout)
|
||||||
@@ -8,10 +8,10 @@ from clan_cli.webui.api_inputs import MachineConfig
|
|||||||
|
|
||||||
from ...config.machine import (
|
from ...config.machine import (
|
||||||
config_for_machine,
|
config_for_machine,
|
||||||
schema_for_machine,
|
|
||||||
set_config_for_machine,
|
set_config_for_machine,
|
||||||
verify_machine_config,
|
verify_machine_config,
|
||||||
)
|
)
|
||||||
|
from ...config.schema import machine_schema
|
||||||
from ...machines.create import create_machine as _create_machine
|
from ...machines.create import create_machine as _create_machine
|
||||||
from ...machines.list import list_machines as _list_machines
|
from ...machines.list import list_machines as _list_machines
|
||||||
from ...types import FlakeName
|
from ...types import FlakeName
|
||||||
@@ -68,17 +68,11 @@ async def set_machine_config(
|
|||||||
set_config_for_machine(flake_name, name, conf)
|
set_config_for_machine(flake_name, name, conf)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/api/{flake_name}/machines/{name}/schema", tags=[Tags.machine])
|
@router.put("/api/{flake_name}/schema", tags=[Tags.machine])
|
||||||
async def get_machine_schema(flake_name: FlakeName, name: str) -> SchemaResponse:
|
async def get_machine_schema(
|
||||||
schema = schema_for_machine(flake_name, name)
|
flake_name: FlakeName, config: Annotated[dict, Body()]
|
||||||
return SchemaResponse(schema=schema)
|
|
||||||
|
|
||||||
|
|
||||||
@router.put("/api/{flake_name}/machines/{name}/schema", tags=[Tags.machine])
|
|
||||||
async def set_machine_schema(
|
|
||||||
flake_name: FlakeName, name: str, config: Annotated[dict, Body()]
|
|
||||||
) -> SchemaResponse:
|
) -> SchemaResponse:
|
||||||
schema = schema_for_machine(flake_name, name, config)
|
schema = machine_schema(flake_name, config=config)
|
||||||
return SchemaResponse(schema=schema)
|
return SchemaResponse(schema=schema)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
, mypy
|
, mypy
|
||||||
, deal
|
, deal
|
||||||
, schemathesis
|
, schemathesis
|
||||||
|
, rope
|
||||||
|
, clan-core-path
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
|
|
||||||
@@ -132,14 +134,30 @@ python3.pkgs.buildPythonApplication {
|
|||||||
propagatedBuildInputs = dependencies;
|
propagatedBuildInputs = dependencies;
|
||||||
|
|
||||||
# also re-expose dependencies so we test them in CI
|
# also re-expose dependencies so we test them in CI
|
||||||
passthru.tests = (lib.mapAttrs' (n: lib.nameValuePair "clan-dep-${n}") runtimeDependenciesAsSet) // {
|
passthru.tests = (lib.mapAttrs' (n: lib.nameValuePair "clan-dep-${n}") runtimeDependenciesAsSet) // rec {
|
||||||
clan-pytest = runCommand "clan-pytest" { nativeBuildInputs = [ checkPython ] ++ pytestDependencies; } ''
|
clan-pytest-without-core = runCommand "clan-pytest-without-core" { nativeBuildInputs = [ checkPython ] ++ pytestDependencies; } ''
|
||||||
cp -r ${source} ./src
|
cp -r ${source} ./src
|
||||||
chmod +w -R ./src
|
chmod +w -R ./src
|
||||||
cd ./src
|
cd ./src
|
||||||
|
|
||||||
export NIX_STATE_DIR=$TMPDIR/nix IN_NIX_SANDBOX=1
|
export NIX_STATE_DIR=$TMPDIR/nix IN_NIX_SANDBOX=1
|
||||||
${checkPython}/bin/python -m pytest -m "not impure" -s ./tests
|
${checkPython}/bin/python -m pytest -m "not impure and not with_core" -s ./tests
|
||||||
|
touch $out
|
||||||
|
'';
|
||||||
|
# separate the tests that can never be cached
|
||||||
|
clan-pytest-with-core = runCommand "clan-pytest-with-core" { nativeBuildInputs = [ checkPython ] ++ pytestDependencies; } ''
|
||||||
|
cp -r ${source} ./src
|
||||||
|
chmod +w -R ./src
|
||||||
|
cd ./src
|
||||||
|
|
||||||
|
export CLAN_CORE=${clan-core-path}
|
||||||
|
export NIX_STATE_DIR=$TMPDIR/nix IN_NIX_SANDBOX=1
|
||||||
|
${checkPython}/bin/python -m pytest -m "not impure and with_core" -s ./tests
|
||||||
|
touch $out
|
||||||
|
'';
|
||||||
|
clan-pytest = runCommand "clan-pytest" { } ''
|
||||||
|
echo ${clan-pytest-without-core}
|
||||||
|
echo ${clan-pytest-with-core}
|
||||||
touch $out
|
touch $out
|
||||||
'';
|
'';
|
||||||
check-for-breakpoints = runCommand "breakpoints" { } ''
|
check-for-breakpoints = runCommand "breakpoints" { } ''
|
||||||
@@ -164,6 +182,7 @@ python3.pkgs.buildPythonApplication {
|
|||||||
passthru.checkPython = checkPython;
|
passthru.checkPython = checkPython;
|
||||||
|
|
||||||
passthru.devDependencies = [
|
passthru.devDependencies = [
|
||||||
|
rope
|
||||||
setuptools
|
setuptools
|
||||||
wheel
|
wheel
|
||||||
] ++ pytestDependencies;
|
] ++ pytestDependencies;
|
||||||
|
|||||||
@@ -1,8 +1,33 @@
|
|||||||
{ inputs, ... }:
|
{ inputs, self, lib, ... }:
|
||||||
{
|
{
|
||||||
perSystem = { self', pkgs, system, ... }:
|
perSystem = { self', pkgs, system, ... }:
|
||||||
let
|
let
|
||||||
luisPythonPkgs = inputs.luispkgs.legacyPackages.${system}.python3Packages;
|
luisPythonPkgs = inputs.luispkgs.legacyPackages.${system}.python3Packages;
|
||||||
|
flakeLock = lib.importJSON (self + /flake.lock);
|
||||||
|
flakeInputs = (builtins.removeAttrs inputs [ "self" ]);
|
||||||
|
flakeLockVendoredDeps = flakeLock // {
|
||||||
|
nodes = flakeLock.nodes // (
|
||||||
|
lib.flip lib.mapAttrs flakeInputs (name: _: flakeLock.nodes.${name} // {
|
||||||
|
locked = {
|
||||||
|
inherit (flakeLock.nodes.${name}.locked) narHash;
|
||||||
|
lastModified =
|
||||||
|
# lol, nixpkgs has a different timestamp on the fs???
|
||||||
|
if name == "nixpkgs"
|
||||||
|
then 0
|
||||||
|
else 1;
|
||||||
|
path = "${inputs.${name}}";
|
||||||
|
type = "path";
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
flakeLockFile = builtins.toFile "clan-core-flake.lock"
|
||||||
|
(builtins.toJSON flakeLockVendoredDeps);
|
||||||
|
clanCoreWithVendoredDeps = lib.trace flakeLockFile pkgs.runCommand "clan-core-with-vendored-deps" { } ''
|
||||||
|
cp -r ${self} $out
|
||||||
|
chmod +w -R $out
|
||||||
|
cp ${flakeLockFile} $out/flake.lock
|
||||||
|
'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
devShells.clan-cli = pkgs.callPackage ./shell.nix {
|
devShells.clan-cli = pkgs.callPackage ./shell.nix {
|
||||||
@@ -14,6 +39,7 @@
|
|||||||
inherit (inputs) nixpkgs;
|
inherit (inputs) nixpkgs;
|
||||||
deal = luisPythonPkgs.deal;
|
deal = luisPythonPkgs.deal;
|
||||||
schemathesis = luisPythonPkgs.schemathesis;
|
schemathesis = luisPythonPkgs.schemathesis;
|
||||||
|
clan-core-path = clanCoreWithVendoredDeps;
|
||||||
};
|
};
|
||||||
inherit (self'.packages.clan-cli) clan-openapi;
|
inherit (self'.packages.clan-cli) clan-openapi;
|
||||||
default = self'.packages.clan-cli;
|
default = self'.packages.clan-cli;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from api import TestClient
|
|||||||
from fixtures_flakes import FlakeForTest
|
from fixtures_flakes import FlakeForTest
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.impure()
|
@pytest.mark.with_core
|
||||||
def test_configure_machine(api: TestClient, test_flake_with_core: FlakeForTest) -> None:
|
def test_configure_machine(api: TestClient, test_flake_with_core: FlakeForTest) -> None:
|
||||||
# retrieve the list of available clanModules
|
# retrieve the list of available clanModules
|
||||||
response = api.get(f"/api/{test_flake_with_core.name}/clan_modules")
|
response = api.get(f"/api/{test_flake_with_core.name}/clan_modules")
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import pytest
|
||||||
from api import TestClient
|
from api import TestClient
|
||||||
from fixtures_flakes import FlakeForTest
|
from fixtures_flakes import FlakeForTest
|
||||||
|
|
||||||
@@ -21,37 +22,46 @@ def test_machines(api: TestClient, test_flake: FlakeForTest) -> None:
|
|||||||
assert response.json() == {"machines": [{"name": "test", "status": "unknown"}]}
|
assert response.json() == {"machines": [{"name": "test", "status": "unknown"}]}
|
||||||
|
|
||||||
|
|
||||||
def test_configure_machine(api: TestClient, test_flake: FlakeForTest) -> None:
|
@pytest.mark.with_core
|
||||||
|
def test_configure_machine(api: TestClient, test_flake_with_core: FlakeForTest) -> None:
|
||||||
# ensure error 404 if machine does not exist when accessing the config
|
# ensure error 404 if machine does not exist when accessing the config
|
||||||
response = api.get(f"/api/{test_flake.name}/machines/machine1/config")
|
response = api.get(f"/api/{test_flake_with_core.name}/machines/machine1/config")
|
||||||
assert response.status_code == 404
|
assert response.status_code == 404
|
||||||
|
|
||||||
# ensure error 404 if machine does not exist when writing to the config
|
# ensure error 404 if machine does not exist when writing to the config
|
||||||
response = api.put(f"/api/{test_flake.name}/machines/machine1/config", json={})
|
response = api.put(
|
||||||
|
f"/api/{test_flake_with_core.name}/machines/machine1/config", json={}
|
||||||
|
)
|
||||||
assert response.status_code == 404
|
assert response.status_code == 404
|
||||||
|
|
||||||
# create the machine
|
# create the machine
|
||||||
response = api.post(f"/api/{test_flake.name}/machines", json={"name": "machine1"})
|
response = api.post(
|
||||||
|
f"/api/{test_flake_with_core.name}/machines", json={"name": "machine1"}
|
||||||
|
)
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
|
||||||
# ensure an empty config is returned by default for a new machine
|
# ensure an empty config is returned by default for a new machine
|
||||||
response = api.get(f"/api/{test_flake.name}/machines/machine1/config")
|
response = api.get(f"/api/{test_flake_with_core.name}/machines/machine1/config")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == {
|
assert response.json() == {
|
||||||
"clanImports": [],
|
"clanImports": [],
|
||||||
"clan": {},
|
"clan": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
# get jsonschema for machine
|
# get jsonschema for without imports
|
||||||
response = api.get(f"/api/{test_flake.name}/machines/machine1/schema")
|
response = api.put(
|
||||||
|
f"/api/{test_flake_with_core.name}/schema",
|
||||||
|
json={"clanImports": []},
|
||||||
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
json_response = response.json()
|
json_response = response.json()
|
||||||
assert "schema" in json_response and "properties" in json_response["schema"]
|
assert "schema" in json_response and "properties" in json_response["schema"]
|
||||||
|
|
||||||
# an invalid config missing the fileSystems
|
# an invalid config missing the fileSystems
|
||||||
invalid_config = dict(
|
invalid_config = dict(
|
||||||
clan=dict(
|
clan=dict(),
|
||||||
jitsi=dict(
|
services=dict(
|
||||||
|
nginx=dict(
|
||||||
enable=True,
|
enable=True,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -59,7 +69,7 @@ def test_configure_machine(api: TestClient, test_flake: FlakeForTest) -> None:
|
|||||||
|
|
||||||
# verify an invalid config (fileSystems missing) fails
|
# verify an invalid config (fileSystems missing) fails
|
||||||
response = api.put(
|
response = api.put(
|
||||||
f"/api/{test_flake.name}/machines/machine1/verify",
|
f"/api/{test_flake_with_core.name}/machines/machine1/verify",
|
||||||
json=invalid_config,
|
json=invalid_config,
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
@@ -70,13 +80,13 @@ def test_configure_machine(api: TestClient, test_flake: FlakeForTest) -> None:
|
|||||||
|
|
||||||
# set come invalid config (fileSystems missing)
|
# set come invalid config (fileSystems missing)
|
||||||
response = api.put(
|
response = api.put(
|
||||||
f"/api/{test_flake.name}/machines/machine1/config",
|
f"/api/{test_flake_with_core.name}/machines/machine1/config",
|
||||||
json=invalid_config,
|
json=invalid_config,
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
# ensure the config has actually been updated
|
# ensure the config has actually been updated
|
||||||
response = api.get(f"/api/{test_flake.name}/machines/machine1/config")
|
response = api.get(f"/api/{test_flake_with_core.name}/machines/machine1/config")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == dict(clanImports=[], **invalid_config)
|
assert response.json() == dict(clanImports=[], **invalid_config)
|
||||||
|
|
||||||
@@ -99,8 +109,9 @@ def test_configure_machine(api: TestClient, test_flake: FlakeForTest) -> None:
|
|||||||
|
|
||||||
# set some valid config
|
# set some valid config
|
||||||
config2 = dict(
|
config2 = dict(
|
||||||
clan=dict(
|
clan=dict(),
|
||||||
jitsi=dict(
|
services=dict(
|
||||||
|
nginx=dict(
|
||||||
enable=True,
|
enable=True,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -108,20 +119,20 @@ def test_configure_machine(api: TestClient, test_flake: FlakeForTest) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
response = api.put(
|
response = api.put(
|
||||||
f"/api/{test_flake.name}/machines/machine1/config",
|
f"/api/{test_flake_with_core.name}/machines/machine1/config",
|
||||||
json=config2,
|
json=config2,
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
# ensure the config has been applied
|
# ensure the config has been applied
|
||||||
response = api.get(
|
response = api.get(
|
||||||
f"/api/{test_flake.name}/machines/machine1/config",
|
f"/api/{test_flake_with_core.name}/machines/machine1/config",
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == dict(clanImports=[], **config2)
|
assert response.json() == dict(clanImports=[], **config2)
|
||||||
|
|
||||||
# get the config again
|
# get the config again
|
||||||
response = api.get(f"/api/{test_flake.name}/machines/machine1/config")
|
response = api.get(f"/api/{test_flake_with_core.name}/machines/machine1/config")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == {"clanImports": [], **config2}
|
assert response.json() == {"clanImports": [], **config2}
|
||||||
|
|
||||||
@@ -129,36 +140,36 @@ def test_configure_machine(api: TestClient, test_flake: FlakeForTest) -> None:
|
|||||||
# For example, this should not result in the boot.loader.grub.devices being
|
# For example, this should not result in the boot.loader.grub.devices being
|
||||||
# set twice (eg. merged)
|
# set twice (eg. merged)
|
||||||
response = api.put(
|
response = api.put(
|
||||||
f"/api/{test_flake.name}/machines/machine1/config",
|
f"/api/{test_flake_with_core.name}/machines/machine1/config",
|
||||||
json=config2,
|
json=config2,
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
# ensure the config has been applied
|
# ensure the config has been applied
|
||||||
response = api.get(
|
response = api.get(
|
||||||
f"/api/{test_flake.name}/machines/machine1/config",
|
f"/api/{test_flake_with_core.name}/machines/machine1/config",
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == dict(clanImports=[], **config2)
|
assert response.json() == dict(clanImports=[], **config2)
|
||||||
|
|
||||||
# verify the machine config evaluates
|
# verify the machine config evaluates
|
||||||
response = api.get(f"/api/{test_flake.name}/machines/machine1/verify")
|
response = api.get(f"/api/{test_flake_with_core.name}/machines/machine1/verify")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
assert response.json() == {"success": True, "error": None}
|
assert response.json() == {"success": True, "error": None}
|
||||||
|
|
||||||
# get the schema with an extra module imported
|
# get the schema with an extra module imported
|
||||||
response = api.put(
|
response = api.put(
|
||||||
f"/api/{test_flake.name}/machines/machine1/schema",
|
f"/api/{test_flake_with_core.name}/schema",
|
||||||
json={"clanImports": ["fake-module"]},
|
json={"clanImports": ["diskLayouts"]},
|
||||||
)
|
)
|
||||||
# expect the result schema to contain the fake-module.fake-flag option
|
# expect the result schema to contain the deltachat option
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert (
|
assert (
|
||||||
response.json()["schema"]["properties"]["fake-module"]["properties"][
|
response.json()["schema"]["properties"]["diskLayouts"]["properties"][
|
||||||
"fake-flag"
|
"singleDiskExt4"
|
||||||
]["type"]
|
]["properties"]["device"]["type"]
|
||||||
== "boolean"
|
== "string"
|
||||||
)
|
)
|
||||||
|
|
||||||
# new config importing an extra clanModule (clanModules.fake-module)
|
# new config importing an extra clanModule (clanModules.fake-module)
|
||||||
@@ -174,14 +185,14 @@ def test_configure_machine(api: TestClient, test_flake: FlakeForTest) -> None:
|
|||||||
|
|
||||||
# set the fake-module.fake-flag option to true
|
# set the fake-module.fake-flag option to true
|
||||||
response = api.put(
|
response = api.put(
|
||||||
f"/api/{test_flake.name}/machines/machine1/config",
|
f"/api/{test_flake_with_core.name}/machines/machine1/config",
|
||||||
json=config_with_imports,
|
json=config_with_imports,
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
# ensure the config has been applied
|
# ensure the config has been applied
|
||||||
response = api.get(
|
response = api.get(
|
||||||
f"/api/{test_flake.name}/machines/machine1/config",
|
f"/api/{test_flake_with_core.name}/machines/machine1/config",
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == {
|
assert response.json() == {
|
||||||
@@ -200,14 +211,14 @@ def test_configure_machine(api: TestClient, test_flake: FlakeForTest) -> None:
|
|||||||
**fs_config,
|
**fs_config,
|
||||||
)
|
)
|
||||||
response = api.put(
|
response = api.put(
|
||||||
f"/api/{test_flake.name}/machines/machine1/config",
|
f"/api/{test_flake_with_core.name}/machines/machine1/config",
|
||||||
json=config_with_empty_imports,
|
json=config_with_empty_imports,
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
# ensure the config has been applied
|
# ensure the config has been applied
|
||||||
response = api.get(
|
response = api.get(
|
||||||
f"/api/{test_flake.name}/machines/machine1/config",
|
f"/api/{test_flake_with_core.name}/machines/machine1/config",
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == {
|
assert response.json() == {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
import pytest
|
||||||
from fixtures_flakes import FlakeForTest
|
from fixtures_flakes import FlakeForTest
|
||||||
|
|
||||||
from clan_cli.config import machine
|
from clan_cli.config.schema import machine_schema
|
||||||
|
|
||||||
|
|
||||||
def test_schema_for_machine(test_flake: FlakeForTest) -> None:
|
@pytest.mark.with_core
|
||||||
schema = machine.schema_for_machine(test_flake.name, "machine1")
|
def test_schema_for_machine(test_flake_with_core: FlakeForTest) -> None:
|
||||||
|
schema = machine_schema(test_flake_with_core.name, config={})
|
||||||
assert "properties" in schema
|
assert "properties" in schema
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { setMachineSchema } from "@/api/machine/machine";
|
import { getMachineSchema } from "@/api/machine/machine";
|
||||||
import { useListClanModules } from "@/api/modules/modules";
|
import { useListClanModules } from "@/api/modules/modules";
|
||||||
import { Alert, AlertTitle, FormHelperText, Typography } from "@mui/material";
|
import { Alert, AlertTitle, FormHelperText, Typography } from "@mui/material";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
@@ -32,7 +32,7 @@ export default function ClanModules(props: ClanModulesProps) {
|
|||||||
const selectedModules = formHooks.watch("modules");
|
const selectedModules = formHooks.watch("modules");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMachineSchema(clanName, "example_machine", {
|
getMachineSchema(clanName, {
|
||||||
imports: [],
|
imports: [],
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
if (response.statusText == "OK") {
|
if (response.statusText == "OK") {
|
||||||
@@ -52,7 +52,7 @@ export default function ClanModules(props: ClanModulesProps) {
|
|||||||
} = event;
|
} = event;
|
||||||
const newValue = typeof value === "string" ? value.split(",") : value;
|
const newValue = typeof value === "string" ? value.split(",") : value;
|
||||||
formHooks.setValue("modules", newValue);
|
formHooks.setValue("modules", newValue);
|
||||||
setMachineSchema(clanName, "example_machine", {
|
getMachineSchema(clanName, {
|
||||||
imports: newValue,
|
imports: newValue,
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user