Skip to content

Commit

Permalink
Use CLI to push docker image
Browse files Browse the repository at this point in the history
Preserves existing authentication information handling behavior:

1. If registry_credentials are present, they are used but not leaked
   on to existing ~/.docker/config
2. If registry_credentials are not present, they are not used
3. Regardless of registry_credentials being present, we still will use
   existing authentication info in DOCKER_CONFIG
  • Loading branch information
yuvipanda committed Feb 26, 2025
1 parent 17a23c4 commit ac0def4
Showing 1 changed file with 41 additions and 11 deletions.
52 changes: 41 additions & 11 deletions repo2docker/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
Docker container engine for repo2docker
"""

import os
import shutil
import subprocess
import tarfile
import tempfile
from contextlib import contextmanager
from pathlib import Path

from iso8601 import parse_date
from traitlets import Dict, List, Unicode
Expand Down Expand Up @@ -58,7 +62,7 @@ class DockerEngine(ContainerEngine):
https://docker-py.readthedocs.io/en/4.2.0/api.html#module-docker.api.build
"""

string_output = False
string_output = True

extra_init_args = Dict(
{},
Expand Down Expand Up @@ -141,18 +145,12 @@ def build(

args += [d]

for line in execute_cmd(args, True):
# Simulate structured JSON output from buildx build, since we
# do get structured json output from pushing and running
yield {"stream": line}
yield from execute_cmd(args, True)
else:
# Assume 'path' is passed in
args += [path]

for line in execute_cmd(args, True):
# Simulate structured JSON output from buildx build, since we
# do get structured json output from pushing and running
yield {"stream": line}
yield from execute_cmd(args, True)

def images(self):
images = self._apiclient.images()
Expand All @@ -162,10 +160,42 @@ def inspect_image(self, image):
image = self._apiclient.inspect_image(image)
return Image(tags=image["RepoTags"], config=image["Config"])

@contextmanager
def docker_login(self, username, password, registry):
# Determine existing DOCKER_CONFIG
dc_path = Path(
os.environ.get("DOCKER_CONFIG", os.path.expanduser("~/.docker/config.json"))
)

with tempfile.TemporaryDirectory() as d:
new_dc_path = Path(d) / "config.json"
if dc_path.exists():
# If there is an existing DOCKER_CONFIG, copy it to new location so we inherit
# whatever configuration the user has already set
shutil.copy2(dc_path, new_dc_path)

env = os.environ.copy()
subprocess.check_call(
# FIXME: This should be using --password-stdin instead
[
"docker",
"login",
"--username",
username,
"--password",
password,
registry,
],
env=env,
)
yield

def push(self, image_spec):
if self.registry_credentials:
self._apiclient.login(**self.registry_credentials)
return self._apiclient.push(image_spec, stream=True)
with self.docker_login(**self.registry_credentials):
yield from execute_cmd(["docker", "push", image_spec], capture=True)
else:
yield from execute_cmd(["docker", "push", image_spec], capture=True)

def run(
self,
Expand Down

0 comments on commit ac0def4

Please sign in to comment.