Source code for dml_util.lib.dkr

#!/usr/bin/env python3
import base64
import re
from dataclasses import dataclass, field
from tempfile import NamedTemporaryFile, TemporaryDirectory
from typing import TYPE_CHECKING
from urllib.parse import urlparse
from uuid import uuid4

from dml_util.aws import get_client
from dml_util.core.daggerml import Node, Resource
from dml_util.core.utils import _run_cli

if TYPE_CHECKING:
    import boto3  # noqa: F401


[docs] @dataclass class Ecr: ecr: "boto3.client" = field(default_factory=lambda: get_client("ecr")) s3: "boto3.client" = field(default_factory=lambda: get_client("s3")) @staticmethod def _cli(*args, **kwargs): return _run_cli(*args, capture_output=False, **kwargs)
[docs] def build(self, tarball, build_flags=(), repo=None): p = urlparse(tarball.uri) with TemporaryDirectory() as tmpd: with NamedTemporaryFile(suffix=".tar") as tmpf: self.s3.download_file(p.netloc, p.path[1:], tmpf.name) self._cli(["tar", "-xvf", tmpf.name, "-C", tmpd]) _tag = uuid4().hex local_image = f"dml:{_tag}" self._cli( ["docker", "build", *build_flags, "-t", local_image, tmpd], ) if repo: if isinstance(repo, Node): repo = repo.value() if isinstance(repo, Resource): repo = repo.uri return self.push(local_image, repo) return {"image": Resource(local_image), "tag": _tag}
def _login(self, proxy_endpoint, password): return self._cli( [ "docker", "login", "--username", "AWS", "--password-stdin", proxy_endpoint, ], input=password, )
[docs] def login(self): auth_response = self.ecr.get_authorization_token() auth_data = auth_response["authorizationData"][0] auth_token = auth_data["authorizationToken"] proxy_endpoint = auth_data["proxyEndpoint"] decoded_token = base64.b64decode(auth_token).decode("utf-8") username, password = decoded_token.split(":") return self._login(proxy_endpoint[8:], password)
def _tag(self, local_image, remote_image): self._cli(["docker", "tag", local_image, remote_image]) def _push(self, remote_image): self._cli(["docker", "push", remote_image])
[docs] def push(self, local_image, repo_uri): tag = local_image.split(":")[-1] remote_image = f"{repo_uri}:{tag}" self.login() self._tag(local_image, remote_image) self._push(remote_image) (repo_name,) = re.match(r"^[^/]+/([^:]+)$", repo_uri).groups() response = self.ecr.describe_images(repositoryName=repo_name, imageIds=[{"imageTag": tag}]) digest = response["imageDetails"][0]["imageDigest"] return { "image": Resource(f"{repo_uri}:{tag}@{digest}"), "tag": tag, "digest": digest, }