#!/usr/bin/env python3 """ACDL Phase 15 — push the consumer microservice Docker image to ECR. Steps performed by this script: 1. Load AWS creds from /root/acdl/.env.secrets (ACDL_AWS_ACCESS_KEY_ID, ACDL_AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION). 2. Create the ECR repo `acdl-microservice` if it doesn't exist (ecr:DescribeRepositories / ecr:CreateRepository). Region: us-east-1. 3. Get the ECR login password (ecr:GetAuthorizationToken) and run `docker login` with it. After this script runs, it prints the docker `tag` and `push` commands for the caller to run in the shell (steps 4-5 of T-15.1). Usage: python3 scripts/push_consumer_image.py Constraints (T-15.1): the `aws` CLI is NOT installed — boto3 is used for every AWS API call. `docker` is invoked via subprocess for the login (since docker is the only thing that can use the auth token meaningfully). """ import os import sys import subprocess import pathlib import boto3 REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent ENV_FILE = REPO_ROOT / ".env.secrets" AWS_ACCOUNT_ID = "581513795199" AWS_REGION = "us-east-1" ECR_REPO_NAME = "acdl-microservice" IMAGE_TAG = "latest" def _load_env(path): """Load ACDL_AWS_* + AWS_DEFAULT_REGION from a flat KEY=VALUE file.""" creds = {} with open(path, "r") as fh: for line in fh: line = line.strip() if not line or line.startswith("#") or "=" not in line: continue k, v = line.split("=", 1) creds[k.strip()] = v.strip() return creds def main(): if not ENV_FILE.exists(): print(f"FAIL: {ENV_FILE} not found", file=sys.stderr) return 2 creds = _load_env(ENV_FILE) access_key = creds.get("ACDL_AWS_ACCESS_KEY_ID") secret_key = creds.get("ACDL_AWS_SECRET_ACCESS_KEY") region = creds.get("AWS_DEFAULT_REGION", AWS_REGION) if not access_key or not secret_key: print("FAIL: ACDL_AWS_ACCESS_KEY_ID / ACDL_AWS_SECRET_ACCESS_KEY missing", file=sys.stderr) return 2 # Export the creds for the docker subprocess (it doesn't need them, but # keeps parity with the terraform step that runs after this). os.environ["AWS_ACCESS_KEY_ID"] = access_key os.environ["AWS_SECRET_ACCESS_KEY"] = secret_key os.environ["AWS_DEFAULT_REGION"] = region session = boto3.Session( aws_access_key_id=access_key, aws_secret_access_key=secret_key, region_name=region, ) ecr = session.client("ecr") # Step 2: create the ECR repo if it doesn't exist. repo_uri = None try: resp = ecr.describe_repositories(repositoryNames=[ECR_REPO_NAME]) repo = resp["repositories"][0] repo_uri = repo["repositoryUri"] print(f"ecr: repository {ECR_REPO_NAME!r} already exists -> {repo_uri}") except ecr.exceptions.RepositoryNotFoundException: print(f"ecr: repository {ECR_REPO_NAME!r} not found, creating...") resp = ecr.create_repository(repositoryName=ECR_REPO_NAME) repo = resp["repository"] repo_uri = repo["repositoryUri"] print(f"ecr: created repository {ECR_REPO_NAME!r} -> {repo_uri}") except Exception as exc: print(f"FAIL: ecr describe/create failed: {exc}", file=sys.stderr) return 1 # Step 3: get login password + run `docker login`. auth = ecr.get_authorization_token() token = auth["authorizationData"][0]["authorizationToken"] # The token is base64(USERNAME:PASSWORD); docker login wants them split. import base64 user_pw = base64.b64decode(token).decode("utf-8") username, password = user_pw.split(":", 1) registry = f"{AWS_ACCOUNT_ID}.dkr.ecr.{region}.amazonaws.com" print(f"docker: logging in to {registry} ...") login_cmd = [ "docker", "login", "--username", username, "--password-stdin", registry, ] proc = subprocess.run(login_cmd, input=password.encode("utf-8"), capture_output=True) if proc.returncode != 0: print("FAIL: docker login failed:", file=sys.stderr) sys.stderr.write(proc.stderr.decode("utf-8", "replace")) return 1 print("docker: login OK") # Steps 4-5: print the tag + push commands for the caller to run. full_tag = f"{repo_uri}:{IMAGE_TAG}" print("") print("=== NEXT: run these commands in the shell to tag + push ===") print(f"docker tag acdl-microservice:latest {full_tag}") print(f"docker push {full_tag}") print("") print(f"ECR_IMAGE={full_tag}") return 0 if __name__ == "__main__": sys.exit(main())