Coverage for dlabel/traefik_conf.py: 99%
194 statements
« prev ^ index » next coverage.py v7.10.0, created at 2025-07-25 23:32 +0000
« prev ^ index » next coverage.py v7.10.0, created at 2025-07-25 23:32 +0000
1from dictknife import deepmerge
2from pydantic import BaseModel, model_validator, BeforeValidator, ConfigDict
3from typing import Any, Annotated
4from logging import getLogger
6_log = getLogger(__name__)
8excludes = dict(exclude_none=True, exclude_defaults=True, exclude_unset=True)
11class Model(BaseModel):
12 """traefik configuration data model"""
14 model_config = ConfigDict(extra="allow")
16 @model_validator(mode="before")
17 def __lowercase_property_keys__(cls, values: Any) -> Any:
18 def __lower__(value: Any) -> Any:
19 if isinstance(value, dict):
20 return {k.lower(): __lower__(v) for k, v in value.items()}
21 return value
23 return __lower__(values)
25 def merge(self, other: BaseModel):
26 if other is None:
27 return self
28 _log.debug("merge: %s + %s", self, other)
29 obj = deepmerge(
30 self.model_dump(**excludes), other.model_dump(**excludes))
31 _log.debug("merged: %s", obj)
32 return self.model_validate(obj)
34 def setbyaddr(self, address: list[str], value):
35 _log.debug("set(addr) %s -> %s", address, value)
36 res: dict[str, Any] = {}
37 tgt = res
38 for k in address[:-1]:
39 tgt[k] = {}
40 tgt = tgt[k]
41 if value == "true":
42 value = {}
43 tgt[address[-1]] = value
44 _log.debug("set-dict: %s", res)
45 return self.merge(self.model_validate(res))
47 def __str__(self) -> str:
48 return self.model_dump_json(**excludes)
50 def to_dict(self) -> dict:
51 return self.model_dump(exclude_unset=True, exclude_defaults=True, exclude_none=True)
54def csv_list(v: Any) -> list[str]:
55 if isinstance(v, str):
56 return v.split(",")
57 return v
60ListStr = Annotated[list[str], BeforeValidator(csv_list)]
63class CertFile(Model):
64 certfile: str | None = None
65 keyfile: str | None = None
68class StoreCert(Model):
69 defaultcertificate: CertFile | None = None
70 defaultgeneratedcert: dict[str, Any] | None = None
73class TlsCert(CertFile):
74 stores: list[str] | None = None
77class TlsConfig(Model):
78 certificates: list[TlsCert] | None = None
79 stores: dict[str, StoreCert] | None = None
80 options: dict[str, Any] | None = None
83class HttpRouter(Model):
84 entrypoints: ListStr | None = None
85 rule: str | None = None
86 rulesyntax: str | None = None
87 middlewares: ListStr | None = None
88 service: str | None = None
89 priority: int | None = None
90 tls: dict[str, Any] | bool | None = None
93class HttpLoadBalancerServer(Model):
94 # incompatible with traefik configuration (used by docker label)
95 host: str | None = None
96 ipaddress: str | None = None
97 port: int | None = None
100class HttpLoadBalancerServers(Model):
101 url: str | None = None
104class HttpLoadBalancer(Model):
105 servers: list[HttpLoadBalancerServers] | None = None
106 server: HttpLoadBalancerServer | None = None
107 sticky: dict[str, Any] | None = None
108 healthcheck: dict[str, str] | None = None
109 passhostheader: bool | None = None
110 serverstransport: str | None = None
111 responseforwarding: dict | None = None
114class HttpService(Model):
115 loadbalancer: HttpLoadBalancer | None = None
116 weighted: dict[str, Any] | None = None
117 mirroring: dict[str, Any] | None = None
118 failover: dict[str, Any] | None = None
121class CompressMiddleware(Model):
122 excludedcontenttypes: list[str] | None = None
123 includedcontenttypes: list[str] | None = None
124 minresponsebodybytes: int | None = None
125 defaultencoding: str | None = None
126 encodings: ListStr | None = None
129class HeadersMiddleware(Model):
130 customrequestheaders: dict[str, str] | None = None
131 customresponseheaders: dict[str, str] | None = None
134class StripprefixMiddleware(Model):
135 prefixes: ListStr | None = None
136 forceslash: bool | None = None
139class StripprefixregexMiddleware(Model):
140 regex: ListStr | None = None
143class AddprefixMiddleware(Model):
144 prefix: str | None = None
147class HttpMiddleware(Model):
148 addprefix: AddprefixMiddleware | None = None
149 basicauth: dict[str, Any] | None = None
150 buffering: dict[str, Any] | None = None
151 chain: dict[str, Any] | None = None
152 circuitbreaker: dict[str, Any] | None = None
153 compress: CompressMiddleware | bool | None = None
154 contenttype: dict[str, Any] | bool | None = None
155 digestauth: dict[str, Any] | None = None
156 errors: dict[str, Any] | None = None
157 forwardauth: dict[str, Any] | None = None
158 grpcweb: dict[str, Any] | None = None
159 headers: HeadersMiddleware | None = None
160 ipwhitelist: dict[str, Any] | None = None
161 ipallowlist: dict[str, Any] | None = None
162 inflightreq: dict[str, Any] | None = None
163 passtlsclientcert: dict[str, Any] | None = None
164 ratelimit: dict[str, Any] | None = None
165 redirectregex: dict[str, Any] | None = None
166 redirectscheme: dict[str, Any] | None = None
167 replacepath: dict[str, Any] | None = None
168 replacepathregex: dict[str, Any] | None = None
169 retry: dict[str, Any] | None = None
170 stripprefix: StripprefixMiddleware | None = None
171 stripprefixregex: StripprefixregexMiddleware | None = None
174class HttpConfig(Model):
175 middlewares: dict[str, HttpMiddleware] | None = None
176 routers: dict[str, HttpRouter] | None = None
177 services: dict[str, HttpService] | None = None
178 serverstransports: dict[str, dict] | None = None
181class AccessLogField(Model):
182 defaultmode: str | None = None
183 names: dict[str, str] | None = None
184 headers: dict[str, Any] | None = None
187class AccessLogConfig(Model):
188 addinternals: bool = False
189 filepath: str | None = None
190 format: str | None = None
191 bufferingsize: int | None = None
192 filters: dict[str, Any] | None = None
193 fields: AccessLogField | None = None
196class EntrypointHttp(Model):
197 redirections: dict[str, Any] | None = None
198 encodequerysemicolons: bool | None = None
199 middlewares: list[str] | None = None
200 tls: dict[str, Any] | None = None
203class EntrypointHttp2(Model):
204 maxconcurrentstreams: int | None = None
207class EntrypointHttp3(Model):
208 advertisedport: int | None = None
211class EntrypointConfig(Model):
212 address: str | None = None
213 http: EntrypointHttp | None = None
214 http2: EntrypointHttp2 | None = None
215 http3: EntrypointHttp3 | bool | None = None
216 udp: dict[str, Any] | None = None
217 allowacmebypass: bool | None = None
218 reuseport: bool | None = None
219 asdefault: bool | None = None
220 forwardedheaders: dict[str, Any] | None = None
221 transport: dict[str, Any] | None = None
222 proxyprotocol: dict[str, Any] | None = None
225class FileProvider(Model):
226 filename: str | None = None
227 directory: str | None = None
228 watch: bool | None = None
231class ProviderConfig(Model):
232 docker: dict[str, Any] | bool | None = None
233 file: FileProvider | None = None
234 swarm: dict[str, Any] | None = None
235 kubernetescrd: dict[str, Any] | None = None
236 kubernetesingress: dict[str, Any] | bool | None = None
237 kubernetesgateway: dict[str, Any] | bool | None = None
238 consulcatalog: dict[str, Any] | bool | None = None
239 nomad: dict[str, Any] | bool | None = None
240 ecs: dict[str, Any] | bool | None = None
241 consul: dict[str, Any] | None = None
242 etcd: dict[str, Any] | None = None
243 zookeeper: dict[str, Any] | None = None
244 redis: dict[str, Any] | None = None
245 http: dict[str, Any] | None = None
248class TraefikConfig(Model):
249 tls: TlsConfig | None = None
250 http: HttpConfig | None = None
251 tcp: dict[str, Any] | None = None
252 udp: dict[str, Any] | None = None
253 entrypoints: dict[str, EntrypointConfig] | None = None
254 providers: ProviderConfig | None = None
255 api: dict[str, Any] | None = None
256 accesslog: dict[str, Any] | None = None
257 experimental: dict[str, Any] | None = None
258 log: dict[str, Any] | None = None
259 metrics: dict[str, Any] | None = None
260 tracing: dict[str, Any] | None = None
261 certificatesresolvers: dict[str, Any] | None = None
262 spiffe: dict[str, Any] | None = None