Skip to content

Commit e9082dd

Browse files
committed
e2e: use port-forward instead of hostPort for registry access
Replace the localhost:30000 hostPort-based registry access with Kubernetes port-forwarding. This makes the test runner work regardless of the cluster network topology (not just kind with extraPortMappings). - Remove port 30000 extraPortMappings from kind configs - Add PortForward() to the registry package using SPDY - Use port-forward in e2e steps and extension-developer-e2e - Remove LOCAL_REGISTRY_HOST env var (no longer needed) - Keep NodePort service for containerd on kind nodes (hosts.toml)
1 parent 6e5ecac commit e9082dd

File tree

9 files changed

+78
-61
lines changed

9 files changed

+78
-61
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ require (
9090
github.com/containerd/typeurl/v2 v2.2.3 // indirect
9191
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect
9292
github.com/containers/ocicrypt v1.2.1 // indirect
93+
github.com/creack/pty v1.1.24 // indirect
9394
github.com/cucumber/gherkin/go/v26 v26.2.0 // indirect
9495
github.com/cucumber/messages/go/v21 v21.0.1 // indirect
9596
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5z
8989
github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU=
9090
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
9191
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
92-
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
93-
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
92+
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
93+
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
9494
github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI=
9595
github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0=
9696
github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI=

hack/kind-config/containerd/certs.d/docker-registry.operator-controller-e2e.svc.cluster.local:5000/hosts.toml

Lines changed: 0 additions & 3 deletions
This file was deleted.

hack/kind-config/containerd/certs.d/go.mod

Lines changed: 0 additions & 5 deletions
This file was deleted.

kind-config/kind-config-2node.yaml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ nodes:
2020
kubeletExtraArgs:
2121
node-labels: "ingress-ready=true"
2222
taints: []
23-
extraMounts:
24-
- hostPath: ./hack/kind-config/containerd/certs.d
25-
containerPath: /etc/containerd/certs.d
2623
- role: control-plane
2724
kubeadmConfigPatches:
2825
- |
@@ -31,10 +28,3 @@ nodes:
3128
kubeletExtraArgs:
3229
node-labels: "ingress-ready=true"
3330
taints: []
34-
extraMounts:
35-
- hostPath: ./hack/kind-config/containerd/certs.d
36-
containerPath: /etc/containerd/certs.d
37-
containerdConfigPatches:
38-
- |-
39-
[plugins."io.containerd.grpc.v1.cri".registry]
40-
config_path = "/etc/containerd/certs.d"

kind-config/kind-config.yaml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,3 @@ nodes:
1414
apiServer:
1515
extraArgs:
1616
enable-admission-plugins: OwnerReferencesPermissionEnforcement
17-
extraMounts:
18-
- hostPath: ./hack/kind-config/containerd/certs.d
19-
containerPath: /etc/containerd/certs.d
20-
containerdConfigPatches:
21-
- |-
22-
[plugins."io.containerd.grpc.v1.cri".registry]
23-
config_path = "/etc/containerd/certs.d"

test/extension-developer-e2e/extension_developer_test.go

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import (
88
"testing"
99
"time"
1010

11+
"github.com/google/go-containerregistry/pkg/crane"
12+
"github.com/google/go-containerregistry/pkg/name"
13+
"github.com/google/go-containerregistry/pkg/v1/tarball"
1114
"github.com/stretchr/testify/assert"
1215
"github.com/stretchr/testify/require"
1316
corev1 "k8s.io/api/core/v1"
@@ -49,7 +52,6 @@ func TestMain(m *testing.M) {
4952
}
5053

5154
// Set env vars for setup.sh — single source of truth
52-
os.Setenv("LOCAL_REGISTRY_HOST", localAddr)
5355
os.Setenv("CATALOG_TAG", catalogTag)
5456
os.Setenv("REG_PKG_NAME", regPkgName)
5557

@@ -60,9 +62,56 @@ func TestMain(m *testing.M) {
6062
panic(fmt.Sprintf("failed to run setup.sh: %v", err))
6163
}
6264

65+
// Push images via crane through the port-forward.
66+
// setup.sh tags images with CLUSTER_REGISTRY_HOST. We export them
67+
// from the container runtime via "save" and push through the
68+
// port-forward with crane.
69+
containerRuntime := os.Getenv("CONTAINER_RUNTIME")
70+
bundlePath := "bundles/registry-v1/registry-bundle:v0.0.1"
71+
for _, path := range []string{bundlePath, catalogTag} {
72+
srcRef := fmt.Sprintf("%s/%s", clusterRegistryHost, path)
73+
pushRef := fmt.Sprintf("%s/%s", localAddr, path)
74+
if err := saveAndPush(containerRuntime, srcRef, pushRef); err != nil {
75+
panic(fmt.Sprintf("failed to push image %s: %v", pushRef, err))
76+
}
77+
}
78+
6379
os.Exit(m.Run())
6480
}
6581

82+
// saveAndPush exports an image from the container runtime to a temp file,
83+
// then loads and pushes it to the registry via crane.
84+
func saveAndPush(containerRuntime, srcRef, pushRef string) error {
85+
f, err := os.CreateTemp("", "image-*.tar")
86+
if err != nil {
87+
return fmt.Errorf("failed to create temp file: %w", err)
88+
}
89+
defer os.Remove(f.Name())
90+
defer f.Close()
91+
92+
saveCmd := exec.Command(containerRuntime, "save", srcRef) //nolint:gosec
93+
saveCmd.Stdout = f
94+
if err := saveCmd.Run(); err != nil {
95+
return fmt.Errorf("failed to save image %s: %w", srcRef, err)
96+
}
97+
if err := f.Close(); err != nil {
98+
return fmt.Errorf("failed to close temp file: %w", err)
99+
}
100+
101+
tag, err := name.NewTag(srcRef)
102+
if err != nil {
103+
return fmt.Errorf("failed to parse tag %s: %w", srcRef, err)
104+
}
105+
img, err := tarball.ImageFromPath(f.Name(), &tag)
106+
if err != nil {
107+
return fmt.Errorf("failed to load image %s from tarball: %w", srcRef, err)
108+
}
109+
if err := crane.Push(img, pushRef, crane.Insecure); err != nil {
110+
return fmt.Errorf("failed to push image %s: %w", pushRef, err)
111+
}
112+
return nil
113+
}
114+
66115
func TestExtensionDeveloper(t *testing.T) {
67116
t.Parallel()
68117
cfg := ctrl.GetConfigOrDie()

test/extension-developer-e2e/setup.sh

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@ help="setup.sh is used to build extensions using the operator-sdk and
88
build the image + bundle image, and create a FBC image for the
99
following bundle formats:
1010
- registry+v1
11-
This script will ensure that all images built are loaded onto
12-
a KinD cluster with the name specified in the arguments.
11+
Images are built and tagged locally; pushing to the registry is
12+
handled by the Go test code via crane + port-forward.
1313
The following environment variables are required for configuring this script:
1414
- \$OPERATOR_SDK - path to the operator-sdk binary.
1515
- \$CONTAINER_RUNTIME - container runtime to use (e.g. docker, podman).
16-
- \$LOCAL_REGISTRY_HOST - registry address accessible from the test process.
1716
- \$CLUSTER_REGISTRY_HOST - registry address accessible from inside the cluster.
1817
- \$CATALOG_TAG - OCI tag for the catalog image (e.g. e2e/test-catalog:v1).
1918
- \$REG_PKG_NAME - the name of the package for the extension.
@@ -26,7 +25,7 @@ Usage:
2625
# Input validation
2726
########################################
2827

29-
for var in OPERATOR_SDK CONTAINER_RUNTIME LOCAL_REGISTRY_HOST CLUSTER_REGISTRY_HOST CATALOG_TAG REG_PKG_NAME; do
28+
for var in OPERATOR_SDK CONTAINER_RUNTIME CLUSTER_REGISTRY_HOST CATALOG_TAG REG_PKG_NAME; do
3029
if [[ -z "${!var:-}" ]]; then
3130
echo "\$$var is required to be set"
3231
echo "${help}"
@@ -49,25 +48,13 @@ mkdir -p "${REG_DIR}"
4948

5049
operator_sdk="${OPERATOR_SDK}"
5150
container_tool="${CONTAINER_RUNTIME}"
52-
# The path we use to push the image from _outside_ the cluster
53-
local_registry_host="${LOCAL_REGISTRY_HOST}"
54-
# The path we use _inside_ the cluster
5551
cluster_registry_host="${CLUSTER_REGISTRY_HOST}"
5652

57-
tls_flag=""
58-
if [[ "$container_tool" == "podman" ]]; then
59-
echo "Using podman container runtime; adding tls disable flag"
60-
tls_flag="--tls-verify=false"
61-
fi
62-
63-
catalog_push_tag="${local_registry_host}/${CATALOG_TAG}"
53+
catalog_tag="${cluster_registry_host}/${CATALOG_TAG}"
6454
reg_pkg_name="${REG_PKG_NAME}"
6555

6656
reg_img="${DOMAIN}/registry:v0.0.1"
67-
reg_bundle_path="bundles/registry-v1/registry-bundle:v0.0.1"
68-
69-
reg_bundle_img="${cluster_registry_host}/${reg_bundle_path}"
70-
reg_bundle_push_tag="${local_registry_host}/${reg_bundle_path}"
57+
reg_bundle_img="${cluster_registry_host}/bundles/registry-v1/registry-bundle:v0.0.1"
7158

7259
########################################
7360
# Create the registry+v1 based extension
@@ -98,10 +85,14 @@ reg_bundle_push_tag="${local_registry_host}/${reg_bundle_path}"
9885
make docker-build IMG="${reg_img}" && \
9986
sed -i -e 's/$(OPERATOR_SDK) generate kustomize manifests -q/$(OPERATOR_SDK) generate kustomize manifests -q --interactive=false/g' Makefile && \
10087
make bundle IMG="${reg_img}" VERSION=0.0.1 && \
101-
make bundle-build BUNDLE_IMG="${reg_bundle_push_tag}"
102-
${container_tool} push ${reg_bundle_push_tag} ${tls_flag}
88+
make bundle-build BUNDLE_IMG="${reg_bundle_img}"
10389
)
10490

91+
# Push is handled by the Go test via crane + port-forward,
92+
# because docker push goes through the Docker daemon which
93+
# may be in a different network context (e.g. colima VM).
94+
95+
10596
###############################
10697
# Create the FBC that contains
10798
# the registry+v1 extensions
@@ -146,5 +137,6 @@ cat <<EOF > "${TMP_ROOT}"/catalog/index.yaml
146137
}
147138
EOF
148139

149-
${container_tool} build --provenance=false -f "${TMP_ROOT}/catalog.Dockerfile" -t "${catalog_push_tag}" "${TMP_ROOT}/"
150-
${container_tool} push ${catalog_push_tag} ${tls_flag}
140+
${container_tool} build --provenance=false -f "${TMP_ROOT}/catalog.Dockerfile" -t "${catalog_tag}" "${TMP_ROOT}/"
141+
142+
# Push is handled by the Go test via crane + port-forward.

test/internal/registry/registry.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import (
3232
const (
3333
DefaultNamespace = "operator-controller-e2e"
3434
DefaultName = "docker-registry"
35-
nodePort = int32(30000)
3635
)
3736

3837
// Deploy ensures the image registry namespace, TLS certificate, deployment,
@@ -123,18 +122,14 @@ func Deploy(ctx context.Context, cfg *rest.Config, namespace, name string) error
123122
return fmt.Errorf("failed to apply deployment: %w", err)
124123
}
125124

126-
// Apply service — NodePort so that containerd on the kind node can
127-
// reach the registry via localhost:30000 (configured in hosts.toml).
128-
// Test runners access the registry via port-forward instead.
125+
// Apply service
129126
svc := corev1ac.Service(name, namespace).
130127
WithSpec(corev1ac.ServiceSpec().
131128
WithSelector(map[string]string{"app": "registry"}).
132-
WithType(corev1.ServiceTypeNodePort).
133129
WithPorts(corev1ac.ServicePort().
134130
WithName("http").
135131
WithPort(5000).
136-
WithTargetPort(intstr.FromInt32(5000)).
137-
WithNodePort(nodePort),
132+
WithTargetPort(intstr.FromInt32(5000)),
138133
),
139134
)
140135
if err := c.Apply(ctx, svc, fieldOwner, client.ForceOwnership); err != nil {
@@ -167,21 +162,26 @@ func Deploy(ctx context.Context, cfg *rest.Config, namespace, name string) error
167162
// PortForward establishes a port-forward to the registry pod and returns
168163
// the local address (e.g. "localhost:12345") that can be used to push images.
169164
// The returned stop function should be called to clean up the port-forward.
170-
func PortForward(ctx context.Context, cfg *rest.Config, namespace, name string) (localAddr string, stop func(), err error) {
165+
func PortForward(ctx context.Context, cfg *rest.Config, namespace, name string) (string, func(), error) {
171166
clientset, err := kubernetes.NewForConfig(cfg)
172167
if err != nil {
173168
return "", nil, fmt.Errorf("failed to create kubernetes client: %w", err)
174169
}
175170

171+
deploy, err := clientset.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{})
172+
if err != nil {
173+
return "", nil, fmt.Errorf("failed to get deployment %s/%s: %w", namespace, name, err)
174+
}
175+
labelSelector := metav1.FormatLabelSelector(deploy.Spec.Selector)
176176
pods, err := clientset.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{
177-
LabelSelector: "app=registry",
177+
LabelSelector: labelSelector,
178178
FieldSelector: "status.phase=Running",
179179
})
180180
if err != nil {
181-
return "", nil, fmt.Errorf("failed to list registry pods: %w", err)
181+
return "", nil, fmt.Errorf("failed to list pods for deployment %s: %w", name, err)
182182
}
183183
if len(pods.Items) == 0 {
184-
return "", nil, fmt.Errorf("no running registry pods found in %s", namespace)
184+
return "", nil, fmt.Errorf("no running pods found for deployment %s/%s", namespace, name)
185185
}
186186
podName := pods.Items[0].Name
187187

0 commit comments

Comments
 (0)