kopia lustrzana https://github.com/jupyterhub/repo2docker
Add a docker registry integration test with real registry
rodzic
364a18932c
commit
82e049fcec
|
@ -65,6 +65,7 @@ jobs:
|
|||
- unit
|
||||
- venv
|
||||
- contentproviders
|
||||
- registry
|
||||
# Playwright test
|
||||
- ui
|
||||
include:
|
||||
|
@ -73,22 +74,9 @@ jobs:
|
|||
python_version: "3.9"
|
||||
repo_type: venv
|
||||
|
||||
services:
|
||||
# So that we can test this in PRs/branches
|
||||
local-registry:
|
||||
image: registry:2
|
||||
ports:
|
||||
- 5000:5000
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
# Allows pushing to registry on localhost:5000
|
||||
driver-opts: network=host
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "${{ matrix.python_version }}"
|
||||
|
|
|
@ -37,7 +37,7 @@ from .buildpacks import (
|
|||
RBuildPack,
|
||||
)
|
||||
from .engine import BuildError, ContainerEngineException, ImageLoadError
|
||||
from .utils import ByteSpecification, R2dState, chdir, get_platform
|
||||
from .utils import ByteSpecification, R2dState, chdir, get_platform, get_free_port
|
||||
|
||||
|
||||
class Repo2Docker(Application):
|
||||
|
@ -660,7 +660,7 @@ class Repo2Docker(Application):
|
|||
container_port = int(container_port_proto.split("/", 1)[0])
|
||||
else:
|
||||
# no port specified, pick a random one
|
||||
container_port = host_port = str(self._get_free_port())
|
||||
container_port = host_port = str(get_free_port())
|
||||
self.ports = {f"{container_port}/tcp": host_port}
|
||||
self.port = host_port
|
||||
# To use the option --NotebookApp.custom_display_url
|
||||
|
@ -744,17 +744,6 @@ class Repo2Docker(Application):
|
|||
if exit_code:
|
||||
sys.exit(exit_code)
|
||||
|
||||
def _get_free_port(self):
|
||||
"""
|
||||
Hacky method to get a free random port on local host
|
||||
"""
|
||||
import socket
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind(("", 0))
|
||||
port = s.getsockname()[1]
|
||||
s.close()
|
||||
return port
|
||||
|
||||
def find_image(self):
|
||||
# if this is a dry run it is Ok for dockerd to be unreachable so we
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import os
|
||||
import socket
|
||||
import platform
|
||||
import re
|
||||
import subprocess
|
||||
|
@ -545,3 +546,14 @@ def get_platform():
|
|||
else:
|
||||
warnings.warn(f"Unexpected platform '{m}', defaulting to linux/amd64")
|
||||
return "linux/amd64"
|
||||
|
||||
|
||||
def get_free_port():
|
||||
"""
|
||||
Hacky method to get a free random port on local host
|
||||
"""
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind(("", 0))
|
||||
port = s.getsockname()[1]
|
||||
s.close()
|
||||
return port
|
|
@ -0,0 +1,2 @@
|
|||
# Smallest possible dockerfile, used only for building images to be tested
|
||||
FROM scratch
|
|
@ -0,0 +1,50 @@
|
|||
from pathlib import Path
|
||||
import subprocess
|
||||
import pytest
|
||||
from repo2docker.__main__ import make_r2d
|
||||
from repo2docker.utils import get_free_port
|
||||
import time
|
||||
import requests
|
||||
import secrets
|
||||
|
||||
HERE = Path(__file__).parent
|
||||
|
||||
@pytest.fixture
|
||||
def registry():
|
||||
port = get_free_port()
|
||||
cmd = [
|
||||
"docker", "run", "-it", "-p", f"{port}:5000", "registry:3.0.0-rc.3"
|
||||
]
|
||||
proc = subprocess.Popen(cmd)
|
||||
health_url = f'http://localhost:{port}/v2'
|
||||
# Wait for the registry to actually come up
|
||||
for i in range(10):
|
||||
try:
|
||||
resp = requests.get(health_url)
|
||||
if resp.status_code in (401, 200):
|
||||
break
|
||||
except requests.ConnectionError:
|
||||
# The service is not up yet
|
||||
pass
|
||||
time.sleep(i)
|
||||
else:
|
||||
raise TimeoutError("Test registry did not come up in time")
|
||||
|
||||
try:
|
||||
yield f"localhost:{port}"
|
||||
finally:
|
||||
proc.terminate()
|
||||
proc.wait()
|
||||
|
||||
|
||||
def test_registry(registry):
|
||||
image_name = f"{registry}/{secrets.token_hex(8)}:latest"
|
||||
r2d = make_r2d([
|
||||
"--image", image_name,
|
||||
"--push", "--no-run", str(HERE)
|
||||
])
|
||||
|
||||
r2d.start()
|
||||
|
||||
proc = subprocess.run(["docker", "manifest", "inspect", "--insecure", image_name])
|
||||
assert proc.returncode == 0
|
|
@ -22,43 +22,3 @@ def test_git_credential_env():
|
|||
.strip()
|
||||
)
|
||||
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