2021-10-12 17:06:49 +00:00
|
|
|
from ipaddress import IPv4Network
|
|
|
|
from pathlib import Path
|
2021-10-11 00:58:49 +00:00
|
|
|
from typing import Optional, Dict, List
|
2020-08-04 18:24:19 +00:00
|
|
|
|
2021-10-11 00:58:49 +00:00
|
|
|
import pydantic
|
2020-08-06 01:45:12 +00:00
|
|
|
|
2021-10-12 17:06:49 +00:00
|
|
|
from ._constants import RE_SEMVER, RE_VARNAME
|
|
|
|
|
2020-08-04 14:52:30 +00:00
|
|
|
|
2021-10-11 00:58:49 +00:00
|
|
|
class _Storage(pydantic.BaseModel):
|
|
|
|
"""a storage subsection"""
|
2020-08-13 08:48:01 +00:00
|
|
|
|
2021-10-12 17:06:49 +00:00
|
|
|
directory: Path
|
2020-08-06 01:45:12 +00:00
|
|
|
|
2020-08-13 08:48:01 +00:00
|
|
|
|
2021-10-11 00:58:49 +00:00
|
|
|
class _Project(pydantic.BaseModel):
|
|
|
|
"""a project subsection"""
|
2020-08-06 12:34:25 +00:00
|
|
|
|
2021-10-12 17:06:49 +00:00
|
|
|
name: pydantic.constr(
|
|
|
|
regex=RE_VARNAME
|
|
|
|
)
|
2021-10-11 00:58:49 +00:00
|
|
|
enabled: bool = True
|
2021-10-12 17:06:49 +00:00
|
|
|
override_storage: Optional[_Storage]
|
2020-08-06 12:34:25 +00:00
|
|
|
|
2021-10-11 00:58:49 +00:00
|
|
|
@pydantic.root_validator(pre=True)
|
|
|
|
@classmethod
|
2021-10-12 17:06:49 +00:00
|
|
|
def unify_project(cls, values):
|
|
|
|
"""parse different project notations"""
|
|
|
|
|
|
|
|
if "name" in values:
|
|
|
|
# default format
|
|
|
|
return values
|
|
|
|
|
|
|
|
elif len(values) == 1:
|
|
|
|
# short format:
|
|
|
|
# - <name>: <enabled>
|
2020-08-11 15:23:24 +00:00
|
|
|
|
2021-10-12 17:06:49 +00:00
|
|
|
name, enabled = list(values.items())[0]
|
|
|
|
return {
|
|
|
|
"name": name,
|
|
|
|
"enabled": True if enabled is None else enabled
|
|
|
|
}
|
2020-08-11 15:23:24 +00:00
|
|
|
|
2021-10-12 17:06:49 +00:00
|
|
|
else:
|
|
|
|
# undefined format
|
|
|
|
raise ValueError
|
2020-08-20 11:29:08 +00:00
|
|
|
|
|
|
|
|
2021-10-11 00:58:49 +00:00
|
|
|
class _Network(pydantic.BaseModel):
|
|
|
|
"""a network subsection"""
|
2020-08-20 11:29:08 +00:00
|
|
|
|
2021-10-12 17:06:49 +00:00
|
|
|
name: pydantic.constr(
|
|
|
|
to_lower=True,
|
|
|
|
regex=RE_VARNAME
|
|
|
|
)
|
|
|
|
cidr: IPv4Network
|
2020-08-13 08:48:01 +00:00
|
|
|
|
2020-08-06 12:34:25 +00:00
|
|
|
|
2021-10-11 00:58:49 +00:00
|
|
|
class Config(pydantic.BaseModel):
|
|
|
|
"""represents a kiwi.yml"""
|
2020-08-08 17:41:11 +00:00
|
|
|
|
2021-10-12 17:06:49 +00:00
|
|
|
version: pydantic.constr(
|
|
|
|
regex=RE_SEMVER
|
|
|
|
)
|
2021-10-11 00:58:49 +00:00
|
|
|
shells: Optional[List[str]]
|
|
|
|
environment: Optional[Dict[str, Optional[str]]]
|
2020-08-13 08:48:01 +00:00
|
|
|
|
2021-10-11 00:58:49 +00:00
|
|
|
projects: Optional[List[_Project]]
|
|
|
|
storage: _Storage
|
|
|
|
network: _Network
|
2020-08-08 17:41:11 +00:00
|
|
|
|
2021-10-11 00:58:49 +00:00
|
|
|
@pydantic.validator("environment", pre=True)
|
2020-08-06 11:43:45 +00:00
|
|
|
@classmethod
|
2021-10-12 17:06:49 +00:00
|
|
|
def unify_environment(cls, value) -> Optional[Dict[str, Optional[str]]]:
|
|
|
|
"""parse different environment notations"""
|
|
|
|
|
|
|
|
def parse_str(var_val: str) -> (str, Optional[str]):
|
|
|
|
"""parse a "<variable>=<value>" string"""
|
|
|
|
|
|
|
|
idx = var_val.find("=")
|
|
|
|
if idx == -1:
|
|
|
|
# don't split, just define the variable
|
|
|
|
return var_val, None
|
|
|
|
else:
|
|
|
|
# split string, set variable to value
|
|
|
|
return var_val[:idx], var_val[idx + 1:]
|
|
|
|
|
|
|
|
if value is None:
|
|
|
|
# empty environment
|
|
|
|
return None
|
|
|
|
|
|
|
|
elif isinstance(value, dict):
|
|
|
|
# native dict format
|
2021-10-11 00:58:49 +00:00
|
|
|
return value
|
2021-10-12 17:06:49 +00:00
|
|
|
|
2021-10-11 00:58:49 +00:00
|
|
|
elif isinstance(value, list):
|
2021-10-12 17:06:49 +00:00
|
|
|
# list format (multiple strings)
|
|
|
|
|
2021-10-11 00:58:49 +00:00
|
|
|
result: Dict[str, Optional[str]] = {}
|
|
|
|
for item in value:
|
2021-10-12 17:06:49 +00:00
|
|
|
key, value = parse_str(item)
|
2021-10-11 00:58:49 +00:00
|
|
|
result[key] = value
|
|
|
|
|
|
|
|
return result
|
2021-10-12 17:06:49 +00:00
|
|
|
|
|
|
|
elif isinstance(value, str):
|
|
|
|
# string format (single variable):
|
|
|
|
# "<var>=<value>"
|
|
|
|
|
|
|
|
key, value = parse_str(value)
|
|
|
|
return {key: value}
|
|
|
|
|
|
|
|
elif isinstance(value, int):
|
|
|
|
# integer format (just define single oddly named variable)
|
|
|
|
return {str(value): None}
|
|
|
|
|
2021-10-11 00:58:49 +00:00
|
|
|
else:
|
2021-10-12 17:06:49 +00:00
|
|
|
# undefined format
|
|
|
|
raise ValueError
|