Release v0.1.16
This commit is contained in:
@@ -76,13 +76,20 @@ def render_kubernetes(
|
||||
namespace: str = "govoplan",
|
||||
secret_name: str = "govoplan-runtime",
|
||||
tls_secret_name: str = "govoplan-tls",
|
||||
s3_ca_secret_name: str | None = None,
|
||||
ingress_class_name: str | None = None,
|
||||
backup_required: bool = True,
|
||||
backup_evidence: Mapping[str, object] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Render runtime roles only; shared state services stay externally managed."""
|
||||
|
||||
_validate_cluster_profile(spec, environment, namespace, secret_name)
|
||||
_validate_cluster_profile(
|
||||
spec,
|
||||
environment,
|
||||
namespace,
|
||||
secret_name,
|
||||
s3_ca_secret_name=s3_ca_secret_name,
|
||||
)
|
||||
worker_pools = _worker_pools(spec, environment)
|
||||
database_capacity = _database_capacity(spec, environment, worker_pools)
|
||||
name = _resource_name(spec.installation_id)
|
||||
@@ -155,6 +162,7 @@ def render_kubernetes(
|
||||
),
|
||||
config_name=config_name,
|
||||
secret_name=secret_name,
|
||||
s3_ca_secret_name=s3_ca_secret_name,
|
||||
service_account=service_account,
|
||||
container_port=8000,
|
||||
readiness_path="/health/ready",
|
||||
@@ -179,6 +187,7 @@ def render_kubernetes(
|
||||
command=(),
|
||||
config_name=None,
|
||||
secret_name=None,
|
||||
s3_ca_secret_name=None,
|
||||
service_account=service_account,
|
||||
container_port=8080,
|
||||
extra_environment={"GOVOPLAN_API_UPSTREAM": f"http://{name}-api:8000"},
|
||||
@@ -198,6 +207,7 @@ def render_kubernetes(
|
||||
image=spec.release.api_image,
|
||||
config_name=config_name,
|
||||
secret_name=secret_name,
|
||||
s3_ca_secret_name=s3_ca_secret_name,
|
||||
service_account=service_account,
|
||||
database_environment=_role_database_environment(
|
||||
environment,
|
||||
@@ -237,6 +247,7 @@ def render_kubernetes(
|
||||
),
|
||||
config_name=config_name,
|
||||
secret_name=secret_name,
|
||||
s3_ca_secret_name=s3_ca_secret_name,
|
||||
service_account=service_account,
|
||||
extra_environment={
|
||||
**_role_database_environment(environment, "WORKER"),
|
||||
@@ -287,9 +298,12 @@ def render_kubernetes(
|
||||
"beat",
|
||||
"--loglevel",
|
||||
"INFO",
|
||||
"--schedule",
|
||||
"/tmp/celerybeat-schedule",
|
||||
),
|
||||
config_name=config_name,
|
||||
secret_name=secret_name,
|
||||
s3_ca_secret_name=s3_ca_secret_name,
|
||||
service_account=service_account,
|
||||
extra_environment=_role_database_environment(
|
||||
environment,
|
||||
@@ -318,6 +332,7 @@ def render_kubernetes(
|
||||
"annotations": {
|
||||
"govoplan.add-ideas.de/profile": "stateless-shared-state",
|
||||
"govoplan.add-ideas.de/secret-contract": ",".join(_SECRET_KEYS),
|
||||
"govoplan.add-ideas.de/s3-ca-secret": s3_ca_secret_name or "",
|
||||
"govoplan.add-ideas.de/database-connection-peak": str(
|
||||
database_capacity["peak"]
|
||||
),
|
||||
@@ -342,9 +357,13 @@ def _validate_cluster_profile(
|
||||
environment: Mapping[str, str],
|
||||
namespace: str,
|
||||
secret_name: str,
|
||||
*,
|
||||
s3_ca_secret_name: str | None,
|
||||
) -> None:
|
||||
if not _DNS_LABEL.fullmatch(namespace) or not _DNS_LABEL.fullmatch(secret_name):
|
||||
raise ValueError("Kubernetes namespace and secret names must be DNS labels")
|
||||
if s3_ca_secret_name is not None and not _DNS_LABEL.fullmatch(s3_ca_secret_name):
|
||||
raise ValueError("Kubernetes S3 CA secret name must be a DNS label")
|
||||
if spec.installation_id == "govoplan-local":
|
||||
raise ValueError(
|
||||
"Kubernetes export requires a non-default stable installation id"
|
||||
@@ -633,6 +652,7 @@ def _deployment(
|
||||
command: tuple[str, ...],
|
||||
config_name: str | None,
|
||||
secret_name: str | None,
|
||||
s3_ca_secret_name: str | None,
|
||||
service_account: str,
|
||||
container_port: int | None = None,
|
||||
readiness_path: str | None = None,
|
||||
@@ -660,6 +680,10 @@ def _deployment(
|
||||
)
|
||||
if secret_name:
|
||||
environment.extend(_secret_environment(secret_name))
|
||||
if s3_ca_secret_name:
|
||||
environment.append(
|
||||
{"name": "AWS_CA_BUNDLE", "value": "/etc/govoplan/trust/s3-ca.crt"}
|
||||
)
|
||||
container: dict[str, Any] = {
|
||||
"name": role,
|
||||
"image": image,
|
||||
@@ -704,12 +728,16 @@ def _deployment(
|
||||
{
|
||||
"maxSkew": 1,
|
||||
"topologyKey": "kubernetes.io/hostname",
|
||||
"whenUnsatisfiable": "ScheduleAnyway",
|
||||
"whenUnsatisfiable": "DoNotSchedule",
|
||||
"matchLabelKeys": ["pod-template-hash"],
|
||||
"labelSelector": {"matchLabels": role_labels},
|
||||
}
|
||||
],
|
||||
}
|
||||
container["volumeMounts"] = [{"name": "tmp", "mountPath": "/tmp"}]
|
||||
if s3_ca_secret_name:
|
||||
pod_spec["volumes"].append(_s3_ca_volume(s3_ca_secret_name))
|
||||
container["volumeMounts"].append(_s3_ca_volume_mount())
|
||||
if config_name:
|
||||
pod_spec["containers"][0]["envFrom"] = [{"configMapRef": {"name": config_name}}]
|
||||
if config_name and secret_name:
|
||||
@@ -731,6 +759,16 @@ def _deployment(
|
||||
{"name": "GOVOPLAN_RUNTIME_ROLE", "value": "migration-wait"},
|
||||
{"name": "GOVOPLAN_DB_POOL_SIZE", "value": "1"},
|
||||
{"name": "GOVOPLAN_DB_MAX_OVERFLOW", "value": "0"},
|
||||
*(
|
||||
[
|
||||
{
|
||||
"name": "AWS_CA_BUNDLE",
|
||||
"value": "/etc/govoplan/trust/s3-ca.crt",
|
||||
}
|
||||
]
|
||||
if s3_ca_secret_name
|
||||
else []
|
||||
),
|
||||
*_secret_environment(secret_name),
|
||||
],
|
||||
"securityContext": {
|
||||
@@ -738,7 +776,10 @@ def _deployment(
|
||||
"capabilities": {"drop": ["ALL"]},
|
||||
"readOnlyRootFilesystem": True,
|
||||
},
|
||||
"volumeMounts": [{"name": "tmp", "mountPath": "/tmp"}],
|
||||
"volumeMounts": [
|
||||
{"name": "tmp", "mountPath": "/tmp"},
|
||||
*([_s3_ca_volume_mount()] if s3_ca_secret_name else []),
|
||||
],
|
||||
}
|
||||
]
|
||||
return {
|
||||
@@ -769,6 +810,7 @@ def _migration_job(
|
||||
image: str,
|
||||
config_name: str,
|
||||
secret_name: str,
|
||||
s3_ca_secret_name: str | None,
|
||||
service_account: str,
|
||||
database_environment: Mapping[str, str],
|
||||
backup_required: bool,
|
||||
@@ -832,6 +874,16 @@ def _migration_job(
|
||||
"env": [
|
||||
{"name": "TMPDIR", "value": "/tmp"},
|
||||
{"name": "GOVOPLAN_RUNTIME_ROLE", "value": "migration"},
|
||||
*(
|
||||
[
|
||||
{
|
||||
"name": "AWS_CA_BUNDLE",
|
||||
"value": "/etc/govoplan/trust/s3-ca.crt",
|
||||
}
|
||||
]
|
||||
if s3_ca_secret_name
|
||||
else []
|
||||
),
|
||||
*(
|
||||
{"name": key, "value": value}
|
||||
for key, value in sorted(
|
||||
@@ -851,10 +903,24 @@ def _migration_job(
|
||||
"capabilities": {"drop": ["ALL"]},
|
||||
"readOnlyRootFilesystem": True,
|
||||
},
|
||||
"volumeMounts": [{"name": "tmp", "mountPath": "/tmp"}],
|
||||
"volumeMounts": [
|
||||
{"name": "tmp", "mountPath": "/tmp"},
|
||||
*(
|
||||
[_s3_ca_volume_mount()]
|
||||
if s3_ca_secret_name
|
||||
else []
|
||||
),
|
||||
],
|
||||
}
|
||||
],
|
||||
"volumes": [{"name": "tmp", "emptyDir": {}}],
|
||||
"volumes": [
|
||||
{"name": "tmp", "emptyDir": {}},
|
||||
*(
|
||||
[_s3_ca_volume(s3_ca_secret_name)]
|
||||
if s3_ca_secret_name
|
||||
else []
|
||||
),
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -873,6 +939,24 @@ def _secret_environment(secret_name: str) -> list[dict[str, Any]]:
|
||||
]
|
||||
|
||||
|
||||
def _s3_ca_volume(secret_name: str) -> dict[str, Any]:
|
||||
return {
|
||||
"name": "s3-ca",
|
||||
"secret": {
|
||||
"secretName": secret_name,
|
||||
"items": [{"key": "ca.crt", "path": "s3-ca.crt"}],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _s3_ca_volume_mount() -> dict[str, Any]:
|
||||
return {
|
||||
"name": "s3-ca",
|
||||
"mountPath": "/etc/govoplan/trust",
|
||||
"readOnly": True,
|
||||
}
|
||||
|
||||
|
||||
def _service(
|
||||
*,
|
||||
name: str,
|
||||
|
||||
Reference in New Issue
Block a user