Source code for miniwerk.config

"""Configuration"""
from __future__ import annotations
from typing import ClassVar, Optional, List, Dict
from pathlib import Path
from enum import StrEnum

from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict


[docs] class KeyType(StrEnum): """Valid key types for certbot/mkcert"""
[docs] RSA = "rsa"
[docs] ECDSA = "ecdsa"
[docs] class ProductSettings(BaseSettings): """Configs for each product"""
[docs] api_port: int = Field(description="port for the API")
[docs] class MWConfig(BaseSettings): """Config for MiniWerk""" # Things you must or should define
[docs] domain: str = Field(description="Domain under which we operate")
[docs] le_email: str = Field(description="email given to letsencrypt")
[docs] le_test: bool = Field(default=True, description="Use LE staging/test env")
[docs] subdomains: str = Field(default="mtls", description="Comma separated list of extra subdomains to get certs for")
[docs] products: str = Field( default="fake,tak", description="Comma separated list of products to create manifests and get subdomains for" )
[docs] fake: ProductSettings = Field( description="Setting for fakeproduct intration API", default_factory=lambda: ProductSettings(api_port=4625) )
[docs] tak: ProductSettings = Field( description="Setting for TAK intration API", default_factory=lambda: ProductSettings(api_port=4626) )
[docs] rasenmaeher: ProductSettings = Field( description="Setting for RASENMAEHER API", default_factory=lambda: ProductSettings(api_port=443) )
[docs] le_cert_name: str = Field(default="rasenmaeher", description="--cert-name for LE, used to determine directory name")
[docs] le_copy_path: Path = Field(default="/le_certs", description="Where to copy letsencrypt certs and keys")
[docs] data_path: Path = Field(default="/data/persistent", description="Where do we keep our data")
[docs] manifests_base: Path = Field( default="/pvarkishares", description="Path for manifests etc, each product gets a subdir" )
[docs] mkcert: bool = Field(default=False, description="Use mkcert instead of certbot")
[docs] ci: bool = Field(default=False, alias="CI", description="Are we running in CI")
[docs] keytype: KeyType = Field(default="ecdsa", description="Which key types to use, rsa or ecdsa (default)")
[docs] model_config = SettingsConfigDict(env_prefix="mw_", env_file=".env", extra="ignore", env_nested_delimiter="__")
[docs] _singleton: ClassVar[Optional[MWConfig]] = None
@classmethod
[docs] def singleton(cls) -> MWConfig: """Return singleton""" if not MWConfig._singleton: MWConfig._singleton = MWConfig() # type: ignore[call-arg] return MWConfig._singleton
@property
[docs] def le_config_path(self) -> Path: """LE configuration dir""" return self.data_path / "le" / "conf"
@property
[docs] def mkcert_path(self) -> Path: """mkcert certs dir""" return self.data_path / "mkcert"
@property
[docs] def le_work_path(self) -> Path: """LE work dir (doesn't seem to actually hold anything persistent)""" return self.data_path / "le" / "work"
@property
[docs] def le_cert_dir(self) -> Path: """The "live" dir for the cert we have, remember the "file" here are symlinks""" return self.le_config_path / "live" / self.le_cert_name
@property
[docs] def mk_cert_dir(self) -> Path: """The "live" dir for the cert we have""" return self.mkcert_path / self.le_cert_name
@property
[docs] def fqdns(self) -> List[str]: """Main domain and all subdomains and FQDNs""" ret = [f"{subd.strip()}.{self.domain}" for subd in str(self.subdomains).split(",")] for proddomain in [f"{prod.strip()}.{self.domain}" for prod in str(self.products).split(",")]: ret.append(proddomain) ret += [f"{subd.strip()}.{proddomain}" for subd in str(self.subdomains).split(",")] ret.append(self.domain) return ret
@property
[docs] def product_manifest_paths(self) -> Dict[str, Path]: """Paths for product manifests keyed by product""" return {prod.strip(): self.manifests_base / prod.strip() for prod in str(self.products).split(",")}