-
Notifications
You must be signed in to change notification settings - Fork 6
HYPERFLEET-1412 - feat: Support disconnected installs #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ VERSION ?= 0.0.1 | |
| # Set the Operator SDK version to use. By default, what is installed on the system is used. | ||
| # This is useful for CI or a project to utilize a specific version of the operator-sdk toolkit. | ||
| OPERATOR_SDK_VERSION ?= v1.42.3 | ||
| YQ_VERSION ?= v4.44.1 | ||
|
|
||
| # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) | ||
| ifeq (,$(shell go env GOBIN)) | ||
|
|
@@ -120,8 +121,12 @@ cleanup-test-e2e: ## Tear down the Kind cluster used for e2e tests | |
|
|
||
| ##@ Lint | ||
|
|
||
| .PHONY: verify-related-images | ||
| verify-related-images: ## Verify immutable deployable images match CSV relatedImages. | ||
| go run ./hack/verify-related-images | ||
|
|
||
| .PHONY: lint | ||
| lint: ## Run golangci-lint linter | ||
| lint: verify-related-images ## Run image verification and golangci-lint. | ||
| $(GOLANGCI_LINT) run | ||
|
|
||
| .PHONY: lint-fix | ||
|
|
@@ -134,6 +139,18 @@ lint-config: ## Verify golangci-lint linter configuration | |
|
|
||
| ##@ Build | ||
|
|
||
| OC_MIRROR_IMAGE ?= hyperfleet-oc-mirror:local | ||
|
|
||
| .PHONY: build-oc-mirror-image | ||
| build-oc-mirror-image: ## Build the containerized oc-mirror runner. | ||
| $(CONTAINER_TOOL) build -f hack/oc-mirror.Dockerfile -t $(OC_MIRROR_IMAGE) . | ||
|
|
||
| .PHONY: test-disconnected-mirror | ||
| test-disconnected-mirror: ## Exercise the disk-to-mirror archive transfer. | ||
| CONTAINER_TOOL=$(CONTAINER_TOOL) OC_MIRROR_IMAGE=$(OC_MIRROR_IMAGE) \ | ||
| BUNDLE_IMAGE="$(BUNDLE_IMAGE)" OPERATOR_IMAGE="$(OPERATOR_IMAGE)" API_IMAGE="$(API_IMAGE)" \ | ||
| ./hack/test-disconnected-mirror.sh | ||
|
|
||
| .PHONY: build | ||
| build: manifests generate fmt vet ## Build manager binary. | ||
| go build -o bin/manager cmd/main.go | ||
|
|
@@ -350,16 +367,18 @@ FROM_INDEX_OPT := --from-index $(CATALOG_BASE_IMG) | |
| endif | ||
|
|
||
| .PHONY: bundle | ||
| bundle: manifests operator-sdk ## Generate bundle manifests and metadata, then validate generated files. | ||
| bundle: manifests operator-sdk yq ## Generate bundle manifests and metadata, then validate generated files. | ||
| $(OPERATOR_SDK) generate kustomize manifests -q | ||
| $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS) | ||
| HYPERFLEET_OPERATOR_IMAGE_PULLSPEC="$$($(YQ) eval '.spec.install.spec.deployments[].spec.template.spec.containers[] | select(.name == "manager") | .image' bundle/manifests/hyperfleet-operator.clusterserviceversion.yaml)" CSV_FILE=bundle/manifests/hyperfleet-operator.clusterserviceversion.yaml ./hack/bundle/add_operator_related_image.sh | ||
| $(OPERATOR_SDK) bundle validate ./bundle | ||
|
|
||
| .PHONY: bundle-override-img | ||
| bundle-override-img: manifests operator-sdk ## Generate bundle with IMG override, then restore kustomization.yaml | ||
| bundle-override-img: manifests operator-sdk yq ## Generate bundle with IMG override, then restore kustomization.yaml | ||
| $(OPERATOR_SDK) generate kustomize manifests -q | ||
| cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) | ||
| $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS) | ||
| HYPERFLEET_OPERATOR_IMAGE_PULLSPEC="$$($(YQ) eval '.spec.install.spec.deployments[].spec.template.spec.containers[] | select(.name == "manager") | .image' bundle/manifests/hyperfleet-operator.clusterserviceversion.yaml)" CSV_FILE=bundle/manifests/hyperfleet-operator.clusterserviceversion.yaml ./hack/bundle/add_operator_related_image.sh --allow-tag | ||
| $(OPERATOR_SDK) bundle validate ./bundle | ||
| @echo "Bundle generated with IMG=$(IMG)" | ||
| @echo "Note: config/manager/kustomization.yaml has been modified. Commit or reset as needed." | ||
|
|
@@ -396,6 +415,23 @@ $(LOCALBIN): | |
| KUBECTL ?= kubectl | ||
| KIND ?= kind | ||
|
|
||
| .PHONY: yq | ||
| YQ ?= $(LOCALBIN)/yq | ||
| yq: ## Download yq locally if necessary. | ||
| ifeq (,$(wildcard $(YQ))) | ||
| ifeq (, $(shell which yq 2>/dev/null)) | ||
| @{ \ | ||
| set -e ;\ | ||
| mkdir -p $(dir $(YQ)) ;\ | ||
| OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ | ||
| curl -sSLo $(YQ) https://github.com/mikefarah/yq/releases/download/$(YQ_VERSION)/yq_$${OS}_$${ARCH} ;\ | ||
| chmod +x $(YQ) ;\ | ||
|
Comment on lines
+427
to
+428
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- Makefile lines 400-445 ---'
sed -n '400,445p' Makefile
printf '%s\n' '--- YQ definitions and uses ---'
rg -n -C 3 '(^|[[:space:]])YQ(_VERSION)?[[:space:]]*[:?+]?=|\\$\\(YQ\\)|yq_' Makefile
printf '%s\n' '--- relevant Make targets ---'
rg -n -C 5 'install.*yq|yq|bundle|disconnected|verify-related' MakefileRepository: openshift-hyperfleet/hyperfleet-operator Length of output: 10228 Other (CWE-494): Download of Code Without Integrity Check Reachability: External · Exploitability: Difficult Verify the downloaded yq binary before execution. This recipe downloads As per path instructions, tool installation must use checksummed downloads. 🤖 Prompt for AI AgentsSource: Path instructions |
||
| } | ||
| else | ||
| YQ = $(shell which yq) | ||
| endif | ||
| endif | ||
|
|
||
| .PHONY: operator-sdk | ||
| OPERATOR_SDK ?= $(LOCALBIN)/operator-sdk | ||
| operator-sdk: ## Download operator-sdk locally if necessary. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| # Source of truth for the images deployable by the bundle CSV. | ||
| images: | ||
| - name: hyperfleet-operator | ||
| image: quay.io/redhat-user-workloads/hyperfleet-tenant/hyperfleet/hyperfleet-operator@sha256:31e365d312b6f3d483913d4029eba565abd64ab38a6d117658324afe225f708d | ||
| - name: hyperfleet-api | ||
| image: quay.io/redhat-services-prod/hyperfleet-tenant/hyperfleet/hyperfleet-api@sha256:8533d0d875480f31f5112e454659a095a5d2e993c139a9045a06be6b67b829ca |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| # Disconnected mirroring with oc-mirror v2 | ||
|
|
||
| This is the minimal disk-to-registry procedure for the HyperFleet Operator. | ||
| Use a released bundle, operator image, and API image identified by immutable | ||
| `@sha256:<64 lowercase hex characters>` pullspecs. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| * `oc-mirror` v2 on the connected and disconnected hosts | ||
| * read access to the source registries | ||
| * write access to the disconnected registry | ||
| * transfer media with enough space for the archive | ||
| * an auth file and registry trust configured on both hosts | ||
|
|
||
| Do not put credentials in the configuration file: | ||
|
|
||
| ```bash | ||
| export REGISTRY_AUTH_FILE=$HOME/.config/containers/auth.json | ||
| ``` | ||
|
|
||
| ## 1. Create one ImageSetConfiguration | ||
|
|
||
| Set up the mirror workspace and copy [`docs/examples/imageset-config-standalone.yaml`](examples/imageset-config-standalone.yaml): | ||
|
|
||
| ```bash | ||
| export MIRROR_ROOT="$HOME/hyperfleet-mirror" | ||
| rm -rf "$MIRROR_ROOT" | ||
| mkdir -p "$MIRROR_ROOT" | ||
| cp docs/examples/imageset-config-standalone.yaml "$MIRROR_ROOT/imageset-config.yaml" | ||
| ``` | ||
|
|
||
| Edit `$MIRROR_ROOT/imageset-config.yaml` to replace its three example pullspecs | ||
| with the released bundle, operator, and API image digests. The file uses | ||
| `additionalImages` intentionally: it transfers exactly the three listed | ||
| artifacts and does not discover a catalog or CSV. | ||
|
|
||
| Run the image check before mirroring: | ||
|
|
||
| ```bash | ||
| make verify-related-images | ||
| ``` | ||
|
|
||
| It verifies this equality: | ||
|
|
||
| ```text | ||
| deployable-images.yaml == CSV manager image + RELATED_IMAGE_* values == CSV spec.relatedImages | ||
| ``` | ||
|
|
||
| ## 2. Mirror to disk on the connected host | ||
|
|
||
| ```bash | ||
| oc-mirror --v2 \ | ||
| --config "$MIRROR_ROOT/imageset-config.yaml" \ | ||
| file://"$MIRROR_ROOT/archive" | ||
| ``` | ||
|
|
||
| Keep the complete `archive` directory. Transfer it and the configuration to the | ||
| disconnected mirroring host using approved media: | ||
|
|
||
| ```bash | ||
| tar -C "$MIRROR_ROOT" \ | ||
| -czf /media/transfer/hyperfleet-mirror.tgz \ | ||
| archive imageset-config.yaml | ||
|
|
||
| mkdir -p /var/tmp/hyperfleet-mirror | ||
| tar -C /var/tmp/hyperfleet-mirror \ | ||
| -xzf /media/transfer/hyperfleet-mirror.tgz | ||
| ``` | ||
|
|
||
| ## 3. Mirror from disk into the disconnected registry | ||
|
|
||
| ```bash | ||
| export DESTINATION='mirror.example.com:8443/hyperfleet' | ||
|
|
||
| oc-mirror --v2 \ | ||
| --config /var/tmp/hyperfleet-mirror/imageset-config.yaml \ | ||
| --from file:///var/tmp/hyperfleet-mirror/archive \ | ||
| docker://"$DESTINATION" | ||
| ``` | ||
|
|
||
| Save the command output. Apply any generated mirror resources to the cluster | ||
| before installing the bundle, for example: | ||
|
|
||
| ```bash | ||
| CLUSTER_RESOURCES="$(find /var/tmp/hyperfleet-mirror \ | ||
| -type d -path '*/working-dir/cluster-resources' | head -1)" | ||
| oc apply -f "$CLUSTER_RESOURCES" | ||
| ``` | ||
|
|
||
| Use the mirrored bundle with the normal installation procedure. The | ||
| `additionalImages` configuration does not create a catalog. Do not manually | ||
| rewrite image digests. | ||
|
|
||
| ## Acceptance evidence | ||
|
|
||
| Exercise the connected disk export and disconnected import procedure once on an | ||
| isolated OpenShift cluster. Record the command output in the PR Test Plan, | ||
| including the cluster and OpenShift version, destination registry, mirrored | ||
| bundle digest, successful CSV/operator/API readiness, and runtime image IDs | ||
| ending in the expected digests. Do not include credentials or Secret values. | ||
|
|
||
| For a repeatable local transfer check, use the containerized oc-mirror runner: | ||
|
|
||
| ```bash | ||
| BUNDLE_IMAGE='quay.io/.../hyperfleet-operator-bundle@sha256:<bundle-digest>' \ | ||
| make test-disconnected-mirror | ||
| ``` | ||
|
|
||
| The runner is built from [`hack/oc-mirror.Dockerfile`](../hack/oc-mirror.Dockerfile) | ||
| and deliberately keeps oc-mirror in a container. This check exercises archive | ||
| transfer only; it is not a cluster installation framework. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| # Standalone registry+v1 fallback. Replace every example with an authenticated | ||
| # released pullspec. additionalImages copies exactly these artifacts; it does | ||
| # not discover bundle relatedImages and does not create an OLM catalog. | ||
| apiVersion: mirror.openshift.io/v2alpha1 | ||
| kind: ImageSetConfiguration | ||
| mirror: | ||
| additionalImages: | ||
| - name: registry.example.com/hyperfleet/hyperfleet-operator-bundle@sha256:0000000000000000000000000000000000000000000000000000000000000000 | ||
| - name: registry.example.com/hyperfleet/hyperfleet-operator@sha256:0000000000000000000000000000000000000000000000000000000000000000 | ||
| - name: registry.example.com/hyperfleet/hyperfleet-api@sha256:0000000000000000000000000000000000000000000000000000000000000000 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| CSV_FILE="${CSV_FILE:-bundle/manifests/hyperfleet-operator.clusterserviceversion.yaml}" | ||
| image="${HYPERFLEET_OPERATOR_IMAGE_PULLSPEC:-}" | ||
| allow_tag=false | ||
|
|
||
| case "${1:-}" in | ||
| "") ;; | ||
| --allow-tag) | ||
| allow_tag=true | ||
| ;; | ||
| *) | ||
| echo "usage: $0 [--allow-tag]" >&2 | ||
| exit 1 | ||
| ;; | ||
| esac | ||
|
|
||
| if [[ "$image" =~ ^[^[:space:]]+@sha256:[0-9a-f]{64}$ ]]; then | ||
| : | ||
| elif [[ "$allow_tag" == true && "$image" =~ ^[^[:space:]@]+:[^[:space:]@/]+$ ]]; then | ||
| : | ||
| else | ||
| if [[ "$allow_tag" == true ]]; then | ||
| echo "error: HYPERFLEET_OPERATOR_IMAGE_PULLSPEC must be a sha256 digest pullspec or tagged pullspec" >&2 | ||
| else | ||
| echo "error: HYPERFLEET_OPERATOR_IMAGE_PULLSPEC must be a sha256 digest pullspec" >&2 | ||
| fi | ||
| exit 1 | ||
| fi | ||
| [[ -f "$CSV_FILE" ]] || { echo "error: CSV not found: $CSV_FILE" >&2; exit 1; } | ||
|
|
||
| # operator-sdk derives operand relatedImages from RELATED_IMAGE_* variables but | ||
| # does not include the manager image itself. Insert that one generated entry | ||
| # without reserializing the whole generated CSV. | ||
| if grep -q '^[[:space:]]*name: hyperfleet-operator$' "$CSV_FILE"; then | ||
| echo "error: CSV already contains a hyperfleet-operator relatedImages entry" >&2 | ||
| exit 1 | ||
| fi | ||
| if [[ "$(grep -c '^ relatedImages:$' "$CSV_FILE")" -ne 1 ]]; then | ||
| echo "error: expected exactly one spec.relatedImages block in $CSV_FILE" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| tmp="$(mktemp "${CSV_FILE}.XXXXXX")" | ||
| trap 'rm -f "$tmp"' EXIT | ||
| awk -v image="$image" ' | ||
| /^ relatedImages:$/ { | ||
| print " - image: " image | ||
| print " name: hyperfleet-operator" | ||
| next | ||
| } | ||
| { print } | ||
| ' "$CSV_FILE" >"$tmp" | ||
| mv "$tmp" "$CSV_FILE" | ||
| trap - EXIT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: openshift-hyperfleet/hyperfleet-operator
Length of output: 13716
Injection (CWE-78): Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
Exploitability: Moderate
Quote and validate Make variables before shell execution.
CONTAINER_TOOLandOC_MIRROR_IMAGEcan be overridden through Make or the environment. Quote their expansions at lines 146 and 150, and validateCONTAINER_TOOLagainst an allowlist. Otherwise, shell metacharacters can execute commands. This is CWE-78.🤖 Prompt for AI Agents
Source: Path instructions