diff --git a/.gitignore b/.gitignore index 2b7fe6a..98ff8f9 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ bin/* dist/ _output/ Dockerfile.cross +config/manifests/dev/kustomization.yaml # Test binary, built with `go test -c` *.test diff --git a/.tekton/hyperfleet-operator-bundle-push.yaml b/.tekton/hyperfleet-operator-bundle-push.yaml index b15d97c..2fb99dc 100644 --- a/.tekton/hyperfleet-operator-bundle-push.yaml +++ b/.tekton/hyperfleet-operator-bundle-push.yaml @@ -8,8 +8,10 @@ metadata: pipelinesascode.tekton.dev/cancel-in-progress: "false" 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() - || "hack/bundle/***".pathChanged() || "bundle/***".pathChanged() ) + == "main" && + (".tekton/hyperfleet-operator-bundle-push.yaml".pathChanged() || + "bundle.Dockerfile".pathChanged() || + "config/***".pathChanged()) labels: appstudio.openshift.io/application: hyperfleet appstudio.openshift.io/component: hyperfleet-operator-bundle @@ -25,7 +27,7 @@ spec: - name: output-image value: quay.io/redhat-user-workloads/hyperfleet-tenant/hyperfleet/hyperfleet-operator-bundle:{{revision}} - name: dockerfile - value: ./bundle.konflux.Dockerfile + value: ./bundle.Dockerfile - name: path-context value: . pipelineSpec: @@ -223,6 +225,7 @@ spec: - name: BUILD_ARGS value: - $(params.build-args[*]) + - KUSTOMIZE_VARIANT=config/manifests/prod/kustomization.yaml - name: BUILD_ARGS_FILE value: $(params.build-args-file) - name: PRIVILEGED_NESTED diff --git a/.tekton/hyperfleet-operator-push.yaml b/.tekton/hyperfleet-operator-push.yaml index 72f8056..2cc9a57 100644 --- a/.tekton/hyperfleet-operator-push.yaml +++ b/.tekton/hyperfleet-operator-push.yaml @@ -2,7 +2,7 @@ apiVersion: tekton.dev/v1 kind: PipelineRun metadata: annotations: - build.appstudio.openshift.io/build-nudge-files: bundle.konflux.Dockerfile + build.appstudio.openshift.io/build-nudge-files: config/manager/prod/kustomization.yaml build.appstudio.openshift.io/repo: https://github.com/openshift-hyperfleet/hyperfleet-operator?rev={{revision}} build.appstudio.redhat.com/commit_sha: '{{revision}}' build.appstudio.redhat.com/target_branch: '{{target_branch}}' @@ -12,10 +12,8 @@ metadata: event == "push" && target_branch == "main" && !(files.all.all(x, - x.matches('^bundle\\.konflux\\.Dockerfile$') - || x.matches('^bundle\\.Dockerfile$') - || x.matches('^hack/bundle/') - || x.matches('^bundle/') + x.matches('^bundle\\.Dockerfile$') + || x.matches('^config/manifests/prod/') || x.matches('^hack/test-disconnected-mirror\\.sh$') || x.matches('^\\.tekton/hyperfleet-operator-bundle-push\\.yaml$') )) diff --git a/Makefile b/Makefile index f4b154d..28b6051 100644 --- a/Makefile +++ b/Makefile @@ -188,6 +188,9 @@ IMG_REGISTRY ?= quay.io/$(QUAY_REPO) IMG_NAME ?= hyperfleet-operator IMG_TAG ?= $(APP_VERSION) OPERATOR_IMG ?= $(IMG_REGISTRY)/$(IMG_NAME):$(IMG_TAG) +export RELATED_IMAGE_HYPERFLEET_OPERATOR ?= $(OPERATOR_IMG) +export RELATED_IMAGE_HYPERFLEET_API ?= quay.io/redhat-services-prod/hyperfleet-tenant/hyperfleet/hyperfleet-api:latest + # Base image for production builds - matches Dockerfile default # Override with DEV_BASE_IMAGE for dev builds (see image-dev target) BASE_IMAGE ?= registry.access.redhat.com/ubi9-micro:latest @@ -282,23 +285,16 @@ undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/confi # Non-olm installs # Generates dist/install.yaml -# Install resources -# kubectl apply -f dist/install.yaml -# Uninstall resources -# kubectl delete -f dist/install.yaml -# For image overrides edit config/manager/kustomization.yaml +# Install resources: kubectl apply -f dist/install.yaml +# Uninstall resources: kubectl delete -f dist/install.yaml +# Override images via env vars: +# make build-deployer RELATED_IMAGE_HYPERFLEET_OPERATOR= RELATED_IMAGE_HYPERFLEET_API= + .PHONY: build-deployer build-deployer: manifests generate ## Generate a consolidated YAML with CRDs and deployment. @mkdir -p dist - @$(KUSTOMIZE) build config/default > dist/install.yaml + @$(KUSTOMIZE) build config/default | envsubst > dist/install.yaml -.PHONY: build-deployer-override-img -build-deployer-override-img: manifests generate ## Generate deployer with IMG override, then restore kustomization.yaml - @mkdir -p dist - cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) - @$(KUSTOMIZE) build config/default > dist/install.yaml - @echo "Deployer generated with IMG=$(IMG)" - @echo "Note: config/manager/kustomization.yaml has been modified. Commit or reset as needed." # For now `stable` channel is the default and only channel # CHANNELS define the bundle channels used in the bundle. @@ -350,24 +346,21 @@ ifneq ($(origin CATALOG_BASE_IMG), undefined) FROM_INDEX_OPT := --from-index $(CATALOG_BASE_IMG) endif -.PHONY: bundle -bundle: manifests operator-sdk ## 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) - $(OPERATOR_SDK) bundle validate ./bundle - -.PHONY: bundle-override-img -bundle-override-img: manifests operator-sdk ## Generate bundle with IMG override, then restore kustomization.yaml - $(OPERATOR_SDK) generate kustomize manifests -q - cd config/manager && $(KUSTOMIZE) edit set image controller=$(OPERATOR_IMG) - $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS) - $(OPERATOR_SDK) bundle validate ./bundle - @echo "Bundle generated with $(OPERATOR_IMG)" - @echo "Note: config/manager/kustomization.yaml has been modified. Commit or reset as needed." - +# Substitutes RELATED_IMAGE_* env vars into patch-images.yaml via envsubst, +# then builds the bundle image. This mirrors the Konflux pipeline bundle build. +# To override the operator and API images: +# make bundle-build RELATED_IMAGE_HYPERFLEET_OPERATOR= RELATED_IMAGE_HYPERFLEET_API= +KUSTOMIZE_VARIANT ?= config/manifests/dev .PHONY: bundle-build -bundle-build: ## Build the bundle image. - $(CONTAINER_TOOL) build --platform=$(PLATFORM) -f bundle.Dockerfile -t $(BUNDLE_IMG) . +bundle-build: ## Builds the bundle and bundle image. + cat config/manifests/dev/patch-images.yaml | envsubst > config/manifests/dev/kustomization.yaml + $(CONTAINER_TOOL) build -f bundle.Dockerfile \ + --platform $(PLATFORM) \ + --build-arg VERSION=$(VERSION) \ + --build-arg CHANNELS=$(CHANNELS) \ + --build-arg KUSTOMIZE_VARIANT=$(KUSTOMIZE_VARIANT) \ + --build-arg APP_VERSION=$(APP_VERSION) \ + -t $(BUNDLE_IMG) . .PHONY: bundle-push bundle-push: check-container-tool ## Push bundle image to registry diff --git a/bundle.Dockerfile b/bundle.Dockerfile index ed59506..1631420 100644 --- a/bundle.Dockerfile +++ b/bundle.Dockerfile @@ -1,4 +1,25 @@ -FROM scratch +FROM registry.redhat.io/openshift4/ose-cli-rhel9:v4.18 AS kustomize + +COPY config/ /workdir/config/ + +# Specify the kustomize variant, either bases/kustomization.yaml or prod/kustomization.yaml +# prod/kustomization.yaml gets image update references from konflux. +ARG KUSTOMIZE_VARIANT=config/manifests/dev +# ARG KUSTOMIZE_VARIANT=config/manifests/prod for konflux builds +RUN oc kustomize /workdir/${KUSTOMIZE_VARIANT} > /workdir/manifests.yaml + +FROM registry.redhat.io/openshift4/ose-operator-sdk-rhel9:v4.18 AS operator +WORKDIR /workdir +COPY --from=kustomize /workdir/manifests.yaml /workdir/manifests.yaml +ARG CHANNELS=stable +ARG VERSION=0.0.1 +RUN mkdir -p /workdir/bundle +RUN cat manifests.yaml | operator-sdk generate bundle -q --version ${VERSION} \ + --channels=${CHANNELS} --default-channel=stable \ + --package=hyperfleet-operator && \ + operator-sdk bundle validate ./bundle + +FROM alpine # Core bundle labels. LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 @@ -15,7 +36,20 @@ LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v4 LABEL operators.operatorframework.io.test.mediatype.v1=scorecard+v1 LABEL operators.operatorframework.io.test.config.v1=tests/scorecard/ -# Copy files to locations specified by labels. -COPY bundle/manifests /manifests/ -COPY bundle/metadata /metadata/ -COPY bundle/tests/scorecard /tests/scorecard/ +# Copy patched manifests from builder, metadata and tests from source. +COPY --from=operator /workdir/bundle/manifests /manifests/ +COPY --from=operator /workdir/bundle/metadata /metadata/ +COPY --from=operator /workdir/bundle/tests/scorecard /tests/scorecard/ + +ARG APP_VERSION="0.0.0-dev" +LABEL name="hyperfleet-operator-bundle" \ + vendor="Red Hat, Inc." \ + version="${APP_VERSION}" \ + summary="OLM bundle for the HyperFleet Operator" \ + description="OLM bundle for the HyperFleet Operator, which installs and manages HyperFleet." \ + com.redhat.component="hyperfleet-operator-bundle-container" \ + io.k8s.description="OLM bundle for the HyperFleet Operator, which installs and manages HyperFleet." \ + distribution-scope="public" \ + release="1" \ + url="https://github.com/openshift-hyperfleet/hyperfleet-operator" \ + maintainer="Red Hat HyperFleet Team" \ No newline at end of file diff --git a/bundle.konflux.Dockerfile b/bundle.konflux.Dockerfile deleted file mode 100644 index f7c1cea..0000000 --- a/bundle.konflux.Dockerfile +++ /dev/null @@ -1,59 +0,0 @@ -# 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 -RUN microdnf install -y tar gzip && \ - curl -fsSLo /tmp/yq.tar.gz https://github.com/mikefarah/yq/releases/download/v4.44.1/yq_linux_amd64.tar.gz && \ - tar -xzf /tmp/yq.tar.gz && \ - mv yq_linux_amd64 /usr/bin/yq && \ - rm /tmp/yq.tar.gz - -FROM builder-runner AS builder -# Hack to set the operator container image in the deployment -# Konflux nudges update these variables with the latest digest-pinned pullspecs. -ARG HYPERFLEET_OPERATOR_IMAGE_PULLSPEC="quay.io/redhat-services-prod/hyperfleet-tenant/hyperfleet/hyperfleet-operator@sha256:b7803da7d6931296024354f353a61cae275936717ae07dfdb46fe86cee47362b" -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:7ed75c76344501769c0b843dcfc85d7a8eb3898401fb335e126fede0cb1abe90" -ENV HYPERFLEET_API_IMAGE_PULLSPEC=${HYPERFLEET_API_IMAGE_PULLSPEC} - -COPY hack/bundle . -COPY bundle/manifests /manifests/ - -RUN ./update_bundle.sh - -FROM scratch - -# Core bundle labels. -LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 -LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ -LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ -LABEL operators.operatorframework.io.bundle.package.v1=hyperfleet-operator -LABEL operators.operatorframework.io.bundle.channels.v1=stable -LABEL operators.operatorframework.io.bundle.channel.default.v1=stable -LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.42.3 -LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 -LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v4 - -# Labels for testing. -LABEL operators.operatorframework.io.test.mediatype.v1=scorecard+v1 -LABEL operators.operatorframework.io.test.config.v1=tests/scorecard/ - -# Copy patched manifests from builder, metadata and tests from source. -COPY --from=builder /manifests /manifests/ -COPY bundle/metadata /metadata/ -COPY bundle/tests/scorecard /tests/scorecard/ - - -ARG APP_VERSION="0.0.0-dev" -LABEL name="hyperfleet-operator-bundle" \ - vendor="Red Hat, Inc." \ - version="${APP_VERSION}" \ - summary="OLM bundle for the HyperFleet Operator" \ - description="OLM bundle for the HyperFleet Operator, which installs and manages HyperFleet." \ - com.redhat.component="hyperfleet-operator-bundle-container" \ - io.k8s.description="OLM bundle for the HyperFleet Operator, which installs and manages HyperFleet." \ - distribution-scope="public" \ - release="1" \ - url="https://github.com/openshift-hyperfleet/hyperfleet-operator" \ - maintainer="Red Hat HyperFleet Team" diff --git a/bundle/manifests/hyperfleet-operator-controller-manager-metrics-service_v1_service.yaml b/bundle/manifests/hyperfleet-operator-controller-manager-metrics-service_v1_service.yaml deleted file mode 100644 index 74029b9..0000000 --- a/bundle/manifests/hyperfleet-operator-controller-manager-metrics-service_v1_service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - creationTimestamp: null - labels: - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: hyperfleet-operator - control-plane: controller-manager - name: hyperfleet-operator-controller-manager-metrics-service -spec: - ports: - - name: metrics - port: 9090 - protocol: TCP - targetPort: metrics - selector: - app.kubernetes.io/name: hyperfleet-operator - control-plane: controller-manager -status: - loadBalancer: {} diff --git a/bundle/manifests/hyperfleet-operator-hyperfleetconfig-admin-role_rbac.authorization.k8s.io_v1_clusterrole.yaml b/bundle/manifests/hyperfleet-operator-hyperfleetconfig-admin-role_rbac.authorization.k8s.io_v1_clusterrole.yaml deleted file mode 100644 index 99652ea..0000000 --- a/bundle/manifests/hyperfleet-operator-hyperfleetconfig-admin-role_rbac.authorization.k8s.io_v1_clusterrole.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - labels: - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: hyperfleet-operator - name: hyperfleet-operator-hyperfleetconfig-admin-role -rules: -- apiGroups: - - hyperfleet.redhat.com - resources: - - hyperfleetconfigs - verbs: - - '*' -- apiGroups: - - hyperfleet.redhat.com - resources: - - hyperfleetconfigs/status - verbs: - - get diff --git a/bundle/manifests/hyperfleet-operator-hyperfleetconfig-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml b/bundle/manifests/hyperfleet-operator-hyperfleetconfig-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml deleted file mode 100644 index 9ffd846..0000000 --- a/bundle/manifests/hyperfleet-operator-hyperfleetconfig-editor-role_rbac.authorization.k8s.io_v1_clusterrole.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - labels: - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: hyperfleet-operator - name: hyperfleet-operator-hyperfleetconfig-editor-role -rules: -- apiGroups: - - hyperfleet.redhat.com - resources: - - hyperfleetconfigs - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - hyperfleet.redhat.com - resources: - - hyperfleetconfigs/status - verbs: - - get diff --git a/bundle/manifests/hyperfleet-operator-hyperfleetconfig-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml b/bundle/manifests/hyperfleet-operator-hyperfleetconfig-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml deleted file mode 100644 index cf45968..0000000 --- a/bundle/manifests/hyperfleet-operator-hyperfleetconfig-viewer-role_rbac.authorization.k8s.io_v1_clusterrole.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - labels: - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: hyperfleet-operator - name: hyperfleet-operator-hyperfleetconfig-viewer-role -rules: -- apiGroups: - - hyperfleet.redhat.com - resources: - - hyperfleetconfigs - verbs: - - get - - list - - watch -- apiGroups: - - hyperfleet.redhat.com - resources: - - hyperfleetconfigs/status - verbs: - - get diff --git a/bundle/manifests/hyperfleet-operator-metrics-reader_rbac.authorization.k8s.io_v1_clusterrole.yaml b/bundle/manifests/hyperfleet-operator-metrics-reader_rbac.authorization.k8s.io_v1_clusterrole.yaml deleted file mode 100644 index 4450500..0000000 --- a/bundle/manifests/hyperfleet-operator-metrics-reader_rbac.authorization.k8s.io_v1_clusterrole.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - labels: - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: hyperfleet-operator - name: hyperfleet-operator-metrics-reader -rules: -- nonResourceURLs: - - /metrics - verbs: - - get diff --git a/bundle/manifests/hyperfleet-operator.clusterserviceversion.yaml b/bundle/manifests/hyperfleet-operator.clusterserviceversion.yaml deleted file mode 100644 index ec11be7..0000000 --- a/bundle/manifests/hyperfleet-operator.clusterserviceversion.yaml +++ /dev/null @@ -1,314 +0,0 @@ -apiVersion: operators.coreos.com/v1alpha1 -kind: ClusterServiceVersion -metadata: - annotations: - alm-examples: |- - [ - { - "apiVersion": "hyperfleet.redhat.com/v1alpha1", - "kind": "HyperFleetConfig", - "metadata": { - "labels": { - "app.kubernetes.io/managed-by": "kustomize", - "app.kubernetes.io/name": "hyperfleet-operator" - }, - "name": "cluster" - }, - "spec": { - "api": { - "auth": { - "audience": "hyperfleet-api", - "enabled": true, - "issuer": "https://issuer.example.com" - }, - "database": { - "secretRef": { - "name": "hyperfleet-db" - } - }, - "profile": "small" - }, - "bundle": "cloud-capi" - } - } - ] - capabilities: Basic Install - createdAt: "2026-09-04T09:48:43Z" - features.operators.openshift.io/disconnected: "true" - features.operators.openshift.io/fips-compliant: "false" - features.operators.openshift.io/proxy-aware: "false" - features.operators.openshift.io/tls-profiles: "false" - features.operators.openshift.io/token-auth-aws: "false" - features.operators.openshift.io/token-auth-azure: "false" - features.operators.openshift.io/token-auth-gcp: "false" - operators.openshift.io/valid-subscription: '["OpenShift Container Platform"]' - operators.operatorframework.io/builder: operator-sdk-v1.42.3 - operators.operatorframework.io/project_layout: go.kubebuilder.io/v4 - name: hyperfleet-operator.v0.0.1 - namespace: placeholder -spec: - apiservicedefinitions: {} - customresourcedefinitions: - owned: - - description: |- - HyperFleetConfig is the Schema for the hyperfleetconfigs API. It is a - cluster-scoped singleton: exactly one instance, named "cluster", is permitted. - displayName: Hyper Fleet Config - kind: HyperFleetConfig - name: hyperfleetconfigs.hyperfleet.redhat.com - version: v1alpha1 - description: |- - Delivers HyperFleet as a standard Kubernetes operator, installed and - managed through OLM. It exposes a single cluster-scoped CR: HyperFleetConfig. - displayName: HyperFleet Operator - icon: - - base64data: "" - mediatype: "" - install: - spec: - clusterPermissions: - - rules: - - apiGroups: - - "" - resources: - - configmaps - - serviceaccounts - - services - verbs: - - create - - get - - list - - patch - - update - - watch - - apiGroups: - - apps - resources: - - deployments - verbs: - - create - - get - - list - - patch - - update - - watch - - apiGroups: - - hyperfleet.redhat.com - resources: - - hyperfleetconfigs - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - hyperfleet.redhat.com - resources: - - hyperfleetconfigs/finalizers - verbs: - - update - - apiGroups: - - hyperfleet.redhat.com - resources: - - hyperfleetconfigs/status - verbs: - - get - - patch - - update - - apiGroups: - - rbac.authorization.k8s.io - resources: - - rolebindings - - roles - verbs: - - create - - get - - list - - patch - - update - - watch - - apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create - - apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create - serviceAccountName: hyperfleet-operator-controller-manager - deployments: - - label: - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: hyperfleet-operator - control-plane: controller-manager - name: hyperfleet-operator-controller-manager - spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: hyperfleet-operator - control-plane: controller-manager - strategy: {} - template: - metadata: - annotations: - kubectl.kubernetes.io/default-container: manager - labels: - app.kubernetes.io/name: hyperfleet-operator - control-plane: controller-manager - spec: - containers: - - args: - - --leader-elect - - --health-probe-bind-address=:8080 - - --metrics-bind-address=:9090 - - --metrics-secure=false - command: - - /manager - env: - - name: OPERATOR_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: RELATED_IMAGE_HYPERFLEET_API - value: quay.io/redhat-services-prod/hyperfleet-tenant/hyperfleet/hyperfleet-api:latest - image: quay.io/redhat-services-prod/hyperfleet-tenant/hyperfleet/hyperfleet-operator:latest - livenessProbe: - failureThreshold: 3 - httpGet: - path: /healthz - port: 8080 - initialDelaySeconds: 15 - periodSeconds: 20 - timeoutSeconds: 5 - name: manager - ports: - - containerPort: 9090 - name: metrics - protocol: TCP - - containerPort: 8080 - name: health - protocol: TCP - readinessProbe: - failureThreshold: 3 - httpGet: - path: /readyz - port: 8080 - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 3 - resources: - limits: - cpu: 500m - memory: 128Mi - requests: - cpu: 10m - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - securityContext: - runAsNonRoot: true - seccompProfile: - type: RuntimeDefault - serviceAccountName: hyperfleet-operator-controller-manager - terminationGracePeriodSeconds: 30 - permissions: - - rules: - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - apiGroups: - - "" - resources: - - secrets - verbs: - - get - - list - - watch - - apiGroups: - - monitoring.coreos.com - resources: - - servicemonitors - verbs: - - create - - get - - list - - patch - - update - - watch - - apiGroups: - - networking.k8s.io - resources: - - networkpolicies - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - serviceAccountName: hyperfleet-operator-controller-manager - strategy: deployment - installModes: - - supported: false - type: OwnNamespace - - supported: false - type: SingleNamespace - - supported: false - type: MultiNamespace - - supported: true - type: AllNamespaces - keywords: - - hyperfleet - - cluster-management - - multicluster - links: - - name: HyperFleet Operator - url: https://github.com/openshift-hyperfleet/hyperfleet-operator - minKubeVersion: 1.27.0 - provider: - name: Red Hat - url: https://github.com/openshift-hyperfleet - relatedImages: - - image: quay.io/redhat-services-prod/hyperfleet-tenant/hyperfleet/hyperfleet-api:latest - name: hyperfleet-api - version: 0.0.1 diff --git a/bundle/manifests/hyperfleet.redhat.com_hyperfleetconfigs.yaml b/bundle/manifests/hyperfleet.redhat.com_hyperfleetconfigs.yaml deleted file mode 100644 index 18a37a1..0000000 --- a/bundle/manifests/hyperfleet.redhat.com_hyperfleetconfigs.yaml +++ /dev/null @@ -1,304 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.21.0 - creationTimestamp: null - labels: - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: hyperfleet-operator - name: hyperfleetconfigs.hyperfleet.redhat.com -spec: - group: hyperfleet.redhat.com - names: - kind: HyperFleetConfig - listKind: HyperFleetConfigList - plural: hyperfleetconfigs - shortNames: - - hfc - singular: hyperfleetconfig - scope: Cluster - versions: - - additionalPrinterColumns: - - jsonPath: .spec.bundle - name: Bundle - type: string - - jsonPath: .spec.api.profile - name: Profile - type: string - - jsonPath: .status.conditions[?(@.type=="Available")].status - name: Available - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: |- - HyperFleetConfig is the Schema for the hyperfleetconfigs API. It is a - cluster-scoped singleton: exactly one instance, named "cluster", is permitted. - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: |- - HyperFleetConfigSpec defines the desired state of HyperFleetConfig. It captures - partner intent only; internal machinery (broker, adapters, sentinel) is never - expressed here. - properties: - api: - description: api is the partner-facing configuration for the HyperFleet - API component. - properties: - auth: - description: auth configures partner-facing JWT authentication - intent. - properties: - audience: - description: |- - audience is the token audience the API requires. Required and non-empty - when enabled is true. - maxLength: 253 - minLength: 1 - type: string - enabled: - default: true - description: |- - enabled turns JWT authentication on for the API endpoint. It defaults to - true, so a config that omits it gets authentication ON. It is a pointer to - distinguish "unset" (apply the default, true) from an explicit false - (disable auth), which a non-pointer bool cannot express: with omitempty a - plain false is dropped and re-defaulted to true, so auth could never be - turned off via the typed client; without omitempty an unset field serializes - as false and suppresses the default. Only *bool avoids both traps. - type: boolean - issuer: - description: |- - issuer is the OIDC issuer URL that mints accepted tokens. Required when - enabled is true. Whenever it is set (regardless of enabled) it must be a - valid https URL with a host, so a malformed issuer is rejected at admission - rather than surfacing later at token-validation time. - maxLength: 2048 - minLength: 1 - type: string - x-kubernetes-validations: - - message: issuer must be a valid https URL - rule: isURL(self) && url(self).getScheme() == 'https' && - url(self).getHostname() != '' - jwkCertSecretRef: - description: |- - jwkCertSecretRef optionally references a Secret holding the JWKS document, - for air-gapped or private environments where the API cannot reach a JWKS - URL. The Secret must provide the key "jwks.json" containing a JSON Web Key - Set (the format the API parses; see HYPERFLEET-1408). When unset, the - operator derives the JWKS URL from the issuer via OIDC discovery - ({issuer}/.well-known/openid-configuration → jwks_uri). - properties: - name: - description: |- - name is the name of the Secret in the operator's namespace. It must be a - valid DNS-1123 subdomain, matching what k8s.io/apimachinery/pkg/util/validation - enforces for Secret names (IsDNS1123Subdomain, max length 253), so an - unresolvable reference is rejected at admission rather than failing opaquely - when the reference is later resolved. - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - type: object - x-kubernetes-validations: - - message: issuer and audience are required when auth is enabled - rule: '!self.enabled || (has(self.issuer) && has(self.audience))' - database: - description: database configures the external PostgreSQL connection. - properties: - secretRef: - description: |- - secretRef references a Secret holding the database connection credentials. - The Secret must provide the keys db.host, db.port, db.name, db.user and - db.password. - properties: - name: - description: |- - name is the name of the Secret in the operator's namespace. It must be a - valid DNS-1123 subdomain, matching what k8s.io/apimachinery/pkg/util/validation - enforces for Secret names (IsDNS1123Subdomain, max length 253), so an - unresolvable reference is rejected at admission rather than failing opaquely - when the reference is later resolved. - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - secretRef - type: object - profile: - default: small - description: profile selects a sizing profile for the API. Defaults - to "small". - enum: - - small - - medium - - large - type: string - tls: - description: |- - tls optionally configures TLS for the API endpoint. When omitted, the - operator applies its default serving configuration. - properties: - secretRef: - description: |- - secretRef references a kubernetes.io/tls Secret (providing tls.crt and - tls.key) used to serve the API endpoint. - properties: - name: - description: |- - name is the name of the Secret in the operator's namespace. It must be a - valid DNS-1123 subdomain, matching what k8s.io/apimachinery/pkg/util/validation - enforces for Secret names (IsDNS1123Subdomain, max length 253), so an - unresolvable reference is rejected at admission rather than failing opaquely - when the reference is later resolved. - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - secretRef - type: object - required: - - auth - - database - type: object - bundle: - description: |- - bundle selects one of the operator-internal bundle definitions. It is - immutable after creation: switching deployments requires recreating the - resource. - enum: - - cloud-capi - - onprem-agent - type: string - x-kubernetes-validations: - - message: bundle is immutable - rule: self == oldSelf - required: - - api - - bundle - type: object - status: - description: |- - HyperFleetConfigStatus defines the observed state of HyperFleetConfig. It is - populated by the bundle controller in later stories; this story defines the - schema only. - properties: - conditions: - description: |- - conditions represent the current installation health of the operand. - Recognized types are Available, Progressing and Degraded. - items: - description: Condition contains details for one aspect of the current - state of this API Resource. - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - observedGeneration: - description: observedGeneration is the .metadata.generation the operator - last acted on. - format: int64 - minimum: 0 - type: integer - type: object - required: - - spec - type: object - x-kubernetes-validations: - - message: the only permitted name is 'cluster'; HyperFleetConfig is a cluster-scoped - singleton - rule: self.metadata.name == 'cluster' - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: null - storedVersions: null diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml deleted file mode 100644 index d1973b6..0000000 --- a/bundle/metadata/annotations.yaml +++ /dev/null @@ -1,15 +0,0 @@ -annotations: - # Core bundle annotations. - operators.operatorframework.io.bundle.mediatype.v1: registry+v1 - operators.operatorframework.io.bundle.manifests.v1: manifests/ - operators.operatorframework.io.bundle.metadata.v1: metadata/ - operators.operatorframework.io.bundle.package.v1: hyperfleet-operator - operators.operatorframework.io.bundle.channels.v1: stable - operators.operatorframework.io.bundle.channel.default.v1: stable - operators.operatorframework.io.metrics.builder: operator-sdk-v1.42.3 - operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 - operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v4 - - # Annotations for testing. - operators.operatorframework.io.test.mediatype.v1: scorecard+v1 - operators.operatorframework.io.test.config.v1: tests/scorecard/ diff --git a/bundle/tests/scorecard/config.yaml b/bundle/tests/scorecard/config.yaml deleted file mode 100644 index b2761e6..0000000 --- a/bundle/tests/scorecard/config.yaml +++ /dev/null @@ -1,70 +0,0 @@ -apiVersion: scorecard.operatorframework.io/v1alpha3 -kind: Configuration -metadata: - name: config -stages: -- parallel: true - tests: - - entrypoint: - - scorecard-test - - basic-check-spec - image: quay.io/operator-framework/scorecard-test:v1.42.3 - labels: - suite: basic - test: basic-check-spec-test - storage: - spec: - mountPath: {} - - entrypoint: - - scorecard-test - - olm-bundle-validation - image: quay.io/operator-framework/scorecard-test:v1.42.3 - labels: - suite: olm - test: olm-bundle-validation-test - storage: - spec: - mountPath: {} - - entrypoint: - - scorecard-test - - olm-crds-have-validation - image: quay.io/operator-framework/scorecard-test:v1.42.3 - labels: - suite: olm - test: olm-crds-have-validation-test - storage: - spec: - mountPath: {} - - entrypoint: - - scorecard-test - - olm-crds-have-resources - image: quay.io/operator-framework/scorecard-test:v1.42.3 - labels: - suite: olm - test: olm-crds-have-resources-test - storage: - spec: - mountPath: {} - - entrypoint: - - scorecard-test - - olm-spec-descriptors - image: quay.io/operator-framework/scorecard-test:v1.42.3 - labels: - suite: olm - test: olm-spec-descriptors-test - storage: - spec: - mountPath: {} - - entrypoint: - - scorecard-test - - olm-status-descriptors - image: quay.io/operator-framework/scorecard-test:v1.42.3 - labels: - suite: olm - test: olm-status-descriptors-test - storage: - spec: - mountPath: {} -storage: - spec: - mountPath: {} diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 93a768e..a0bdf69 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -4,37 +4,24 @@ kind: Kustomization resources: - manager.yaml -# Base image configuration for local development -# For production/Konflux builds, digest-pinned images are set via bundle.konflux.Dockerfile ARG overrides -# -# Local development override: -# make bundle-override-img IMG=quay.io//hyperfleet-operator:dev- -# make build-deployer-override-img IMG=quay.io//hyperfleet-operator:dev- -# -# NOTE: These commands modify this file in place. Restore before committing: -# git checkout config/manager/kustomization.yaml -images: -- name: controller - newName: quay.io/redhat-services-prod/hyperfleet-tenant/hyperfleet/hyperfleet-operator - newTag: latest - -# RELATED_IMAGE_HYPERFLEET_API environment variable -# Sets the image used for the API operand. -# -# IMPORTANT: Must stay in sync with api.DefaultImage in the operator code -# (v0.4.0+: config schema compatibility plus HYPERFLEET-1603 database *_FILE support) -# -# For local development with a custom API image, manually edit the value below -# or use yq to update programmatically, then restore before committing. -# -# Production/Konflux: Digest-pinned via bundle.konflux.Dockerfile ARG overrides +# These values are overridden with: +# `make build-deployer RELATED_IMAGE_HYPERFLEET_API=.. RELATED_IMAGE_HYPERFLEET_OPERATOR=...` +# Or images can be set overridden here by modifying the image values patches: - patch: |- - op: add path: /spec/template/spec/containers/0/env/- value: name: RELATED_IMAGE_HYPERFLEET_API - value: quay.io/redhat-services-prod/hyperfleet-tenant/hyperfleet/hyperfleet-api:latest + value: ${RELATED_IMAGE_HYPERFLEET_API} + - op: add + path: /spec/template/spec/containers/0/env/- + value: + name: RELATED_IMAGE_HYPERFLEET_OPERATOR + value: ${RELATED_IMAGE_HYPERFLEET_OPERATOR} + - op: replace + path: /spec/template/spec/containers/0/image + value: ${RELATED_IMAGE_HYPERFLEET_OPERATOR} target: kind: Deployment name: controller-manager diff --git a/config/manifests/kustomization.yaml b/config/manifests/bases/kustomization.yaml similarity index 94% rename from config/manifests/kustomization.yaml rename to config/manifests/bases/kustomization.yaml index 29fe55f..6a7f64a 100644 --- a/config/manifests/kustomization.yaml +++ b/config/manifests/bases/kustomization.yaml @@ -1,10 +1,10 @@ # These resources constitute the fully configured set of manifests # used to generate the 'manifests/' directory in a bundle. resources: -- bases/hyperfleet-operator.clusterserviceversion.yaml -- ../default -- ../samples -- ../scorecard +- hyperfleet-operator.clusterserviceversion.yaml +- ../../default +- ../../samples +- ../../scorecard # The Prometheus ServiceMonitor is deliberately NOT included in the bundle. OLM # applies a bundle's arbitrary manifests but does not install the CRDs they need, # so bundling the ServiceMonitor would fail the InstallPlan — and block the whole diff --git a/config/manifests/dev/patch-images.yaml b/config/manifests/dev/patch-images.yaml new file mode 100644 index 0000000..2ebc30e --- /dev/null +++ b/config/manifests/dev/patch-images.yaml @@ -0,0 +1,20 @@ +resources: +- ../bases/ +patches: +- patch: |- + - op: replace + path: /spec/template/spec/containers/0/env/1 + value: + name: RELATED_IMAGE_HYPERFLEET_API + value: ${RELATED_IMAGE_HYPERFLEET_API} + - op: replace + path: /spec/template/spec/containers/0/env/2 + value: + name: RELATED_IMAGE_HYPERFLEET_OPERATOR + value: ${RELATED_IMAGE_HYPERFLEET_OPERATOR} + - op: replace + path: /spec/template/spec/containers/0/image + value: ${RELATED_IMAGE_HYPERFLEET_OPERATOR} + target: + kind: Deployment + name: controller-manager \ No newline at end of file diff --git a/config/manifests/prod/kustomization.yaml b/config/manifests/prod/kustomization.yaml new file mode 100644 index 0000000..13c3bc5 --- /dev/null +++ b/config/manifests/prod/kustomization.yaml @@ -0,0 +1,20 @@ +resources: +- ../bases/ +patches: +- patch: |- + - op: replace + path: /spec/template/spec/containers/0/env/1 + value: + name: RELATED_IMAGE_HYPERFLEET_API + value: quay.io/redhat-services-prod/hyperfleet-tenant/hyperfleet/hyperfleet-api@sha256:99f8cdda580069de21ba0e13b5b171cf82b81b93dc88b12bcaa8294e72e84fc3 + - op: replace + path: /spec/template/spec/containers/0/env/2 + value: + name: RELATED_IMAGE_HYPERFLEET_OPERATOR + value: quay.io/redhat-services-prod/hyperfleet-tenant/hyperfleet/hyperfleet-operator@sha256:3e8610721d3495d08b7394d7cd4879eb594596e32f2897c50a0f99665846d9c9 + - op: replace + path: /spec/template/spec/containers/0/image + value: quay.io/redhat-services-prod/hyperfleet-tenant/hyperfleet/hyperfleet-operator@sha256:3e8610721d3495d08b7394d7cd4879eb594596e32f2897c50a0f99665846d9c9 + target: + kind: Deployment + name: controller-manager \ No newline at end of file diff --git a/hack/bundle/update_bundle.sh b/hack/bundle/update_bundle.sh deleted file mode 100755 index 7f81749..0000000 --- a/hack/bundle/update_bundle.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -CSV_FILE="${CSV_FILE:-/manifests/hyperfleet-operator.clusterserviceversion.yaml}" -YQ="${YQ:-yq}" - -require_digest_pullspec() { - local variable_name="$1" - local pullspec="${!variable_name:-}" - if [[ ! "${pullspec}" =~ ^[^[:space:]]+@sha256:[0-9a-f]{64}$ ]]; then - echo "error: ${variable_name} must be a non-empty sha256 digest pullspec, got '${pullspec}'" >&2 - exit 1 - fi -} - -require_digest_pullspec HYPERFLEET_OPERATOR_IMAGE_PULLSPEC -require_digest_pullspec HYPERFLEET_API_IMAGE_PULLSPEC -[[ -f "${CSV_FILE}" ]] || { echo "error: CSV not found: ${CSV_FILE}" >&2; exit 1; } - -# Fail before patching if the runtime override disappeared from the template. -# yq assignments to an empty selection can otherwise silently do nothing. -"${YQ}" eval -p yaml -o yaml -e ' - [.spec.install.spec.deployments[].spec.template.spec.containers[] - | select(.name == "manager")] | length == 1 -' "${CSV_FILE}" >/dev/null -if ! "${YQ}" eval -p yaml -o yaml -e ' - [.spec.install.spec.deployments[].spec.template.spec.containers[] - | select(.name == "manager") | .env[] - | select(.name == "RELATED_IMAGE_HYPERFLEET_API")] | length == 1 -' "${CSV_FILE}" >/dev/null; then - echo "error: CSV is missing exactly one RELATED_IMAGE_HYPERFLEET_API runtime override" >&2 - exit 1 -fi - -# Update image references in the CSV file using yq -"${YQ}" eval -p yaml -o yaml ' - # Update operator deployment image - (.spec.install.spec.deployments[].spec.template.spec.containers[] | select(.name == "manager") | .image) = strenv(HYPERFLEET_OPERATOR_IMAGE_PULLSPEC) | - - # Update RELATED_IMAGE_HYPERFLEET_API env var - (.spec.install.spec.deployments[].spec.template.spec.containers[] | select(.name == "manager") | .env[] | select(.name == "RELATED_IMAGE_HYPERFLEET_API") | .value) = strenv(HYPERFLEET_API_IMAGE_PULLSPEC) | - - # Update containerImage annotation - .metadata.annotations.containerImage = strenv(HYPERFLEET_OPERATOR_IMAGE_PULLSPEC) | - - # Update relatedImages - .spec.relatedImages = [ - {"name": "hyperfleet-operator", "image": strenv(HYPERFLEET_OPERATOR_IMAGE_PULLSPEC)}, - {"name": "hyperfleet-api", "image": strenv(HYPERFLEET_API_IMAGE_PULLSPEC)} - ] -' -i "${CSV_FILE}" - -cat "${CSV_FILE}"