kopia lustrzana https://github.com/jupyterhub/repo2docker
Add registry optional credentials to push()
rodzic
1e61d4f1ae
commit
5e8ee1ca7d
|
@ -120,6 +120,8 @@ class DockerEngine(ContainerEngine):
|
||||||
return Image(tags=image["RepoTags"], config=image["ContainerConfig"])
|
return Image(tags=image["RepoTags"], config=image["ContainerConfig"])
|
||||||
|
|
||||||
def push(self, image_spec):
|
def push(self, image_spec):
|
||||||
|
if self.registry_credentials:
|
||||||
|
self._apiclient.login(**self.registry_credentials)
|
||||||
return self._apiclient.push(image_spec, stream=True)
|
return self._apiclient.push(image_spec, stream=True)
|
||||||
|
|
||||||
def run(
|
def run(
|
||||||
|
|
|
@ -2,8 +2,11 @@
|
||||||
Interface for a repo2docker container engine
|
Interface for a repo2docker container engine
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
from traitlets import Dict, default
|
||||||
from traitlets.config import LoggingConfigurable
|
from traitlets.config import LoggingConfigurable
|
||||||
|
|
||||||
# Based on https://docker-py.readthedocs.io/en/4.2.0/containers.html
|
# Based on https://docker-py.readthedocs.io/en/4.2.0/containers.html
|
||||||
|
@ -142,6 +145,37 @@ class ContainerEngine(LoggingConfigurable):
|
||||||
Initialised with a reference to the parent so can also be configured using traitlets.
|
Initialised with a reference to the parent so can also be configured using traitlets.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
registry_credentials = Dict(
|
||||||
|
help="""
|
||||||
|
Credentials dictionary, if set will be used to authenticate with
|
||||||
|
the registry. Typically this will include the keys:
|
||||||
|
|
||||||
|
- `username`: The registry username
|
||||||
|
- `password`: The registry password or token
|
||||||
|
- `registry`: The registry URL
|
||||||
|
|
||||||
|
This can also be set by passing a JSON object in the
|
||||||
|
CONTAINER_ENGINE_REGISTRY_CREDENTIALS environment variable.
|
||||||
|
""",
|
||||||
|
config=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
@default("registry_credentials")
|
||||||
|
def _registry_credentials_default(self):
|
||||||
|
"""
|
||||||
|
Set the registry credentials from CONTAINER_ENGINE_REGISTRY_CREDENTIALS
|
||||||
|
"""
|
||||||
|
obj = os.getenv("CONTAINER_ENGINE_REGISTRY_CREDENTIALS")
|
||||||
|
if obj:
|
||||||
|
try:
|
||||||
|
return json.loads(obj)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
self.log.error(
|
||||||
|
"CONTAINER_ENGINE_REGISTRY_CREDENTIALS is not valid JSON"
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
return {}
|
||||||
|
|
||||||
string_output = True
|
string_output = True
|
||||||
"""
|
"""
|
||||||
Whether progress events should be strings or an object.
|
Whether progress events should be strings or an object.
|
||||||
|
@ -251,6 +285,9 @@ class ContainerEngine(LoggingConfigurable):
|
||||||
"""
|
"""
|
||||||
Push image to a registry
|
Push image to a registry
|
||||||
|
|
||||||
|
If the registry_credentials traitlets is set it should be used to
|
||||||
|
authenticate with the registry before pushing.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
image_spec : str
|
image_spec : str
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from subprocess import check_output
|
from subprocess import check_output
|
||||||
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
|
from repo2docker.docker import DockerEngine
|
||||||
|
|
||||||
repo_root = os.path.abspath(
|
repo_root = os.path.abspath(
|
||||||
os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
|
os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
|
||||||
|
@ -19,3 +22,43 @@ def test_git_credential_env():
|
||||||
.strip()
|
.strip()
|
||||||
)
|
)
|
||||||
assert out == credential_env
|
assert out == credential_env
|
||||||
|
|
||||||
|
|
||||||
|
class MockDockerEngine(DockerEngine):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self._apiclient = Mock()
|
||||||
|
|
||||||
|
|
||||||
|
def test_docker_push_no_credentials():
|
||||||
|
engine = MockDockerEngine()
|
||||||
|
|
||||||
|
engine.push("image")
|
||||||
|
|
||||||
|
assert len(engine._apiclient.method_calls) == 1
|
||||||
|
engine._apiclient.push.assert_called_once_with("image", stream=True)
|
||||||
|
|
||||||
|
|
||||||
|
def test_docker_push_dict_credentials():
|
||||||
|
engine = MockDockerEngine()
|
||||||
|
engine.registry_credentials = {"username": "abc", "password": "def"}
|
||||||
|
|
||||||
|
engine.push("image")
|
||||||
|
|
||||||
|
assert len(engine._apiclient.method_calls) == 2
|
||||||
|
engine._apiclient.login.assert_called_once_with(username="abc", password="def")
|
||||||
|
engine._apiclient.push.assert_called_once_with("image", stream=True)
|
||||||
|
|
||||||
|
|
||||||
|
def test_docker_push_env_credentials():
|
||||||
|
engine = MockDockerEngine()
|
||||||
|
with patch.dict(
|
||||||
|
"os.environ",
|
||||||
|
{
|
||||||
|
"CONTAINER_ENGINE_REGISTRY_CREDENTIALS": '{"username": "abc", "password": "def"}'
|
||||||
|
},
|
||||||
|
):
|
||||||
|
engine.push("image")
|
||||||
|
|
||||||
|
assert len(engine._apiclient.method_calls) == 2
|
||||||
|
engine._apiclient.login.assert_called_once_with(username="abc", password="def")
|
||||||
|
engine._apiclient.push.assert_called_once_with("image", stream=True)
|
||||||
|
|
Ładowanie…
Reference in New Issue