Config -> KiwiConfig, _Storage -> StorageConfig, _Network -> NetworkConfig

This commit is contained in:
Jörn-Michael Miehe 2021-10-26 15:56:58 +02:00
parent 7dc6e6789f
commit 8260ddef3c
3 changed files with 75 additions and 76 deletions

View file

@ -6,7 +6,7 @@ from pathlib import Path
import click import click
from .._constants import KIWI_CONF_NAME from .._constants import KIWI_CONF_NAME
from ..config import Config from ..config import KiwiConfig
from ..instance import Instance, pass_instance from ..instance import Instance, pass_instance
from ..misc import user_query from ..misc import user_query
@ -42,7 +42,7 @@ def cmd(ctx: Instance, output: Path, force: bool, show: bool):
if output is not None: if output is not None:
ctx.directory = output ctx.directory = output
current_config = Config() if force else ctx.config current_config = KiwiConfig() if force else ctx.config
if show: if show:
# just show the currently effective kiwi.yml # just show the currently effective kiwi.yml
@ -72,4 +72,4 @@ def cmd(ctx: Instance, output: Path, force: bool, show: bool):
# write out the new kiwi.yml # write out the new kiwi.yml
with open(ctx.directory.joinpath(KIWI_CONF_NAME), "w") as file: with open(ctx.directory.joinpath(KIWI_CONF_NAME), "w") as file:
Config.parse_obj(kiwi_dict).dump_kiwi_yml(file) KiwiConfig.parse_obj(kiwi_dict).dump_kiwi_yml(file)

View file

@ -4,14 +4,14 @@ from ipaddress import IPv4Network
from pathlib import Path from pathlib import Path
from typing import Optional, Dict, List, Any, TextIO from typing import Optional, Dict, List, Any, TextIO
import ruamel.yaml
from pydantic import BaseModel, constr, root_validator, validator from pydantic import BaseModel, constr, root_validator, validator
from ruamel.yaml import YAML
from ._constants import RE_SEMVER, RE_VARNAME, KIWI_CONF_NAME from ._constants import RE_SEMVER, RE_VARNAME, KIWI_CONF_NAME
from .misc import _format_kiwi_yml from .misc import _format_kiwi_yml
class _Storage(BaseModel): class StorageConfig(BaseModel):
"""a storage subsection""" """a storage subsection"""
directory: Path directory: Path
@ -36,12 +36,12 @@ class _Storage(BaseModel):
raise ValueError("Invalid Storage Format") raise ValueError("Invalid Storage Format")
class _Project(BaseModel): class ProjectConfig(BaseModel):
"""a project subsection""" """a project subsection"""
name: constr(regex=RE_VARNAME) name: constr(regex=RE_VARNAME)
enabled: bool = True enabled: bool = True
override_storage: Optional[_Storage] override_storage: Optional[StorageConfig]
@property @property
def kiwi_dict(self) -> Dict[str, Any]: def kiwi_dict(self) -> Dict[str, Any]:
@ -97,7 +97,7 @@ class _Project(BaseModel):
raise ValueError("Invalid Project Format") raise ValueError("Invalid Project Format")
class _Network(BaseModel): class NetworkConfig(BaseModel):
"""a network subsection""" """a network subsection"""
name: constr(to_lower=True, regex=RE_VARNAME) name: constr(to_lower=True, regex=RE_VARNAME)
@ -113,7 +113,7 @@ class _Network(BaseModel):
} }
class Config(BaseModel): class KiwiConfig(BaseModel):
"""represents a kiwi.yml""" """represents a kiwi.yml"""
version: constr(regex=RE_SEMVER) = "0.2.0" version: constr(regex=RE_SEMVER) = "0.2.0"
@ -122,28 +122,27 @@ class Config(BaseModel):
Path("/bin/bash"), Path("/bin/bash"),
] ]
projects: List[_Project] = [] projects: List[ProjectConfig] = []
environment: Dict[str, Optional[str]] = {} environment: Dict[str, Optional[str]] = {}
storage: _Storage = _Storage( storage: StorageConfig = StorageConfig(
directory="/var/local/kiwi", directory="/var/local/kiwi",
) )
network: _Network = _Network( network: NetworkConfig = NetworkConfig(
name="kiwi_hub", name="kiwi_hub",
cidr="10.22.46.0/24", cidr="10.22.46.0/24",
) )
@classmethod @classmethod
@functools.lru_cache(maxsize=5) @functools.lru_cache(maxsize=5)
def from_directory(cls, instance: Path): def from_directory(cls, directory: Path):
"""parses an actual kiwi.yml from disk (cached)""" """parses an actual kiwi.yml from disk (cached)"""
try: try:
with open(instance.joinpath(KIWI_CONF_NAME)) as kc: with open(directory.joinpath(KIWI_CONF_NAME)) as kc:
yml = ruamel.yaml.round_trip_load(kc) return cls.parse_obj(YAML().load(kc))
return cls.parse_obj(yml)
except FileNotFoundError: except FileNotFoundError:
# return the defaults if no kiwi.yml found # return the defaults if no kiwi.yml found
@ -183,7 +182,7 @@ class Config(BaseModel):
def dump_kiwi_yml(self, stream: TextIO) -> None: def dump_kiwi_yml(self, stream: TextIO) -> None:
"""dump a kiwi.yml file""" """dump a kiwi.yml file"""
yml = ruamel.yaml.YAML() yml = YAML()
yml.indent(offset=2) yml.indent(offset=2)
yml.dump(self.kiwi_dict, stream=stream, transform=_format_kiwi_yml) yml.dump(self.kiwi_dict, stream=stream, transform=_format_kiwi_yml)

View file

@ -6,7 +6,7 @@ import pytest
import ruamel.yaml import ruamel.yaml
from pydantic import ValidationError from pydantic import ValidationError
from kiwi_scp.config import Config from kiwi_scp.config import KiwiConfig
class UnCoercible: class UnCoercible:
@ -19,10 +19,10 @@ class UnCoercible:
def test_default(): def test_default():
import toml import toml
c = Config() c = KiwiConfig()
version = toml.load("./pyproject.toml")["tool"]["poetry"]["version"] version = toml.load("./pyproject.toml")["tool"]["poetry"]["version"]
assert c == Config.from_default() assert c == KiwiConfig.from_default()
assert c.version == version assert c.version == version
assert len(c.shells) == 1 assert len(c.shells) == 1
@ -61,23 +61,23 @@ def test_default():
######### #########
def test_version_valid(): def test_version_valid():
c = Config(version="0.0.0") c = KiwiConfig(version="0.0.0")
assert c.version == "0.0.0" assert c.version == "0.0.0"
c = Config(version="0.0") c = KiwiConfig(version="0.0")
assert c.version == "0.0" assert c.version == "0.0"
c = Config(version="0") c = KiwiConfig(version="0")
assert c.version == "0" assert c.version == "0"
c = Config(version=1.0) c = KiwiConfig(version=1.0)
assert c.version == "1.0" assert c.version == "1.0"
c = Config(version=1) c = KiwiConfig(version=1)
assert c.version == "1" assert c.version == "1"
@ -85,7 +85,7 @@ def test_version_valid():
def test_version_invalid(): def test_version_invalid():
# definitely not a version # definitely not a version
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(version="dnaf") KiwiConfig(version="dnaf")
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
@ -94,7 +94,7 @@ def test_version_invalid():
# barely a version # barely a version
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
c = Config(version="0.0.0alpha") c = KiwiConfig(version="0.0.0alpha")
print(c.version) print(c.version)
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
@ -108,42 +108,42 @@ def test_version_invalid():
######## ########
def test_shells_empty(): def test_shells_empty():
c = Config(shells=None) c = KiwiConfig(shells=None)
assert c == Config(shells=[]) assert c == KiwiConfig(shells=[])
assert c.shells == [] assert c.shells == []
def test_shells_list(): def test_shells_list():
c = Config(shells=["/bin/sh", "sh"]) c = KiwiConfig(shells=["/bin/sh", "sh"])
assert len(c.shells) == 2 assert len(c.shells) == 2
assert c.shells[0] == Path("/bin/sh") assert c.shells[0] == Path("/bin/sh")
assert c.shells[1] == Path("sh") assert c.shells[1] == Path("sh")
c = Config(shells=["/bin/bash"]) c = KiwiConfig(shells=["/bin/bash"])
assert len(c.shells) == 1 assert len(c.shells) == 1
assert c.shells[0] == Path("/bin/bash") assert c.shells[0] == Path("/bin/bash")
def test_shells_dict(): def test_shells_dict():
c = Config(shells={"/bin/bash": None}) c = KiwiConfig(shells={"/bin/bash": None})
assert len(c.shells) == 1 assert len(c.shells) == 1
assert c.shells[0] == Path("/bin/bash") assert c.shells[0] == Path("/bin/bash")
def test_shells_coercible(): def test_shells_coercible():
c = Config(shells="/bin/bash") c = KiwiConfig(shells="/bin/bash")
assert c == Config(shells=Path("/bin/bash")) assert c == KiwiConfig(shells=Path("/bin/bash"))
assert len(c.shells) == 1 assert len(c.shells) == 1
assert c.shells[0] == Path("/bin/bash") assert c.shells[0] == Path("/bin/bash")
c = Config(shells=123) c = KiwiConfig(shells=123)
assert len(c.shells) == 1 assert len(c.shells) == 1
assert c.shells[0] == Path("123") assert c.shells[0] == Path("123")
@ -151,7 +151,7 @@ def test_shells_coercible():
def test_shells_uncoercible(): def test_shells_uncoercible():
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(shells=UnCoercible()) KiwiConfig(shells=UnCoercible())
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
@ -159,7 +159,7 @@ def test_shells_uncoercible():
assert error["type"] == "value_error" assert error["type"] == "value_error"
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(shells=["/bin/bash", UnCoercible()]) KiwiConfig(shells=["/bin/bash", UnCoercible()])
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
@ -172,9 +172,9 @@ def test_shells_uncoercible():
########## ##########
def test_proj_empty(): def test_proj_empty():
c = Config(projects=None) c = KiwiConfig(projects=None)
assert c == Config(projects=[]) assert c == KiwiConfig(projects=[])
assert c.projects == [] assert c.projects == []
@ -185,7 +185,7 @@ def test_proj_long():
"enabled": False, "enabled": False,
"override_storage": {"directory": "/test/directory"}, "override_storage": {"directory": "/test/directory"},
} }
c = Config(projects=[kiwi_dict]) c = KiwiConfig(projects=[kiwi_dict])
assert len(c.projects) == 1 assert len(c.projects) == 1
p = c.projects[0] p = c.projects[0]
@ -202,7 +202,7 @@ def test_proj_storage_str():
"enabled": False, "enabled": False,
"override_storage": "/test/directory", "override_storage": "/test/directory",
} }
c = Config(projects=[kiwi_dict]) c = KiwiConfig(projects=[kiwi_dict])
assert len(c.projects) == 1 assert len(c.projects) == 1
p = c.projects[0] p = c.projects[0]
@ -217,7 +217,7 @@ def test_proj_storage_list():
"enabled": False, "enabled": False,
"override_storage": ["/test/directory"], "override_storage": ["/test/directory"],
} }
c = Config(projects=[kiwi_dict]) c = KiwiConfig(projects=[kiwi_dict])
assert len(c.projects) == 1 assert len(c.projects) == 1
p = c.projects[0] p = c.projects[0]
@ -233,7 +233,7 @@ def test_proj_storage_invalid():
"override_storage": True, "override_storage": True,
} }
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(projects=[kiwi_dict]) KiwiConfig(projects=[kiwi_dict])
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
@ -245,7 +245,7 @@ def test_proj_short():
kiwi_dict = { kiwi_dict = {
"project": False, "project": False,
} }
c = Config(projects=[kiwi_dict]) c = KiwiConfig(projects=[kiwi_dict])
assert len(c.projects) == 1 assert len(c.projects) == 1
p = c.projects[0] p = c.projects[0]
@ -256,9 +256,9 @@ def test_proj_short():
def test_proj_dict(): def test_proj_dict():
c = Config(projects={"name": "project"}) c = KiwiConfig(projects={"name": "project"})
assert c == Config(projects=[{"name": "project"}]) assert c == KiwiConfig(projects=[{"name": "project"}])
assert len(c.projects) == 1 assert len(c.projects) == 1
p = c.projects[0] p = c.projects[0]
@ -269,7 +269,7 @@ def test_proj_dict():
def test_proj_invalid_dict(): def test_proj_invalid_dict():
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(projects={ KiwiConfig(projects={
"random key 1": "random value 1", "random key 1": "random value 1",
"random key 2": "random value 2", "random key 2": "random value 2",
}) })
@ -281,9 +281,9 @@ def test_proj_invalid_dict():
def test_proj_coercible(): def test_proj_coercible():
c = Config(projects="project") c = KiwiConfig(projects="project")
assert c == Config(projects=["project"]) assert c == KiwiConfig(projects=["project"])
assert len(c.projects) == 1 assert len(c.projects) == 1
p = c.projects[0] p = c.projects[0]
@ -294,7 +294,7 @@ def test_proj_coercible():
def test_proj_uncoercible(): def test_proj_uncoercible():
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(projects=["valid", UnCoercible()]) KiwiConfig(projects=["valid", UnCoercible()])
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
@ -302,7 +302,7 @@ def test_proj_uncoercible():
assert error["type"] == "value_error" assert error["type"] == "value_error"
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(projects=UnCoercible()) KiwiConfig(projects=UnCoercible())
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
@ -315,18 +315,18 @@ def test_proj_uncoercible():
############# #############
def test_env_empty(): def test_env_empty():
c = Config(environment=None) c = KiwiConfig(environment=None)
assert c.environment == {} assert c.environment == {}
def test_env_dict(): def test_env_dict():
c = Config(environment={}) c = KiwiConfig(environment={})
assert c.environment == {} assert c.environment == {}
kiwi_dict = {"variable": "value"} kiwi_dict = {"variable": "value"}
c = Config(environment=kiwi_dict) c = KiwiConfig(environment=kiwi_dict)
assert len(c.environment) == 1 assert len(c.environment) == 1
assert "variable" in c.environment assert "variable" in c.environment
@ -336,11 +336,11 @@ def test_env_dict():
def test_env_list(): def test_env_list():
c = Config(environment=[]) c = KiwiConfig(environment=[])
assert c.environment == {} assert c.environment == {}
c = Config(environment=[ c = KiwiConfig(environment=[
"variable=value", "variable=value",
]) ])
@ -348,7 +348,7 @@ def test_env_list():
assert "variable" in c.environment assert "variable" in c.environment
assert c.environment["variable"] == "value" assert c.environment["variable"] == "value"
c = Config(environment=[ c = KiwiConfig(environment=[
"variable", "variable",
]) ])
@ -356,7 +356,7 @@ def test_env_list():
assert "variable" in c.environment assert "variable" in c.environment
assert c.environment["variable"] is None assert c.environment["variable"] is None
c = Config(environment=[ c = KiwiConfig(environment=[
123, 123,
]) ])
@ -366,25 +366,25 @@ def test_env_list():
def test_env_coercible(): def test_env_coercible():
c = Config(environment="variable=value") c = KiwiConfig(environment="variable=value")
assert len(c.environment) == 1 assert len(c.environment) == 1
assert "variable" in c.environment assert "variable" in c.environment
assert c.environment["variable"] == "value" assert c.environment["variable"] == "value"
c = Config(environment="variable") c = KiwiConfig(environment="variable")
assert len(c.environment) == 1 assert len(c.environment) == 1
assert "variable" in c.environment assert "variable" in c.environment
assert c.environment["variable"] is None assert c.environment["variable"] is None
c = Config(environment=123) c = KiwiConfig(environment=123)
assert len(c.environment) == 1 assert len(c.environment) == 1
assert "123" in c.environment assert "123" in c.environment
assert c.environment["123"] is None assert c.environment["123"] is None
c = Config(environment=123.4) c = KiwiConfig(environment=123.4)
assert len(c.environment) == 1 assert len(c.environment) == 1
assert "123.4" in c.environment assert "123.4" in c.environment
@ -393,7 +393,7 @@ def test_env_coercible():
def test_env_uncoercible(): def test_env_uncoercible():
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(environment=UnCoercible()) KiwiConfig(environment=UnCoercible())
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
@ -401,7 +401,7 @@ def test_env_uncoercible():
assert error["type"] == "value_error" assert error["type"] == "value_error"
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(environment=["valid", UnCoercible()]) KiwiConfig(environment=["valid", UnCoercible()])
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
@ -415,7 +415,7 @@ def test_env_uncoercible():
def test_storage_empty(): def test_storage_empty():
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(storage=None) KiwiConfig(storage=None)
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
@ -425,7 +425,7 @@ def test_storage_empty():
def test_storage_dict(): def test_storage_dict():
kiwi_dict = {"directory": "/test/directory"} kiwi_dict = {"directory": "/test/directory"}
c = Config(storage=kiwi_dict) c = KiwiConfig(storage=kiwi_dict)
assert c.storage.directory == Path("/test/directory") assert c.storage.directory == Path("/test/directory")
assert c.storage.kiwi_dict == kiwi_dict assert c.storage.kiwi_dict == kiwi_dict
@ -433,7 +433,7 @@ def test_storage_dict():
def test_storage_invalid_dict(): def test_storage_invalid_dict():
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(storage={"random key": "random value"}) KiwiConfig(storage={"random key": "random value"})
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
@ -442,20 +442,20 @@ def test_storage_invalid_dict():
def test_storage_str(): def test_storage_str():
c = Config(storage="/test/directory") c = KiwiConfig(storage="/test/directory")
assert c.storage.directory == Path("/test/directory") assert c.storage.directory == Path("/test/directory")
def test_storage_list(): def test_storage_list():
c = Config(storage=["/test/directory"]) c = KiwiConfig(storage=["/test/directory"])
assert c.storage.directory == Path("/test/directory") assert c.storage.directory == Path("/test/directory")
def test_storage_invalid(): def test_storage_invalid():
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(storage=True) KiwiConfig(storage=True)
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
@ -469,7 +469,7 @@ def test_storage_invalid():
def test_network_empty(): def test_network_empty():
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(network=None) KiwiConfig(network=None)
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
@ -482,9 +482,9 @@ def test_network_dict():
"name": "test_hub", "name": "test_hub",
"cidr": "1.2.3.4/32", "cidr": "1.2.3.4/32",
} }
c = Config(network=kiwi_dict) c = KiwiConfig(network=kiwi_dict)
assert c == Config(network={ assert c == KiwiConfig(network={
"name": "TEST_HUB", "name": "TEST_HUB",
"cidr": "1.2.3.4/32", "cidr": "1.2.3.4/32",
}) })
@ -496,7 +496,7 @@ def test_network_dict():
def test_network_invalid_dict(): def test_network_invalid_dict():
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(network={"name": "test_hub"}) KiwiConfig(network={"name": "test_hub"})
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
@ -504,7 +504,7 @@ def test_network_invalid_dict():
assert error["type"] == "value_error.missing" assert error["type"] == "value_error.missing"
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(network={ KiwiConfig(network={
"name": "test_hub", "name": "test_hub",
"cidr": "1.2.3.4/123", "cidr": "1.2.3.4/123",
}) })
@ -517,7 +517,7 @@ def test_network_invalid_dict():
def test_network_invalid(): def test_network_invalid():
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
Config(network=True) KiwiConfig(network=True)
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]