Harden runtime distribution acceptance
This commit is contained in:
@@ -27,13 +27,52 @@ from govoplan_deploy.model import default_spec # noqa: E402
|
||||
DIGEST_IMAGE = re.compile(r"^[^@\s]+@sha256:[0-9a-f]{64}$")
|
||||
|
||||
|
||||
def _run(argv: list[str], *, check: bool = True) -> subprocess.CompletedProcess[str]:
|
||||
return subprocess.run(
|
||||
argv,
|
||||
check=check,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=60,
|
||||
def _run(
|
||||
argv: list[str],
|
||||
*,
|
||||
check: bool = True,
|
||||
input_text: str | None = None,
|
||||
) -> subprocess.CompletedProcess[str]:
|
||||
try:
|
||||
return subprocess.run(
|
||||
argv,
|
||||
check=check,
|
||||
capture_output=True,
|
||||
input=input_text,
|
||||
text=True,
|
||||
timeout=60,
|
||||
)
|
||||
except subprocess.CalledProcessError as exc:
|
||||
stderr = exc.stderr.strip()
|
||||
if stderr:
|
||||
print(stderr, file=sys.stderr)
|
||||
raise
|
||||
|
||||
|
||||
def _write_volume_file(
|
||||
*,
|
||||
image: str,
|
||||
volume: str,
|
||||
filename: str,
|
||||
content: str,
|
||||
) -> None:
|
||||
if not re.fullmatch(r"[A-Za-z0-9_.-]+", filename):
|
||||
raise ValueError(f"invalid config filename: {filename!r}")
|
||||
_run(
|
||||
[
|
||||
"docker",
|
||||
"run",
|
||||
"--rm",
|
||||
"--interactive",
|
||||
"--mount",
|
||||
f"type=volume,src={volume},dst=/govoplan-config",
|
||||
"--entrypoint",
|
||||
"sh",
|
||||
image,
|
||||
"-c",
|
||||
f"umask 022; cat > /govoplan-config/{filename}",
|
||||
],
|
||||
input_text=content,
|
||||
)
|
||||
|
||||
|
||||
@@ -85,15 +124,33 @@ def main() -> int:
|
||||
backend = f"govoplan-ingress-backend-{suffix}"
|
||||
data_volume = f"govoplan-ingress-data-{suffix}"
|
||||
config_volume = f"govoplan-ingress-config-{suffix}"
|
||||
backend_config_volume = f"govoplan-ingress-backend-config-{suffix}"
|
||||
ingress_config_volume = f"govoplan-ingress-caddy-config-{suffix}"
|
||||
load_balancer_config_volume = f"govoplan-ingress-haproxy-config-{suffix}"
|
||||
cleanup = [
|
||||
["docker", "rm", "--force", ingress, backend],
|
||||
["docker", "network", "rm", network],
|
||||
["docker", "volume", "rm", data_volume, config_volume],
|
||||
[
|
||||
"docker",
|
||||
"volume",
|
||||
"rm",
|
||||
data_volume,
|
||||
config_volume,
|
||||
backend_config_volume,
|
||||
ingress_config_volume,
|
||||
load_balancer_config_volume,
|
||||
],
|
||||
]
|
||||
try:
|
||||
_run(["docker", "network", "create", network])
|
||||
_run(["docker", "volume", "create", data_volume])
|
||||
_run(["docker", "volume", "create", config_volume])
|
||||
for volume in (
|
||||
data_volume,
|
||||
config_volume,
|
||||
backend_config_volume,
|
||||
ingress_config_volume,
|
||||
load_balancer_config_volume,
|
||||
):
|
||||
_run(["docker", "volume", "create", volume])
|
||||
with tempfile.TemporaryDirectory(prefix="govoplan-ingress-") as directory:
|
||||
root = Path(directory)
|
||||
backend_config = root / "backend.Caddyfile"
|
||||
@@ -127,6 +184,24 @@ def main() -> int:
|
||||
encoding="utf-8",
|
||||
)
|
||||
load_balancer_config.chmod(0o644)
|
||||
_write_volume_file(
|
||||
image=args.load_balancer_image,
|
||||
volume=load_balancer_config_volume,
|
||||
filename="haproxy.cfg",
|
||||
content=load_balancer_config.read_text(encoding="utf-8"),
|
||||
)
|
||||
_write_volume_file(
|
||||
image=args.caddy_image,
|
||||
volume=backend_config_volume,
|
||||
filename="Caddyfile",
|
||||
content=backend_config.read_text(encoding="utf-8"),
|
||||
)
|
||||
_write_volume_file(
|
||||
image=args.caddy_image,
|
||||
volume=ingress_config_volume,
|
||||
filename="Caddyfile",
|
||||
content=ingress_config.read_text(encoding="utf-8"),
|
||||
)
|
||||
_run(
|
||||
[
|
||||
"docker",
|
||||
@@ -136,7 +211,11 @@ def main() -> int:
|
||||
"--cap-drop",
|
||||
"ALL",
|
||||
"--mount",
|
||||
f"type=bind,src={load_balancer_config},dst=/usr/local/etc/haproxy/haproxy.cfg,readonly",
|
||||
(
|
||||
"type=volume,"
|
||||
f"src={load_balancer_config_volume},"
|
||||
"dst=/usr/local/etc/haproxy,readonly"
|
||||
),
|
||||
args.load_balancer_image,
|
||||
"haproxy",
|
||||
"-c",
|
||||
@@ -154,16 +233,22 @@ def main() -> int:
|
||||
backend,
|
||||
"--network",
|
||||
network,
|
||||
"--network-alias",
|
||||
"load-balancer",
|
||||
"--read-only",
|
||||
"--tmpfs",
|
||||
"/tmp:rw,noexec,nosuid,size=16m",
|
||||
"--mount",
|
||||
f"type=bind,src={backend_config},dst=/etc/caddy/Caddyfile,readonly",
|
||||
(
|
||||
"type=volume,"
|
||||
f"src={backend_config_volume},"
|
||||
"dst=/govoplan-config,readonly"
|
||||
),
|
||||
args.caddy_image,
|
||||
"caddy",
|
||||
"run",
|
||||
"--config",
|
||||
"/etc/caddy/Caddyfile",
|
||||
"/govoplan-config/Caddyfile",
|
||||
]
|
||||
)
|
||||
ingress_command = [
|
||||
@@ -186,7 +271,11 @@ def main() -> int:
|
||||
"--publish",
|
||||
"127.0.0.1::8443",
|
||||
"--mount",
|
||||
f"type=bind,src={ingress_config},dst=/etc/caddy/Caddyfile,readonly",
|
||||
(
|
||||
"type=volume,"
|
||||
f"src={ingress_config_volume},"
|
||||
"dst=/govoplan-config,readonly"
|
||||
),
|
||||
"--mount",
|
||||
f"type=volume,src={data_volume},dst=/data",
|
||||
"--mount",
|
||||
@@ -195,7 +284,7 @@ def main() -> int:
|
||||
"caddy",
|
||||
"run",
|
||||
"--config",
|
||||
"/etc/caddy/Caddyfile",
|
||||
"/govoplan-config/Caddyfile",
|
||||
]
|
||||
_run(ingress_command)
|
||||
http_port = _published_port(ingress, 8080)
|
||||
|
||||
Reference in New Issue
Block a user