diff --git a/ci-operator/config/openshift/kubernetes-nmstate/openshift-kubernetes-nmstate-main.yaml b/ci-operator/config/openshift/kubernetes-nmstate/openshift-kubernetes-nmstate-main.yaml index e465969644c2e..89a7fb1681439 100644 --- a/ci-operator/config/openshift/kubernetes-nmstate/openshift-kubernetes-nmstate-main.yaml +++ b/ci-operator/config/openshift/kubernetes-nmstate/openshift-kubernetes-nmstate-main.yaml @@ -98,6 +98,48 @@ tests: steps: cluster_profile: openshift-org-azure workflow: kubernetes-nmstate-e2e-azure +- always_run: false + as: e2e-handler-aws-disconnected + capabilities: + - intranet + optional: true + steps: + cluster_profile: openshift-org-aws + env: + MIRROR_CUSTOM_IMAGES: kubernetes-nmstate-handler,kubernetes-nmstate-operator + workflow: kubernetes-nmstate-e2e-handler-aws-disconnected +- always_run: false + as: e2e-handler-aws-ipv6-disconnected + capabilities: + - intranet + optional: true + steps: + cluster_profile: openshift-org-aws + env: + IP_FAMILY: DualStackIPv6Primary + MIRROR_CUSTOM_IMAGES: kubernetes-nmstate-handler,kubernetes-nmstate-operator + workflow: kubernetes-nmstate-e2e-handler-aws-disconnected +- always_run: false + as: e2e-handler-azure-ipv6-disconnected + capabilities: + - intranet + optional: true + steps: + cluster_profile: openshift-org-azure + env: + IP_FAMILY: DualStackIPv6Primary + MIRROR_CUSTOM_IMAGES: kubernetes-nmstate-handler,kubernetes-nmstate-operator + workflow: kubernetes-nmstate-e2e-handler-azure-disconnected +- always_run: false + as: e2e-handler-gcp-disconnected + capabilities: + - intranet + optional: true + steps: + cluster_profile: openshift-org-gcp + env: + MIRROR_CUSTOM_IMAGES: kubernetes-nmstate-handler,kubernetes-nmstate-operator + workflow: kubernetes-nmstate-e2e-handler-gcp-disconnected - as: e2e-handler-ovn-ipv4-nightly-periodic capabilities: - intranet diff --git a/ci-operator/jobs/openshift/kubernetes-nmstate/openshift-kubernetes-nmstate-main-presubmits.yaml b/ci-operator/jobs/openshift/kubernetes-nmstate/openshift-kubernetes-nmstate-main-presubmits.yaml index b04578a1dc992..aead354a2b5e2 100644 --- a/ci-operator/jobs/openshift/kubernetes-nmstate/openshift-kubernetes-nmstate-main-presubmits.yaml +++ b/ci-operator/jobs/openshift/kubernetes-nmstate/openshift-kubernetes-nmstate-main-presubmits.yaml @@ -66,6 +66,180 @@ presubmits: secret: secretName: result-aggregator trigger: (?m)^/test( | .* )check-generate-bundle,?($|\s.*) + - agent: kubernetes + always_run: false + branches: + - ^main$ + - ^main- + cluster: build05 + context: ci/prow/e2e-handler-aws-disconnected + decorate: true + decoration_config: + sparse_checkout_files: + - .ci-operator.yaml + - build/Dockerfile.openshift + - build/Dockerfile.operator.openshift + labels: + capability/intranet: intranet + ci-operator.openshift.io/cloud: aws + ci-operator.openshift.io/cloud-cluster-profile: openshift-org-aws + ci.openshift.io/generator: prowgen + pj-rehearse.openshift.io/can-be-rehearsed: "true" + name: pull-ci-openshift-kubernetes-nmstate-main-e2e-handler-aws-disconnected + optional: true + rerun_command: /test e2e-handler-aws-disconnected + spec: + containers: + - args: + - --gcs-upload-secret=/secrets/gcs/service-account.json + - --image-import-pull-secret=/etc/pull-secret/.dockerconfigjson + - --lease-server-credentials-file=/etc/boskos/credentials + - --report-credentials-file=/etc/report/credentials + - --secret-dir=/secrets/ci-pull-credentials + - --target=e2e-handler-aws-disconnected + command: + - ci-operator + env: + - name: HTTP_SERVER_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + image: quay-proxy.ci.openshift.org/openshift/ci:ci_ci-operator_latest + imagePullPolicy: Always + name: "" + ports: + - containerPort: 8080 + name: http + resources: + requests: + cpu: 10m + volumeMounts: + - mountPath: /etc/boskos + name: boskos + readOnly: true + - mountPath: /secrets/ci-pull-credentials + name: ci-pull-credentials + readOnly: true + - mountPath: /secrets/gcs + name: gcs-credentials + readOnly: true + - mountPath: /secrets/manifest-tool + name: manifest-tool-local-pusher + readOnly: true + - mountPath: /etc/pull-secret + name: pull-secret + readOnly: true + - mountPath: /etc/report + name: result-aggregator + readOnly: true + serviceAccountName: ci-operator + volumes: + - name: boskos + secret: + items: + - key: credentials + path: credentials + secretName: boskos-credentials + - name: ci-pull-credentials + secret: + secretName: ci-pull-credentials + - name: manifest-tool-local-pusher + secret: + secretName: manifest-tool-local-pusher + - name: pull-secret + secret: + secretName: registry-pull-credentials + - name: result-aggregator + secret: + secretName: result-aggregator + trigger: (?m)^/test( | .* )e2e-handler-aws-disconnected,?($|\s.*) + - agent: kubernetes + always_run: false + branches: + - ^main$ + - ^main- + cluster: build05 + context: ci/prow/e2e-handler-aws-ipv6-disconnected + decorate: true + decoration_config: + sparse_checkout_files: + - .ci-operator.yaml + - build/Dockerfile.openshift + - build/Dockerfile.operator.openshift + labels: + capability/intranet: intranet + ci-operator.openshift.io/cloud: aws + ci-operator.openshift.io/cloud-cluster-profile: openshift-org-aws + ci.openshift.io/generator: prowgen + pj-rehearse.openshift.io/can-be-rehearsed: "true" + name: pull-ci-openshift-kubernetes-nmstate-main-e2e-handler-aws-ipv6-disconnected + optional: true + rerun_command: /test e2e-handler-aws-ipv6-disconnected + spec: + containers: + - args: + - --gcs-upload-secret=/secrets/gcs/service-account.json + - --image-import-pull-secret=/etc/pull-secret/.dockerconfigjson + - --lease-server-credentials-file=/etc/boskos/credentials + - --report-credentials-file=/etc/report/credentials + - --secret-dir=/secrets/ci-pull-credentials + - --target=e2e-handler-aws-ipv6-disconnected + command: + - ci-operator + env: + - name: HTTP_SERVER_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + image: quay-proxy.ci.openshift.org/openshift/ci:ci_ci-operator_latest + imagePullPolicy: Always + name: "" + ports: + - containerPort: 8080 + name: http + resources: + requests: + cpu: 10m + volumeMounts: + - mountPath: /etc/boskos + name: boskos + readOnly: true + - mountPath: /secrets/ci-pull-credentials + name: ci-pull-credentials + readOnly: true + - mountPath: /secrets/gcs + name: gcs-credentials + readOnly: true + - mountPath: /secrets/manifest-tool + name: manifest-tool-local-pusher + readOnly: true + - mountPath: /etc/pull-secret + name: pull-secret + readOnly: true + - mountPath: /etc/report + name: result-aggregator + readOnly: true + serviceAccountName: ci-operator + volumes: + - name: boskos + secret: + items: + - key: credentials + path: credentials + secretName: boskos-credentials + - name: ci-pull-credentials + secret: + secretName: ci-pull-credentials + - name: manifest-tool-local-pusher + secret: + secretName: manifest-tool-local-pusher + - name: pull-secret + secret: + secretName: registry-pull-credentials + - name: result-aggregator + secret: + secretName: result-aggregator + trigger: (?m)^/test( | .* )e2e-handler-aws-ipv6-disconnected,?($|\s.*) - agent: kubernetes always_run: false branches: @@ -153,6 +327,180 @@ presubmits: secret: secretName: result-aggregator trigger: (?m)^/test( | .* )e2e-handler-azure,?($|\s.*) + - agent: kubernetes + always_run: false + branches: + - ^main$ + - ^main- + cluster: build05 + context: ci/prow/e2e-handler-azure-ipv6-disconnected + decorate: true + decoration_config: + sparse_checkout_files: + - .ci-operator.yaml + - build/Dockerfile.openshift + - build/Dockerfile.operator.openshift + labels: + capability/intranet: intranet + ci-operator.openshift.io/cloud: azure4 + ci-operator.openshift.io/cloud-cluster-profile: openshift-org-azure + ci.openshift.io/generator: prowgen + pj-rehearse.openshift.io/can-be-rehearsed: "true" + name: pull-ci-openshift-kubernetes-nmstate-main-e2e-handler-azure-ipv6-disconnected + optional: true + rerun_command: /test e2e-handler-azure-ipv6-disconnected + spec: + containers: + - args: + - --gcs-upload-secret=/secrets/gcs/service-account.json + - --image-import-pull-secret=/etc/pull-secret/.dockerconfigjson + - --lease-server-credentials-file=/etc/boskos/credentials + - --report-credentials-file=/etc/report/credentials + - --secret-dir=/secrets/ci-pull-credentials + - --target=e2e-handler-azure-ipv6-disconnected + command: + - ci-operator + env: + - name: HTTP_SERVER_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + image: quay-proxy.ci.openshift.org/openshift/ci:ci_ci-operator_latest + imagePullPolicy: Always + name: "" + ports: + - containerPort: 8080 + name: http + resources: + requests: + cpu: 10m + volumeMounts: + - mountPath: /etc/boskos + name: boskos + readOnly: true + - mountPath: /secrets/ci-pull-credentials + name: ci-pull-credentials + readOnly: true + - mountPath: /secrets/gcs + name: gcs-credentials + readOnly: true + - mountPath: /secrets/manifest-tool + name: manifest-tool-local-pusher + readOnly: true + - mountPath: /etc/pull-secret + name: pull-secret + readOnly: true + - mountPath: /etc/report + name: result-aggregator + readOnly: true + serviceAccountName: ci-operator + volumes: + - name: boskos + secret: + items: + - key: credentials + path: credentials + secretName: boskos-credentials + - name: ci-pull-credentials + secret: + secretName: ci-pull-credentials + - name: manifest-tool-local-pusher + secret: + secretName: manifest-tool-local-pusher + - name: pull-secret + secret: + secretName: registry-pull-credentials + - name: result-aggregator + secret: + secretName: result-aggregator + trigger: (?m)^/test( | .* )e2e-handler-azure-ipv6-disconnected,?($|\s.*) + - agent: kubernetes + always_run: false + branches: + - ^main$ + - ^main- + cluster: build05 + context: ci/prow/e2e-handler-gcp-disconnected + decorate: true + decoration_config: + sparse_checkout_files: + - .ci-operator.yaml + - build/Dockerfile.openshift + - build/Dockerfile.operator.openshift + labels: + capability/intranet: intranet + ci-operator.openshift.io/cloud: gcp + ci-operator.openshift.io/cloud-cluster-profile: openshift-org-gcp + ci.openshift.io/generator: prowgen + pj-rehearse.openshift.io/can-be-rehearsed: "true" + name: pull-ci-openshift-kubernetes-nmstate-main-e2e-handler-gcp-disconnected + optional: true + rerun_command: /test e2e-handler-gcp-disconnected + spec: + containers: + - args: + - --gcs-upload-secret=/secrets/gcs/service-account.json + - --image-import-pull-secret=/etc/pull-secret/.dockerconfigjson + - --lease-server-credentials-file=/etc/boskos/credentials + - --report-credentials-file=/etc/report/credentials + - --secret-dir=/secrets/ci-pull-credentials + - --target=e2e-handler-gcp-disconnected + command: + - ci-operator + env: + - name: HTTP_SERVER_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + image: quay-proxy.ci.openshift.org/openshift/ci:ci_ci-operator_latest + imagePullPolicy: Always + name: "" + ports: + - containerPort: 8080 + name: http + resources: + requests: + cpu: 10m + volumeMounts: + - mountPath: /etc/boskos + name: boskos + readOnly: true + - mountPath: /secrets/ci-pull-credentials + name: ci-pull-credentials + readOnly: true + - mountPath: /secrets/gcs + name: gcs-credentials + readOnly: true + - mountPath: /secrets/manifest-tool + name: manifest-tool-local-pusher + readOnly: true + - mountPath: /etc/pull-secret + name: pull-secret + readOnly: true + - mountPath: /etc/report + name: result-aggregator + readOnly: true + serviceAccountName: ci-operator + volumes: + - name: boskos + secret: + items: + - key: credentials + path: credentials + secretName: boskos-credentials + - name: ci-pull-credentials + secret: + secretName: ci-pull-credentials + - name: manifest-tool-local-pusher + secret: + secretName: manifest-tool-local-pusher + - name: pull-secret + secret: + secretName: registry-pull-credentials + - name: result-aggregator + secret: + secretName: result-aggregator + trigger: (?m)^/test( | .* )e2e-handler-gcp-disconnected,?($|\s.*) - agent: kubernetes always_run: true branches: diff --git a/ci-operator/step-registry/ipi/aws/pre/disconnected/ipi-aws-pre-disconnected-chain.yaml b/ci-operator/step-registry/ipi/aws/pre/disconnected/ipi-aws-pre-disconnected-chain.yaml index 558306a15edd2..505df43d19868 100644 --- a/ci-operator/step-registry/ipi/aws/pre/disconnected/ipi-aws-pre-disconnected-chain.yaml +++ b/ci-operator/step-registry/ipi/aws/pre/disconnected/ipi-aws-pre-disconnected-chain.yaml @@ -4,6 +4,9 @@ chain: - ref: aws-provision-vpc-disconnected - chain: aws-provision-bastionhost - chain: mirror-images-payload + # Mirror any caller-provided custom images (MIRROR_CUSTOM_IMAGES) into the bastion + # registry and emit the matching redirect. No-op unless MIRROR_CUSTOM_IMAGES is set. + - ref: mirror-images-custom - ref: ipi-conf - ref: ipi-conf-telemetry - ref: ipi-conf-aws-custom-vpc diff --git a/ci-operator/step-registry/ipi/azure/pre/disconnected/OWNERS b/ci-operator/step-registry/ipi/azure/pre/disconnected/OWNERS new file mode 100644 index 0000000000000..216717735cf55 --- /dev/null +++ b/ci-operator/step-registry/ipi/azure/pre/disconnected/OWNERS @@ -0,0 +1,6 @@ +approvers: +- jianlinliu +- patrickdillon +- technical-release-team-approvers +- vrutkovs +- yunjiang29 diff --git a/ci-operator/step-registry/ipi/azure/pre/disconnected/ipi-azure-pre-disconnected-chain.metadata.json b/ci-operator/step-registry/ipi/azure/pre/disconnected/ipi-azure-pre-disconnected-chain.metadata.json new file mode 100644 index 0000000000000..a08726f030879 --- /dev/null +++ b/ci-operator/step-registry/ipi/azure/pre/disconnected/ipi-azure-pre-disconnected-chain.metadata.json @@ -0,0 +1,12 @@ +{ + "path": "ipi/azure/pre/disconnected/ipi-azure-pre-disconnected-chain.yaml", + "owners": { + "approvers": [ + "jianlinliu", + "patrickdillon", + "technical-release-team-approvers", + "vrutkovs", + "yunjiang29" + ] + } +} \ No newline at end of file diff --git a/ci-operator/step-registry/ipi/azure/pre/disconnected/ipi-azure-pre-disconnected-chain.yaml b/ci-operator/step-registry/ipi/azure/pre/disconnected/ipi-azure-pre-disconnected-chain.yaml new file mode 100644 index 0000000000000..3702d4771d181 --- /dev/null +++ b/ci-operator/step-registry/ipi/azure/pre/disconnected/ipi-azure-pre-disconnected-chain.yaml @@ -0,0 +1,58 @@ +chain: + as: ipi-azure-pre-disconnected + steps: + - ref: azure-provision-resourcegroup + - ref: azure-provision-vnet + - chain: azure-provision-bastionhost + - ref: openshift-cluster-bot-rbac + - chain: mirror-images-by-oc-adm + # Mirror any caller-provided custom images (MIRROR_CUSTOM_IMAGES) into the bastion + # registry and emit the matching redirect. No-op unless MIRROR_CUSTOM_IMAGES is set. + - ref: mirror-images-custom + - chain: ipi-conf-azure + - ref: ipi-conf-mirror + - ref: ipi-conf-azure-provisionednetwork + - chain: azure-provision-service-principal-minimal-permission + - ref: ipi-install-install + - ref: ipi-install-times-collection + # Disable the unreachable default OperatorHub sources. Runs post-install (patches a live + # cluster); inlined per chain to match ipi-aws-pre-disconnected (not extracted to a ref). + - as: disable-default-sources + from: cli + commands: |- + set -euo pipefail + if test -f "${SHARED_DIR}/proxy-conf.sh"; then + source "${SHARED_DIR}/proxy-conf.sh" + fi + oc patch OperatorHub cluster --type json \ + -p '[{"op": "add", "path": "/spec/disableAllDefaultSources", "value": true}]' + resources: + requests: + cpu: 100m + memory: 100Mi + timeout: 5m0s + grace_period: 5m0s + env: + - name: RESTRICTED_NETWORK + default: "yes" + documentation: "Create an isolated (disconnected) network." + - name: REGISTER_MIRROR_REGISTRY_DNS + default: "yes" + documentation: "Register the bastion mirror registry DNS and write ${SHARED_DIR}/mirror_registry_url." + - name: MIRROR_IN_BASTION + default: "yes" + documentation: "Mirror images from the bastion host rather than the build farm." + - name: BASE_DOMAIN + default: ci.azure.devcluster.openshift.com + documentation: "Base domain (matches ipi-conf-azure) used for the bastion mirror-registry private DNS zone." + - name: BASE_RESOURCE_GROUP + default: os4-common + documentation: "Resource group holding the base domain, required by azure-provision-bastionhost when registering mirror DNS." + documentation: |- + The ipi-azure-pre-disconnected chain provisions a fully disconnected OpenShift + cluster on Azure: a resource group and VNet with a restricted (no direct internet) + network, a bastion host providing a mirror registry, egress proxy and SSH jump host, + then mirrors the release payload (and any MIRROR_CUSTOM_IMAGES) and installs the + cluster. Modeled on the QE cucushift disconnected recipe, without the QE-only steps, + so it is reusable by any team. Set ENABLE_IDMS=yes to use the IDMS/ITMS redirect + family (required for tag-referenced custom images). diff --git a/ci-operator/step-registry/ipi/gcp/pre/disconnected/OWNERS b/ci-operator/step-registry/ipi/gcp/pre/disconnected/OWNERS new file mode 100644 index 0000000000000..216717735cf55 --- /dev/null +++ b/ci-operator/step-registry/ipi/gcp/pre/disconnected/OWNERS @@ -0,0 +1,6 @@ +approvers: +- jianlinliu +- patrickdillon +- technical-release-team-approvers +- vrutkovs +- yunjiang29 diff --git a/ci-operator/step-registry/ipi/gcp/pre/disconnected/ipi-gcp-pre-disconnected-chain.metadata.json b/ci-operator/step-registry/ipi/gcp/pre/disconnected/ipi-gcp-pre-disconnected-chain.metadata.json new file mode 100644 index 0000000000000..eaa8a2f8a8c4d --- /dev/null +++ b/ci-operator/step-registry/ipi/gcp/pre/disconnected/ipi-gcp-pre-disconnected-chain.metadata.json @@ -0,0 +1,12 @@ +{ + "path": "ipi/gcp/pre/disconnected/ipi-gcp-pre-disconnected-chain.yaml", + "owners": { + "approvers": [ + "jianlinliu", + "patrickdillon", + "technical-release-team-approvers", + "vrutkovs", + "yunjiang29" + ] + } +} \ No newline at end of file diff --git a/ci-operator/step-registry/ipi/gcp/pre/disconnected/ipi-gcp-pre-disconnected-chain.yaml b/ci-operator/step-registry/ipi/gcp/pre/disconnected/ipi-gcp-pre-disconnected-chain.yaml new file mode 100644 index 0000000000000..0f38a0d4e4180 --- /dev/null +++ b/ci-operator/step-registry/ipi/gcp/pre/disconnected/ipi-gcp-pre-disconnected-chain.yaml @@ -0,0 +1,52 @@ +chain: + as: ipi-gcp-pre-disconnected + steps: + - ref: gcp-provision-minimal-permission + - ref: openshift-cluster-bot-rbac + - ref: gcp-provision-vpc + - ref: ignition-bastionhost + - ref: gcp-provision-bastionhost + - chain: mirror-images-by-oc-adm + # Mirror any caller-provided custom images (MIRROR_CUSTOM_IMAGES) into the bastion + # registry and emit the matching redirect. No-op unless MIRROR_CUSTOM_IMAGES is set. + - ref: mirror-images-custom + - chain: ipi-conf-gcp + - ref: ipi-conf-mirror + - ref: ipi-install-install + - ref: ipi-install-times-collection + # Disable the unreachable default OperatorHub sources. Runs post-install (patches a live + # cluster); inlined per chain to match ipi-aws-pre-disconnected (not extracted to a ref). + - as: disable-default-sources + from: cli + commands: |- + set -euo pipefail + if test -f "${SHARED_DIR}/proxy-conf.sh"; then + source "${SHARED_DIR}/proxy-conf.sh" + fi + oc patch OperatorHub cluster --type json \ + -p '[{"op": "add", "path": "/spec/disableAllDefaultSources", "value": true}]' + resources: + requests: + cpu: 100m + memory: 100Mi + timeout: 5m0s + grace_period: 5m0s + env: + - name: RESTRICTED_NETWORK + default: "yes" + documentation: "Create an isolated (disconnected) network." + - name: REGISTER_MIRROR_REGISTRY_DNS + default: "yes" + documentation: "Register the bastion mirror registry DNS and write ${SHARED_DIR}/mirror_registry_url." + - name: MIRROR_IN_BASTION + default: "yes" + documentation: "Mirror images from the bastion host rather than the build farm." + documentation: |- + The ipi-gcp-pre-disconnected chain provisions a fully disconnected OpenShift cluster + on GCP: a VPC with a restricted (no direct internet) network, a bastion host providing + a mirror registry, egress proxy and SSH jump host, then mirrors the release payload + (and any MIRROR_CUSTOM_IMAGES) and installs the cluster. Modeled on the QE cucushift + disconnected recipe, without the QE-only steps, so it is reusable by any team. GCP is + IPv4-only (the platform has no dual-stack support), so there is no IPv6 variant. Set + ENABLE_IDMS=yes to use the IDMS/ITMS redirect family (required for tag-referenced + custom images). diff --git a/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/aws/OWNERS b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/aws/OWNERS new file mode 100644 index 0000000000000..1e2e314796fd9 --- /dev/null +++ b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/aws/OWNERS @@ -0,0 +1,11 @@ +approvers: +- cybertron +- phoracek +- qinqon +- rhrazdil +reviewers: +- cybertron +- phoracek +- qinqon +- ramlavi +- rhrazdil diff --git a/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/aws/disconnected/OWNERS b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/aws/disconnected/OWNERS new file mode 100644 index 0000000000000..1e2e314796fd9 --- /dev/null +++ b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/aws/disconnected/OWNERS @@ -0,0 +1,11 @@ +approvers: +- cybertron +- phoracek +- qinqon +- rhrazdil +reviewers: +- cybertron +- phoracek +- qinqon +- ramlavi +- rhrazdil diff --git a/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/aws/disconnected/kubernetes-nmstate-e2e-handler-aws-disconnected-workflow.metadata.json b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/aws/disconnected/kubernetes-nmstate-e2e-handler-aws-disconnected-workflow.metadata.json new file mode 100644 index 0000000000000..c7fe89f5be34f --- /dev/null +++ b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/aws/disconnected/kubernetes-nmstate-e2e-handler-aws-disconnected-workflow.metadata.json @@ -0,0 +1,18 @@ +{ + "path": "kubernetes-nmstate/e2e/handler/aws/disconnected/kubernetes-nmstate-e2e-handler-aws-disconnected-workflow.yaml", + "owners": { + "approvers": [ + "cybertron", + "phoracek", + "qinqon", + "rhrazdil" + ], + "reviewers": [ + "cybertron", + "phoracek", + "qinqon", + "ramlavi", + "rhrazdil" + ] + } +} \ No newline at end of file diff --git a/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/aws/disconnected/kubernetes-nmstate-e2e-handler-aws-disconnected-workflow.yaml b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/aws/disconnected/kubernetes-nmstate-e2e-handler-aws-disconnected-workflow.yaml new file mode 100644 index 0000000000000..f77adf79850bf --- /dev/null +++ b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/aws/disconnected/kubernetes-nmstate-e2e-handler-aws-disconnected-workflow.yaml @@ -0,0 +1,19 @@ +workflow: + as: kubernetes-nmstate-e2e-handler-aws-disconnected + steps: + env: + SKIP_IMAGE_BUILD: "true" + IMAGE_BUILDER: podman + HANDLER_NAMESPACE: openshift-nmstate + OPERATOR_NAMESPACE: openshift-nmstate + pre: + - chain: ipi-aws-pre-disconnected + test: + - ref: kubernetes-nmstate-e2e-handler + post: + - chain: ipi-aws-post-disconnected + documentation: |- + Provision a disconnected OpenShift cluster on AWS, mirror the kubernetes-nmstate + handler and operator images into the bastion registry (via MIRROR_CUSTOM_IMAGES on + mirror-images-custom, inside ipi-aws-pre-disconnected), and run the handler e2e tests. + Set IP_FAMILY=DualStackIPv6Primary in the test to exercise the disconnected IPv6 path. diff --git a/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/azure/OWNERS b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/azure/OWNERS new file mode 100644 index 0000000000000..1e2e314796fd9 --- /dev/null +++ b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/azure/OWNERS @@ -0,0 +1,11 @@ +approvers: +- cybertron +- phoracek +- qinqon +- rhrazdil +reviewers: +- cybertron +- phoracek +- qinqon +- ramlavi +- rhrazdil diff --git a/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/azure/disconnected/OWNERS b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/azure/disconnected/OWNERS new file mode 100644 index 0000000000000..1e2e314796fd9 --- /dev/null +++ b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/azure/disconnected/OWNERS @@ -0,0 +1,11 @@ +approvers: +- cybertron +- phoracek +- qinqon +- rhrazdil +reviewers: +- cybertron +- phoracek +- qinqon +- ramlavi +- rhrazdil diff --git a/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/azure/disconnected/kubernetes-nmstate-e2e-handler-azure-disconnected-workflow.metadata.json b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/azure/disconnected/kubernetes-nmstate-e2e-handler-azure-disconnected-workflow.metadata.json new file mode 100644 index 0000000000000..91d17b1917bc8 --- /dev/null +++ b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/azure/disconnected/kubernetes-nmstate-e2e-handler-azure-disconnected-workflow.metadata.json @@ -0,0 +1,18 @@ +{ + "path": "kubernetes-nmstate/e2e/handler/azure/disconnected/kubernetes-nmstate-e2e-handler-azure-disconnected-workflow.yaml", + "owners": { + "approvers": [ + "cybertron", + "phoracek", + "qinqon", + "rhrazdil" + ], + "reviewers": [ + "cybertron", + "phoracek", + "qinqon", + "ramlavi", + "rhrazdil" + ] + } +} \ No newline at end of file diff --git a/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/azure/disconnected/kubernetes-nmstate-e2e-handler-azure-disconnected-workflow.yaml b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/azure/disconnected/kubernetes-nmstate-e2e-handler-azure-disconnected-workflow.yaml new file mode 100644 index 0000000000000..4be8c82d5f572 --- /dev/null +++ b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/azure/disconnected/kubernetes-nmstate-e2e-handler-azure-disconnected-workflow.yaml @@ -0,0 +1,23 @@ +workflow: + as: kubernetes-nmstate-e2e-handler-azure-disconnected + steps: + env: + SKIP_IMAGE_BUILD: "true" + IMAGE_BUILDER: podman + HANDLER_NAMESPACE: openshift-nmstate + OPERATOR_NAMESPACE: openshift-nmstate + pre: + - chain: ipi-azure-pre-disconnected + test: + - ref: kubernetes-nmstate-e2e-handler + post: + - ref: gather-mirror-registry + - chain: gather-network + - chain: ipi-deprovision + - ref: azure-deprovision-resourcegroup + documentation: |- + Provision a disconnected OpenShift cluster on Azure, mirror the kubernetes-nmstate + handler and operator images into the bastion registry (via MIRROR_CUSTOM_IMAGES on + mirror-images-custom, inside ipi-azure-pre-disconnected), and run the handler e2e + tests. Set IP_FAMILY=DualStackIPv6Primary in the test to exercise the disconnected + IPv6 path. The resource-group deprovision removes the VNet and bastion. diff --git a/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/gcp/OWNERS b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/gcp/OWNERS new file mode 100644 index 0000000000000..1e2e314796fd9 --- /dev/null +++ b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/gcp/OWNERS @@ -0,0 +1,11 @@ +approvers: +- cybertron +- phoracek +- qinqon +- rhrazdil +reviewers: +- cybertron +- phoracek +- qinqon +- ramlavi +- rhrazdil diff --git a/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/gcp/disconnected/OWNERS b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/gcp/disconnected/OWNERS new file mode 100644 index 0000000000000..1e2e314796fd9 --- /dev/null +++ b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/gcp/disconnected/OWNERS @@ -0,0 +1,11 @@ +approvers: +- cybertron +- phoracek +- qinqon +- rhrazdil +reviewers: +- cybertron +- phoracek +- qinqon +- ramlavi +- rhrazdil diff --git a/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/gcp/disconnected/kubernetes-nmstate-e2e-handler-gcp-disconnected-workflow.metadata.json b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/gcp/disconnected/kubernetes-nmstate-e2e-handler-gcp-disconnected-workflow.metadata.json new file mode 100644 index 0000000000000..0a5a4fbe6eda7 --- /dev/null +++ b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/gcp/disconnected/kubernetes-nmstate-e2e-handler-gcp-disconnected-workflow.metadata.json @@ -0,0 +1,18 @@ +{ + "path": "kubernetes-nmstate/e2e/handler/gcp/disconnected/kubernetes-nmstate-e2e-handler-gcp-disconnected-workflow.yaml", + "owners": { + "approvers": [ + "cybertron", + "phoracek", + "qinqon", + "rhrazdil" + ], + "reviewers": [ + "cybertron", + "phoracek", + "qinqon", + "ramlavi", + "rhrazdil" + ] + } +} \ No newline at end of file diff --git a/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/gcp/disconnected/kubernetes-nmstate-e2e-handler-gcp-disconnected-workflow.yaml b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/gcp/disconnected/kubernetes-nmstate-e2e-handler-gcp-disconnected-workflow.yaml new file mode 100644 index 0000000000000..df63a4682ab67 --- /dev/null +++ b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/gcp/disconnected/kubernetes-nmstate-e2e-handler-gcp-disconnected-workflow.yaml @@ -0,0 +1,23 @@ +workflow: + as: kubernetes-nmstate-e2e-handler-gcp-disconnected + steps: + env: + SKIP_IMAGE_BUILD: "true" + IMAGE_BUILDER: podman + HANDLER_NAMESPACE: openshift-nmstate + OPERATOR_NAMESPACE: openshift-nmstate + pre: + - chain: ipi-gcp-pre-disconnected + test: + - ref: kubernetes-nmstate-e2e-handler + post: + - ref: gather-mirror-registry + - chain: gather-network + - chain: ipi-deprovision + - ref: gcp-deprovision-bastionhost + - ref: gcp-deprovision-vpc + documentation: |- + Provision a disconnected OpenShift cluster on GCP (IPv4 only - GCP has no dual-stack + support), mirror the kubernetes-nmstate handler and operator images into the bastion + registry (via MIRROR_CUSTOM_IMAGES on mirror-images-custom, inside + ipi-gcp-pre-disconnected), and run the handler e2e tests. diff --git a/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/kubernetes-nmstate-e2e-handler-commands.sh b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/kubernetes-nmstate-e2e-handler-commands.sh index 01c3eb901b3d3..a40bcfcd0c5cd 100755 --- a/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/kubernetes-nmstate-e2e-handler-commands.sh +++ b/ci-operator/step-registry/kubernetes-nmstate/e2e/handler/kubernetes-nmstate-e2e-handler-commands.sh @@ -2,6 +2,13 @@ export KUBECONFIG=${SHARED_DIR}/kubeconfig +# On disconnected/Internal-publish clusters the API is only reachable via the bastion +# egress proxy. Sourcing proxy-conf.sh is a no-op on connected (e.g. bare-metal) jobs. +if test -f "${SHARED_DIR}/proxy-conf.sh"; then + # shellcheck disable=SC1091 + source "${SHARED_DIR}/proxy-conf.sh" +fi + # wait for all clusteroperators to reach progressing=false to ensure that we achieved the configuration specified at installation # time before we run our e2e tests. function check_clusteroperators_status() { diff --git a/ci-operator/step-registry/mirror-images/custom/OWNERS b/ci-operator/step-registry/mirror-images/custom/OWNERS new file mode 100644 index 0000000000000..bee99e2c36155 --- /dev/null +++ b/ci-operator/step-registry/mirror-images/custom/OWNERS @@ -0,0 +1,7 @@ +approvers: + - aguidirh + - r4f4 +reviewers: + - aguidirh + - r4f4 + - adolfo-ab diff --git a/ci-operator/step-registry/mirror-images/custom/mirror-images-custom-commands.sh b/ci-operator/step-registry/mirror-images/custom/mirror-images-custom-commands.sh new file mode 100644 index 0000000000000..5e6b448d90416 --- /dev/null +++ b/ci-operator/step-registry/mirror-images/custom/mirror-images-custom-commands.sh @@ -0,0 +1,302 @@ +#!/bin/bash + +set -o nounset +set -o errexit +set -o pipefail + +# Save an exit code for the junit generated in gather-must-gather: pre-config steps +# report 100 on failure, 0 on success (see other ipi/*-pre steps). We also clean up any +# credential uploaded to the bastion. A single EXIT/TERM handler does both. +EXIT_CODE=100 +REMOTE_CLEANUP_CMD="" +function on_exit() { + local rc=$? + if [[ "${rc}" == "0" ]]; then EXIT_CODE=0; fi + echo "${EXIT_CODE}" > "${SHARED_DIR}/install-pre-config-status.txt" + if [[ -n "${REMOTE_CLEANUP_CMD}" ]]; then eval "${REMOTE_CLEANUP_CMD}" >/dev/null 2>&1 || true; fi +} +trap on_exit EXIT TERM + +# No-op unless the caller asked for custom images. This keeps the step safe to place in +# shared disconnected chains. +if [[ -z "${MIRROR_CUSTOM_IMAGES:-}" ]]; then + echo "MIRROR_CUSTOM_IMAGES is empty; nothing to mirror. Skipping." + exit 0 +fi + +if [[ "${CUSTOM_MIRROR_APPLY_MODE}" != "manifest" ]]; then + echo "ERROR: CUSTOM_MIRROR_APPLY_MODE='${CUSTOM_MIRROR_APPLY_MODE}' is not supported yet; only 'manifest' is implemented." >&2 + exit 1 +fi + +export HOME="${HOME:-/tmp/home}" +export XDG_RUNTIME_DIR="${HOME}/run" +mkdir -p "${XDG_RUNTIME_DIR}" + +if [[ ! -f "${SHARED_DIR}/mirror_registry_url" ]]; then + echo "ERROR: ${SHARED_DIR}/mirror_registry_url not found. This step requires a disconnected job with a bastion mirror registry." >&2 + exit 1 +fi +MIRROR_REGISTRY_HOST="$(head -n 1 "${SHARED_DIR}/mirror_registry_url")" +echo "MIRROR_REGISTRY_HOST: ${MIRROR_REGISTRY_HOST}" + +# ci-operator points KUBECONFIG at the cluster under test once it exists; unset it so every +# oc call here talks to the build farm (which hosts the pipeline imagestream). +unset KUBECONFIG + +work="$(mktemp -d)" +authfile="${work}/auth.json" + +# Build a combined auth file: cluster pull-secret + custom mirror-registry credential + +# build-farm registry credentials (for pulling pipeline images). We never enable `set -x`, +# so credentials are not traced into the CI logs. +registry_cred="$(head -n 1 /var/run/vault/mirror-registry/registry_creds | base64 -w 0)" +jq --argjson a "{\"${MIRROR_REGISTRY_HOST}\": {\"auth\": \"${registry_cred}\"}}" \ + '.auths |= . + $a' "${CLUSTER_PROFILE_DIR}/pull-secret" > "${authfile}" +oc registry login --to "${authfile}" +chmod 600 "${authfile}" + +# Public repository of this job's pipeline imagestream. ci-operator resolves pipeline +# dependencies to "@", so deriving the redirect source from the same +# value guarantees it matches the pullspec the workload actually deploys. +pipeline_repo="" +if oc get imagestream pipeline -n "${NAMESPACE}" >/dev/null 2>&1; then + pipeline_repo="$(oc get imagestream pipeline -n "${NAMESPACE}" -o jsonpath='{.status.publicDockerImageRepository}')" +fi +echo "pipeline imagestream repo: ${pipeline_repo:-}" + +# Wait (bounded) for a pipeline tag to be built, then echo "@". ci-operator +# does not gate this pre-step on image builds, so some step in the workflow must declare the +# tag as a dependency (the consumer e2e ref does); this only covers the case where the build +# is still in flight when the pre-phase reaches us. istag has no watch verb, so we poll. +function resolve_pipeline_tag() { + local tag="$1" deadline=$(( SECONDS + 900 )) digest="" + while true; do + if oc get istag "pipeline:${tag}" -n "${NAMESPACE}" >/dev/null 2>&1; then + digest="$(oc get istag "pipeline:${tag}" -n "${NAMESPACE}" -o jsonpath='{.image.metadata.name}')" + [[ -n "${digest}" ]] && break + fi + if oc get builds -n "${NAMESPACE}" -o jsonpath='{range .items[*]}{.status.phase}{"\n"}{end}' 2>/dev/null | grep -qx 'Failed'; then + echo "ERROR: a pipeline Build reports phase=Failed while waiting for pipeline:${tag}." >&2 + return 1 + fi + if (( SECONDS >= deadline )); then + echo "ERROR: timed out (15m) waiting for pipeline:${tag} to be built." >&2 + return 1 + fi + echo "waiting for pipeline:${tag} to be built..." >&2 + sleep 15 + done + if [[ -z "${pipeline_repo}" ]]; then + echo "ERROR: pipeline imagestream public repository could not be resolved in namespace ${NAMESPACE}." >&2 + return 1 + fi + echo "${pipeline_repo}@${digest}" +} + +function retry() { + local n=0 max="$1"; shift + until "$@"; do + n=$(( n + 1 )) + if (( n >= max )); then return 1; fi + echo "attempt ${n}/${max} failed; retrying in 30s..." >&2 + sleep 30 + done +} + +# SSH helpers for the bastion. ssh_opts intentionally word-splits. +function bssh() { + # shellcheck disable=SC2086,SC2029 + ssh ${ssh_opts} "${bastion_user}@${bastion_ip}" "$@" +} +function bscp() { + # shellcheck disable=SC2086 + scp ${ssh_opts} "$1" "${bastion_user}@${bastion_ip}:$2" +} + +# Resolve every token into a mirror pair (SRC=DEST) and a redirect (source repo -> mirror repo). +mirror_pairs=() # lines "SRC=DEST" for `oc image mirror` +verify_targets=() # destination pullspecs to confirm landed +declare -A digest_mirrors=() # source_repo -> mirror_repo (digest references) +declare -A tag_mirrors=() # source_repo -> mirror_repo (tag references) + +IFS=',' read -ra _tokens <<< "${MIRROR_CUSTOM_IMAGES}" +for _raw in "${_tokens[@]}"; do + tok="${_raw//[[:space:]]/}" + [[ -z "${tok}" ]] && continue + if [[ "${tok}" == *"/"* ]]; then + src="${tok}" # external pullspec, used verbatim + else + src="$(resolve_pipeline_tag "${tok}")" # pipeline tag -> repo@digest + fi + echo "resolved '${tok}' -> ${src}" + src_repo="${src%@*}"; src_repo="${src_repo%:*}" # strip @digest or :tag + repo_path="${src_repo#*/}" # drop registry host, keep repo path + dest_repo="${MIRROR_REGISTRY_HOST}/${repo_path}" + if [[ "${src}" == *"@sha256:"* ]]; then + digest="${src##*@}" + mirror_pairs+=("${src}=${dest_repo}") # push by digest (bare destination repo) + verify_targets+=("${dest_repo}@${digest}") + digest_mirrors["${src_repo}"]="${dest_repo}" + else + tag="${src##*:}"; [[ "${tag}" == "${src}" ]] && tag="latest" + mirror_pairs+=("${src}=${dest_repo}:${tag}") # preserve the tag + verify_targets+=("${dest_repo}:${tag}") + tag_mirrors["${src_repo}"]="${dest_repo}" + fi +done + +if [[ ${#mirror_pairs[@]} -eq 0 ]]; then + echo "No images resolved to mirror." + exit 0 +fi + +# Detect and match the redirect family established by the release-payload mirror. A cluster +# cannot run ImageContentSourcePolicy together with ImageDigestMirrorSet/ImageTagMirrorSet. +patch="${SHARED_DIR}/install-config-mirror.yaml.patch" +family="icsp" +if [[ -f "${patch}" ]] && grep -q '^imageDigestSources:' "${patch}"; then + family="idms" +elif [[ -f "${patch}" ]] && grep -q '^imageContentSources:' "${patch}"; then + family="icsp" +fi +echo "redirect family (matched to payload mirror): ${family}" + +if [[ "${family}" == "icsp" && ${#tag_mirrors[@]} -gt 0 ]]; then + echo "ERROR: tag-referenced sources require the IDMS/ITMS family, but the payload mirror uses ICSP." >&2 + echo " Set ENABLE_IDMS=yes at the chain level so both the payload and this step use IDMS/ITMS." >&2 + echo " Offending sources: ${!tag_mirrors[*]}" >&2 + exit 1 +fi + +mirror_list="${work}/mirror-list.txt" +printf '%s\n' "${mirror_pairs[@]}" > "${mirror_list}" +echo "Images to mirror (SRC=DEST):" +cat "${mirror_list}" + +# --- perform the mirror, on the bastion over SSH or directly from the build farm --- +if [[ "${MIRROR_IN_BASTION}" == "yes" ]]; then + # A random UID must exist in /etc/passwd to be able to SSH. + if ! whoami &> /dev/null; then + if [[ -w /etc/passwd ]]; then + echo "${USER_NAME:-default}:x:$(id -u):0:${USER_NAME:-default} user:${HOME}:/sbin/nologin" >> /etc/passwd + else + echo "ERROR: /etc/passwd is not writeable and no user matches this uid." >&2 + exit 1 + fi + fi + ssh_key="${CLUSTER_PROFILE_DIR}/ssh-privatekey" + bastion_ip="$(<"${SHARED_DIR}/bastion_private_address")" + if [[ -s "${SHARED_DIR}/bastion_public_address" ]]; then + bastion_ip="$(<"${SHARED_DIR}/bastion_public_address")" + fi + bastion_user="$(<"${SHARED_DIR}/bastion_ssh_user")" + ssh_opts="-o UserKnownHostsFile=/dev/null -o IdentityFile=${ssh_key} -o StrictHostKeyChecking=no" + remote_auth="/tmp/mirror-images-custom-auth.json" + remote_oc="/tmp/oc" + + oc_bin="oc" + if bssh "which oc && oc version --client" >/dev/null 2>&1; then + echo "using oc already installed on the bastion" + elif bssh "test -x ${remote_oc}"; then + oc_bin="${remote_oc}" + else + echo "copying oc to the bastion" + bscp "$(command -v oc)" "${remote_oc}" + oc_bin="${remote_oc}" + fi + + bscp "${authfile}" "${remote_auth}" + # Remove the uploaded credential when the step ends. + REMOTE_CLEANUP_CMD="bssh 'rm -f ${remote_auth}'" + + mirror_flags="--insecure=true" + if bssh "${oc_bin} image mirror --help 2>&1 | grep -q -- --keep-manifest-list"; then + mirror_flags="${mirror_flags} --keep-manifest-list=true" + fi + # Mirror one image per invocation: several images (e.g. handler + operator) share the + # same destination repo (.../pipeline), which `oc image mirror` refuses to accept in a + # single mapping set ("each destination tag may only be specified once"). + for pair in "${mirror_pairs[@]}"; do + echo "mirroring (bastion): ${pair}" + retry 3 bssh "${oc_bin} image mirror ${mirror_flags} --registry-config=${remote_auth} ${pair}" + done + + echo "verifying mirrored images exist in the bastion registry" + for t in "${verify_targets[@]}"; do + retry 3 bssh "${oc_bin} image info --insecure=true -a ${remote_auth} ${t} >/dev/null" \ + || { echo "ERROR: mirrored image not found in registry: ${t}" >&2; exit 1; } + echo " ok: ${t}" + done +else + mirror_flags=(--insecure=true) + if oc image mirror --help 2>&1 | grep -q -- --keep-manifest-list; then + mirror_flags+=(--keep-manifest-list=true) + fi + # Mirror one image per invocation (see the note in the bastion branch above). + for pair in "${mirror_pairs[@]}"; do + echo "mirroring: ${pair}" + retry 3 oc image mirror "${mirror_flags[@]}" "--registry-config=${authfile}" "${pair}" + done + + echo "verifying mirrored images exist in the bastion registry" + for t in "${verify_targets[@]}"; do + retry 3 oc image info --insecure=true -a "${authfile}" "${t}" >/dev/null \ + || { echo "ERROR: mirrored image not found in registry: ${t}" >&2; exit 1; } + echo " ok: ${t}" + done +fi + +# --- emit the redirect as day-1 install manifests (matched family) --- +function digest_mirror_entries() { + local src + for src in "${!digest_mirrors[@]}"; do + printf ' - mirrors:\n - %s\n source: %s\n' "${digest_mirrors[$src]}" "${src}" + if [[ "${1:-}" == "idms" ]]; then + printf ' mirrorSourcePolicy: NeverContactSource\n' + fi + done + return 0 +} + +if [[ "${family}" == "idms" ]]; then + if [[ ${#digest_mirrors[@]} -gt 0 ]]; then + { + echo "apiVersion: config.openshift.io/v1" + echo "kind: ImageDigestMirrorSet" + echo "metadata:" + echo " name: mirror-images-custom" + echo "spec:" + echo " imageDigestMirrors:" + digest_mirror_entries idms + } > "${SHARED_DIR}/manifest_mirror-images-custom-idms.yaml" + echo "wrote IDMS manifest:"; cat "${SHARED_DIR}/manifest_mirror-images-custom-idms.yaml" + fi + if [[ ${#tag_mirrors[@]} -gt 0 ]]; then + { + echo "apiVersion: config.openshift.io/v1" + echo "kind: ImageTagMirrorSet" + echo "metadata:" + echo " name: mirror-images-custom" + echo "spec:" + echo " imageTagMirrors:" + for src in "${!tag_mirrors[@]}"; do + printf ' - mirrors:\n - %s\n source: %s\n mirrorSourcePolicy: NeverContactSource\n' "${tag_mirrors[$src]}" "${src}" + done + } > "${SHARED_DIR}/manifest_mirror-images-custom-itms.yaml" + echo "wrote ITMS manifest:"; cat "${SHARED_DIR}/manifest_mirror-images-custom-itms.yaml" + fi +else + { + echo "apiVersion: operator.openshift.io/v1alpha1" + echo "kind: ImageContentSourcePolicy" + echo "metadata:" + echo " name: mirror-images-custom" + echo "spec:" + echo " repositoryDigestMirrors:" + digest_mirror_entries icsp + } > "${SHARED_DIR}/manifest_mirror-images-custom-icsp.yaml" + echo "wrote ICSP manifest:"; cat "${SHARED_DIR}/manifest_mirror-images-custom-icsp.yaml" +fi + +echo "mirror-images-custom completed successfully." diff --git a/ci-operator/step-registry/mirror-images/custom/mirror-images-custom-ref.metadata.json b/ci-operator/step-registry/mirror-images/custom/mirror-images-custom-ref.metadata.json new file mode 100644 index 0000000000000..23dc7e8ee5741 --- /dev/null +++ b/ci-operator/step-registry/mirror-images/custom/mirror-images-custom-ref.metadata.json @@ -0,0 +1,14 @@ +{ + "path": "mirror-images/custom/mirror-images-custom-ref.yaml", + "owners": { + "approvers": [ + "aguidirh", + "r4f4" + ], + "reviewers": [ + "aguidirh", + "r4f4", + "adolfo-ab" + ] + } +} \ No newline at end of file diff --git a/ci-operator/step-registry/mirror-images/custom/mirror-images-custom-ref.yaml b/ci-operator/step-registry/mirror-images/custom/mirror-images-custom-ref.yaml new file mode 100644 index 0000000000000..dc146b0525e4d --- /dev/null +++ b/ci-operator/step-registry/mirror-images/custom/mirror-images-custom-ref.yaml @@ -0,0 +1,59 @@ +ref: + as: mirror-images-custom + from: upi-installer + grace_period: 10m + timeout: 1h0m0s + commands: mirror-images-custom-commands.sh + credentials: + - namespace: test-credentials + name: openshift-custom-mirror-registry + mount_path: /var/run/vault/mirror-registry + env: + - name: MIRROR_CUSTOM_IMAGES + default: "" + documentation: |- + Comma-separated list of images to mirror into the disconnected cluster's + bastion mirror registry. Each entry is either: + * a pipeline imagestream tag built by this job (e.g. "my-operator"), which + is resolved to its build-farm digest pullspec; or + * a full external pullspec ("quay.io/org/img:tag" or "registry/img@sha256:..."). + List every image the workload DEPLOYS (operands, sidecars, console plugins). + When empty (default) the step is a no-op, so it is safe to include in shared + disconnected chains. + - name: MIRROR_IN_BASTION + default: "yes" + documentation: |- + When "yes", run the mirror on the bastion host over SSH (the bastion has + egress to the source registries and local access to the mirror registry). + When "no", mirror from the build-farm pod directly to the bastion registry. + Requires CLUSTER_PROFILE_DIR/ssh-privatekey when "yes". + - name: CUSTOM_MIRROR_APPLY_MODE + default: "manifest" + documentation: |- + How the image-mirror redirect is published to the cluster. Only "manifest" is + currently implemented: the step writes ${SHARED_DIR}/manifest_*.yaml (an + ImageContentSourcePolicy, or ImageDigestMirrorSet/ImageTagMirrorSet, matched to + the family the release-payload mirror already established) which the installer + applies as day-1 manifests (no node reboot). "install-config" and "day2" are + reserved for future use and are rejected for now. + resources: + requests: + cpu: 10m + memory: 100Mi + documentation: |- + Mirror arbitrary container images (pipeline images built by the job, or external + pullspecs) into the disconnected cluster's bastion mirror registry and emit the + matching image-mirror redirect (ImageContentSourcePolicy, or + ImageDigestMirrorSet/ImageTagMirrorSet). This lets a test deploy its own images by + their original pullspecs on a disconnected cluster with no test-code change, + mirroring the bare-metal dev-scripts MIRROR_CUSTOM_IMAGES capability. + + The redirect family is auto-detected from and matched to the release-payload + mirror (install-config-mirror.yaml.patch): a cluster cannot mix ICSP with + IDMS/ITMS. Tag-referenced sources require the IDMS/ITMS family (chain-wide + ENABLE_IDMS=yes) because ICSP is digest-only. No-op when MIRROR_CUSTOM_IMAGES is + empty. + + Consumed ${SHARED_DIR} contracts (written by the cloud bastion provisioning): + mirror_registry_url, bastion_public_address, bastion_private_address, + bastion_ssh_user; and, for family detection, install-config-mirror.yaml.patch.