Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .tekton/hyperfleet-operator-bundle-push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ metadata:
pipelinesascode.tekton.dev/max-keep-runs: "3"
pipelinesascode.tekton.dev/on-cel-expression: event == "push" && target_branch
== "main" && ( ".tekton/hyperfleet-operator-bundle-push.yaml".pathChanged() || "bundle.konflux.Dockerfile".pathChanged()
|| "bundle-hack/***".pathChanged() || "bundle/***".pathChanged() )
|| "hack/bundle/***".pathChanged() || "bundle/***".pathChanged() )
labels:
appstudio.openshift.io/application: hyperfleet
appstudio.openshift.io/component: hyperfleet-operator-bundle
Expand Down
5 changes: 4 additions & 1 deletion .tekton/hyperfleet-operator-push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ metadata:
&& !(files.all.all(x,
x.matches('^bundle\\.konflux\\.Dockerfile$')
|| x.matches('^bundle\\.Dockerfile$')
|| x.matches('^bundle-hack/')
|| x.matches('^hack/bundle/')
|| x.matches('^bundle/')
|| x.matches('^hack/test-disconnected-mirror\\.sh$')
|| x.matches('^\\.tekton/hyperfleet-operator-bundle-push\\.yaml$')
))
labels:
Expand All @@ -38,6 +39,8 @@ spec:
value: .
- name: prefetch-input
value: '{"type": "gomod"}'
- name: hermetic
value: "true"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know code rabbit asked for this, its a concern yes, but look all our images don't use hermetic builds, right now its not a requirement for us, and it can have some side effects in konflux.

I would suggest to please our code rabbit overlord, that we create a jira for later on to test and validate hermetic builds, at least we can keep it isolated as we can only test this when it lands on main.

Regardless not a priority right now

pipelineSpec:
description: |
This pipeline is ideal for building container images from a Containerfile while maintaining trust after pipeline customization.
Expand Down
37 changes: 33 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,23 @@ cleanup-test-e2e: ## Tear down the Kind cluster used for e2e tests

##@ Lint

.PHONY: verify-related-images
verify-related-images: ## Verify a final built bundle CSV (CSV_FILE is required).
@test -n "$(CSV_FILE)" || { echo "Set CSV_FILE to the CSV extracted from the built bundle"; exit 1; }
go run ./hack/verify-related-images -csv "$(CSV_FILE)"

.PHONY: lint
lint: ## Run golangci-lint linter
lint: verify-bundle-related-images ## Check bundle image metadata and run golangci-lint.
$(GOLANGCI_LINT) run

.PHONY: verify-bundle-related-images
verify-bundle-related-images: ## Transform the repository bundle CSV and verify its related images.
@set -euo pipefail; \
yq_path=$$($(call gotool,-n yq)); \
YQ="$$yq_path" bash ./hack/verify-bundle-related-images.sh; \
PATH="$$(dirname "$$yq_path"):$$PATH" go test -tags integration ./hack/verify-related-images; \
YQ="$$yq_path" bash ./hack/test-verify-bundle-related-images.sh

.PHONY: lint-fix
lint-fix: ## Run golangci-lint linter and perform fixes
$(GOLANGCI_LINT) run --fix
Expand All @@ -134,6 +147,23 @@ lint-config: ## Verify golangci-lint linter configuration

##@ Build

OC_MIRROR_IMAGE ?= hyperfleet-oc-mirror:local
# Disposable destination registry used only by test-disconnected-mirror to
# simulate the disconnected mirror; it is not the source or production registry.
REGISTRY_IMAGE ?= docker.io/library/registry@sha256:a3d8aaa63ed8681a604f1dea0aa03f100d5895b6a58ace528858a7b332415373

.PHONY: build-oc-mirror-image
build-oc-mirror-image: check-container-tool ## Build the containerized oc-mirror runner.
"$(CONTAINER_TOOL)" build --platform "$(PLATFORM)" -f hack/oc-mirror.Dockerfile -t "$(OC_MIRROR_IMAGE)" .

.PHONY: test-disconnected-mirror
test-disconnected-mirror: build-oc-mirror-image ## Test catalog archive import using a catalog archive (no cluster install).
"$(CONTAINER_TOOL)" pull --platform "$(PLATFORM)" "$(REGISTRY_IMAGE)"
CONTAINER_TOOL="$(CONTAINER_TOOL)" OC_MIRROR_IMAGE="$(OC_MIRROR_IMAGE)" \
CATALOG_IMG="$(CATALOG_IMG)" \
REGISTRY_IMAGE="$(REGISTRY_IMAGE)" REGISTRY_AUTH_FILE="$(REGISTRY_AUTH_FILE)" CONTAINER_DNS="$(CONTAINER_DNS)" MIRROR_PLATFORM="$(PLATFORM)" \
./hack/test-disconnected-mirror.sh

.PHONY: build
build: manifests generate fmt vet ## Build manager binary.
go build -o bin/manager cmd/main.go
Expand Down Expand Up @@ -169,7 +199,7 @@ GIT_DIRTY ?= $(shell [ -z "$$(git status --porcelain 2>/dev/null)" ] || echo "-m

# Go build flags (FIPS compliant)
CGO_ENABLED ?= 1
GOEXPERIMENT ?= boringcrypto
GOEXPERIMENT ?= boringcrypto
GOFLAGS ?= -trimpath
# LDFLAGS := -s -w \
# -X github.com/openshift-hyperfleet/hyperfleet-operator/pkg/version.Version=$(APP_VERSION) \
Expand Down Expand Up @@ -283,7 +313,7 @@ undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/confi
# Generates dist/install.yaml
# Install resources
# kubectl apply -f dist/install.yaml
# Uninstall resources
# Uninstall resources
# kubectl delete -f dist/install.yaml
# For image overrides edit config/manager/kustomization.yaml
.PHONY: build-deployer
Expand Down Expand Up @@ -384,7 +414,6 @@ catalog-build: opm ## Build a catalog image.
catalog-push: ## Push a catalog image.
$(MAKE) docker-push IMG=$(CATALOG_IMG)


##@ Dependencies

## Location to install dependencies to
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ A Kubernetes operator for HyperFleet cluster lifecycle management.

hyperfleet-operator packages and delivers HyperFleet as a standard Kubernetes operator, installed and managed through OLM. It exposes a single cluster-scoped custom resource, `HyperFleetConfig`, as the entire partner-facing surface: install, configure, and observe HyperFleet through that one CR and its status conditions, with everything else the operator manages kept internal.

## Installation guides

- [Developer workflow: operator and bundle images](docs/bundle.md)
- [Disconnected OpenShift installation with oc-mirror v2](docs/disconnected-install.md)

The disconnected workflow mirrors the published catalog. The catalog selects
the OLM bundle and its related images.

## Getting Started

### Prerequisites
Expand Down Expand Up @@ -83,4 +91,3 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

24 changes: 0 additions & 24 deletions bundle-hack/update_bundle.sh

This file was deleted.

18 changes: 13 additions & 5 deletions bundle.konflux.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
# Konflux bundle image build. Unlike the auto-generated bundle.Dockerfile (used
# for local dev with operator-sdk), this runs bundle-hack/update_bundle.sh to
# Konflux bundle image build. Unlike the auto-generated bundle.Dockerfile used
# for local development, this runs hack/bundle/update_bundle.sh to
# patch digest-pinned image references into the CSV at build time.
FROM registry.access.redhat.com/ubi9/ubi-minimal:latest AS builder-runner
ARG TARGETARCH
RUN microdnf install -y tar gzip && \
curl -sL https://github.com/mikefarah/yq/releases/download/v4.44.1/yq_linux_amd64.tar.gz | tar xz && \
mv yq_linux_amd64 /usr/bin/yq
case "${TARGETARCH:-$(uname -m)}" in \
amd64|x86_64) YQ_ARCH=amd64 ;; \
arm64|aarch64) YQ_ARCH=arm64 ;; \
*) echo "Unsupported yq architecture" >&2; exit 1 ;; \
esac && \
curl -fsSLo /tmp/yq.tar.gz "https://github.com/mikefarah/yq/releases/download/v4.44.1/yq_linux_${YQ_ARCH}.tar.gz" && \
tar -xzf /tmp/yq.tar.gz && \
mv "yq_linux_${YQ_ARCH}" /usr/bin/yq && \
rm /tmp/yq.tar.gz

FROM builder-runner AS builder
# Hack to set the operator container image in the deployment
Expand All @@ -15,7 +23,7 @@ ENV HYPERFLEET_OPERATOR_IMAGE_PULLSPEC=${HYPERFLEET_OPERATOR_IMAGE_PULLSPEC}
ARG HYPERFLEET_API_IMAGE_PULLSPEC="quay.io/redhat-services-prod/hyperfleet-tenant/hyperfleet/hyperfleet-api@sha256:99f8cdda580069de21ba0e13b5b171cf82b81b93dc88b12bcaa8294e72e84fc3"
ENV HYPERFLEET_API_IMAGE_PULLSPEC=${HYPERFLEET_API_IMAGE_PULLSPEC}

COPY bundle-hack .
COPY hack/bundle .
Comment thread
kuudori marked this conversation as resolved.
COPY bundle/manifests /manifests/

RUN ./update_bundle.sh
Expand Down
3 changes: 2 additions & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook"

hyperfleetv1alpha1 "github.com/openshift-hyperfleet/hyperfleet-operator/api/v1alpha1"
"github.com/openshift-hyperfleet/hyperfleet-operator/internal/component/api"
"github.com/openshift-hyperfleet/hyperfleet-operator/internal/controller"
// +kubebuilder:scaffold:imports
)
Expand Down Expand Up @@ -235,7 +236,7 @@ func main() {
// it at bundle-build time via the relatedImages convention. Warn — but do not
// fail — when it is unset or uses a mutable tag, so `make run` and tag-based
// deploys keep working while the risk is surfaced in the logs.
apiImage := os.Getenv("RELATED_IMAGE_HYPERFLEET_API")
apiImage := os.Getenv(api.RelatedImageEnv)
switch {
case apiImage == "":
setupLog.Info("RELATED_IMAGE_HYPERFLEET_API not set; falling back to the " +
Expand Down
191 changes: 191 additions & 0 deletions docs/disconnected-install.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# Disconnected installation from a published catalog

This workflow starts with a **published HyperFleet operator catalog**. The
catalog selects the bundles; their published image metadata determines the
operator and operand images to mirror. The CSV in this repository is a
development/build template, not the published bundle manifest.

Catalog publication is a prerequisite owned by the catalog publishing workflow. Obtain
the catalog digest, package, channel, and supported OpenShift/oc-mirror versions
from the catalog publisher. The example below uses package
`hyperfleet-operator` and channel `stable`; confirm these against the published
catalog. A bundle image alone cannot substitute for the catalog.

## 1. Prepare on the connected host

Requirements:

- The publisher-supported oc-mirror v2 binary and source registry credentials.
- A published catalog containing the intended release bundle and its related
images, all accessible to the mirroring account.
- A destination registry reachable by the disconnected cluster and import host.
- An existing OpenShift cluster with OLM and its platform images provisioned for
disconnected operation. Platform mirroring is a separate prerequisite.
- Registry authentication and CA trust configured for the import host and
cluster. Configuring the host alone does not configure cluster image pulls.

Use the same oc-mirror version for export and import. OpenShift 4.17 documents
oc-mirror v2 as Technology Preview; the local
test helper uses 4.18.18. Confirm the supported tool/cluster combination for
your release before customer installation. Use a fresh
workspace to avoid an incremental archive that depends on an earlier transfer:

```bash
export MIRROR_ROOT="$(mktemp -d)"
cp docs/examples/imageset-config-catalog.yaml "$MIRROR_ROOT/imageset-config.yaml"
export REGISTRY_AUTH_FILE='/path/to/source-auth.json'
```

`oc-mirror` requires a containers-style auth file containing inline `auth`
entries. Create the file on the connected host with `skopeo login --authfile
"$REGISTRY_AUTH_FILE" quay.io`, or export an equivalent pull-secret; do not
transfer or commit it.

Replace the catalog placeholder with the published digest and confirm the
package/channel. The example selects the channel head in that immutable catalog
snapshot. Select a publisher-supported version range if you need older bundles
or an upgrade path.

Use `mirror.operators`. Do not enumerate the bundle, operator and API under
`additionalImages`: that bypasses catalog bundle and related-image discovery.
The catalog digest is the only release input to `oc-mirror`; it selects the OLM
bundle and its related images. The repository CSV is not an installation input.
List any dependent operator packages explicitly; `oc-mirror` does not infer
inter-operator dependencies. Do not use `skipDependencies` or blocked-image
filters to suppress required release content.

## 2. Export and transfer

```bash
oc-mirror --v2 --authfile "$REGISTRY_AUTH_FILE" \
--config "$MIRROR_ROOT/imageset-config.yaml" \
file://"$MIRROR_ROOT/archive"
tar -C "$MIRROR_ROOT" -czf /media/transfer/hyperfleet-mirror.tgz \
archive imageset-config.yaml
```

Transfer the complete archive and configuration. Source credentials are not
part of the transfer artifact. Keep the catalog digest, configuration, tool
version and export logs as release evidence.

## 3. Import on the disconnected host

Configure destination authentication and CA trust on this host. Use a fresh
directory and a destination reachable from every cluster node:

```bash
export IMPORT_ROOT="$(mktemp -d)"
tar -C "$IMPORT_ROOT" -xzf /media/transfer/hyperfleet-mirror.tgz
export DESTINATION='mirror.example.com:8443'
export REGISTRY_AUTH_FILE='/path/to/destination-auth.json'
oc-mirror --v2 --authfile "$REGISTRY_AUTH_FILE" \
--config "$IMPORT_ROOT/imageset-config.yaml" \
--from file://"$IMPORT_ROOT/archive" docker://"$DESTINATION"
```

Some registries limit repository nesting. Use `--max-nested-paths` if required
and supported by your selected oc-mirror version. Grant pull access to
the service accounts used by CatalogSource, OLM bundle unpack, manager and
operands, including cross-project access when images live in another project.
The import user's successful push does not grant those workloads pull access.

Apply the generated image-mirror resources and CatalogSource. The generated
file names may vary, so apply every matching IDMS, ITMS, and `cs-*.yaml` file:

```bash
export CLUSTER_RESOURCES="$IMPORT_ROOT/archive/working-dir/cluster-resources"
for manifest in "$CLUSTER_RESOURCES"/idms-*.yaml \
"$CLUSTER_RESOURCES"/itms-*.yaml \
"$CLUSTER_RESOURCES"/cs-*.yaml; do
[ -e "$manifest" ] || continue
oc apply -f "$manifest"
done
oc get catalogsource -n openshift-marketplace
```

Select the OLM v0 CatalogSource resources for this operator, not an OLM v1
ClusterCatalog.

Use the **generated** CatalogSource image reference: filtering can rebuild the
catalog, so its destination digest need not equal the source catalog digest.
Wait for registry configuration rollout and the CatalogSource connection state
to become `READY` before subscribing. Do not proceed on incomplete import or
missing image errors.

## 4. Install through OLM

Public registry access must be unavailable during an isolated acceptance test.
Verify the restriction at the node/container-runtime pull path, not only with
a namespace NetworkPolicy. Use fresh nodes or establish that the tested images
are not already cached; a new namespace alone does not do this. Preserve proof
of the restriction and the resulting mirror pulls.

Create a dedicated
namespace, an all-namespaces OperatorGroup, and a Subscription. Replace the
source name below with `metadata.name` from the generated CatalogSource.

```yaml
apiVersion: v1
kind: Namespace
metadata:
name: hyperfleet-system
---
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: hyperfleet
namespace: hyperfleet-system
spec: {}
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: hyperfleet-operator
namespace: hyperfleet-system
spec:
channel: stable
name: hyperfleet-operator
source: REPLACE_WITH_GENERATED_CATALOGSOURCE_NAME
sourceNamespace: openshift-marketplace
installPlanApproval: Automatic
```

Save the manifest as `hyperfleet-subscription.yaml`, apply it, and wait for OLM
to install the operator:

```bash
oc apply -f hyperfleet-subscription.yaml
oc get installplan,csv -n hyperfleet-system
```

With `installPlanApproval: Automatic`, OLM creates and approves the InstallPlan.
Wait for the installed CSV to reach `Succeeded`; do not hardcode a CSV version
from the development repository. If your cluster requires change control, use a
separate, manual-approval procedure: set `installPlanApproval: Manual`, inspect
the generated InstallPlan and its selected CSV, then approve that specific plan.
The bundle supports `AllNamespaces`; do not add `targetNamespaces` to this
OperatorGroup.

Create a valid HyperFleetConfig and its referenced Secrets, with reachable
database and authentication services as required by that configuration. Confirm
operator and API readiness and inspect pod events for failed pulls. Compare
runtime images with the selected release bundle; multi-architecture image IDs
may identify platform manifests beneath the declared image index.

For the release installed by this guide, provide the database Secret referenced
by `spec.api.database.secretRef.name`; database provisioning is outside this
installation procedure. Its keys are `db.host`, `db.port`, `db.name`, `db.user`
and `db.password`. Consult the API contract and installation documentation
shipped with the selected release for its database requirements.

Do not substitute `operator-sdk run bundle` for this installation path: its
development catalog helpers are not the mirrored release catalog.

Keep a sanitized installation record containing catalog and bundle digests,
package/channel, tool and cluster versions, export/import results, generated
mirror resources, isolation checks, and OLM/operand states. Never include
credentials. Successful archive transfer alone does not establish successful
installation or application readiness.

References: [oc-mirror filtering](https://github.com/openshift/oc-mirror/blob/main/docs/features/filtering.md),
[generated cluster resources](https://github.com/openshift/oc-mirror/blob/main/docs/features/cluster-resources.md).
Loading