Skip to content
Closed
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
101 changes: 97 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: build test test-unit test-authz test-coverage test-e2e test-e2e-api test-e2e-cli test-e2e-platform-monitoring test-e2e-zoa lint clean image image-push run generate generate-swagger help fmt vet
.PHONY: build test test-unit test-authz test-coverage test-e2e test-e2e-api test-e2e-cli test-e2e-platform-monitoring test-e2e-zoa lint clean image image-push run generate generate-swagger help fmt vet codegen-install-tools codegen-passthrough codegen-registry codegen-openapi codegen-verify get-hypershift-version swagger-ui-serve swagger-ui-open

BINARY_NAME := rosa-regional-platform-api
IMAGE_REPO ?= quay.io/openshift-online/rosa-regional-platform-api
Expand Down Expand Up @@ -76,11 +76,23 @@ help:
@echo " image-e2e-push-multiarch - Build and push E2E test container (multiarch)"
@echo ""
@echo "Code Generation:"
@echo " deps - Download and tidy dependencies"
@echo " generate - Generate OpenAPI code"
@echo " deps - Download and tidy dependencies"
@echo " generate - Generate OpenAPI code"
@echo " generate-swagger - Regenerate swagger-ui.html"
@echo ""
@echo " all - Run all checks (deps, fmt, vet, lint, test, build)"
@echo "Codegen Integration:"
@echo " codegen-install-tools - Install passthrough-gen, marker-scanner, and openapi-gen binaries"
@echo " codegen-passthrough - Regenerate passthrough types from HyperShift CRDs"
@echo " codegen-registry - Regenerate field metadata registry from annotated types"
@echo " codegen-openapi - Generate OpenAPI schemas from Go types and merge into openapi.yaml"
@echo " codegen-verify - Verify codegen and dependent packages compile"
@echo " get-hypershift-version - Show current HyperShift version in go.mod"
@echo ""
@echo "API Documentation:"
@echo " swagger-ui-serve - Serve Swagger UI locally (requires Python 3)"
@echo " swagger-ui-open - Open Swagger UI in browser (requires swagger-ui-serve running)"
@echo ""
@echo " all - Run all checks (deps, fmt, vet, lint, test, build)"

# Build the binary
build:
Expand Down Expand Up @@ -340,5 +352,86 @@ verify:
go mod tidy
git diff --exit-code go.mod go.sum

# --- Codegen integration ---
# API types with markers live in api/v2alpha1/ (checked in).
# Runtime libraries (registry, featuregate, validation) live in internal/codegen/.
# Generator tools are installed as binaries from the codegen repo.

CODEGEN_TOOLS_MODULE ?= github.com/cdoan1/hyperfleet-api-codegen
CODEGEN_TOOLS_VERSION ?= v0.1.7
HYPERSHIFT_IMPORT_PATH ?= github.com/openshift/hypershift/api/hypershift/v1beta1
HYPERSHIFT_TYPES ?= HostedClusterSpec,NodePoolSpec

codegen-install-tools:
GOBIN=$(PWD)/bin go install $(CODEGEN_TOOLS_MODULE)/cmd/passthrough-gen@$(CODEGEN_TOOLS_VERSION)
GOBIN=$(PWD)/bin go install $(CODEGEN_TOOLS_MODULE)/cmd/marker-scanner@$(CODEGEN_TOOLS_VERSION)
GOBIN=$(PWD)/bin go install $(CODEGEN_TOOLS_MODULE)/cmd/openapi-gen@$(CODEGEN_TOOLS_VERSION)

codegen-passthrough: codegen-install-tools
@echo "Generating passthrough types from $(HYPERSHIFT_IMPORT_PATH)..."
bin/passthrough-gen \
--import-path=$(HYPERSHIFT_IMPORT_PATH) \
--types=$(HYPERSHIFT_TYPES) \
--output-dir=api/v2alpha1 \
--package=v2alpha1
@if [ -f api/v2alpha1/zz_generated.passthrough.go ]; then \
cp api/v2alpha1/zz_generated.passthrough.go api/v2alpha1/hostedclusterspec.passthrough.go; \
rm api/v2alpha1/zz_generated.passthrough.go; \
fi
@echo "Done. Edit api/v2alpha1/hostedclusterspec.passthrough.go to curate field markers."
Comment on lines +377 to +381

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Preserve the documented raw passthrough output.

The recipe deletes zz_generated.passthrough.go without creating zz_generated.passthrough.go.raw, so the documented reference artifact is lost.

Proposed fix
 	`@if` [ -f api/v2alpha1/zz_generated.passthrough.go ]; then \
-		cp api/v2alpha1/zz_generated.passthrough.go api/v2alpha1/hostedclusterspec.passthrough.go; \
-		rm api/v2alpha1/zz_generated.passthrough.go; \
+		cp api/v2alpha1/zz_generated.passthrough.go api/v2alpha1/zz_generated.passthrough.go.raw; \
+		mv api/v2alpha1/zz_generated.passthrough.go api/v2alpha1/hostedclusterspec.passthrough.go; \
 	fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@if [ -f api/v2alpha1/zz_generated.passthrough.go ]; then \
cp api/v2alpha1/zz_generated.passthrough.go api/v2alpha1/hostedclusterspec.passthrough.go; \
rm api/v2alpha1/zz_generated.passthrough.go; \
fi
@echo "Done. Edit api/v2alpha1/hostedclusterspec.passthrough.go to curate field markers."
`@if` [ -f api/v2alpha1/zz_generated.passthrough.go ]; then \
cp api/v2alpha1/zz_generated.passthrough.go api/v2alpha1/zz_generated.passthrough.go.raw; \
mv api/v2alpha1/zz_generated.passthrough.go api/v2alpha1/hostedclusterspec.passthrough.go; \
fi
`@echo` "Done. Edit api/v2alpha1/hostedclusterspec.passthrough.go to curate field markers."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 377 - 381, The passthrough-generation recipe removes
zz_generated.passthrough.go without preserving its raw reference copy. Update
the recipe around the existing copy and rm commands to first create
api/v2alpha1/zz_generated.passthrough.go.raw, then continue copying the
generated file to hostedclusterspec.passthrough.go and removing the original.


VERBOSE ?=

codegen-registry: codegen-install-tools
@echo "Generating field metadata registry from api/v2alpha1/..."
bin/marker-scanner \
--input-dirs=api/v2alpha1 \
--output-file=internal/codegen/registry/field_metadata.go \
$(if $(VERBOSE),--verbose)

KEEP_MARKERS ?=

codegen-openapi: codegen-install-tools
@echo "Generating OpenAPI schemas from api/v2alpha1/..."
bin/openapi-gen \
--input-dirs=api/v2alpha1 \
--output-file=openapi/generated-schemas.json \
--title="ROSA Regional Platform API" \
--version=v2alpha1
@echo "Merging generated schemas into openapi/openapi.yaml..."
hack/merge-openapi.sh $(if $(KEEP_MARKERS),--keep-markers) openapi/generated-schemas.json openapi/openapi.yaml

codegen-verify:
@echo "Verifying codegen packages compile..."
go build ./api/v2alpha1/...
go build ./internal/codegen/...
go build ./pkg/middleware/...
go build ./pkg/handlers/...

get-hypershift-version: ## Show current HyperShift version in go.mod
@PSEUDO_VERSION=$$(grep "github.com/openshift/hypershift/api" go.mod | awk '{print $$2}'); \
COMMIT=$$(echo $$PSEUDO_VERSION | rev | cut -d'-' -f1 | rev); \
echo "Current HyperShift in go.mod:"; \
echo " Pseudo-version: $$PSEUDO_VERSION"; \
echo " Commit: $$COMMIT"; \
TAG=$$(curl -s https://api.github.com/repos/openshift/hypershift/tags | jq -r ".[] | select(.commit.sha | startswith(\"$$COMMIT\")) | .name" | head -1); \
if [ -z "$$TAG" ]; then \
echo " Tag: (no tag found - using commit)"; \
else \
echo " Tag: $$TAG"; \
fi

swagger-ui-serve: ## Serve Swagger UI locally (requires Python 3)
@command -v python3 >/dev/null 2>&1 || { echo "Error: python3 is required"; exit 1; }
@echo "Swagger UI: http://localhost:8080/openapi/swagger-ui/"
@echo "OpenAPI spec: http://localhost:8080/openapi/openapi.yaml"
@echo "Press Ctrl+C to stop"
@python3 -m http.server 8080 --directory .

swagger-ui-open: ## Open Swagger UI in browser (requires swagger-ui-serve running)
@command -v open >/dev/null 2>&1 && open http://localhost:8080/openapi/swagger-ui/ || \
command -v xdg-open >/dev/null 2>&1 && xdg-open http://localhost:8080/openapi/swagger-ui/ || \
echo "Open http://localhost:8080/openapi/swagger-ui/ in your browser"

# All checks
all: deps fmt vet lint test build
111 changes: 111 additions & 0 deletions api/v2alpha1/cluster_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package v2alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// Cluster represents a HyperFleet managed OpenShift cluster
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:scope=Namespaced
type Cluster struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec ClusterSpec `json:"spec"`
Status ClusterStatus `json:"status,omitempty"`
}

// ClusterSpec defines the desired state of a Cluster
type ClusterSpec struct {
// === HyperFleet Envelope Fields ===
// These are HyperFleet-specific fields that wrap the HyperShift cluster

// DisplayName is a human-readable name for the cluster
// +hyperfleet:write-mode=mutable
// +kubebuilder:validation:MaxLength=256
DisplayName string `json:"displayName,omitempty"`

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

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

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

// Tags are customer-defined labels for organizational purposes
// This is a TechPreview feature
// +hyperfleet:write-mode=mutable
// +openshift:enable:FeatureGate=HyperFleetAutoScaling
Tags map[string]string `json:"tags,omitempty"`
Comment on lines +41 to +45

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use a feature gate that represents tags.

Tags is gated by HyperFleetAutoScaling, whose registry description says it enables cluster autoscaling. This blocks tags unless an unrelated feature is enabled and exposes them whenever autoscaling is enabled. Define a dedicated tags gate or remove the marker if tags are GA.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/v2alpha1/cluster_types.go` around lines 41 - 45, Update the feature-gate
marker on the Tags field to use a dedicated gate representing tags, rather than
HyperFleetAutoScaling; if tags are intended to be GA, remove the feature-gate
marker instead. Preserve the existing mutability and JSON annotations.


// CloudUrl is the CloudFront URL for accessing the cluster console (auto-populated by server)
// +k8s:openapi-gen=true
// +hyperfleet:write-mode=service-set
CloudUrl string `json:"cloudUrl,omitempty"`

// Placement is the management cluster name (auto-populated if not provided)
// +hyperfleet:write-mode=mutable
Placement string `json:"placement,omitempty"`

// AccountID identifies the customer account (platform-managed, hidden from API)
// +k8s:openapi-gen=false
// +hyperfleet:write-mode=service-set
AccountID string `json:"accountId,omitempty"`

// CreatorARN is the AWS ARN of the user who created this cluster (platform-managed, hidden)
// +k8s:openapi-gen=false
// +hyperfleet:write-mode=service-set
CreatorARN string `json:"creatorARN,omitempty"`

// InternalID is an internal platform identifier (platform-managed, hidden)
// +k8s:openapi-gen=false
// +hyperfleet:write-mode=service-set
InternalID string `json:"internalId,omitempty"`

// === HyperShift Passthrough ===
// This embeds all upstream HyperShift HostedCluster fields

// HostedCluster contains the full HyperShift HostedCluster configuration
// All fields are generated from upstream and have safe defaults (hidden + service-set)
// until explicitly reviewed and exposed
HostedCluster *HostedClusterSpecPassthrough `json:"hostedCluster,omitempty"`
}

// ClusterStatus defines the observed state of a Cluster
type ClusterStatus struct {
// State represents the high-level cluster state
// +kubebuilder:validation:Enum=pending;provisioning;ready;degraded;deleting;failed
State string `json:"state,omitempty"`

// Conditions represent detailed cluster status
Conditions []metav1.Condition `json:"conditions,omitempty"`

// Version is the observed OpenShift version
Version string `json:"version,omitempty"`

// APIEndpoint is the cluster API server endpoint
APIEndpoint string `json:"apiEndpoint,omitempty"`

// ConsoleURL is the web console URL
ConsoleURL string `json:"consoleUrl,omitempty"`

// ProvisionStartTime is when provisioning began
ProvisionStartTime *metav1.Time `json:"provisionStartTime,omitempty"`

// ReadyTime is when the cluster became ready
ReadyTime *metav1.Time `json:"readyTime,omitempty"`
}

// ClusterList contains a list of Clusters
// +kubebuilder:object:root=true
type ClusterList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Cluster `json:"items"`
}
Loading