Skip to content

Commit

Permalink
Add pull through cache registry
Browse files Browse the repository at this point in the history
  • Loading branch information
berkayoz committed Nov 14, 2024
1 parent aa8b78f commit 5bdf803
Show file tree
Hide file tree
Showing 6 changed files with 234 additions and 0 deletions.
2 changes: 2 additions & 0 deletions tests/integration/templates/registry/hosts.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[host."http://$IP:$PORT"]
capabilities = ["pull", "resolve"]
20 changes: 20 additions & 0 deletions tests/integration/templates/registry/registry-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: 0.1
log:
fields:
service: registry
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry/$NAME
http:
addr: :$PORT
headers:
X-Content-Type-Options: [nosniff]
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
proxy:
remoteurl: $REMOTE
15 changes: 15 additions & 0 deletions tests/integration/templates/registry/registry.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[Unit]
Description=registry-$NAME
Documentation=https://github.com/distribution/distribution

[Service]
Type=simple
Restart=always
RestartSec=5s
LimitNOFILE=40000
TimeoutStartSec=0

ExecStart=/bin/registry serve /etc/distribution/$NAME.yaml

[Install]
WantedBy=multi-user.target
27 changes: 27 additions & 0 deletions tests/integration/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
#
import itertools
import logging
from string import Template
from pathlib import Path
from typing import Generator, Iterator, List, Optional, Union

import pytest
from test_util import config, harness, util
from test_util.etcd import EtcdCluster
from test_util.registry import Registry

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -79,6 +81,11 @@ def h() -> harness.Harness:
_harness_clean(h)


@pytest.fixture(scope="session")
def registry(h: harness.Harness) -> Registry:
yield Registry(h)


def pytest_configure(config):
config.addinivalue_line(
"markers",
Expand Down Expand Up @@ -141,6 +148,7 @@ def network_type(request) -> Union[str, None]:
@pytest.fixture(scope="function")
def instances(
h: harness.Harness,
registry: Registry,
node_count: int,
tmp_path: Path,
disable_k8s_bootstrapping: bool,
Expand All @@ -166,6 +174,25 @@ def instances(
if not no_setup:
util.setup_k8s_snap(instance, tmp_path, snap)

for mirror in registry.mirrors:

substitutes = {
"IP": registry.ip,
"PORT": mirror.port,
}

instance.exec(["mkdir", "-p", f"/etc/containerd/hosts.d/{mirror.name}"])

with open(config.REGISTRY_DIR / "hosts.toml", "r") as registry_template:
src = Template(registry_template.read())
instance.exec(
[
"dd",
f"of=/etc/containerd/hosts.d/{mirror.name}/hosts.toml",
],
input=str.encode(src.substitute(substitutes)),
)

if not disable_k8s_bootstrapping and not no_setup:
first_node, *_ = instances

Expand Down
12 changes: 12 additions & 0 deletions tests/integration/tests/test_util/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@
# ETCD_VERSION is the version of etcd to use.
ETCD_VERSION = os.getenv("ETCD_VERSION") or "v3.4.34"

# REGISTRY_DIR contains all templates required to setup an registry mirror.
REGISTRY_DIR = MANIFESTS_DIR / "registry"

# REGISTRY_URL is the url from which the registry binary should be downloaded.
REGISTRY_URL = (
os.getenv("REGISTRY_URL")
or "https://github.com/distribution/distribution/releases/download"
)

# REGISTRY_VERSION is the version of registry to use.
REGISTRY_VERSION = os.getenv("REGISTRY_VERSION") or "v2.8.3"

# FLAVOR is the flavor of the snap to use.
FLAVOR = os.getenv("TEST_FLAVOR") or ""

Expand Down
158 changes: 158 additions & 0 deletions tests/integration/tests/test_util/registry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#
# Copyright 2024 Canonical, Ltd.
#
import logging
from string import Template
from typing import List

from test_util import config
from test_util.harness import Harness, Instance
from test_util.util import get_default_ip

LOG = logging.getLogger(__name__)


class Mirror:
def __init__(self, name: str, port: int, remote: str):
"""
Initialize the Mirror object.
Args:
name (str): The name of the mirror.
port (int): The port of the mirror.
remote (str): The remote URL of the upstream registry.
"""
self._name = name
self._port = port
self._remote = remote

@property
def name(self) -> str:
"""
Get the name of the mirror.
Returns:
str: The name of the mirror.
"""
return self._name

@property
def port(self) -> int:
"""
Get the port of the mirror.
Returns:
int: The port of the mirror.
"""
return self._port

@property
def remote(self) -> str:
"""
Get the remote URL of the upstream registry.
Returns:
str: The remote URL of the upstream registry.
"""
return self._remote


class Registry:

def __init__(self, h: Harness):
"""
Initialize the Registry object.
Args:
h (Harness): The test harness object.
"""
self.registry_url = config.REGISTRY_URL
self.registry_version = config.REGISTRY_VERSION
self.instance: Instance = None
self.harness: Harness = h
self._mirrors: List[Mirror] = [
Mirror("ghcr.io", 5000, "https://ghcr.io"),
Mirror("docker.io", 5001, "https://registry-1.docker.io"),
]
self.instance = self.harness.new_instance()

arch = self.instance.arch
self.instance.exec(
[
"curl",
"-L",
f"{self.registry_url}/{self.registry_version}/registry_{self.registry_version[1:]}_linux_{arch}.tar.gz",
"-o",
f"/tmp/registry_{self.registry_version}_linux_{arch}.tar.gz",
]
)

self.instance.exec(
[
"tar",
"xzvf",
f"/tmp/registry_{self.registry_version}_linux_{arch}.tar.gz",
"-C",
"/bin/",
"registry",
],
)

self._ip = get_default_ip(self.instance)

self.add_mirrors()

def add_mirrors(self):
for mirror in self._mirrors:
self.add_mirror(mirror)

def add_mirror(self, mirror: Mirror):

substitutes = {
"NAME": mirror.name,
"PORT": mirror.port,
"REMOTE": mirror.remote,
}

self.instance.exec(["mkdir", "-p", "/etc/distribution"])
self.instance.exec(["mkdir", "-p", f"/var/lib/registry/{mirror.name}"])

with open(
config.REGISTRY_DIR / "registry-config.yaml", "r"
) as registry_template:
src = Template(registry_template.read())
self.instance.exec(
["dd", f"of=/etc/distribution/{mirror.name}.yaml"],
input=str.encode(src.substitute(substitutes)),
)

with open(config.REGISTRY_DIR / "registry.service", "r") as registry_template:
src = Template(registry_template.read())
self.instance.exec(
["dd", f"of=/etc/systemd/system/registry-{mirror.name}.service"],
input=str.encode(src.substitute(substitutes)),
)

self.instance.exec(["systemctl", "daemon-reload"])
self.instance.exec(["systemctl", "enable", f"registry-{mirror.name}.service"])
self.instance.exec(["systemctl", "start", f"registry-{mirror.name}.service"])

@property
def mirrors(self) -> List[Mirror]:
"""
Get the list of mirrors in the registry.
Returns:
List[Mirror]: The list of mirrors.
"""
return self._mirrors

@property
def ip(self) -> str:
"""
Get the IP address of the registry.
Returns:
str: The IP address of the registry.
"""
return self._ip

0 comments on commit 5bdf803

Please sign in to comment.