diff --git a/.gitignore b/.gitignore index 802359dd..ac28e79a 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,6 @@ hyperfleet-operator/bin/ # Compiled operator binaries (built outside bin/) hyperfleet-operator/manager hyperfleet-operator/compactor + +# Codegen intermediate files +*.passthrough.go.raw diff --git a/Makefile b/Makefile index 2d1b379b..53037923 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,9 @@ test-e2e test-e2e-api test-e2e-cli test-e2e-platform-monitoring test-e2e-zoa test-e2e-authz test-e2e-sdk \ e2e-authz-infra-up e2e-authz-infra-down e2e-init-db \ fmt vet verify deps \ - manifests generate generate-clientset verify-clientset setup-envtest \ + manifests generate generate-clientset verify-clientset \ + generate-public-deepcopy setup-envtest \ + codegen-passthrough codegen-registry codegen-verify codegen verify-codegen \ image-api image-operator image-push-api image-push-operator # ── Configuration ──────────────────────────────────────────────────────── @@ -106,9 +108,15 @@ help: @echo "" @echo "Code Generation:" @echo " manifests Generate CRD manifests" - @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 " generate Generate deepcopy methods (v1alpha1)" + @echo " generate-clientset Generate typed client SDK from CRD types" + @echo " verify-clientset Fail if generated clientset is out of date" + @echo " generate-public-deepcopy Generate deepcopy methods (v2alpha1 public API)" + @echo " codegen Full codegen pipeline (passthrough → deepcopy → registry)" + @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 " verify-codegen Fail if codegen outputs are out of date" @echo " setup-envtest Install envtest binaries (etcd, kube-apiserver)" @echo " deps Download and tidy all modules" @echo "" @@ -260,6 +268,7 @@ verify: cd hyperfleet-db && go mod tidy cd hyperfleet-operator/api && go mod tidy cd hyperfleet-operator && go mod tidy + cd api/public/v2alpha1 && go mod tidy cd platform-api && go mod tidy cd test && go mod tidy cd hack/tools && go mod tidy @@ -268,6 +277,7 @@ verify: hyperfleet-db/go.mod hyperfleet-db/go.sum \ hyperfleet-operator/api/go.mod hyperfleet-operator/api/go.sum \ hyperfleet-operator/go.mod hyperfleet-operator/go.sum \ + api/public/v2alpha1/go.mod api/public/v2alpha1/go.sum \ platform-api/go.mod platform-api/go.sum \ test/go.mod test/go.sum \ hack/tools/go.mod hack/tools/go.sum \ @@ -277,6 +287,7 @@ deps: cd hyperfleet-db && go mod download && go mod tidy cd hyperfleet-operator/api && go mod download && go mod tidy cd hyperfleet-operator && go mod download && go mod tidy + cd api/public/v2alpha1 && go mod download && go mod tidy cd platform-api && go mod download && go mod tidy cd test && go mod download && go mod tidy cd hack/api-codegen && go mod download && go mod tidy @@ -315,6 +326,32 @@ generate-clientset: $(CLIENT_GEN) $(WIRE_GEN) verify-clientset: generate-clientset git diff --exit-code clientset/ +codegen-passthrough: build-api-codegen + cd api/public/v2alpha1 && ../../../bin/passthrough-gen \ + -import-path github.com/openshift/hypershift/api/hypershift/v1beta1 \ + -types HostedClusterSpec,NodePoolSpec \ + -output-dir . \ + -package v2alpha1 + mv api/public/v2alpha1/zz_generated.passthrough.go api/public/v2alpha1/zz_generated.passthrough.go.raw + +generate-public-deepcopy: codegen-passthrough $(CONTROLLER_GEN) + $(CONTROLLER_GEN) object paths="./api/public/v2alpha1/..." + +codegen-registry: generate-public-deepcopy build-api-codegen + ./bin/marker-scanner \ + -input-dirs api/public/v2alpha1 \ + -output-file platform-api/internal/codegen/registry/field_metadata.go + +codegen-verify: codegen-registry + cd api/public/v2alpha1 && go build ./... + cd platform-api && go build ./internal/codegen/... + +codegen: codegen-verify + +verify-codegen: codegen + git diff --exit-code api/public/v2alpha1/zz_generated.deepcopy.go + git diff --exit-code platform-api/internal/codegen/registry/ + ENVTEST_BIN_DIR ?= $(shell pwd)/.envtest setup-envtest: $(SETUP_ENVTEST) diff --git a/api/public/v2alpha1/cluster_types.go b/api/public/v2alpha1/cluster_types.go new file mode 100644 index 00000000..20ae3855 --- /dev/null +++ b/api/public/v2alpha1/cluster_types.go @@ -0,0 +1,156 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +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. +*/ + +package v2alpha1 + +import ( + hypershiftv1beta1 "github.com/openshift/hypershift/api/hypershift/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// ClusterPhase represents the lifecycle phase of a Cluster. +// +kubebuilder:validation:Enum=WaitingForPlacement;Provisioning;Ready;Deleting +type ClusterPhase string + +const ( + ClusterPhaseWaitingForPlacement ClusterPhase = "WaitingForPlacement" + ClusterPhaseProvisioning ClusterPhase = "Provisioning" + ClusterPhaseReady ClusterPhase = "Ready" + ClusterPhaseDeleting ClusterPhase = "Deleting" +) + +// ClusterSpec defines the desired state of a ROSA HCP cluster. +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. + // +k8s:openapi-gen=true + // +hyperfleet:write-mode=mutable + // +optional + ExpirationTimestamp *metav1.Time `json:"expirationTimestamp,omitempty"` + + // Properties are arbitrary key-value pairs for customer metadata. + // +hyperfleet:write-mode=mutable + // +optional + Properties map[string]string `json:"properties,omitempty"` + + // Tags are customer-defined labels for organizational purposes. + // +hyperfleet:write-mode=mutable + // +openshift:enable:FeatureGate=HyperFleetAutoScaling + // +optional + Tags map[string]string `json:"tags,omitempty"` + + // AccountID identifies the customer account (platform-managed, hidden from API). + // +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. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + // +optional + // +kubebuilder:validation:Pattern=`^arn:aws:` + CreatorARN string `json:"creatorARN,omitempty"` + + // InternalID is an internal platform identifier (platform-managed, hidden). + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + // +optional + InternalID string `json:"internalId,omitempty"` + + // HostedCluster is the full HyperShift HostedClusterSpec. + // +kubebuilder:validation:Required + HostedCluster hypershiftv1beta1.HostedClusterSpec `json:"hostedCluster"` +} + +// ClusterStatus defines the observed state of a Cluster. +type ClusterStatus struct { + // +listType=map + // +listMapKey=type + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // +optional + Phase ClusterPhase `json:"phase,omitempty"` + + // +optional + ControlPlaneEndpoint hypershiftv1beta1.APIEndpoint `json:"controlPlaneEndpoint,omitempty"` + + // +optional + Version string `json:"version,omitempty"` + + // +optional + PlacementRef *PlacementReference `json:"placementRef,omitempty"` + + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` +} + +// PlacementReference identifies the management cluster assignment. +type PlacementReference struct { + Name string `json:"name"` + ManagementCluster string `json:"managementCluster"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Namespaced,shortName=hfc +// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=".status.phase" +// +kubebuilder:printcolumn:name="MC",type=string,JSONPath=".status.placementRef.managementCluster" +// +kubebuilder:printcolumn:name="Endpoint",type=string,JSONPath=".status.controlPlaneEndpoint.host",priority=1 +// +kubebuilder:printcolumn:name="Expires",type=date,JSONPath=".spec.expirationTimestamp",priority=1 +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=".metadata.creationTimestamp" + +// Cluster is the Schema for the clusters API. +type Cluster struct { + metav1.TypeMeta `json:",inline"` + + // +optional + metav1.ObjectMeta `json:"metadata,omitzero"` + + // +required + Spec ClusterSpec `json:"spec"` + + // +optional + Status ClusterStatus `json:"status,omitzero"` +} + +// +kubebuilder:object:root=true + +// ClusterList contains a list of Cluster. +type ClusterList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitzero"` + Items []Cluster `json:"items"` +} + +func init() { + SchemeBuilder.Register(func(s *runtime.Scheme) error { + s.AddKnownTypes(SchemeGroupVersion, &Cluster{}, &ClusterList{}) + return nil + }) +} diff --git a/api/public/v2alpha1/configuration.go b/api/public/v2alpha1/configuration.go new file mode 100644 index 00000000..c19d15de --- /dev/null +++ b/api/public/v2alpha1/configuration.go @@ -0,0 +1,219 @@ +package v2alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ClusterConfiguration specifies configuration for individual OCP components in the cluster. +// This is a HyperFleet-owned mirror of hypershiftv1beta1.ClusterConfiguration that allows +// us to add granular markers to nested fields like kubelet config. +type ClusterConfiguration struct { + // apiServer contains advanced network settings for the API server. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + APIServer *APIServerNetworkConfiguration `json:"apiServer,omitempty"` + + // authentication contains configuration for the cluster authentication. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Authentication *ClusterAuthentication `json:"authentication,omitempty"` + + // featureGate contains the desired configuration for feature gates. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + FeatureGate *FeatureGateConfiguration `json:"featureGate,omitempty"` + + // image contains the configuration for internal registry. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Image *ImageConfiguration `json:"image,omitempty"` + + // ingress contains the configuration for ingress. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Ingress *IngressConfiguration `json:"ingress,omitempty"` + + // network contains the configuration for cluster networking. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Network *NetworkConfiguration `json:"network,omitempty"` + + // oauth contains the configuration for OAuth. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + OAuth *OAuthConfiguration `json:"oauth,omitempty"` + + // scheduler contains the configuration for scheduler. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Scheduler *SchedulerConfiguration `json:"scheduler,omitempty"` + + // proxy contains the configuration for the cluster-wide proxy. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Proxy *ProxyConfiguration `json:"proxy,omitempty"` + + // kubelet contains the configuration for kubelet on nodes. + // +hyperfleet:write-mode=service-set + Kubelet *KubeletConfig `json:"kubelet,omitempty"` + + // machineConfig contains the configuration for machine-level settings. + // +hyperfleet:write-mode=service-set + MachineConfig *MachineConfigSpec `json:"machineConfig,omitempty"` +} + +// KubeletConfig specifies kubelet configuration with granular markers for customer control. +type KubeletConfig struct { + // +hyperfleet:write-mode=mutable + MaxPods *int32 `json:"maxPods,omitempty"` + + // +hyperfleet:write-mode=mutable + PodPidsLimit *int64 `json:"podPidsLimit,omitempty"` + + // +hyperfleet:write-mode=immutable + SystemReserved map[string]string `json:"systemReserved,omitempty"` + + // +hyperfleet:write-mode=immutable + KubeReserved map[string]string `json:"kubeReserved,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + EvictionHard map[string]string `json:"evictionHard,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + EvictionSoft map[string]string `json:"evictionSoft,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + EvictionSoftGracePeriod map[string]string `json:"evictionSoftGracePeriod,omitempty"` + + // +hyperfleet:write-mode=mutable + ImageGCHighThresholdPercent *int32 `json:"imageGCHighThresholdPercent,omitempty"` + + // +hyperfleet:write-mode=mutable + ImageGCLowThresholdPercent *int32 `json:"imageGCLowThresholdPercent,omitempty"` + + // +hyperfleet:write-mode=mutable + ImageMinimumGCAge *metav1.Duration `json:"imageMinimumGCAge,omitempty"` + + // +openshift:enable:FeatureGate=HyperFleetKubeletAdvanced + // +hyperfleet:write-mode=mutable + SerializeImagePulls *bool `json:"serializeImagePulls,omitempty"` + + // +openshift:enable:FeatureGate=HyperFleetKubeletAdvanced + // +hyperfleet:write-mode=mutable + RegistryPullQPS *int32 `json:"registryPullQPS,omitempty"` + + // +openshift:enable:FeatureGate=HyperFleetKubeletAdvanced + // +hyperfleet:write-mode=mutable + RegistryBurst *int32 `json:"registryBurst,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + CPUManagerPolicy *string `json:"cpuManagerPolicy,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + CPUManagerPolicyOptions map[string]string `json:"cpuManagerPolicyOptions,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + CPUManagerReconcilePeriod *metav1.Duration `json:"cpuManagerReconcilePeriod,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + TopologyManagerPolicy *string `json:"topologyManagerPolicy,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + TopologyManagerScope *string `json:"topologyManagerScope,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + AllowedUnsafeSysctls []string `json:"allowedUnsafeSysctls,omitempty"` + + // +hyperfleet:write-mode=mutable + StreamingConnectionIdleTimeout *metav1.Duration `json:"streamingConnectionIdleTimeout,omitempty"` + + // +hyperfleet:write-mode=mutable + ContainerLogMaxSize *string `json:"containerLogMaxSize,omitempty"` + + // +hyperfleet:write-mode=mutable + ContainerLogMaxFiles *int32 `json:"containerLogMaxFiles,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + MemoryThrottlingFactor *float64 `json:"memoryThrottlingFactor,omitempty"` +} + +// Placeholder types for configuration areas not yet exposed. + +type APIServerNetworkConfiguration struct{} + +type ClusterAuthentication struct{} + +type FeatureGateConfiguration struct{} + +type ImageConfiguration struct{} + +type IngressConfiguration struct{} + +type NetworkConfiguration struct{} + +type OAuthConfiguration struct{} + +type SchedulerConfiguration struct{} + +type ProxyConfiguration struct{} + +// MachineConfigSpec specifies machine-level configuration. +type MachineConfigSpec struct { + // +openshift:enable:FeatureGate=HyperFleetMachineConfig + // +hyperfleet:write-mode=immutable + AllowedKernelArguments []string `json:"allowedKernelArguments,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + KernelArguments []string `json:"kernelArguments,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + SystemdUnits []SystemdUnit `json:"systemdUnits,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Files []FileSpec `json:"files,omitempty"` + + // +hyperfleet:write-mode=immutable + FIPS *bool `json:"fips,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + KernelType *string `json:"kernelType,omitempty"` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Extensions []string `json:"extensions,omitempty"` +} + +type SystemdUnit struct { + Name string `json:"name"` + Enabled *bool `json:"enabled,omitempty"` + Contents string `json:"contents,omitempty"` + Dropins []SystemdDropin `json:"dropins,omitempty"` +} + +type SystemdDropin struct { + Name string `json:"name"` + Contents string `json:"contents,omitempty"` +} + +type FileSpec struct { + Path string `json:"path"` + Contents string `json:"contents,omitempty"` + Mode *int32 `json:"mode,omitempty"` + User *string `json:"user,omitempty"` + Group *string `json:"group,omitempty"` + Overwrite *bool `json:"overwrite,omitempty"` +} diff --git a/api/public/v2alpha1/go.mod b/api/public/v2alpha1/go.mod new file mode 100644 index 00000000..f5524ec1 --- /dev/null +++ b/api/public/v2alpha1/go.mod @@ -0,0 +1,29 @@ +module github.com/openshift-online/rosa-hyperfleet-api/api/public/v2alpha1 + +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.36.0 + k8s.io/apimachinery v0.36.0 +) + +require ( + github.com/fxamacker/cbor/v2 v2.9.2 // indirect + github.com/go-logr/logr v1.4.4 // indirect + 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/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/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 + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect +) diff --git a/api/public/v2alpha1/go.sum b/api/public/v2alpha1/go.sum new file mode 100644 index 00000000..7fd506bd --- /dev/null +++ b/api/public/v2alpha1/go.sum @@ -0,0 +1,62 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78= +github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= +github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 h1:r0S/yoZAI0iWo1JvoIijaIgWGWf/izg4WiV7Wrtz16k= +github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo= +github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16 h1:QDSh3vkKYq7Fn9utYGlAJadkTdyaRl9IY7Cr6cNDAow= +github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16/go.mod h1:Z3lkj5pFqY+KTl3Do9gXdEZdKWLnkUTSDShLD1HE0CM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= +golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= +golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.36.0 h1:SgqDhZzHdOtMk40xVSvCXkP9ME0H05hPM3p9AB1kL80= +k8s.io/api v0.36.0/go.mod h1:m1LVrGPNYax5NBHdO+QuAedXyuzTt4RryI/qnmNvs34= +k8s.io/apimachinery v0.36.0 h1:jZyPzhd5Z+3h9vJLt0z9XdzW9VzNzWAUw+P1xZ9PXtQ= +k8s.io/apimachinery v0.36.0/go.mod h1:FklypaRJt6n5wUIwWXIP6GJlIpUizTgfo1T/As+Tyxc= +k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= +k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= +k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg= +k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= +k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 h1:jVkFFVfXdXP74B/zbO3hM3hpSFD0xvhQ5U686DPurkE= +k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3/go.mod h1:M2s5JB1lIYP3jzZdorPLHXIPJzt9vv2muW5a6L9DtNM= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= +sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/api/public/v2alpha1/groupversion_info.go b/api/public/v2alpha1/groupversion_info.go new file mode 100644 index 00000000..2ca03a9a --- /dev/null +++ b/api/public/v2alpha1/groupversion_info.go @@ -0,0 +1,35 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +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. +*/ + +// +kubebuilder:object:generate=true +// +groupName=hyperfleet.io +package v2alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + SchemeGroupVersion = schema.GroupVersion{Group: "hyperfleet.io", Version: "v2alpha1"} + GroupVersion = SchemeGroupVersion + SchemeBuilder = runtime.NewSchemeBuilder(func(s *runtime.Scheme) error { + metav1.AddToGroupVersion(s, SchemeGroupVersion) + return nil + }) + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/api/public/v2alpha1/hostedclusterspec.passthrough.go b/api/public/v2alpha1/hostedclusterspec.passthrough.go new file mode 100644 index 00000000..e1d5dc6d --- /dev/null +++ b/api/public/v2alpha1/hostedclusterspec.passthrough.go @@ -0,0 +1,210 @@ +// Code generated by passthrough-gen. DO NOT EDIT. + +package v2alpha1 + +import ( + configv1 "github.com/openshift/api/config/v1" + hypershiftv1beta1 "github.com/openshift/hypershift/api/hypershift/v1beta1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// HostedClusterSpecPassthrough mirrors HostedClusterSpec from upstream HyperShift +type HostedClusterSpecPassthrough struct { + // release specifies the desired OCP release payload for all the hosted cluster components. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Release hypershiftv1beta1.Release `json:"release"` + // controlPlaneRelease is like spec.release but only for the components running on the management cluster. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + ControlPlaneRelease *hypershiftv1beta1.Release `json:"controlPlaneRelease,omitempty"` + // clusterID uniquely identifies this cluster. This is expected to be an RFC4122 UUID value (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx in hexadecimal digits). + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + ClusterID string `json:"clusterID,omitempty"` + // infraID is a globally unique identifier for the cluster. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + InfraID string `json:"infraID,omitempty"` + // updateService may be used to specify the preferred upstream update service. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + UpdateService configv1.URL `json:"updateService,omitempty"` + // channel is an identifier for explicitly requesting that a non-default set of updates be applied to this cluster. + // +k8s:openapi-gen=true + // +hyperfleet:write-mode=service-set + Channel string `json:"channel,omitempty"` + // platform specifies the underlying infrastructure provider for the cluster + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Platform hypershiftv1beta1.PlatformSpec `json:"platform"` + // kubeAPIServerDNSName specifies a desired DNS name to resolve to the KAS. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + KubeAPIServerDNSName string `json:"kubeAPIServerDNSName,omitempty"` + // controllerAvailabilityPolicy specifies the availability policy applied to critical control plane components like the Kube API Server. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + ControllerAvailabilityPolicy hypershiftv1beta1.AvailabilityPolicy `json:"controllerAvailabilityPolicy,omitempty"` + // infrastructureAvailabilityPolicy specifies the availability policy applied to infrastructure services which run on the hosted cluster data plane like the ingress controller and image registry controller. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + InfrastructureAvailabilityPolicy hypershiftv1beta1.AvailabilityPolicy `json:"infrastructureAvailabilityPolicy,omitempty"` + // dns specifies the DNS configuration for the hosted cluster ingress. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + DNS hypershiftv1beta1.DNSSpec `json:"dns,omitempty"` + // networking specifies network configuration for the hosted cluster. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Networking hypershiftv1beta1.ClusterNetworking `json:"networking"` + // autoscaling specifies auto-scaling behavior that applies to all NodePools + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Autoscaling hypershiftv1beta1.ClusterAutoscaling `json:"autoscaling,omitempty"` + // autoNode specifies the configuration for automatic node provisioning and lifecycle management. + // +k8s:openapi-gen=true + // +hyperfleet:write-mode=service-set + AutoNode hypershiftv1beta1.AutoNode `json:"autoNode,omitzero"` + // etcd specifies configuration for the control plane etcd cluster. The + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Etcd hypershiftv1beta1.EtcdSpec `json:"etcd"` + // services specifies how individual control plane services endpoints are published for consumption. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Services []hypershiftv1beta1.ServicePublishingStrategyMapping `json:"services"` + // pullSecret is a local reference to a Secret that must have a ".dockerconfigjson" key whose content must be a valid Openshift pull secret JSON. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + PullSecret corev1.LocalObjectReference `json:"pullSecret"` + // sshKey is a local reference to a Secret that must have a "id_rsa.pub" key whose content must be the public part of 1..N SSH keys. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + SSHKey corev1.LocalObjectReference `json:"sshKey"` + // issuerURL is an OIDC issuer URL which will be used as the issuer in all + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + IssuerURL string `json:"issuerURL,omitempty"` + // serviceAccountSigningKey is a local reference to a secret that must have a "key" key whose content must be the private key + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + ServiceAccountSigningKey *corev1.LocalObjectReference `json:"serviceAccountSigningKey,omitempty"` + // configuration specifies configuration for individual OCP components in the + // +k8s:openapi-gen=true + // +hyperfleet:write-mode=service-set + Configuration *hypershiftv1beta1.ClusterConfiguration `json:"configuration,omitempty"` + // operatorConfiguration specifies configuration for individual OCP operators in the cluster. + // +k8s:openapi-gen=true + // +hyperfleet:write-mode=service-set + OperatorConfiguration *hypershiftv1beta1.OperatorConfiguration `json:"operatorConfiguration,omitempty"` + // auditWebhook contains metadata for configuring an audit webhook endpoint + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + AuditWebhook *corev1.LocalObjectReference `json:"auditWebhook,omitempty"` + // imageContentSources specifies image mirrors that can be used by cluster + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + ImageContentSources []hypershiftv1beta1.ImageContentSource `json:"imageContentSources,omitempty"` + // additionalTrustBundle is a local reference to a ConfigMap that must have a "ca-bundle.crt" key + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + AdditionalTrustBundle *corev1.LocalObjectReference `json:"additionalTrustBundle,omitempty"` + // secretEncryption specifies a Kubernetes secret encryption strategy for the + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + SecretEncryption *hypershiftv1beta1.SecretEncryptionSpec `json:"secretEncryption,omitempty"` + // fips indicates whether this cluster's nodes will be running in FIPS mode. + // +k8s:openapi-gen=true + // +hyperfleet:write-mode=service-set + FIPS bool `json:"fips"` + // pausedUntil is a field that can be used to pause reconciliation on the HostedCluster controller, resulting in any change to the HostedCluster being ignored. + // +k8s:openapi-gen=true + // +hyperfleet:write-mode=service-set + PausedUntil *string `json:"pausedUntil,omitempty"` + // olmCatalogPlacement specifies the placement of OLM catalog components. By default, + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + OLMCatalogPlacement hypershiftv1beta1.OLMCatalogPlacement `json:"olmCatalogPlacement,omitempty"` + // nodeSelector when specified, is propagated to all control plane Deployments and Stateful sets running management side. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + NodeSelector map[string]string `json:"nodeSelector,omitempty"` + // tolerations when specified, define what custom tolerations are added to the hcp pods. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Tolerations []corev1.Toleration `json:"tolerations,omitempty"` + // labels when specified, define what custom labels are added to the hcp pods. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Labels map[string]string `json:"labels,omitempty"` + // capabilities allows for disabling optional components at cluster install time. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Capabilities *hypershiftv1beta1.Capabilities `json:"capabilities,omitempty"` +} + +// NodePoolSpecPassthrough mirrors NodePoolSpec from upstream HyperShift +type NodePoolSpecPassthrough struct { + // clusterName is the name of the HostedCluster this NodePool belongs to. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + ClusterName string `json:"clusterName"` + // release specifies the OCP release used for this NodePool. It drives the machine ignition configuration (including + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Release hypershiftv1beta1.Release `json:"release"` + // platform specifies the underlying infrastructure provider for the NodePool + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Platform hypershiftv1beta1.NodePoolPlatform `json:"platform"` + // replicas is the desired number of nodes the pool should maintain. If unset, the controller default value is 0. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Replicas *int32 `json:"replicas,omitempty"` + // management specifies behavior for managing nodes in the pool, such as + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Management hypershiftv1beta1.NodePoolManagement `json:"management"` + // autoScaling specifies auto-scaling behavior for the NodePool. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + AutoScaling *hypershiftv1beta1.NodePoolAutoScaling `json:"autoScaling,omitempty"` + // config is a list of references to ConfigMaps containing serialized + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Config []corev1.LocalObjectReference `json:"config,omitempty"` + // nodeDrainTimeout is the maximum amount of time that the controller will spend on retrying to drain a node until it succeeds. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + NodeDrainTimeout *metav1.Duration `json:"nodeDrainTimeout,omitempty"` + // nodeVolumeDetachTimeout is the maximum amount of time that the controller will spend on detaching volumes from a node. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + NodeVolumeDetachTimeout *metav1.Duration `json:"nodeVolumeDetachTimeout,omitempty"` + // nodeLabels propagates a list of labels to Nodes, only once on creation. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + NodeLabels map[string]string `json:"nodeLabels,omitempty"` + // taints if specified, propagates a list of taints to Nodes, only once on creation. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Taints []hypershiftv1beta1.Taint `json:"taints,omitempty"` + // pausedUntil is a field that can be used to pause reconciliation on the NodePool controller. Resulting in any change to the NodePool being ignored. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + PausedUntil *string `json:"pausedUntil,omitempty"` + // tuningConfig is a list of references to ConfigMaps containing serialized + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + TuningConfig []corev1.LocalObjectReference `json:"tuningConfig,omitempty"` + // arch is the preferred processor architecture for the NodePool. Different platforms might have different supported architectures. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Arch string `json:"arch,omitempty"` + // osImageStream specifies an OS stream to be used for nodes in this pool. + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + OSImageStream hypershiftv1beta1.OSImageStreamReference `json:"osImageStream,omitzero"` +} diff --git a/api/public/v2alpha1/nodepool_types.go b/api/public/v2alpha1/nodepool_types.go new file mode 100644 index 00000000..6b7a17f4 --- /dev/null +++ b/api/public/v2alpha1/nodepool_types.go @@ -0,0 +1,119 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +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. +*/ + +package v2alpha1 + +import ( + hypershiftv1beta1 "github.com/openshift/hypershift/api/hypershift/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// NodePoolPhase represents the lifecycle phase of a NodePool. +// +kubebuilder:validation:Enum=WaitingForCluster;Provisioning;Ready;Deleting +type NodePoolPhase string + +const ( + NodePoolPhaseWaitingForCluster NodePoolPhase = "WaitingForCluster" + NodePoolPhaseProvisioning NodePoolPhase = "Provisioning" + NodePoolPhaseReady NodePoolPhase = "Ready" + NodePoolPhaseDeleting NodePoolPhase = "Deleting" +) + +// NodePoolSpec defines the desired state of a NodePool. +type NodePoolSpec struct { + // DisplayName is a human-readable name for the node pool. + // +hyperfleet:write-mode=mutable + // +kubebuilder:validation:MaxLength=256 + // +optional + DisplayName string `json:"displayName,omitempty"` + + // AutoRepair enables automatic repair of unhealthy nodes. + // +hyperfleet:write-mode=mutable + // +optional + AutoRepair *bool `json:"autoRepair,omitempty"` + + // Labels are customer-defined labels applied to nodes. + // +hyperfleet:write-mode=mutable + // +optional + Labels map[string]string `json:"labels,omitempty"` + + // AccountID identifies the customer account (platform-managed, hidden from API). + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + // +optional + AccountID string `json:"accountId,omitempty"` + + // InternalPoolID is an internal platform identifier (platform-managed, hidden). + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + // +optional + InternalPoolID string `json:"internalPoolId,omitempty"` + + // NodePool is the full HyperShift NodePoolSpec. + // +kubebuilder:validation:Required + NodePool hypershiftv1beta1.NodePoolSpec `json:"nodePool"` +} + +// NodePoolStatus defines the observed state of a NodePool. +type NodePoolStatus struct { + // +listType=map + // +listMapKey=type + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // +optional + Phase NodePoolPhase `json:"phase,omitempty"` + + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Namespaced,shortName=hfnp +// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=".status.phase" +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=".metadata.creationTimestamp" + +// NodePool is the Schema for the nodepools API. +type NodePool struct { + metav1.TypeMeta `json:",inline"` + + // +optional + metav1.ObjectMeta `json:"metadata,omitzero"` + + // +required + Spec NodePoolSpec `json:"spec"` + + // +optional + Status NodePoolStatus `json:"status,omitzero"` +} + +// +kubebuilder:object:root=true + +// NodePoolList contains a list of NodePool. +type NodePoolList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitzero"` + Items []NodePool `json:"items"` +} + +func init() { + SchemeBuilder.Register(func(s *runtime.Scheme) error { + s.AddKnownTypes(SchemeGroupVersion, &NodePool{}, &NodePoolList{}) + return nil + }) +} diff --git a/api/public/v2alpha1/zz_generated.deepcopy.go b/api/public/v2alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000..41f8e35d --- /dev/null +++ b/api/public/v2alpha1/zz_generated.deepcopy.go @@ -0,0 +1,908 @@ +//go:build !ignore_autogenerated + +// Code generated by controller-gen. DO NOT EDIT. + +package v2alpha1 + +import ( + "github.com/openshift/hypershift/api/hypershift/v1beta1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *APIServerNetworkConfiguration) DeepCopyInto(out *APIServerNetworkConfiguration) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIServerNetworkConfiguration. +func (in *APIServerNetworkConfiguration) DeepCopy() *APIServerNetworkConfiguration { + if in == nil { + return nil + } + out := new(APIServerNetworkConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Cluster) DeepCopyInto(out *Cluster) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cluster. +func (in *Cluster) DeepCopy() *Cluster { + if in == nil { + return nil + } + out := new(Cluster) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Cluster) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterAuthentication) DeepCopyInto(out *ClusterAuthentication) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterAuthentication. +func (in *ClusterAuthentication) DeepCopy() *ClusterAuthentication { + if in == nil { + return nil + } + out := new(ClusterAuthentication) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterConfiguration) DeepCopyInto(out *ClusterConfiguration) { + *out = *in + if in.APIServer != nil { + in, out := &in.APIServer, &out.APIServer + *out = new(APIServerNetworkConfiguration) + **out = **in + } + if in.Authentication != nil { + in, out := &in.Authentication, &out.Authentication + *out = new(ClusterAuthentication) + **out = **in + } + if in.FeatureGate != nil { + in, out := &in.FeatureGate, &out.FeatureGate + *out = new(FeatureGateConfiguration) + **out = **in + } + if in.Image != nil { + in, out := &in.Image, &out.Image + *out = new(ImageConfiguration) + **out = **in + } + if in.Ingress != nil { + in, out := &in.Ingress, &out.Ingress + *out = new(IngressConfiguration) + **out = **in + } + if in.Network != nil { + in, out := &in.Network, &out.Network + *out = new(NetworkConfiguration) + **out = **in + } + if in.OAuth != nil { + in, out := &in.OAuth, &out.OAuth + *out = new(OAuthConfiguration) + **out = **in + } + if in.Scheduler != nil { + in, out := &in.Scheduler, &out.Scheduler + *out = new(SchedulerConfiguration) + **out = **in + } + if in.Proxy != nil { + in, out := &in.Proxy, &out.Proxy + *out = new(ProxyConfiguration) + **out = **in + } + if in.Kubelet != nil { + in, out := &in.Kubelet, &out.Kubelet + *out = new(KubeletConfig) + (*in).DeepCopyInto(*out) + } + if in.MachineConfig != nil { + in, out := &in.MachineConfig, &out.MachineConfig + *out = new(MachineConfigSpec) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterConfiguration. +func (in *ClusterConfiguration) DeepCopy() *ClusterConfiguration { + if in == nil { + return nil + } + out := new(ClusterConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterList) DeepCopyInto(out *ClusterList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Cluster, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterList. +func (in *ClusterList) DeepCopy() *ClusterList { + if in == nil { + return nil + } + out := new(ClusterList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterSpec) DeepCopyInto(out *ClusterSpec) { + *out = *in + if in.DeleteProtection != nil { + in, out := &in.DeleteProtection, &out.DeleteProtection + *out = new(bool) + **out = **in + } + if in.ExpirationTimestamp != nil { + in, out := &in.ExpirationTimestamp, &out.ExpirationTimestamp + *out = (*in).DeepCopy() + } + if in.Properties != nil { + in, out := &in.Properties, &out.Properties + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + in.HostedCluster.DeepCopyInto(&out.HostedCluster) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSpec. +func (in *ClusterSpec) DeepCopy() *ClusterSpec { + if in == nil { + return nil + } + out := new(ClusterSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.ControlPlaneEndpoint = in.ControlPlaneEndpoint + if in.PlacementRef != nil { + in, out := &in.PlacementRef, &out.PlacementRef + *out = new(PlacementReference) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterStatus. +func (in *ClusterStatus) DeepCopy() *ClusterStatus { + if in == nil { + return nil + } + out := new(ClusterStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FeatureGateConfiguration) DeepCopyInto(out *FeatureGateConfiguration) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FeatureGateConfiguration. +func (in *FeatureGateConfiguration) DeepCopy() *FeatureGateConfiguration { + if in == nil { + return nil + } + out := new(FeatureGateConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FileSpec) DeepCopyInto(out *FileSpec) { + *out = *in + if in.Mode != nil { + in, out := &in.Mode, &out.Mode + *out = new(int32) + **out = **in + } + if in.User != nil { + in, out := &in.User, &out.User + *out = new(string) + **out = **in + } + if in.Group != nil { + in, out := &in.Group, &out.Group + *out = new(string) + **out = **in + } + if in.Overwrite != nil { + in, out := &in.Overwrite, &out.Overwrite + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileSpec. +func (in *FileSpec) DeepCopy() *FileSpec { + if in == nil { + return nil + } + out := new(FileSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HostedClusterSpecPassthrough) DeepCopyInto(out *HostedClusterSpecPassthrough) { + *out = *in + out.Release = in.Release + if in.ControlPlaneRelease != nil { + in, out := &in.ControlPlaneRelease, &out.ControlPlaneRelease + *out = new(v1beta1.Release) + **out = **in + } + in.Platform.DeepCopyInto(&out.Platform) + in.DNS.DeepCopyInto(&out.DNS) + in.Networking.DeepCopyInto(&out.Networking) + in.Autoscaling.DeepCopyInto(&out.Autoscaling) + out.AutoNode = in.AutoNode + in.Etcd.DeepCopyInto(&out.Etcd) + if in.Services != nil { + in, out := &in.Services, &out.Services + *out = make([]v1beta1.ServicePublishingStrategyMapping, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.PullSecret = in.PullSecret + out.SSHKey = in.SSHKey + if in.ServiceAccountSigningKey != nil { + in, out := &in.ServiceAccountSigningKey, &out.ServiceAccountSigningKey + *out = new(corev1.LocalObjectReference) + **out = **in + } + if in.Configuration != nil { + in, out := &in.Configuration, &out.Configuration + *out = new(v1beta1.ClusterConfiguration) + (*in).DeepCopyInto(*out) + } + if in.OperatorConfiguration != nil { + in, out := &in.OperatorConfiguration, &out.OperatorConfiguration + *out = new(v1beta1.OperatorConfiguration) + (*in).DeepCopyInto(*out) + } + if in.AuditWebhook != nil { + in, out := &in.AuditWebhook, &out.AuditWebhook + *out = new(corev1.LocalObjectReference) + **out = **in + } + if in.ImageContentSources != nil { + in, out := &in.ImageContentSources, &out.ImageContentSources + *out = make([]v1beta1.ImageContentSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.AdditionalTrustBundle != nil { + in, out := &in.AdditionalTrustBundle, &out.AdditionalTrustBundle + *out = new(corev1.LocalObjectReference) + **out = **in + } + if in.SecretEncryption != nil { + in, out := &in.SecretEncryption, &out.SecretEncryption + *out = new(v1beta1.SecretEncryptionSpec) + (*in).DeepCopyInto(*out) + } + if in.PausedUntil != nil { + in, out := &in.PausedUntil, &out.PausedUntil + *out = new(string) + **out = **in + } + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]corev1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Capabilities != nil { + in, out := &in.Capabilities, &out.Capabilities + *out = new(v1beta1.Capabilities) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostedClusterSpecPassthrough. +func (in *HostedClusterSpecPassthrough) DeepCopy() *HostedClusterSpecPassthrough { + if in == nil { + return nil + } + out := new(HostedClusterSpecPassthrough) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageConfiguration) DeepCopyInto(out *ImageConfiguration) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageConfiguration. +func (in *ImageConfiguration) DeepCopy() *ImageConfiguration { + if in == nil { + return nil + } + out := new(ImageConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IngressConfiguration) DeepCopyInto(out *IngressConfiguration) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressConfiguration. +func (in *IngressConfiguration) DeepCopy() *IngressConfiguration { + if in == nil { + return nil + } + out := new(IngressConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubeletConfig) DeepCopyInto(out *KubeletConfig) { + *out = *in + if in.MaxPods != nil { + in, out := &in.MaxPods, &out.MaxPods + *out = new(int32) + **out = **in + } + if in.PodPidsLimit != nil { + in, out := &in.PodPidsLimit, &out.PodPidsLimit + *out = new(int64) + **out = **in + } + if in.SystemReserved != nil { + in, out := &in.SystemReserved, &out.SystemReserved + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.KubeReserved != nil { + in, out := &in.KubeReserved, &out.KubeReserved + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.EvictionHard != nil { + in, out := &in.EvictionHard, &out.EvictionHard + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.EvictionSoft != nil { + in, out := &in.EvictionSoft, &out.EvictionSoft + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.EvictionSoftGracePeriod != nil { + in, out := &in.EvictionSoftGracePeriod, &out.EvictionSoftGracePeriod + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.ImageGCHighThresholdPercent != nil { + in, out := &in.ImageGCHighThresholdPercent, &out.ImageGCHighThresholdPercent + *out = new(int32) + **out = **in + } + if in.ImageGCLowThresholdPercent != nil { + in, out := &in.ImageGCLowThresholdPercent, &out.ImageGCLowThresholdPercent + *out = new(int32) + **out = **in + } + if in.ImageMinimumGCAge != nil { + in, out := &in.ImageMinimumGCAge, &out.ImageMinimumGCAge + *out = new(v1.Duration) + **out = **in + } + if in.SerializeImagePulls != nil { + in, out := &in.SerializeImagePulls, &out.SerializeImagePulls + *out = new(bool) + **out = **in + } + if in.RegistryPullQPS != nil { + in, out := &in.RegistryPullQPS, &out.RegistryPullQPS + *out = new(int32) + **out = **in + } + if in.RegistryBurst != nil { + in, out := &in.RegistryBurst, &out.RegistryBurst + *out = new(int32) + **out = **in + } + if in.CPUManagerPolicy != nil { + in, out := &in.CPUManagerPolicy, &out.CPUManagerPolicy + *out = new(string) + **out = **in + } + if in.CPUManagerPolicyOptions != nil { + in, out := &in.CPUManagerPolicyOptions, &out.CPUManagerPolicyOptions + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.CPUManagerReconcilePeriod != nil { + in, out := &in.CPUManagerReconcilePeriod, &out.CPUManagerReconcilePeriod + *out = new(v1.Duration) + **out = **in + } + if in.TopologyManagerPolicy != nil { + in, out := &in.TopologyManagerPolicy, &out.TopologyManagerPolicy + *out = new(string) + **out = **in + } + if in.TopologyManagerScope != nil { + in, out := &in.TopologyManagerScope, &out.TopologyManagerScope + *out = new(string) + **out = **in + } + if in.AllowedUnsafeSysctls != nil { + in, out := &in.AllowedUnsafeSysctls, &out.AllowedUnsafeSysctls + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.StreamingConnectionIdleTimeout != nil { + in, out := &in.StreamingConnectionIdleTimeout, &out.StreamingConnectionIdleTimeout + *out = new(v1.Duration) + **out = **in + } + if in.ContainerLogMaxSize != nil { + in, out := &in.ContainerLogMaxSize, &out.ContainerLogMaxSize + *out = new(string) + **out = **in + } + if in.ContainerLogMaxFiles != nil { + in, out := &in.ContainerLogMaxFiles, &out.ContainerLogMaxFiles + *out = new(int32) + **out = **in + } + if in.MemoryThrottlingFactor != nil { + in, out := &in.MemoryThrottlingFactor, &out.MemoryThrottlingFactor + *out = new(float64) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletConfig. +func (in *KubeletConfig) DeepCopy() *KubeletConfig { + if in == nil { + return nil + } + out := new(KubeletConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineConfigSpec) DeepCopyInto(out *MachineConfigSpec) { + *out = *in + if in.AllowedKernelArguments != nil { + in, out := &in.AllowedKernelArguments, &out.AllowedKernelArguments + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.KernelArguments != nil { + in, out := &in.KernelArguments, &out.KernelArguments + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SystemdUnits != nil { + in, out := &in.SystemdUnits, &out.SystemdUnits + *out = make([]SystemdUnit, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Files != nil { + in, out := &in.Files, &out.Files + *out = make([]FileSpec, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.FIPS != nil { + in, out := &in.FIPS, &out.FIPS + *out = new(bool) + **out = **in + } + if in.KernelType != nil { + in, out := &in.KernelType, &out.KernelType + *out = new(string) + **out = **in + } + if in.Extensions != nil { + in, out := &in.Extensions, &out.Extensions + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineConfigSpec. +func (in *MachineConfigSpec) DeepCopy() *MachineConfigSpec { + if in == nil { + return nil + } + out := new(MachineConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkConfiguration) DeepCopyInto(out *NetworkConfiguration) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkConfiguration. +func (in *NetworkConfiguration) DeepCopy() *NetworkConfiguration { + if in == nil { + return nil + } + out := new(NetworkConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodePool) DeepCopyInto(out *NodePool) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodePool. +func (in *NodePool) DeepCopy() *NodePool { + if in == nil { + return nil + } + out := new(NodePool) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodePool) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodePoolList) DeepCopyInto(out *NodePoolList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]NodePool, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodePoolList. +func (in *NodePoolList) DeepCopy() *NodePoolList { + if in == nil { + return nil + } + out := new(NodePoolList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodePoolList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodePoolSpec) DeepCopyInto(out *NodePoolSpec) { + *out = *in + if in.AutoRepair != nil { + in, out := &in.AutoRepair, &out.AutoRepair + *out = new(bool) + **out = **in + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + in.NodePool.DeepCopyInto(&out.NodePool) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodePoolSpec. +func (in *NodePoolSpec) DeepCopy() *NodePoolSpec { + if in == nil { + return nil + } + out := new(NodePoolSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodePoolSpecPassthrough) DeepCopyInto(out *NodePoolSpecPassthrough) { + *out = *in + out.Release = in.Release + in.Platform.DeepCopyInto(&out.Platform) + if in.Replicas != nil { + in, out := &in.Replicas, &out.Replicas + *out = new(int32) + **out = **in + } + in.Management.DeepCopyInto(&out.Management) + if in.AutoScaling != nil { + in, out := &in.AutoScaling, &out.AutoScaling + *out = new(v1beta1.NodePoolAutoScaling) + (*in).DeepCopyInto(*out) + } + if in.Config != nil { + in, out := &in.Config, &out.Config + *out = make([]corev1.LocalObjectReference, len(*in)) + copy(*out, *in) + } + if in.NodeDrainTimeout != nil { + in, out := &in.NodeDrainTimeout, &out.NodeDrainTimeout + *out = new(v1.Duration) + **out = **in + } + if in.NodeVolumeDetachTimeout != nil { + in, out := &in.NodeVolumeDetachTimeout, &out.NodeVolumeDetachTimeout + *out = new(v1.Duration) + **out = **in + } + if in.NodeLabels != nil { + in, out := &in.NodeLabels, &out.NodeLabels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Taints != nil { + in, out := &in.Taints, &out.Taints + *out = make([]v1beta1.Taint, len(*in)) + copy(*out, *in) + } + if in.PausedUntil != nil { + in, out := &in.PausedUntil, &out.PausedUntil + *out = new(string) + **out = **in + } + if in.TuningConfig != nil { + in, out := &in.TuningConfig, &out.TuningConfig + *out = make([]corev1.LocalObjectReference, len(*in)) + copy(*out, *in) + } + out.OSImageStream = in.OSImageStream +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodePoolSpecPassthrough. +func (in *NodePoolSpecPassthrough) DeepCopy() *NodePoolSpecPassthrough { + if in == nil { + return nil + } + out := new(NodePoolSpecPassthrough) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodePoolStatus) DeepCopyInto(out *NodePoolStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodePoolStatus. +func (in *NodePoolStatus) DeepCopy() *NodePoolStatus { + if in == nil { + return nil + } + out := new(NodePoolStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OAuthConfiguration) DeepCopyInto(out *OAuthConfiguration) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OAuthConfiguration. +func (in *OAuthConfiguration) DeepCopy() *OAuthConfiguration { + if in == nil { + return nil + } + out := new(OAuthConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PlacementReference) DeepCopyInto(out *PlacementReference) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlacementReference. +func (in *PlacementReference) DeepCopy() *PlacementReference { + if in == nil { + return nil + } + out := new(PlacementReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProxyConfiguration) DeepCopyInto(out *ProxyConfiguration) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyConfiguration. +func (in *ProxyConfiguration) DeepCopy() *ProxyConfiguration { + if in == nil { + return nil + } + out := new(ProxyConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SchedulerConfiguration) DeepCopyInto(out *SchedulerConfiguration) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SchedulerConfiguration. +func (in *SchedulerConfiguration) DeepCopy() *SchedulerConfiguration { + if in == nil { + return nil + } + out := new(SchedulerConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SystemdDropin) DeepCopyInto(out *SystemdDropin) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SystemdDropin. +func (in *SystemdDropin) DeepCopy() *SystemdDropin { + if in == nil { + return nil + } + out := new(SystemdDropin) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SystemdUnit) DeepCopyInto(out *SystemdUnit) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) + **out = **in + } + if in.Dropins != nil { + in, out := &in.Dropins, &out.Dropins + *out = make([]SystemdDropin, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SystemdUnit. +func (in *SystemdUnit) DeepCopy() *SystemdUnit { + if in == nil { + return nil + } + out := new(SystemdUnit) + in.DeepCopyInto(out) + return out +} diff --git a/hack/api-codegen/go.mod b/hack/api-codegen/go.mod index aab7dd67..9a0c623b 100644 --- a/hack/api-codegen/go.mod +++ b/hack/api-codegen/go.mod @@ -3,7 +3,7 @@ module github.com/openshift-online/rosa-hyperfleet-api/hack/api-codegen go 1.26.3 require ( - github.com/openshift/hypershift/api v0.0.0-20251113065312-f919037748bf + github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16 gopkg.in/yaml.v3 v3.0.1 k8s.io/apiextensions-apiserver v0.36.0 sigs.k8s.io/controller-tools v0.21.0 @@ -17,7 +17,7 @@ require ( github.com/kr/text v0.2.0 // 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-20250609083529-2b129d95495e // 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/mod v0.38.0 // indirect diff --git a/hack/api-codegen/go.sum b/hack/api-codegen/go.sum index 55a0e604..119aa6f8 100644 --- a/hack/api-codegen/go.sum +++ b/hack/api-codegen/go.sum @@ -88,10 +88,10 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.40.0 h1:Vtol0e1MghCD2ZVIilPDIg44XSL9l2QAn8ZNaljWcJc= github.com/onsi/gomega v1.40.0/go.mod h1:M/Uqpu/8qTjtzCLUA2zJHX9Iilrau25x1PdoSRbWh5A= -github.com/openshift/api v0.0.0-20250609083529-2b129d95495e h1:QjdoupNBBgSMDypMWsbhb+/yfyv27b3mqT9eVj8g0h4= -github.com/openshift/api v0.0.0-20250609083529-2b129d95495e/go.mod h1:yk60tHAmHhtVpJQo3TwVYq2zpuP70iJIFDCmeKMIzPw= -github.com/openshift/hypershift/api v0.0.0-20251113065312-f919037748bf h1:TibqiqqSGwofAm8p5vdZ4Q3nYMwVofdtCcSoF0geF1o= -github.com/openshift/hypershift/api v0.0.0-20251113065312-f919037748bf/go.mod h1:JiaoBwTsYtBVKKPgHcajChZCu20KdM97W2xc0MeBCBA= +github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80 h1:r0S/yoZAI0iWo1JvoIijaIgWGWf/izg4WiV7Wrtz16k= +github.com/openshift/api v0.0.0-20260416105050-3c6b218b8a80/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo= +github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16 h1:QDSh3vkKYq7Fn9utYGlAJadkTdyaRl9IY7Cr6cNDAow= +github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16/go.mod h1:Z3lkj5pFqY+KTl3Do9gXdEZdKWLnkUTSDShLD1HE0CM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/hack/api-codegen/pkg/markers/scanner.go b/hack/api-codegen/pkg/markers/scanner.go index 023f6fb4..9257fcfb 100644 --- a/hack/api-codegen/pkg/markers/scanner.go +++ b/hack/api-codegen/pkg/markers/scanner.go @@ -83,20 +83,41 @@ func (s *MarkerScanner) scanDir(dir string) error { if isRootType(typeName) { visited := make(map[string]bool) visited[typeName] = true - s.processStruct(typeName, structType, "", visited) + prefix := rootTypePrefix(typeName) + s.processStruct(typeName, structType, prefix, visited) } } return nil } -// isRootType returns true for top-level CRD types (not Spec/Status/Passthrough types) +// rootTypePrefix returns a dotted prefix that namespaces registry keys by root +// type, so fields with the same JSON name in different root types (e.g. +// HostedClusterSpecPassthrough.PausedUntil vs NodePoolSpecPassthrough.PausedUntil) +// don't collide in the flat FieldRegistry map. The prefixes mirror +// conversion/generator.go buildFieldPath so consumers can look up entries +// with the same key they construct. +func rootTypePrefix(typeName string) string { + if strings.HasSuffix(typeName, "Passthrough") { + if strings.HasPrefix(typeName, "HostedCluster") { + return "spec.hostedCluster" + } + if strings.HasPrefix(typeName, "NodePool") { + return "spec.nodePool" + } + } + return "" +} + +// isRootType returns true for types that are entry points for marker scanning. +// Passthrough types ARE root types since they carry curated markers. func isRootType(typeName string) bool { - // Root types don't have suffixes + if strings.HasSuffix(typeName, "Passthrough") { + return true + } return !strings.HasSuffix(typeName, "Spec") && !strings.HasSuffix(typeName, "Status") && !strings.HasSuffix(typeName, "List") && - !strings.HasSuffix(typeName, "Passthrough") && typeName != "ClusterReference" } diff --git a/hack/api-codegen/pkg/markers/scanner_test.go b/hack/api-codegen/pkg/markers/scanner_test.go index 249c48f2..6956b948 100644 --- a/hack/api-codegen/pkg/markers/scanner_test.go +++ b/hack/api-codegen/pkg/markers/scanner_test.go @@ -90,6 +90,82 @@ type EtcdSpec struct { } } +func TestPassthroughTypesPrefixed(t *testing.T) { + tmpDir := t.TempDir() + + testFile := filepath.Join(tmpDir, "types.go") + content := `package test + +type HostedClusterSpecPassthrough struct { + // +k8s:openapi-gen=true + // +hyperfleet:write-mode=service-set + PausedUntil *string ` + "`json:\"pausedUntil,omitempty\"`" + ` + + // +k8s:openapi-gen=true + // +hyperfleet:write-mode=immutable + FIPS bool ` + "`json:\"fips\"`" + ` +} + +type NodePoolSpecPassthrough struct { + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + PausedUntil *string ` + "`json:\"pausedUntil,omitempty\"`" + ` + + // +k8s:openapi-gen=false + // +hyperfleet:write-mode=service-set + Replicas *int ` + "`json:\"replicas,omitempty\"`" + ` +} +` + + if err := os.WriteFile(testFile, []byte(content), 0644); err != nil { + t.Fatalf("Failed to write test file: %v", err) + } + + scanner := NewScanner([]string{tmpDir}) + if err := scanner.Scan(); err != nil { + t.Fatalf("Scan failed: %v", err) + } + + tests := []struct { + fieldPath string + writeMode WriteMode + hidden bool + }{ + {"spec.hostedCluster.pausedUntil", ServiceSet, false}, + {"spec.hostedCluster.fips", Immutable, false}, + {"spec.nodePool.pausedUntil", ServiceSet, true}, + {"spec.nodePool.replicas", ServiceSet, true}, + } + + for _, tt := range tests { + t.Run(tt.fieldPath, func(t *testing.T) { + meta, found := scanner.Registry[tt.fieldPath] + if !found { + t.Fatalf("Field %s not found in registry (keys: %v)", tt.fieldPath, registryKeys(scanner.Registry)) + } + if meta.WriteMode != tt.writeMode { + t.Errorf("WriteMode = %v, want %v", meta.WriteMode, tt.writeMode) + } + if meta.Hidden != tt.hidden { + t.Errorf("Hidden = %v, want %v", meta.Hidden, tt.hidden) + } + }) + } + + // Verify no flat "pausedUntil" key exists (the old collision) + if _, found := scanner.Registry["pausedUntil"]; found { + t.Error("flat key \"pausedUntil\" should not exist; passthrough fields must be prefixed") + } +} + +func registryKeys(r FieldRegistry) []string { + keys := make([]string, 0, len(r)) + for k := range r { + keys = append(keys, k) + } + return keys +} + func TestValidation(t *testing.T) { tests := []struct { name string diff --git a/platform-api/Containerfile b/platform-api/Containerfile index ffb84f0c..44b16984 100644 --- a/platform-api/Containerfile +++ b/platform-api/Containerfile @@ -8,11 +8,13 @@ WORKDIR /app COPY hyperfleet-db/go.mod hyperfleet-db/go.sum ./hyperfleet-db/ COPY hyperfleet-operator/api/go.mod hyperfleet-operator/api/go.sum ./hyperfleet-operator/api/ +COPY hack/api-codegen/go.mod hack/api-codegen/go.sum ./hack/api-codegen/ COPY platform-api/go.mod platform-api/go.sum ./platform-api/ RUN cd platform-api && go mod download COPY hyperfleet-db/ ./hyperfleet-db/ COPY hyperfleet-operator/api/ ./hyperfleet-operator/api/ +COPY hack/api-codegen/ ./hack/api-codegen/ COPY platform-api/ ./platform-api/ RUN cd platform-api && \ diff --git a/platform-api/go.mod b/platform-api/go.mod index b422bdf5..148c0c55 100644 --- a/platform-api/go.mod +++ b/platform-api/go.mod @@ -3,6 +3,7 @@ module github.com/openshift-online/rosa-hyperfleet-api/platform-api go 1.26.3 replace ( + github.com/openshift-online/rosa-hyperfleet-api/hack/api-codegen => ../hack/api-codegen github.com/openshift-online/rosa-hyperfleet-api/hyperfleet-db => ../hyperfleet-db github.com/openshift-online/rosa-hyperfleet-api/hyperfleet-operator/api => ../hyperfleet-operator/api ) @@ -20,6 +21,7 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 github.com/onsi/ginkgo/v2 v2.28.1 + github.com/openshift-online/rosa-hyperfleet-api/hack/api-codegen v0.0.0 github.com/openshift-online/rosa-hyperfleet-api/hyperfleet-db v0.0.0 github.com/openshift-online/rosa-hyperfleet-api/hyperfleet-operator/api v0.0.0 github.com/openshift/hypershift/api v0.0.0-20260625052409-9acec4759a16 @@ -114,10 +116,10 @@ require ( k8s.io/apiextensions-apiserver v0.36.0 // indirect k8s.io/client-go v0.36.0 // indirect k8s.io/klog/v2 v2.140.0 // indirect - k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect + k8s.io/kube-openapi v0.0.0-20260706235625-cdb1db5517a0 // indirect k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.4.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/platform-api/go.sum b/platform-api/go.sum index c2ef6c1e..b6f73913 100644 --- a/platform-api/go.sum +++ b/platform-api/go.sum @@ -279,8 +279,8 @@ k8s.io/client-go v0.36.0 h1:pOYi7C4RHChYjMiHpZSpSbIM6ZxVbRXBy7CuiIwqA3c= k8s.io/client-go v0.36.0/go.mod h1:ZKKcpwF0aLYfkHFCjillCKaTK/yBkEDHTDXCFY6AS9Y= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= -k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg= -k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= +k8s.io/kube-openapi v0.0.0-20260706235625-cdb1db5517a0 h1:CVjOUCTXINUThEmDs25FNSna0+vnGSoTleN+wiJu6hE= +k8s.io/kube-openapi v0.0.0-20260706235625-cdb1db5517a0/go.mod h1:rcZ+P5cEvHQB+m154WBOatIGBgOEPjzmLkXjkHfg3ms= k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 h1:jVkFFVfXdXP74B/zbO3hM3hpSFD0xvhQ5U686DPurkE= k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3/go.mod h1:M2s5JB1lIYP3jzZdorPLHXIPJzt9vv2muW5a6L9DtNM= sigs.k8s.io/controller-runtime v0.24.1 h1:miPEwrmirImAvgME1L9qebGHrOnGJoVmVdtOU9fRfo4= @@ -289,7 +289,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.4.1 h1:AkER7js0XVWi/F/V2Iwl5N7O/B9VP2JyrOMmHPdco+g= +sigs.k8s.io/structured-merge-diff/v6 v6.4.1/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/platform-api/internal/codegen/conversion/cluster.go b/platform-api/internal/codegen/conversion/cluster.go new file mode 100644 index 00000000..a5fe086f --- /dev/null +++ b/platform-api/internal/codegen/conversion/cluster.go @@ -0,0 +1,40 @@ +package conversion + +// ClusterServiceSetFields holds platform-injected values for cluster creation. +type ClusterServiceSetFields struct { + CloudURL string + Placement string + CreatorARN string +} + +// InjectClusterServiceSet strips client-supplied service-set fields and +// replaces them with platform-injected values. +func InjectClusterServiceSet(spec map[string]interface{}, ssf ClusterServiceSetFields) { + if spec == nil { + return + } + delete(spec, "cloudUrl") + if ssf.CloudURL != "" { + spec["cloudUrl"] = ssf.CloudURL + } + + delete(spec, "creatorARN") + if ssf.CreatorARN != "" { + spec["creatorARN"] = ssf.CreatorARN + } + + if ssf.Placement != "" { + existing, _ := spec["placement"].(string) + if existing == "" { + spec["placement"] = ssf.Placement + } + } +} + +// RewriteCloudURLWithID sets cloudUrl to baseURL/clusterID in a response spec. +func RewriteCloudURLWithID(spec map[string]interface{}, baseURL, clusterID string) { + if spec == nil { + return + } + spec["cloudUrl"] = baseURL + "/" + clusterID +} diff --git a/platform-api/internal/codegen/featuregate/registry.go b/platform-api/internal/codegen/featuregate/registry.go new file mode 100644 index 00000000..6add7396 --- /dev/null +++ b/platform-api/internal/codegen/featuregate/registry.go @@ -0,0 +1,53 @@ +package featuregate + +import "sort" + +// HyperFleetFeatureGates is the registry of all feature gates. +var HyperFleetFeatureGates = map[string]FeatureGateInfo{ + "HyperFleetEtcdConfig": { + Stage: GA, + Description: "Allows customers to configure etcd settings", + }, + "HyperFleetAutoScaling": { + Stage: TechPreview, + Description: "Enables cluster autoscaling configuration", + }, + "HyperFleetSecretEncryption": { + Stage: TechPreview, + Description: "Allows customers to configure secret encryption", + }, + "HyperFleetCustomDNS": { + Stage: DevPreview, + Description: "Enables custom DNS configuration for development/testing", + }, + "HyperFleetKubeletAdvanced": { + Stage: TechPreview, + Description: "Enables advanced kubelet configuration (serializeImagePulls, registryPullQPS, etc.)", + }, + "HyperFleetMachineConfig": { + Stage: TechPreview, + Description: "Allows customers to request approved kernel parameters via allowlist", + }, +} + +// IsGateEnabled returns true if the given gate is enabled for the feature set. +func IsGateEnabled(gate string, featureSet FeatureSet) bool { + info, exists := HyperFleetFeatureGates[gate] + if !exists { + return false + } + return featureSet.Includes(info.Stage) +} + +// GatesForFeatureSet returns all gates enabled for the given feature set. +func GatesForFeatureSet(featureSet FeatureSet) []string { + var gates []string + maxStage := featureSet.MaxStage() + for gate, info := range HyperFleetFeatureGates { + if info.Stage <= maxStage { + gates = append(gates, gate) + } + } + sort.Strings(gates) + return gates +} diff --git a/platform-api/internal/codegen/featuregate/types.go b/platform-api/internal/codegen/featuregate/types.go new file mode 100644 index 00000000..4c4676e8 --- /dev/null +++ b/platform-api/internal/codegen/featuregate/types.go @@ -0,0 +1,53 @@ +package featuregate + +// FeatureStage represents the maturity stage of a feature gate +type FeatureStage int + +const ( + GA FeatureStage = iota + TechPreview + DevPreview +) + +func (s FeatureStage) String() string { + switch s { + case GA: + return "GA" + case TechPreview: + return "TechPreview" + case DevPreview: + return "DevPreview" + default: + return "Unknown" + } +} + +// FeatureGateInfo describes a single feature gate +type FeatureGateInfo struct { + Stage FeatureStage + Description string +} + +// FeatureSet represents a collection of feature gates +type FeatureSet string + +const ( + Default FeatureSet = "Default" + TechPreviewNoUpgrade FeatureSet = "TechPreviewNoUpgrade" + DevPreviewNoUpgrade FeatureSet = "DevPreviewNoUpgrade" +) + +func (fs FeatureSet) MaxStage() FeatureStage { + switch fs { + case TechPreviewNoUpgrade: + return TechPreview + case DevPreviewNoUpgrade: + return DevPreview + default: + return GA + } +} + +func (fs FeatureSet) Includes(stage FeatureStage) bool { + return stage <= fs.MaxStage() +} diff --git a/platform-api/internal/codegen/registry/field_metadata.go b/platform-api/internal/codegen/registry/field_metadata.go new file mode 100644 index 00000000..a91856e3 --- /dev/null +++ b/platform-api/internal/codegen/registry/field_metadata.go @@ -0,0 +1,603 @@ +// Code generated by marker-scanner. DO NOT EDIT. + +package registry + +import ( + "github.com/openshift-online/rosa-hyperfleet-api/hack/api-codegen/pkg/markers" +) + +// Type aliases re-exported from markers so that consumers of this package +// do not need to import markers directly. +type WriteMode = markers.WriteMode +type FieldMeta = markers.FieldMeta +type FeatureGateWriteMode = markers.FeatureGateWriteMode + +const ( + Mutable = markers.Mutable + Immutable = markers.Immutable + ServiceSet = markers.ServiceSet +) + +// FieldRegistry maps field paths to their metadata +var FieldRegistry = map[string]FieldMeta{ + "allowedUnsafeSysctls": { + FieldPath: "allowedUnsafeSysctls", + WriteMode: ServiceSet, + Hidden: true, + }, + "apiServer": { + FieldPath: "apiServer", + WriteMode: ServiceSet, + Hidden: true, + }, + "authentication": { + FieldPath: "authentication", + WriteMode: ServiceSet, + Hidden: true, + }, + "containerLogMaxFiles": { + FieldPath: "containerLogMaxFiles", + WriteMode: Mutable, + }, + "containerLogMaxSize": { + FieldPath: "containerLogMaxSize", + WriteMode: Mutable, + }, + "cpuManagerPolicy": { + FieldPath: "cpuManagerPolicy", + WriteMode: ServiceSet, + Hidden: true, + }, + "cpuManagerPolicyOptions": { + FieldPath: "cpuManagerPolicyOptions", + WriteMode: ServiceSet, + Hidden: true, + }, + "cpuManagerReconcilePeriod": { + FieldPath: "cpuManagerReconcilePeriod", + WriteMode: ServiceSet, + Hidden: true, + }, + "evictionHard": { + FieldPath: "evictionHard", + WriteMode: ServiceSet, + Hidden: true, + }, + "evictionSoft": { + FieldPath: "evictionSoft", + WriteMode: ServiceSet, + Hidden: true, + }, + "evictionSoftGracePeriod": { + FieldPath: "evictionSoftGracePeriod", + WriteMode: ServiceSet, + Hidden: true, + }, + "featureGate": { + FieldPath: "featureGate", + WriteMode: ServiceSet, + Hidden: true, + }, + "image": { + FieldPath: "image", + WriteMode: ServiceSet, + Hidden: true, + }, + "imageGCHighThresholdPercent": { + FieldPath: "imageGCHighThresholdPercent", + WriteMode: Mutable, + }, + "imageGCLowThresholdPercent": { + FieldPath: "imageGCLowThresholdPercent", + WriteMode: Mutable, + }, + "imageMinimumGCAge": { + FieldPath: "imageMinimumGCAge", + WriteMode: Mutable, + }, + "ingress": { + FieldPath: "ingress", + WriteMode: ServiceSet, + Hidden: true, + }, + "kubeReserved": { + FieldPath: "kubeReserved", + WriteMode: Immutable, + }, + "kubelet": { + FieldPath: "kubelet", + WriteMode: ServiceSet, + }, + "kubelet.allowedUnsafeSysctls": { + FieldPath: "kubelet.allowedUnsafeSysctls", + WriteMode: ServiceSet, + Hidden: true, + }, + "kubelet.containerLogMaxFiles": { + FieldPath: "kubelet.containerLogMaxFiles", + WriteMode: Mutable, + }, + "kubelet.containerLogMaxSize": { + FieldPath: "kubelet.containerLogMaxSize", + WriteMode: Mutable, + }, + "kubelet.cpuManagerPolicy": { + FieldPath: "kubelet.cpuManagerPolicy", + WriteMode: ServiceSet, + Hidden: true, + }, + "kubelet.cpuManagerPolicyOptions": { + FieldPath: "kubelet.cpuManagerPolicyOptions", + WriteMode: ServiceSet, + Hidden: true, + }, + "kubelet.cpuManagerReconcilePeriod": { + FieldPath: "kubelet.cpuManagerReconcilePeriod", + WriteMode: ServiceSet, + Hidden: true, + }, + "kubelet.evictionHard": { + FieldPath: "kubelet.evictionHard", + WriteMode: ServiceSet, + Hidden: true, + }, + "kubelet.evictionSoft": { + FieldPath: "kubelet.evictionSoft", + WriteMode: ServiceSet, + Hidden: true, + }, + "kubelet.evictionSoftGracePeriod": { + FieldPath: "kubelet.evictionSoftGracePeriod", + WriteMode: ServiceSet, + Hidden: true, + }, + "kubelet.imageGCHighThresholdPercent": { + FieldPath: "kubelet.imageGCHighThresholdPercent", + WriteMode: Mutable, + }, + "kubelet.imageGCLowThresholdPercent": { + FieldPath: "kubelet.imageGCLowThresholdPercent", + WriteMode: Mutable, + }, + "kubelet.imageMinimumGCAge": { + FieldPath: "kubelet.imageMinimumGCAge", + WriteMode: Mutable, + }, + "kubelet.kubeReserved": { + FieldPath: "kubelet.kubeReserved", + WriteMode: Immutable, + }, + "kubelet.maxPods": { + FieldPath: "kubelet.maxPods", + WriteMode: Mutable, + }, + "kubelet.memoryThrottlingFactor": { + FieldPath: "kubelet.memoryThrottlingFactor", + WriteMode: ServiceSet, + Hidden: true, + }, + "kubelet.podPidsLimit": { + FieldPath: "kubelet.podPidsLimit", + WriteMode: Mutable, + }, + "kubelet.registryBurst": { + FieldPath: "kubelet.registryBurst", + WriteMode: Mutable, + FeatureGate: "HyperFleetKubeletAdvanced", + }, + "kubelet.registryPullQPS": { + FieldPath: "kubelet.registryPullQPS", + WriteMode: Mutable, + FeatureGate: "HyperFleetKubeletAdvanced", + }, + "kubelet.serializeImagePulls": { + FieldPath: "kubelet.serializeImagePulls", + WriteMode: Mutable, + FeatureGate: "HyperFleetKubeletAdvanced", + }, + "kubelet.streamingConnectionIdleTimeout": { + FieldPath: "kubelet.streamingConnectionIdleTimeout", + WriteMode: Mutable, + }, + "kubelet.systemReserved": { + FieldPath: "kubelet.systemReserved", + WriteMode: Immutable, + }, + "kubelet.topologyManagerPolicy": { + FieldPath: "kubelet.topologyManagerPolicy", + WriteMode: ServiceSet, + Hidden: true, + }, + "kubelet.topologyManagerScope": { + FieldPath: "kubelet.topologyManagerScope", + WriteMode: ServiceSet, + Hidden: true, + }, + "machineConfig": { + FieldPath: "machineConfig", + WriteMode: ServiceSet, + }, + "machineConfig.allowedKernelArguments": { + FieldPath: "machineConfig.allowedKernelArguments", + WriteMode: Immutable, + FeatureGate: "HyperFleetMachineConfig", + }, + "machineConfig.extensions": { + FieldPath: "machineConfig.extensions", + WriteMode: ServiceSet, + Hidden: true, + }, + "machineConfig.files": { + FieldPath: "machineConfig.files", + WriteMode: ServiceSet, + Hidden: true, + }, + "machineConfig.fips": { + FieldPath: "machineConfig.fips", + WriteMode: Immutable, + }, + "machineConfig.kernelArguments": { + FieldPath: "machineConfig.kernelArguments", + WriteMode: ServiceSet, + Hidden: true, + }, + "machineConfig.kernelType": { + FieldPath: "machineConfig.kernelType", + WriteMode: ServiceSet, + Hidden: true, + }, + "machineConfig.systemdUnits": { + FieldPath: "machineConfig.systemdUnits", + WriteMode: ServiceSet, + Hidden: true, + }, + "maxPods": { + FieldPath: "maxPods", + WriteMode: Mutable, + }, + "memoryThrottlingFactor": { + FieldPath: "memoryThrottlingFactor", + WriteMode: ServiceSet, + Hidden: true, + }, + "network": { + FieldPath: "network", + WriteMode: ServiceSet, + Hidden: true, + }, + "oauth": { + FieldPath: "oauth", + WriteMode: ServiceSet, + Hidden: true, + }, + "podPidsLimit": { + FieldPath: "podPidsLimit", + WriteMode: Mutable, + }, + "proxy": { + FieldPath: "proxy", + WriteMode: ServiceSet, + Hidden: true, + }, + "registryBurst": { + FieldPath: "registryBurst", + WriteMode: Mutable, + FeatureGate: "HyperFleetKubeletAdvanced", + }, + "registryPullQPS": { + FieldPath: "registryPullQPS", + WriteMode: Mutable, + FeatureGate: "HyperFleetKubeletAdvanced", + }, + "scheduler": { + FieldPath: "scheduler", + WriteMode: ServiceSet, + Hidden: true, + }, + "serializeImagePulls": { + FieldPath: "serializeImagePulls", + WriteMode: Mutable, + FeatureGate: "HyperFleetKubeletAdvanced", + }, + "spec.accountId": { + FieldPath: "spec.accountId", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.autoRepair": { + FieldPath: "spec.autoRepair", + WriteMode: Mutable, + }, + "spec.creatorARN": { + FieldPath: "spec.creatorARN", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.deleteProtection": { + FieldPath: "spec.deleteProtection", + WriteMode: Mutable, + }, + "spec.displayName": { + FieldPath: "spec.displayName", + WriteMode: Mutable, + }, + "spec.expirationTimestamp": { + FieldPath: "spec.expirationTimestamp", + WriteMode: Mutable, + }, + "spec.hostedCluster.additionalTrustBundle": { + FieldPath: "spec.hostedCluster.additionalTrustBundle", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.auditWebhook": { + FieldPath: "spec.hostedCluster.auditWebhook", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.autoNode": { + FieldPath: "spec.hostedCluster.autoNode", + WriteMode: ServiceSet, + }, + "spec.hostedCluster.autoscaling": { + FieldPath: "spec.hostedCluster.autoscaling", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.capabilities": { + FieldPath: "spec.hostedCluster.capabilities", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.channel": { + FieldPath: "spec.hostedCluster.channel", + WriteMode: ServiceSet, + }, + "spec.hostedCluster.clusterID": { + FieldPath: "spec.hostedCluster.clusterID", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.configuration": { + FieldPath: "spec.hostedCluster.configuration", + WriteMode: ServiceSet, + }, + "spec.hostedCluster.controlPlaneRelease": { + FieldPath: "spec.hostedCluster.controlPlaneRelease", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.controllerAvailabilityPolicy": { + FieldPath: "spec.hostedCluster.controllerAvailabilityPolicy", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.dns": { + FieldPath: "spec.hostedCluster.dns", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.etcd": { + FieldPath: "spec.hostedCluster.etcd", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.fips": { + FieldPath: "spec.hostedCluster.fips", + WriteMode: ServiceSet, + }, + "spec.hostedCluster.imageContentSources": { + FieldPath: "spec.hostedCluster.imageContentSources", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.infraID": { + FieldPath: "spec.hostedCluster.infraID", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.infrastructureAvailabilityPolicy": { + FieldPath: "spec.hostedCluster.infrastructureAvailabilityPolicy", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.issuerURL": { + FieldPath: "spec.hostedCluster.issuerURL", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.kubeAPIServerDNSName": { + FieldPath: "spec.hostedCluster.kubeAPIServerDNSName", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.labels": { + FieldPath: "spec.hostedCluster.labels", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.networking": { + FieldPath: "spec.hostedCluster.networking", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.nodeSelector": { + FieldPath: "spec.hostedCluster.nodeSelector", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.olmCatalogPlacement": { + FieldPath: "spec.hostedCluster.olmCatalogPlacement", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.operatorConfiguration": { + FieldPath: "spec.hostedCluster.operatorConfiguration", + WriteMode: ServiceSet, + }, + "spec.hostedCluster.pausedUntil": { + FieldPath: "spec.hostedCluster.pausedUntil", + WriteMode: ServiceSet, + }, + "spec.hostedCluster.platform": { + FieldPath: "spec.hostedCluster.platform", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.pullSecret": { + FieldPath: "spec.hostedCluster.pullSecret", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.release": { + FieldPath: "spec.hostedCluster.release", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.secretEncryption": { + FieldPath: "spec.hostedCluster.secretEncryption", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.serviceAccountSigningKey": { + FieldPath: "spec.hostedCluster.serviceAccountSigningKey", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.services": { + FieldPath: "spec.hostedCluster.services", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.sshKey": { + FieldPath: "spec.hostedCluster.sshKey", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.tolerations": { + FieldPath: "spec.hostedCluster.tolerations", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.hostedCluster.updateService": { + FieldPath: "spec.hostedCluster.updateService", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.internalId": { + FieldPath: "spec.internalId", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.internalPoolId": { + FieldPath: "spec.internalPoolId", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.labels": { + FieldPath: "spec.labels", + WriteMode: Mutable, + }, + "spec.nodePool.arch": { + FieldPath: "spec.nodePool.arch", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.nodePool.autoScaling": { + FieldPath: "spec.nodePool.autoScaling", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.nodePool.clusterName": { + FieldPath: "spec.nodePool.clusterName", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.nodePool.config": { + FieldPath: "spec.nodePool.config", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.nodePool.management": { + FieldPath: "spec.nodePool.management", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.nodePool.nodeDrainTimeout": { + FieldPath: "spec.nodePool.nodeDrainTimeout", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.nodePool.nodeLabels": { + FieldPath: "spec.nodePool.nodeLabels", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.nodePool.nodeVolumeDetachTimeout": { + FieldPath: "spec.nodePool.nodeVolumeDetachTimeout", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.nodePool.osImageStream": { + FieldPath: "spec.nodePool.osImageStream", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.nodePool.pausedUntil": { + FieldPath: "spec.nodePool.pausedUntil", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.nodePool.platform": { + FieldPath: "spec.nodePool.platform", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.nodePool.release": { + FieldPath: "spec.nodePool.release", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.nodePool.replicas": { + FieldPath: "spec.nodePool.replicas", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.nodePool.taints": { + FieldPath: "spec.nodePool.taints", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.nodePool.tuningConfig": { + FieldPath: "spec.nodePool.tuningConfig", + WriteMode: ServiceSet, + Hidden: true, + }, + "spec.properties": { + FieldPath: "spec.properties", + WriteMode: Mutable, + }, + "spec.tags": { + FieldPath: "spec.tags", + WriteMode: Mutable, + FeatureGate: "HyperFleetAutoScaling", + }, + "streamingConnectionIdleTimeout": { + FieldPath: "streamingConnectionIdleTimeout", + WriteMode: Mutable, + }, + "systemReserved": { + FieldPath: "systemReserved", + WriteMode: Immutable, + }, + "topologyManagerPolicy": { + FieldPath: "topologyManagerPolicy", + WriteMode: ServiceSet, + Hidden: true, + }, + "topologyManagerScope": { + FieldPath: "topologyManagerScope", + WriteMode: ServiceSet, + Hidden: true, + }, +} diff --git a/platform-api/internal/codegen/registry/field_metadata.json b/platform-api/internal/codegen/registry/field_metadata.json new file mode 100644 index 00000000..62347632 --- /dev/null +++ b/platform-api/internal/codegen/registry/field_metadata.json @@ -0,0 +1,582 @@ +[ + { + "fieldPath": "allowedUnsafeSysctls", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "apiServer", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "authentication", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "containerLogMaxFiles", + "writeMode": "mutable" + }, + { + "fieldPath": "containerLogMaxSize", + "writeMode": "mutable" + }, + { + "fieldPath": "cpuManagerPolicy", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "cpuManagerPolicyOptions", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "cpuManagerReconcilePeriod", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "evictionHard", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "evictionSoft", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "evictionSoftGracePeriod", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "featureGate", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "image", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "imageGCHighThresholdPercent", + "writeMode": "mutable" + }, + { + "fieldPath": "imageGCLowThresholdPercent", + "writeMode": "mutable" + }, + { + "fieldPath": "imageMinimumGCAge", + "writeMode": "mutable" + }, + { + "fieldPath": "ingress", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "kubeReserved", + "writeMode": "immutable" + }, + { + "fieldPath": "kubelet", + "writeMode": "service-set" + }, + { + "fieldPath": "kubelet.allowedUnsafeSysctls", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "kubelet.containerLogMaxFiles", + "writeMode": "mutable" + }, + { + "fieldPath": "kubelet.containerLogMaxSize", + "writeMode": "mutable" + }, + { + "fieldPath": "kubelet.cpuManagerPolicy", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "kubelet.cpuManagerPolicyOptions", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "kubelet.cpuManagerReconcilePeriod", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "kubelet.evictionHard", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "kubelet.evictionSoft", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "kubelet.evictionSoftGracePeriod", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "kubelet.imageGCHighThresholdPercent", + "writeMode": "mutable" + }, + { + "fieldPath": "kubelet.imageGCLowThresholdPercent", + "writeMode": "mutable" + }, + { + "fieldPath": "kubelet.imageMinimumGCAge", + "writeMode": "mutable" + }, + { + "fieldPath": "kubelet.kubeReserved", + "writeMode": "immutable" + }, + { + "fieldPath": "kubelet.maxPods", + "writeMode": "mutable" + }, + { + "fieldPath": "kubelet.memoryThrottlingFactor", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "kubelet.podPidsLimit", + "writeMode": "mutable" + }, + { + "fieldPath": "kubelet.registryBurst", + "writeMode": "mutable", + "featureGate": "HyperFleetKubeletAdvanced" + }, + { + "fieldPath": "kubelet.registryPullQPS", + "writeMode": "mutable", + "featureGate": "HyperFleetKubeletAdvanced" + }, + { + "fieldPath": "kubelet.serializeImagePulls", + "writeMode": "mutable", + "featureGate": "HyperFleetKubeletAdvanced" + }, + { + "fieldPath": "kubelet.streamingConnectionIdleTimeout", + "writeMode": "mutable" + }, + { + "fieldPath": "kubelet.systemReserved", + "writeMode": "immutable" + }, + { + "fieldPath": "kubelet.topologyManagerPolicy", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "kubelet.topologyManagerScope", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "machineConfig", + "writeMode": "service-set" + }, + { + "fieldPath": "machineConfig.allowedKernelArguments", + "writeMode": "immutable", + "featureGate": "HyperFleetMachineConfig" + }, + { + "fieldPath": "machineConfig.extensions", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "machineConfig.files", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "machineConfig.fips", + "writeMode": "immutable" + }, + { + "fieldPath": "machineConfig.kernelArguments", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "machineConfig.kernelType", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "machineConfig.systemdUnits", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "maxPods", + "writeMode": "mutable" + }, + { + "fieldPath": "memoryThrottlingFactor", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "network", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "oauth", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "podPidsLimit", + "writeMode": "mutable" + }, + { + "fieldPath": "proxy", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "registryBurst", + "writeMode": "mutable", + "featureGate": "HyperFleetKubeletAdvanced" + }, + { + "fieldPath": "registryPullQPS", + "writeMode": "mutable", + "featureGate": "HyperFleetKubeletAdvanced" + }, + { + "fieldPath": "scheduler", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "serializeImagePulls", + "writeMode": "mutable", + "featureGate": "HyperFleetKubeletAdvanced" + }, + { + "fieldPath": "spec.accountId", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.autoRepair", + "writeMode": "mutable" + }, + { + "fieldPath": "spec.creatorARN", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.deleteProtection", + "writeMode": "mutable" + }, + { + "fieldPath": "spec.displayName", + "writeMode": "mutable" + }, + { + "fieldPath": "spec.expirationTimestamp", + "writeMode": "mutable" + }, + { + "fieldPath": "spec.hostedCluster.additionalTrustBundle", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.auditWebhook", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.autoNode", + "writeMode": "service-set" + }, + { + "fieldPath": "spec.hostedCluster.autoscaling", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.capabilities", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.channel", + "writeMode": "service-set" + }, + { + "fieldPath": "spec.hostedCluster.clusterID", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.configuration", + "writeMode": "service-set" + }, + { + "fieldPath": "spec.hostedCluster.controlPlaneRelease", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.controllerAvailabilityPolicy", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.dns", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.etcd", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.fips", + "writeMode": "service-set" + }, + { + "fieldPath": "spec.hostedCluster.imageContentSources", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.infraID", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.infrastructureAvailabilityPolicy", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.issuerURL", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.kubeAPIServerDNSName", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.labels", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.networking", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.nodeSelector", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.olmCatalogPlacement", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.operatorConfiguration", + "writeMode": "service-set" + }, + { + "fieldPath": "spec.hostedCluster.pausedUntil", + "writeMode": "service-set" + }, + { + "fieldPath": "spec.hostedCluster.platform", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.pullSecret", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.release", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.secretEncryption", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.serviceAccountSigningKey", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.services", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.sshKey", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.tolerations", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.hostedCluster.updateService", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.internalId", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.internalPoolId", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.labels", + "writeMode": "mutable" + }, + { + "fieldPath": "spec.nodePool.arch", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.nodePool.autoScaling", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.nodePool.clusterName", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.nodePool.config", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.nodePool.management", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.nodePool.nodeDrainTimeout", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.nodePool.nodeLabels", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.nodePool.nodeVolumeDetachTimeout", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.nodePool.osImageStream", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.nodePool.pausedUntil", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.nodePool.platform", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.nodePool.release", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.nodePool.replicas", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.nodePool.taints", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.nodePool.tuningConfig", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "spec.properties", + "writeMode": "mutable" + }, + { + "fieldPath": "spec.tags", + "writeMode": "mutable", + "featureGate": "HyperFleetAutoScaling" + }, + { + "fieldPath": "streamingConnectionIdleTimeout", + "writeMode": "mutable" + }, + { + "fieldPath": "systemReserved", + "writeMode": "immutable" + }, + { + "fieldPath": "topologyManagerPolicy", + "writeMode": "service-set", + "hidden": true + }, + { + "fieldPath": "topologyManagerScope", + "writeMode": "service-set", + "hidden": true + } +] \ No newline at end of file