This commit is contained in:
2025-12-15 01:03:25 -06:00
parent cef96db21a
commit 9d3ce193e8
4 changed files with 117 additions and 99 deletions

View File

@@ -3,9 +3,9 @@ from typing import cast
from compose.cfg.entity import CfgData, CfgDataYaml, OrgData
from compose.compose.entity import VolYaml
from compose.service.entity import Service
from compose.service.entity import Service, T_Compose
from compose.service.factory import services_yaml_factory
from compose.util import read_yml
from compose.util import get_replace_name, read_yml
def cfg_get_orgs(data: CfgDataYaml) -> Iterator[OrgData]:
@@ -16,10 +16,63 @@ def cfg_get_orgs(data: CfgDataYaml) -> Iterator[OrgData]:
)
def _get_sec_opts(
data: T_Compose,
) -> frozenset[str]:
sec_opts = frozenset(
"no-new-privileges:true",
)
sec = data.get("security_opt")
if not sec:
return sec_opts
return sec_opts.union(sec)
def _get_labels(
data: T_Compose,
) -> frozenset[str] | None:
org_name = get_replace_name("org_name")
url = get_replace_name("url")
traefik_labels = frozenset(
(
f"traefik.http.routers.{org_name}.rule=Host(`{url}`)",
f"traefik.http.routers.{org_name}.entrypoints=websecure",
f"traefik.docker.network={org_name}_proxy",
f"traefik.http.routers.{org_name}.tls.certresolver=le",
)
)
labels = data.get("labels")
if not labels:
return
if "traefik.enable=true" not in labels:
return frozenset(labels)
return traefik_labels.union(labels)
def cfg_get_services(cfg_data: CfgData) -> Iterator[tuple[str, Service]]:
for path in cfg_data.services:
_dict = services_yaml_factory(path)
yield path.stem, Service.from_dict(_dict)
data = services_yaml_factory(path)
# yield path.stem, Service.from_dict(data)
# @classmethod
command = data.get("command")
volumes = data.get("volumes")
entry = data.get("entrypoint")
service = Service(
tuple(command) if command else None,
get_replace_name("org_name"),
tuple(entry) if entry else None,
data.get("environment"),
data["image"],
_get_labels(data),
None,
Service.get_nets(data),
"unless-stopped",
_get_sec_opts(data),
data.get("user"),
frozenset(volumes) if volumes else None,
)
yield path.stem, service
def cfg_get_volumes(cfg_data: CfgData) -> Iterator[tuple[str, VolYaml]]:

View File

@@ -1,11 +1,10 @@
from dataclasses import asdict, dataclass
from typing import Literal, NotRequired, Self, TypedDict, final
from typing import Literal, NotRequired, TypedDict, final
from compose.cfg import T_YamlDict
from compose.cfg.entity import CfgData
from compose.net.entities import Net, NetTraefik, NetYaml
from compose.service.entity import Service, ServiceYaml, TraefikService
from compose.service.get import services_get_networks
from compose.util import to_yaml
type VolYaml = dict[str, T_YamlDict]
@@ -26,25 +25,25 @@ class Compose:
networks: Net | None
volumes: VolYaml | None
@classmethod
def from_dict(cls, cfg: CfgData, data: ComposeYaml) -> Self:
# services = dict[str, ComposeService]()
services = dict(_get_services_dict(data))
# vols = frozenset(_get_volumes_dict(data))
return cls(
cfg,
services,
services_get_networks(services.values()),
data.get("volumes"),
)
# @classmethod
# def from_dict(cls, cfg: CfgData, data: ComposeYaml) -> Self:
# # services = dict[str, ComposeService]()
# services = dict(_get_services_dict(data))
# # vols = frozenset(_get_volumes_dict(data))
# return cls(
# cfg,
# services,
# services_get_networks(services.values()),
# data.get("volumes"),
# )
def as_yaml(self) -> str:
return to_yaml(asdict(self))
def _get_services_dict(data: ComposeYaml):
for k, v in data["services"].items():
yield k, Service.from_dict(v)
# def _get_services_dict(data: ComposeYaml):
# for k, v in data["services"].items():
# yield k, Service.from_dict(v)
# def _get_volumes_dict(data: ComposeYaml) -> Iterator[VolYaml]:

View File

@@ -1,5 +1,5 @@
from dataclasses import dataclass
from typing import NotRequired, Self, TypedDict, final
from typing import NotRequired, TypedDict, final
type NetTraefik = dict[str, NetArgs]
@@ -15,12 +15,12 @@ class NetArgs:
name: str
external: bool | None
@classmethod
def from_dict(cls, data: NetArgsYaml) -> Self:
return cls(
data["name"],
data.get("external"),
)
# @classmethod
# def from_dict(cls, data: NetArgsYaml) -> Self:
# return cls(
# data["name"],
# data.get("external"),
# )
class NetYaml(TypedDict):
@@ -34,12 +34,12 @@ class Net:
internal: NetArgs | None
proxy: NetArgs | None
@classmethod
def from_class(cls, data: NetYaml) -> Self:
internal = data.get("internal")
if internal is not None:
internal = NetArgs.from_dict(internal)
proxy = data.get("proxy")
if proxy is not None:
proxy = NetArgs.from_dict(proxy)
return cls(internal, proxy)
# @classmethod
# def from_dict(cls, data: NetYaml) -> Self:
# internal = data.get("internal")
# if internal is not None:
# internal = NetArgs.from_dict(internal)
# proxy = data.get("proxy")
# if proxy is not None:
# proxy = NetArgs.from_dict(proxy)
# return cls(internal, proxy)

View File

@@ -1,9 +1,8 @@
from abc import ABCMeta, abstractmethod
from dataclasses import dataclass
from typing import Literal, NotRequired, Self, TypedDict, TypeVar, overload, override
from typing import Literal, NotRequired, TypedDict, TypeVar, overload, override
from compose.cfg import T_Primitive
from compose.util import get_replace_name
type T_NetAbc = str | Literal["proxy", "internal"]
TCo_NetABC = TypeVar("TCo_NetABC", bound=T_NetAbc, covariant=True)
@@ -57,35 +56,35 @@ class ServiceAbc[T_net: T_NetAbc, T_Yaml: T_Compose](metaclass=ABCMeta):
user: str | None
volumes: frozenset[str] | None
@classmethod
def from_dict(cls, data: T_Yaml) -> Self:
command = data.get("command")
volumes = data.get("volumes")
entry = data.get("entrypoint")
name = data.get("container_name")
if name is None:
raise KeyError
return cls(
tuple(command) if command else None,
name,
tuple(entry) if entry else None,
data.get("environment"),
data["image"],
_get_labels(data),
None,
cls.get_nets(data),
"unless-stopped",
_get_sec_opts(data),
data.get("user"),
frozenset(volumes) if volumes else None,
)
# @classmethod
# def from_dict(cls, data: T_Yaml) -> Self:
# command = data.get("command")
# volumes = data.get("volumes")
# entry = data.get("entrypoint")
# name = data.get("container_name")
# if name is None:
# raise KeyError
# return cls(
# tuple(command) if command else None,
# name,
# tuple(entry) if entry else None,
# data.get("environment"),
# data["image"],
# _get_labels(data),
# None,
# cls.get_nets(data),
# "unless-stopped",
# _get_sec_opts(data),
# data.get("user"),
# frozenset(volumes) if volumes else None,
# )
def is_valid(self) -> bool:
attrs = (self.container_name, self.restart, self.logging)
for attr in attrs:
if attr is None:
return False
return True
# def is_valid(self) -> bool:
# attrs = (self.container_name, self.restart, self.logging)
# for attr in attrs:
# if attr is None:
# return False
# return True
@staticmethod
@abstractmethod
@@ -127,36 +126,3 @@ def _get_nets(
if nets is None:
return
return frozenset(nets)
def _get_sec_opts(
data: T_Compose,
) -> frozenset[str]:
sec_opts = frozenset(
"no-new-privileges:true",
)
sec = data.get("security_opt")
if not sec:
return sec_opts
return sec_opts.union(sec)
def _get_labels(
data: T_Compose,
) -> frozenset[str] | None:
org_name = get_replace_name("org_name")
url = get_replace_name("url")
traefik_labels = frozenset(
(
f"traefik.http.routers.{org_name}.rule=Host(`{url}`)",
f"traefik.http.routers.{org_name}.entrypoints=websecure",
f"traefik.docker.network={org_name}_proxy",
f"traefik.http.routers.{org_name}.tls.certresolver=le",
)
)
labels = data.get("labels")
if not labels:
return
if "traefik.enable=true" not in labels:
return frozenset(labels)
return traefik_labels.union(labels)