Skip to content

Commit

Permalink
skopeo end-to-end scenario (#2)
Browse files Browse the repository at this point in the history
Signed-off-by: tarilabs <[email protected]>
  • Loading branch information
tarilabs authored Dec 18, 2024
1 parent eeae8c6 commit 026c3b2
Show file tree
Hide file tree
Showing 7 changed files with 346 additions and 5 deletions.
9 changes: 8 additions & 1 deletion .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

jobs:
e2e-skopeo:
name: E2E using CNCF Distribution Registry
name: E2E using Skopeo
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
Expand All @@ -27,6 +27,13 @@ jobs:
- name: Install dependencies
run: |
make install
- name: Start Kind Cluster
uses: helm/kind-action@v1
with:
cluster_name: kind
- name: Start distribution-registry
run: |
./e2e/deploy_distribution_registry.sh
- name: Run E2E tests
run: |
make test-e2e-skopeo
17 changes: 17 additions & 0 deletions e2e/deploy_distribution_registry.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash

SCRIPT_DIR="$(dirname "$(realpath "$BASH_SOURCE")")"
set -e

kubectl apply -f "${SCRIPT_DIR}/distribution-registry/"

echo "Waiting for Deployment..."
kubectl wait --for=condition=available deployment/distribution-registry-test-deployment --timeout=5m
kubectl logs deployment/distribution-registry-test-deployment
echo "Deployment looks ready."

echo "Starting port-forward..."
kubectl port-forward service/distribution-registry-test-service 5001:5001 &
PID=$!
sleep 2
echo "I have launched port-forward in background with: $PID."
59 changes: 59 additions & 0 deletions e2e/distribution-registry/distribution-registry.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: distribution-registry-test-deployment
labels:
app: distribution-registry-test
spec:
replicas: 1
selector:
matchLabels:
app: distribution-registry-test
template:
metadata:
labels:
app: distribution-registry-test
spec:
containers:
- name: distribution-registry-test
image: docker.io/library/registry:2
args:
- /etc/docker/registry/config.yml
env:
- name: REGISTRY_HTTP_ADDR
value: 0.0.0.0:5001
ports:
- containerPort: 5001
volumeMounts:
- mountPath: /var/lib/registry
name: distribution-registry-storage
volumes:
- name: distribution-registry-storage
persistentVolumeClaim:
claimName: distribution-registry-pvc
---
apiVersion: v1
kind: Service
metadata:
name: distribution-registry-test-service
labels:
app: distribution-registry-test
spec:
selector:
app: distribution-registry-test
ports:
- protocol: TCP
port: 5001
targetPort: 5001
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: distribution-registry-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
7 changes: 7 additions & 0 deletions olot/backend/skopeo.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@
def is_skopeo() -> bool :
return shutil.which("skopeo") is not None


def skopeo_pull(base_image: str, dest: typing.Union[str, os.PathLike]):
if isinstance(dest, os.PathLike):
dest = str(dest)
return subprocess.run(["skopeo", "copy", "--multi-arch", "all", "docker://"+base_image, "oci:"+dest+":latest"], check=True)


def skopeo_push(src: typing.Union[str, os.PathLike], oci_ref: str):
if isinstance(src, os.PathLike):
src = str(src)
return subprocess.run(["skopeo", "copy", "--multi-arch", "all", "--dest-tls-verify=false", "--dest-no-creds", "oci:"+src+":latest", "docker://"+oci_ref], check=True)
214 changes: 213 additions & 1 deletion poetry.lock

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,32 @@ description = "oci layers on top"
authors = ["tarilabs <[email protected]>"]
readme = "README.md"


[tool.poetry.dependencies]
python = "^3.9"
click = "^8.1.7"
pydantic = "^2.10.3"


[tool.poetry.scripts]
olot = "olot.cli:cli"


[tool.poetry.group.test.dependencies]
pytest = "^8.3.4"


[tool.pytest.ini_options]
markers = [
"e2e_skopeo: end-to-end testing with skopeo",
]


[tool.poetry.group.dev.dependencies]
datamodel-code-generator = "^0.26.3"
ruff = "^0.6.1"
mypy = "^1.11.1"
docker = "^7.1.0"


[build-system]
Expand Down
40 changes: 37 additions & 3 deletions tests/backend/test_skopeo.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@

import os
import subprocess
import docker # type: ignore
from pathlib import Path
import pytest
from olot.backend.skopeo import is_skopeo, skopeo_pull
from olot.basics import check_ocilayout, read_ocilayout_root_index
from olot.backend.skopeo import is_skopeo, skopeo_pull, skopeo_push
from olot.basics import check_ocilayout, oci_layers_on_top, read_ocilayout_root_index

@pytest.mark.e2e_skopeo
def test_is_skopeo():
Expand All @@ -24,3 +27,34 @@ def test_skopeo_pull(tmp_path):
assert manifest0.digest == "sha256:d437889e826ecce2116ac711469bd09b1bb3c64d45055cbf23a6f8f3db223b8b"
assert manifest0.size == 491


@pytest.mark.e2e_skopeo
def test_skopeo_scenario(tmp_path):
"""Test skopeo with an end-to-end scenario
"""
skopeo_pull("quay.io/mmortari/hello-world-wait", tmp_path)
model_joblib = Path(__file__).parent / ".." / "data" / "model.joblib"
model_files = [
model_joblib,
Path(__file__).parent / ".." / "data" / "hello.md",
]
oci_layers_on_top(tmp_path, model_files)
skopeo_push(tmp_path, "localhost:5001/nstestorg/modelcar")

# show what has been copied in Container Registry
subprocess.run(["skopeo","list-tags","--tls-verify=false","docker://localhost:5001/nstestorg/modelcar"], check=True)

# copy from Container Registry to Docker daemon for local running the modelcar as-is
result = subprocess.run("skopeo inspect --tls-verify=false --raw docker://localhost:5001/nstestorg/modelcar | jq -r '.manifests[] | select(.platform.architecture == \"amd64\") | .digest'", shell=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
assert result.returncode == 0
digest = result.stdout.strip()
print(digest)
# use by convention the linux/amd64
subprocess.run(["skopeo", "copy", "--src-tls-verify=false", f"docker://localhost:5001/nstestorg/modelcar@{digest}", "docker-daemon:localhost:5001/nstestorg/modelcar:latest"], check=True)
client = docker.from_env()
container = client.containers.run("localhost:5001/nstestorg/modelcar", detach=True)
print(container.logs())
_, stat = container.get_archive('/models/model.joblib')
print(str(stat["size"]))
# assert the model.joblib from the KServe modelcar is in expected location (above) and expected size
assert stat["size"] == os.stat(model_joblib).st_size

0 comments on commit 026c3b2

Please sign in to comment.