Skip to content
Merged
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,7 @@ hyperfleet-operator/bin/
# Compiled operator binaries (built outside bin/)
hyperfleet-operator/manager
hyperfleet-operator/compactor

# Codegen intermediates
*.passthrough.go.raw
api/v1alpha1/public/generated-schemas.json
2 changes: 1 addition & 1 deletion .tekton/rosa-hyperfleet-api-pull-request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ spec:
- name: hermetic
value: "true"
- name: prefetch-input
value: '[{"type": "gomod", "path": "hyperfleet-db"}, {"type": "gomod", "path": "hyperfleet-operator/api"}, {"type": "gomod", "path": "platform-api"}]'
value: '[{"type": "gomod", "path": "hyperfleet-db"}, {"type": "gomod", "path": "api"}, {"type": "gomod", "path": "hack/api-codegen"}, {"type": "gomod", "path": "platform-api"}]'
- name: build-source-image
value: "true"
pipelineSpec:
Expand Down
2 changes: 1 addition & 1 deletion .tekton/rosa-hyperfleet-api-push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ spec:
- name: hermetic
value: "true"
- name: prefetch-input
value: '[{"type": "gomod", "path": "hyperfleet-db"}, {"type": "gomod", "path": "hyperfleet-operator/api"}, {"type": "gomod", "path": "platform-api"}]'
value: '[{"type": "gomod", "path": "hyperfleet-db"}, {"type": "gomod", "path": "api"}, {"type": "gomod", "path": "hack/api-codegen"}, {"type": "gomod", "path": "platform-api"}]'
- name: build-source-image
value: "true"
pipelineSpec:
Expand Down
4 changes: 2 additions & 2 deletions .tekton/rosa-hyperfleet-operator-pull-request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ metadata:
build.appstudio.redhat.com/target_branch: '{{target_branch}}'
pipelinesascode.tekton.dev/cancel-in-progress: "true"
pipelinesascode.tekton.dev/max-keep-runs: "3"
pipelinesascode.tekton.dev/on-cel-expression: event == "pull_request" && target_branch == "main" && ( "hyperfleet-operator/***".pathChanged() || "hyperfleet-db/***".pathChanged() || ".tekton/rosa-hyperfleet-operator-pull-request.yaml".pathChanged() || "hyperfleet-operator/Containerfile".pathChanged() )
pipelinesascode.tekton.dev/on-cel-expression: event == "pull_request" && target_branch == "main" && ( "api/***".pathChanged() || "hyperfleet-operator/***".pathChanged() || "hyperfleet-db/***".pathChanged() || ".tekton/rosa-hyperfleet-operator-pull-request.yaml".pathChanged() || "hyperfleet-operator/Containerfile".pathChanged() )
labels:
appstudio.openshift.io/application: rosa-hyperfleet
appstudio.openshift.io/component: rosa-hyperfleet-operator
Expand All @@ -35,7 +35,7 @@ spec:
- name: hermetic
value: "true"
- name: prefetch-input
value: '[{"type": "gomod", "path": "hyperfleet-db"}, {"type": "gomod", "path": "hyperfleet-operator/api"}, {"type": "gomod", "path": "hyperfleet-operator"}]'
value: '[{"type": "gomod", "path": "hyperfleet-db"}, {"type": "gomod", "path": "api"}, {"type": "gomod", "path": "hyperfleet-operator"}]'
- name: build-source-image
value: "true"
pipelineSpec:
Expand Down
4 changes: 2 additions & 2 deletions .tekton/rosa-hyperfleet-operator-push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ metadata:
build.appstudio.redhat.com/target_branch: '{{target_branch}}'
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" && ( "force_konflux_release".pathChanged() || "hyperfleet-operator/***".pathChanged() || "hyperfleet-db/***".pathChanged() || ".tekton/rosa-hyperfleet-operator-push.yaml".pathChanged() || "hyperfleet-operator/Containerfile".pathChanged() )
pipelinesascode.tekton.dev/on-cel-expression: event == "push" && target_branch == "main" && ( "force_konflux_release".pathChanged() || "api/***".pathChanged() || "hyperfleet-operator/***".pathChanged() || "hyperfleet-db/***".pathChanged() || ".tekton/rosa-hyperfleet-operator-push.yaml".pathChanged() || "hyperfleet-operator/Containerfile".pathChanged() )
labels:
appstudio.openshift.io/application: rosa-hyperfleet
appstudio.openshift.io/component: rosa-hyperfleet-operator
Expand All @@ -32,7 +32,7 @@ spec:
- name: hermetic
value: "true"
- name: prefetch-input
value: '[{"type": "gomod", "path": "hyperfleet-db"}, {"type": "gomod", "path": "hyperfleet-operator/api"}, {"type": "gomod", "path": "hyperfleet-operator"}]'
value: '[{"type": "gomod", "path": "hyperfleet-db"}, {"type": "gomod", "path": "api"}, {"type": "gomod", "path": "hyperfleet-operator"}]'
- name: build-source-image
value: "true"
pipelineSpec:
Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ make generate # Generate deepcopy

```
hyperfleet-db/go.mod ← standalone
hyperfleet-operator/api/go.mod ← standalone (CRD types sub-module)
hyperfleet-operator/go.mod ← requires: fleetdb, hyperfleet-operator/api
platform-api/go.mod ← requires: fleetdb, hyperfleet-operator/api
api/go.mod ← standalone (CRD types sub-module)
hyperfleet-operator/go.mod ← requires: fleetdb, api
platform-api/go.mod ← requires: fleetdb, api
Comment thread
cdoan1 marked this conversation as resolved.
```

Cross-module refs use permanent `replace` directives to sibling dirs.
Expand Down
101 changes: 92 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
e2e-authz-infra-up e2e-authz-infra-down e2e-init-db \
fmt vet verify deps \
manifests generate generate-clientset verify-clientset setup-envtest \
codegen-passthrough codegen-registry codegen-verify codegen verify-codegen \
codegen-conversion verify-conversion \
generate-openapi verify-openapi swagger-ui \
image-api image-operator image-push-api image-push-operator

# ── Configuration ────────────────────────────────────────────────────────
Expand Down Expand Up @@ -40,20 +43,25 @@ GINKGO := $(abspath $(TOOLS_BIN_DIR)/ginkgo)

# ── SDK generation ───────────────────────────────────────────────────────
SDK_MODULE ?= github.com/openshift-online/rosa-hyperfleet-api
SDK_API_PKG ?= $(SDK_MODULE)/hyperfleet-operator/api
SDK_API_PKG ?= $(SDK_MODULE)/api
SDK_INPUT ?= v1alpha1
SDK_CLIENTSET ?= generated
SDK_OUTPUT_DIR ?= $(abspath clientset)
SDK_OUTPUT_PKG ?= $(SDK_MODULE)/clientset
WIRE_INPUT_DIR ?= $(abspath hyperfleet-operator/api/v1alpha1)
WIRE_INPUT_DIR ?= $(abspath api/v1alpha1)
WIRE_OUTPUT_DIR ?= $(abspath clientset/transport)
WIRE_OUTPUT_PKG ?= transport
WRAPPERS_OUTPUT_DIR ?= $(abspath clientset/wrappers)
WRAPPERS_OUTPUT_PKG ?= wrappers
TYPED_PKG_IMPORT ?= $(SDK_MODULE)/clientset/generated/typed/v1alpha1/internalversion
API_PKG_IMPORT ?= $(SDK_MODULE)/hyperfleet-operator/api/v1alpha1
API_PKG_IMPORT ?= $(SDK_MODULE)/api/v1alpha1
SDK_HEADER_FILE ?= $(abspath hack/clientset/license-boilerplate.go.txt)

# ── Code generation ───────────────────────────────────────────────────────
OPENAPI_GENERATED ?= api/v1alpha1/public/generated-schemas.json
OPENAPI_SPEC ?= api/v1alpha1/public/openapi.yaml
SWAGGER_UI_PORT ?= 8282

$(GOLANGCI_LINT): $(TOOLS_DIR)/go.mod
cd $(TOOLS_DIR); go build -tags=tools -o $(abspath $(TOOLS_BIN_DIR))/golangci-lint github.com/golangci/golangci-lint/v2/cmd/golangci-lint

Expand Down Expand Up @@ -109,6 +117,16 @@ help:
@echo " generate Generate deepcopy methods"
@echo " generate-clientset Generate typed client SDK from CRD types"
@echo " verify-clientset Fail if generated clientset is out of date"
@echo " codegen-passthrough Generate passthrough types from HyperShift"
@echo " codegen-registry Generate field metadata registry from markers"
@echo " codegen-verify Verify codegen outputs compile"
@echo " codegen Run full codegen pipeline (passthrough + registry + verify)"
@echo " verify-codegen Fail if codegen outputs are out of date"
@echo " codegen-conversion Generate REST types and conversion functions from CRD types"
@echo " verify-conversion Fail if conversion outputs are out of date"
@echo " generate-openapi Generate and merge typed schemas into OpenAPI spec"
@echo " verify-openapi Fail if OpenAPI spec is out of date with codegen"
@echo " swagger-ui Run Swagger UI locally (default port 8282)"
@echo " setup-envtest Install envtest binaries (etcd, kube-apiserver)"
@echo " deps Download and tidy all modules"
@echo ""
Expand All @@ -134,6 +152,7 @@ build-api-codegen:
cd hack/api-codegen && go build -o ../../bin/passthrough-gen ./cmd/passthrough-gen
cd hack/api-codegen && go build -o ../../bin/marker-scanner ./cmd/marker-scanner
cd hack/api-codegen && go build -o ../../bin/openapi-gen ./cmd/openapi-gen
cd hack/api-codegen && go build -o ../../bin/openapi-merge ./cmd/openapi-merge
cd hack/api-codegen && go build -o ../../bin/conversion-gen ./cmd/conversion-gen
cd hack/api-codegen && go build -o ../../bin/crd-variants ./cmd/crd-variants
cd hack/api-codegen && go build -o ../../bin/featuregate-info ./cmd/featuregate-info
Expand Down Expand Up @@ -258,15 +277,15 @@ lint: $(GOLANGCI_LINT)

verify:
cd hyperfleet-db && go mod tidy
cd hyperfleet-operator/api && go mod tidy
cd api && go mod tidy
cd hyperfleet-operator && go mod tidy
cd platform-api && go mod tidy
cd test && go mod tidy
cd hack/tools && go mod tidy
cd hack/api-codegen && go mod tidy
git diff --exit-code \
hyperfleet-db/go.mod hyperfleet-db/go.sum \
hyperfleet-operator/api/go.mod hyperfleet-operator/api/go.sum \
api/go.mod api/go.sum \
hyperfleet-operator/go.mod hyperfleet-operator/go.sum \
platform-api/go.mod platform-api/go.sum \
test/go.mod test/go.sum \
Expand All @@ -275,7 +294,7 @@ verify:

deps:
cd hyperfleet-db && go mod download && go mod tidy
cd hyperfleet-operator/api && go mod download && go mod tidy
cd api && go mod download && go mod tidy
cd hyperfleet-operator && go mod download && go mod tidy
cd platform-api && go mod download && go mod tidy
cd test && go mod download && go mod tidy
Expand All @@ -284,13 +303,13 @@ deps:
# ── Code Generation ──────────────────────────────────────────────────────

manifests: $(CONTROLLER_GEN)
cd hyperfleet-operator && $(CONTROLLER_GEN) crd paths="./api/..." output:crd:dir=config/crd/bases
cd hyperfleet-operator && $(CONTROLLER_GEN) crd:allowDangerousTypes=true paths="../api/..." output:crd:dir=config/crd/bases

generate: $(CONTROLLER_GEN)
cd hyperfleet-operator && $(CONTROLLER_GEN) object paths="./api/..."
$(CONTROLLER_GEN) object paths="./api/..."

generate-clientset: $(CLIENT_GEN) $(WIRE_GEN)
cd hyperfleet-operator/api && $(CLIENT_GEN) \
cd api && $(CLIENT_GEN) \
--input-base "$(SDK_API_PKG)" \
--input "$(SDK_INPUT)" \
--clientset-name "$(SDK_CLIENTSET)" \
Expand All @@ -315,6 +334,70 @@ generate-clientset: $(CLIENT_GEN) $(WIRE_GEN)
verify-clientset: generate-clientset
git diff --exit-code clientset/

codegen-passthrough: build-api-codegen
cd api && ../bin/passthrough-gen \
-import-path github.com/openshift/hypershift/api/hypershift/v1beta1 \
-types HostedClusterSpec,NodePoolSpec \
-output-dir v1alpha1 \
-package v1alpha1

codegen-registry: generate build-api-codegen
./bin/marker-scanner \
-input-dirs api/v1alpha1 \
-output-file hack/api-codegen/pkg/registry/field_metadata.go \
$(if $(VERBOSE),-verbose)

codegen-verify: codegen-registry
cd api && go build ./...
cd platform-api && go build ./...

codegen: codegen-verify
Comment thread
coderabbitai[bot] marked this conversation as resolved.

verify-codegen: codegen
git diff --exit-code api/v1alpha1/zz_generated.deepcopy.go
git diff --exit-code hack/api-codegen/pkg/registry/

CONVERSION_OUTPUT_DIR ?= platform-api/pkg/conversion/v1alpha1
CONVERSION_OUTPUT_PKG ?= github.com/openshift-online/rosa-hyperfleet-api/platform-api/pkg/conversion
CONVERSION_CRD_PKG ?= github.com/openshift-online/rosa-hyperfleet-api/api/v1alpha1
CONVERSION_REST_DIR ?= api/v1alpha1/public
CONVERSION_REST_PKG ?= github.com/openshift-online/rosa-hyperfleet-api/api/v1alpha1/public

codegen-conversion: codegen-registry build-api-codegen
./bin/conversion-gen \
--api-version=v1alpha1 \
--crd-package=$(CONVERSION_CRD_PKG) \
--input-dirs=./api/v1alpha1 \
--output-dir=$(CONVERSION_OUTPUT_DIR) \
--output-package=$(CONVERSION_OUTPUT_PKG) \
--rest-output-dir=$(CONVERSION_REST_DIR) \
--rest-package=$(CONVERSION_REST_PKG)

verify-conversion: codegen-conversion
cd api && go build ./...
cd platform-api && go build ./...
git diff --exit-code $(CONVERSION_REST_DIR)/ $(CONVERSION_OUTPUT_DIR)/ platform-api/pkg/conversion/types.go

generate-openapi: codegen-registry
cd hack/api-codegen && go build -o ../../bin/openapi-gen ./cmd/openapi-gen
./bin/openapi-gen \
-input-dirs ./api/v1alpha1 \
-output-file $(OPENAPI_GENERATED)
./bin/openapi-merge \
-spec $(OPENAPI_SPEC) \
-generated $(OPENAPI_GENERATED) \
-schemas ClusterSpec,NodePoolSpec,HostedClusterSpecPassthrough,NodePoolSpecPassthrough,ClusterConfiguration,KubeletConfig,MachineConfigSpec

verify-openapi: generate-openapi
git diff --exit-code $(OPENAPI_SPEC)

swagger-ui:
@echo "Swagger UI available at http://localhost:$(SWAGGER_UI_PORT)"
$(CONTAINER_ENGINE) run --rm -p $(SWAGGER_UI_PORT):8080 \
-e SWAGGER_JSON=/spec/openapi.yaml \
-v $(CURDIR)/$(OPENAPI_SPEC):/spec/openapi.yaml:ro \
swaggerapi/swagger-ui

ENVTEST_BIN_DIR ?= $(shell pwd)/.envtest

setup-envtest: $(SETUP_ENVTEST)
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ make help # full target list

```
hyperfleet-db/go.mod ← standalone
hyperfleet-operator/api/go.mod ← standalone (CRD types)
hyperfleet-operator/go.mod ← requires: hyperfleet-db, hyperfleet-operator/api
platform-api/go.mod ← requires: hyperfleet-db, hyperfleet-operator/api
api/go.mod ← standalone (CRD types)
hyperfleet-operator/go.mod ← requires: hyperfleet-db, api
platform-api/go.mod ← requires: hyperfleet-db, api
```

## Docs

- [OpenAPI spec](platform-api/openapi/openapi.yaml)
- [OpenAPI spec](api/v1alpha1/public/openapi.yaml)
- [ZOA Trusted Actions](docs/api/zoa-endpoints.md)
- [Authorization](docs/authz.md)
- [Konflux / Quay image tags](docs/konflux/quay-image-tags.md)
6 changes: 3 additions & 3 deletions hyperfleet-operator/api/go.mod → api/go.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
module github.com/openshift-online/rosa-hyperfleet-api/hyperfleet-operator/api
module github.com/openshift-online/rosa-hyperfleet-api/api

go 1.26.3

require (
github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80
github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16
k8s.io/api v0.35.1
k8s.io/apimachinery v0.36.0
)

Expand All @@ -13,13 +15,11 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
golang.org/x/net v0.56.0 // indirect
golang.org/x/text v0.38.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/api v0.35.1 // indirect
k8s.io/klog/v2 v2.140.0 // indirect
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect
k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 // indirect
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,58 @@ const (
// metadata.Name is the human-readable cluster name; metadata.Namespace is the cluster UUID.
// The owning AWS account is stored as the label hyperfleet.io/account-id.
type ClusterSpec struct {
// DisplayName is a human-readable name for the cluster.
// +hyperfleet:write-mode=mutable
// +kubebuilder:validation:MaxLength=256
// +optional
DisplayName string `json:"displayName,omitempty"`

// DeleteProtection prevents accidental deletion when enabled.
// +hyperfleet:write-mode=mutable
// +optional
DeleteProtection *bool `json:"deleteProtection,omitempty"`

// ExpirationTimestamp marks when this cluster should be automatically deleted.
// +hyperfleet:write-mode=mutable
// +optional
ExpirationTimestamp *metav1.Time `json:"expirationTimestamp,omitempty"`

// Properties are arbitrary key-value pairs for customer metadata.
// +hyperfleet:write-mode=mutable
// +kubebuilder:validation:MaxProperties=100
// +optional
Properties map[string]string `json:"properties,omitempty"`

// Tags are customer-defined labels for organizational purposes.
// +hyperfleet:write-mode=mutable
// +openshift:enable:FeatureGate=HyperFleetAutoScaling
// +kubebuilder:validation:MaxProperties=100
// +optional
Tags map[string]string `json:"tags,omitempty"`

// AccountID is the AWS account that owns this cluster.
// +k8s:openapi-gen=false
// +hyperfleet:write-mode=service-set
// +optional
AccountID string `json:"accountId,omitempty"`

// CreatorARN is the IAM ARN of the user who created this cluster.
// Used to bootstrap the initial cluster-admin RBAC mapping.
// +k8s:openapi-gen=false
// +hyperfleet:write-mode=service-set
// +optional
// +kubebuilder:validation:Pattern=`^arn:aws:`
CreatorARN string `json:"creatorARN,omitempty"`
Comment thread
cdoan1 marked this conversation as resolved.

// ExpirationTimestamp is the time after which the cluster will be
// automatically deleted. If nil, the cluster has no expiration.
// InternalID is a platform-assigned unique identifier.
// +k8s:openapi-gen=false
// +hyperfleet:write-mode=service-set
// +optional
ExpirationTimestamp *metav1.Time `json:"expirationTimestamp,omitempty"`
InternalID string `json:"internalId,omitempty"`

// HostedCluster is the full HyperShift HostedClusterSpec. The customer provides
// the fields they care about; the operator overrides platform-managed fields
// (InfraID, DNS, PullSecret, Services, etc.) at render time.
// HostedCluster contains the upstream HyperShift fields, mirrored as
// passthrough types with per-field visibility and write-mode markers.
// +kubebuilder:validation:Required
HostedCluster hypershiftv1beta1.HostedClusterSpec `json:"hostedCluster"`
HostedCluster HostedClusterSpecPassthrough `json:"hostedCluster"`
}

// ClusterStatus defines the observed state of a Cluster.
Expand Down
Loading