75 lines
4.5 KiB
Python
75 lines
4.5 KiB
Python
"""Guard and apply worker settings to the existing isolated local development stack."""
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import subprocess
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
SIDECAR = "sha256:8a29cb90fcc2817b0d784826d55a172c943f5ad7e1b6105e690a2d79ee15fe87"
|
|
|
|
|
|
def capture(arguments, environment):
|
|
return subprocess.check_output(["rtk", "proxy", *arguments], env=environment, text=True)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--checkout", type=Path, required=True)
|
|
parser.add_argument("--bart-artifact", type=Path, required=True)
|
|
parser.add_argument("--output", type=Path, required=True)
|
|
parser.add_argument("--apply", action="store_true")
|
|
args = parser.parse_args()
|
|
checkout = args.checkout.resolve()
|
|
artifact = args.bart_artifact.resolve()
|
|
environment = {**os.environ, "JOBTRACKER_DEV_BART_ARTIFACT": str(artifact)}
|
|
manifest = json.loads((ROOT / "docs/redesign/phase-9/p9-sec-02/full-model/ARTIFACTS.json").read_text())["weights-only"]
|
|
for row in manifest["files"]:
|
|
path = artifact / row["file"]
|
|
assert path.is_file() and path.stat().st_size == row["bytes"], "Local model file missing or wrong size"
|
|
with path.open("rb") as stream:
|
|
assert hashlib.file_digest(stream, "sha256").hexdigest() == row["sha256"], "Local model integrity mismatch"
|
|
assert json.loads((ROOT / ".artifacts/pre-phase10-ux/local-ai/verification.json").read_text())["status"] == "PASS"
|
|
compose = ["docker", "compose", "--project-directory", str(checkout), "--env-file", str(checkout / ".env.dev"),
|
|
"-f", str(checkout / "docker-compose.dev.yml"), "-f", str(ROOT / "dev/local-workers.override.yml")]
|
|
config = json.loads(capture([*compose, "config", "--format", "json"], environment))
|
|
assert config["name"] == "jobjakt-dev", "Only the local development project is permitted"
|
|
backend = config["services"]["backend"]
|
|
sidecar = config["services"]["ai-service"]
|
|
settings = backend["environment"]
|
|
assert settings["ASPNETCORE_ENVIRONMENT"] == "Development"
|
|
connection = settings["ConnectionStrings__JobTracker"].lower()
|
|
assert "server=mariadb;" in connection and "database=jobtracker_dev;" in connection
|
|
assert settings["Ai__ExternalProcessingEnabled"].lower() == "false"
|
|
assert settings["Email__SmtpHost"] == "mailpit" and settings["Email__SmtpPort"] == "1025"
|
|
assert not settings["Email__SmtpUser"] and not settings["Email__SmtpPassword"]
|
|
assert all(port.get("host_ip") == "127.0.0.1" for port in backend.get("ports", []))
|
|
assert sidecar["environment"]["HF_HUB_OFFLINE"] == "1"
|
|
assert sidecar["environment"]["TRANSFORMERS_OFFLINE"] == "1"
|
|
assert sidecar["environment"]["EXTERNAL_AI_ENABLED"].lower() == "false"
|
|
assert sidecar["environment"]["OLLAMA_BASE_URL"] == "http://jobjakt-dev-ollama:11434"
|
|
assert any(volume.get("source") == str(artifact) and volume.get("read_only") for volume in sidecar["volumes"])
|
|
assert json.loads(capture(["docker", "image", "inspect", sidecar["image"]], environment))[0]["Id"] == SIDECAR
|
|
current = json.loads(capture(["docker", "inspect", "jobjakt-dev-backend-1"], environment))[0]
|
|
assert current["Config"]["Labels"]["com.docker.compose.project"] == "jobjakt-dev"
|
|
assert json.loads(capture(["docker", "image", "inspect", backend["image"]], environment))[0]["Id"] == current["Image"], "This operation changes worker configuration, not backend code"
|
|
record = {"project": config["name"], "verifiedBartRevision": manifest["sourceRevision"], "sidecarImage": SIDECAR,
|
|
"enabledWorkers": {key: value for key, value in settings.items() if key.startswith("Workers__")},
|
|
"emailSink": "Mailpit", "externalAI": False, "applied": False}
|
|
args.output.parent.mkdir(parents=True, exist_ok=True)
|
|
if args.apply:
|
|
with args.output.with_suffix(".log").open("w", encoding="utf-8") as log:
|
|
result = subprocess.run(["rtk", "proxy", *compose, "up", "-d", "--no-deps", "--no-build", "--pull", "never",
|
|
"--wait", "--wait-timeout", "120", "backend", "ai-service"], env=environment, stdout=log, stderr=subprocess.STDOUT)
|
|
record["exitCode"] = result.returncode
|
|
record["applied"] = result.returncode == 0
|
|
args.output.write_text(json.dumps(record, indent=2) + "\n", encoding="utf-8")
|
|
print(json.dumps(record))
|
|
if args.apply:
|
|
raise SystemExit(record["exitCode"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|