From d775362cff2218fa4162469ca085b49ad13a3fd5 Mon Sep 17 00:00:00 2001 From: Georgi Chulkov Date: Fri, 5 Apr 2024 11:39:15 +0200 Subject: [PATCH] Add enum validation to CRDs --- api/v1alpha1/doc.go | 1 + api/v1alpha1/groupversion_info.go | 3 - api/v1alpha1/machine_types.go | 76 ++++++++++--------- api/v1alpha1/machineclaim_types.go | 24 +++--- api/v1alpha1/oob_types.go | 58 +++++++------- api/v1alpha1/oobsecret_types.go | 24 +++--- api/v1alpha1/zz_generated.deepcopy.go | 22 ++++-- .../api/v1alpha1/oobsecretspec.go | 10 +-- client/openapi/zz_generated.openapi.go | 18 +++-- .../metal.ironcore.dev_machineclaims.yaml | 6 ++ .../bases/metal.ironcore.dev_machines.yaml | 18 +++++ config/crd/bases/metal.ironcore.dev_oobs.yaml | 8 ++ .../bases/metal.ironcore.dev_oobsecrets.yaml | 2 +- .../controller/machineclaim_controller.go | 43 ++++++----- internal/{ => util}/utils.go | 2 +- 15 files changed, 186 insertions(+), 129 deletions(-) rename internal/{ => util}/utils.go (93%) diff --git a/api/v1alpha1/doc.go b/api/v1alpha1/doc.go index 8f9e73d3..61d8480e 100644 --- a/api/v1alpha1/doc.go +++ b/api/v1alpha1/doc.go @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 +// +kubebuilder:object:generate=true // +k8s:deepcopy-gen=package // +k8s:openapi-gen=true // +groupName=metal.ironcore.dev diff --git a/api/v1alpha1/groupversion_info.go b/api/v1alpha1/groupversion_info.go index d440e301..0db1afea 100644 --- a/api/v1alpha1/groupversion_info.go +++ b/api/v1alpha1/groupversion_info.go @@ -1,9 +1,6 @@ // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 -// Package v1alpha1 contains API Schema definitions for the metal v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=metal.ironcore.dev package v1alpha1 import ( diff --git a/api/v1alpha1/machine_types.go b/api/v1alpha1/machine_types.go index f0b2ab94..10411109 100644 --- a/api/v1alpha1/machine_types.go +++ b/api/v1alpha1/machine_types.go @@ -17,26 +17,28 @@ const ( // MachineSpec defines the desired state of Machine type MachineSpec struct { - //+kubebuilder:validation:Pattern=`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$` + // +kubebuilder:validation:Pattern=`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$` UUID string `json:"uuid"` OOBRef v1.LocalObjectReference `json:"oobRef"` InventoryRef *v1.LocalObjectReference `json:"inventoryRef,omitempty"` - //+optional + // +optional MachineClaimRef *v1.ObjectReference `json:"machineClaimRef,omitempty"` - //+optional + // +optional LoopbackAddressRef *v1.LocalObjectReference `json:"loopbackAddressRef,omitempty"` - //+optional + // +optional ASN string `json:"asn,omitempty"` - //+optional - Power Power `json:"power,omitempty"` // TODO: Revisit whether this is really optional. + // +kubebuilder:validation:Enum=On;Off + // +optional + Power Power `json:"power,omitempty"` - //+optional + // +kubebuilder:validation:Enum=On;Off;Blinking + // +optional LocatorLED LocatorLED `json:"locatorLED,omitempty"` } @@ -57,67 +59,71 @@ const ( // MachineStatus defines the observed state of Machine type MachineStatus struct { - //+optional + // +optional Manufacturer string `json:"manufacturer,omitempty"` - //+optional + // +optional SKU string `json:"sku,omitempty"` - //+optional + // +optional SerialNumber string `json:"serialNumber,omitempty"` - //+optional + // +kubebuilder:validation:Enum=On;Off + // +optional Power Power `json:"power,omitempty"` - //+optional + // +kubebuilder:validation:Enum=On;Off;Blinking + // +optional LocatorLED LocatorLED `json:"locatorLED,omitempty"` - //+optional + // +optional ShutdownDeadline *metav1.Time `json:"shutdownDeadline,omitempty"` - //+optional + // +optional NetworkInterfaces []MachineNetworkInterface `json:"networkInterfaces"` - //+optional + // +optional + // +kubebuilder:validation:Enum=Ready;Unready;Error State MachineState `json:"state,omitempty"` - //+patchStrategy=merge - //+patchMergeKey=type - //+optional + // +patchStrategy=merge + // +patchMergeKey=type + // +optional Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"` } type MachineNetworkInterface struct { Name string `json:"name"` - //+kubebuilder:validation:Pattern=`^[0-9a-f]{12}$` + // +kubebuilder:validation:Pattern=`^[0-9a-f]{12}$` MacAddress string `json:"macAddress"` - //+optional + // +optional IPRef *v1.LocalObjectReference `json:"IPRef,omitempty"` - //+optional + // +optional SwitchRef *v1.LocalObjectReference `json:"switchRef,omitempty"` } type MachineState string const ( - MachineStateReady MachineState = "Ready" - MachineStateError MachineState = "Error" + MachineStateReady MachineState = "Ready" + MachineStateUneady MachineState = "Unready" + MachineStateError MachineState = "Error" ) -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:resource:scope=Cluster -//+kubebuilder:printcolumn:name="UUID",type=string,JSONPath=`.status.uuid` -//+kubebuilder:printcolumn:name="Manufacturer",type=string,JSONPath=`.status.manufacturer` -//+kubebuilder:printcolumn:name="SKU",type=string,JSONPath=`.status.sku`,priority=100 -//+kubebuilder:printcolumn:name="SerialNumber",type=string,JSONPath=`.status.serialNumber`,priority=100 -//+kubebuilder:printcolumn:name="Power",type=string,JSONPath=`.status.power` -//+kubebuilder:printcolumn:name="LocatorLED",type=string,JSONPath=`.status.locatorLED`,priority=100 -//+kubebuilder:printcolumn:name="State",type=string,JSONPath=`.status.state` -//+kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimeStamp` +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster +// +kubebuilder:printcolumn:name="UUID",type=string,JSONPath=`.status.uuid` +// +kubebuilder:printcolumn:name="Manufacturer",type=string,JSONPath=`.status.manufacturer` +// +kubebuilder:printcolumn:name="SKU",type=string,JSONPath=`.status.sku`,priority=100 +// +kubebuilder:printcolumn:name="SerialNumber",type=string,JSONPath=`.status.serialNumber`,priority=100 +// +kubebuilder:printcolumn:name="Power",type=string,JSONPath=`.status.power` +// +kubebuilder:printcolumn:name="LocatorLED",type=string,JSONPath=`.status.locatorLED`,priority=100 +// +kubebuilder:printcolumn:name="State",type=string,JSONPath=`.status.state` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimeStamp` // +genclient // Machine is the Schema for the machines API @@ -129,7 +135,7 @@ type Machine struct { Status MachineStatus `json:"status,omitempty"` } -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true // MachineList contains a list of Machine type MachineList struct { diff --git a/api/v1alpha1/machineclaim_types.go b/api/v1alpha1/machineclaim_types.go index 3ddb1bd6..0c007fbd 100644 --- a/api/v1alpha1/machineclaim_types.go +++ b/api/v1alpha1/machineclaim_types.go @@ -11,21 +11,22 @@ import ( // MachineClaimSpec defines the desired state of MachineClaim // TODO: Validate that exactly one of MachineRef or MachineSelector is set. type MachineClaimSpec struct { - //+optional + // +optional MachineRef *v1.LocalObjectReference `json:"machineRef,omitempty"` - //+optional + // +optional MachineSelector *metav1.LabelSelector `json:"machineSelector,omitempty"` Image string `json:"image"` + // +kubebuilder:validation:Enum=On;Off Power Power `json:"power"` - //+optional + // +optional IgnitionSecretRef *v1.LocalObjectReference `json:"ignitionSecretRef,omitempty"` - //+optional - NetworkInterfaces []MachineClaimNetworkInterface `json:"networkInterfaces,omitempty"` // TODO: Revisit whether this is really optional. + // +optional + NetworkInterfaces []MachineClaimNetworkInterface `json:"networkInterfaces,omitempty"` } type MachineClaimNetworkInterface struct { @@ -36,7 +37,8 @@ type MachineClaimNetworkInterface struct { // MachineClaimStatus defines the observed state of MachineClaim type MachineClaimStatus struct { - //+optional + // +kubebuilder:validation:Enum=Bound;Unbound + // +optional Phase MachineClaimPhase `json:"phase,omitempty"` } @@ -47,10 +49,10 @@ const ( MachineClaimPhaseUnbound MachineClaimPhase = "Unbound" ) -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` -//+kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimeStamp` +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimeStamp` // +genclient // MachineClaim is the Schema for the machineclaims API @@ -62,7 +64,7 @@ type MachineClaim struct { Status MachineClaimStatus `json:"status,omitempty"` } -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true // MachineClaimList contains a list of MachineClaim type MachineClaimList struct { diff --git a/api/v1alpha1/oob_types.go b/api/v1alpha1/oob_types.go index 0b32899d..cd849588 100644 --- a/api/v1alpha1/oob_types.go +++ b/api/v1alpha1/oob_types.go @@ -15,21 +15,21 @@ const ( // OOBSpec defines the desired state of OOB type OOBSpec struct { - //+kubebuilder:validation:Pattern=`^[0-9a-f]{12}$` + // +kubebuilder:validation:Pattern=`^[0-9a-f]{12}$` MACAddress string `json:"macAddress"` EndpointRef v1.LocalObjectReference `json:"endpointRef"` - //+optional - SecretRef v1.LocalObjectReference `json:"secretRef,omitempty"` + // +optional + SecretRef *v1.LocalObjectReference `json:"secretRef,omitempty"` - //+optional - Protocol Protocol `json:"protocol,omitempty"` + // +optional + Protocol *Protocol `json:"protocol,omitempty"` - //+optional + // +optional Flags map[string]string `json:"flags,omitempty"` - //+optional + // +optional ConsoleProtocol *ConsoleProtocol `json:"consoleProtocol,omitempty"` } @@ -62,27 +62,29 @@ const ( // OOBStatus defines the observed state of OOB type OOBStatus struct { - //+optional + // +kubebuilder:validation:Enum=Machine;Router;Switch + // +optional Type OOBType `json:"type,omitempty"` - //+optional + // +optional Manufacturer string `json:"manufacturer,omitempty"` - //+optional + // +optional SKU string `json:"sku,omitempty"` - //+optional + // +optional SerialNumber string `json:"serialNumber,omitempty"` - //+optional + // +optional FirmwareVersion string `json:"firmwareVersion,omitempty"` - //+optional + // +kubebuilder:validation:Enum=Ready;Unready;Error + // +optional State OOBState `json:"state,omitempty"` - //+patchStrategy=merge - //+patchMergeKey=type - //+optional + // +patchStrategy=merge + // +patchMergeKey=type + // +optional Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"` } @@ -102,17 +104,17 @@ const ( OOBStateError OOBState = "Error" ) -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:resource:scope=Cluster -//+kubebuilder:printcolumn:name="MACAddress",type=string,JSONPath=`.spec.macAddress` -//+kubebuilder:printcolumn:name="Type",type=string,JSONPath=`.status.type` -//+kubebuilder:printcolumn:name="Manufacturer",type=string,JSONPath=`.status.manufacturer` -//+kubebuilder:printcolumn:name="SKU",type=string,JSONPath=`.status.sku`,priority=100 -//+kubebuilder:printcolumn:name="SerialNumber",type=string,JSONPath=`.status.serialNumber`,priority=100 -//+kubebuilder:printcolumn:name="FirmwareVersion",type=string,JSONPath=`.status.firmwareVersion`,priority=100 -//+kubebuilder:printcolumn:name="State",type=string,JSONPath=`.status.state` -//+kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimeStamp` +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster +// +kubebuilder:printcolumn:name="MACAddress",type=string,JSONPath=`.spec.macAddress` +// +kubebuilder:printcolumn:name="Type",type=string,JSONPath=`.status.type` +// +kubebuilder:printcolumn:name="Manufacturer",type=string,JSONPath=`.status.manufacturer` +// +kubebuilder:printcolumn:name="SKU",type=string,JSONPath=`.status.sku`,priority=100 +// +kubebuilder:printcolumn:name="SerialNumber",type=string,JSONPath=`.status.serialNumber`,priority=100 +// +kubebuilder:printcolumn:name="FirmwareVersion",type=string,JSONPath=`.status.firmwareVersion`,priority=100 +// +kubebuilder:printcolumn:name="State",type=string,JSONPath=`.status.state` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimeStamp` // +genclient // OOB is the Schema for the oobs API @@ -124,7 +126,7 @@ type OOB struct { Status OOBStatus `json:"status,omitempty"` } -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true // OOBList contains a list of OOB type OOBList struct { diff --git a/api/v1alpha1/oobsecret_types.go b/api/v1alpha1/oobsecret_types.go index 26f1dd6f..bc34d15c 100644 --- a/api/v1alpha1/oobsecret_types.go +++ b/api/v1alpha1/oobsecret_types.go @@ -9,30 +9,30 @@ import ( // OOBSecretSpec defines the desired state of OOBSecret type OOBSecretSpec struct { - //+kubebuilder:validation:Pattern=`^[0-9a-f]{12}$` + // +kubebuilder:validation:Pattern=`^[0-9a-f]{12}$` MACAddress string `json:"macAddress"` Username string `json:"username"` Password string `json:"password"` - //+optional - ExpirationDate *metav1.Time `json:"expirationDate,omitempty"` + // +optional + ExpirationTime *metav1.Time `json:"expirationTime,omitempty"` } // OOBSecretStatus defines the observed state of OOBSecret type OOBSecretStatus struct { - //+patchStrategy=merge - //+patchMergeKey=type - //+optional + // +patchStrategy=merge + // +patchMergeKey=type + // +optional Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"` } -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:resource:scope=Cluster -//+kubebuilder:printcolumn:name="MACAddress",type=string,JSONPath=`.spec.macAddress` -//+kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimeStamp` +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster +// +kubebuilder:printcolumn:name="MACAddress",type=string,JSONPath=`.spec.macAddress` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimeStamp` // +genclient // OOBSecret is the Schema for the oobsecrets API @@ -44,7 +44,7 @@ type OOBSecret struct { Status OOBSecretStatus `json:"status,omitempty"` } -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true // OOBSecretList contains a list of OOBSecret type OOBSecretList struct { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 7531d857..5d715a88 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1,10 +1,14 @@ +//go:build !ignore_autogenerated + // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 +// Code generated by controller-gen. DO NOT EDIT. + package v1alpha1 import ( - v1 "k8s.io/api/core/v1" + "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -420,8 +424,8 @@ func (in *OOBSecretList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OOBSecretSpec) DeepCopyInto(out *OOBSecretSpec) { *out = *in - if in.ExpirationDate != nil { - in, out := &in.ExpirationDate, &out.ExpirationDate + if in.ExpirationTime != nil { + in, out := &in.ExpirationTime, &out.ExpirationTime *out = (*in).DeepCopy() } } @@ -462,8 +466,16 @@ func (in *OOBSecretStatus) DeepCopy() *OOBSecretStatus { func (in *OOBSpec) DeepCopyInto(out *OOBSpec) { *out = *in out.EndpointRef = in.EndpointRef - out.SecretRef = in.SecretRef - out.Protocol = in.Protocol + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(v1.LocalObjectReference) + **out = **in + } + if in.Protocol != nil { + in, out := &in.Protocol, &out.Protocol + *out = new(Protocol) + **out = **in + } if in.Flags != nil { in, out := &in.Flags, &out.Flags *out = make(map[string]string, len(*in)) diff --git a/client/applyconfiguration/api/v1alpha1/oobsecretspec.go b/client/applyconfiguration/api/v1alpha1/oobsecretspec.go index 775e4dea..9034c438 100644 --- a/client/applyconfiguration/api/v1alpha1/oobsecretspec.go +++ b/client/applyconfiguration/api/v1alpha1/oobsecretspec.go @@ -15,7 +15,7 @@ type OOBSecretSpecApplyConfiguration struct { MACAddress *string `json:"macAddress,omitempty"` Username *string `json:"username,omitempty"` Password *string `json:"password,omitempty"` - ExpirationDate *v1.Time `json:"expirationDate,omitempty"` + ExpirationTime *v1.Time `json:"expirationTime,omitempty"` } // OOBSecretSpecApplyConfiguration constructs an declarative configuration of the OOBSecretSpec type for use with @@ -48,10 +48,10 @@ func (b *OOBSecretSpecApplyConfiguration) WithPassword(value string) *OOBSecretS return b } -// WithExpirationDate sets the ExpirationDate field in the declarative configuration to the given value +// WithExpirationTime sets the ExpirationTime field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the ExpirationDate field is set to the value of the last call. -func (b *OOBSecretSpecApplyConfiguration) WithExpirationDate(value v1.Time) *OOBSecretSpecApplyConfiguration { - b.ExpirationDate = &value +// If called multiple times, the ExpirationTime field is set to the value of the last call. +func (b *OOBSecretSpecApplyConfiguration) WithExpirationTime(value v1.Time) *OOBSecretSpecApplyConfiguration { + b.ExpirationTime = &value return b } diff --git a/client/openapi/zz_generated.openapi.go b/client/openapi/zz_generated.openapi.go index 099fb97d..1ec8c5b3 100644 --- a/client/openapi/zz_generated.openapi.go +++ b/client/openapi/zz_generated.openapi.go @@ -1047,7 +1047,7 @@ func schema_ironcore_dev_metal_api_v1alpha1_OOBSecretSpec(ref common.ReferenceCa Format: "", }, }, - "expirationDate": { + "expirationTime": { SchemaProps: spec.SchemaProps{ Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, @@ -1117,14 +1117,12 @@ func schema_ironcore_dev_metal_api_v1alpha1_OOBSpec(ref common.ReferenceCallback }, "secretRef": { SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/api/core/v1.LocalObjectReference"), + Ref: ref("k8s.io/api/core/v1.LocalObjectReference"), }, }, "protocol": { SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/ironcore-dev/metal/api/v1alpha1.Protocol"), + Ref: ref("github.com/ironcore-dev/metal/api/v1alpha1.Protocol"), }, }, "flags": { @@ -7322,6 +7320,7 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimSpec(ref common.ReferenceCall Default: "", Type: []string{"string"}, Format: "", + Enum: []interface{}{"ReadOnlyMany", "ReadWriteMany", "ReadWriteOnce", "ReadWriteOncePod"}, }, }, }, @@ -7414,6 +7413,7 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimStatus(ref common.ReferenceCa Default: "", Type: []string{"string"}, Format: "", + Enum: []interface{}{"ReadOnlyMany", "ReadWriteMany", "ReadWriteOnce", "ReadWriteOncePod"}, }, }, }, @@ -7483,6 +7483,7 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimStatus(ref common.ReferenceCa Default: "", Type: []string{"string"}, Format: "", + Enum: []interface{}{"ControllerResizeFailed", "ControllerResizeInProgress", "NodeResizeFailed", "NodeResizeInProgress", "NodeResizePending"}, }, }, }, @@ -7929,6 +7930,7 @@ func schema_k8sio_api_core_v1_PersistentVolumeSpec(ref common.ReferenceCallback) Default: "", Type: []string{"string"}, Format: "", + Enum: []interface{}{"ReadOnlyMany", "ReadWriteMany", "ReadWriteOnce", "ReadWriteOncePod"}, }, }, }, @@ -10944,6 +10946,7 @@ func schema_k8sio_api_core_v1_ResourceQuotaSpec(ref common.ReferenceCallback) co Default: "", Type: []string{"string"}, Format: "", + Enum: []interface{}{"BestEffort", "CrossNamespacePodAffinity", "NotBestEffort", "NotTerminating", "PriorityClass", "Terminating"}, }, }, }, @@ -12360,10 +12363,10 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O }, "externalTrafficPolicy": { SchemaProps: spec.SchemaProps{ - Description: "externalTrafficPolicy describes how nodes distribute service traffic they receive on one of the Service's \"externally-facing\" addresses (NodePorts, ExternalIPs, and LoadBalancer IPs). If set to \"Local\", the proxy will configure the service in a way that assumes that external load balancers will take care of balancing the service traffic between nodes, and so each node will deliver traffic only to the node-local endpoints of the service, without masquerading the client source IP. (Traffic mistakenly sent to a node with no endpoints will be dropped.) The default value, \"Cluster\", uses the standard behavior of routing to all endpoints evenly (possibly modified by topology and other features). Note that traffic sent to an External IP or LoadBalancer IP from within the cluster will always get \"Cluster\" semantics, but clients sending to a NodePort from within the cluster may need to take traffic policy into account when picking a node.\n\nPossible enum values:\n - `\"Cluster\"`\n - `\"Cluster\"` routes traffic to all endpoints.\n - `\"Local\"`\n - `\"Local\"` preserves the source IP of the traffic by routing only to endpoints on the same node as the traffic was received on (dropping the traffic if there are no local endpoints).", + Description: "externalTrafficPolicy describes how nodes distribute service traffic they receive on one of the Service's \"externally-facing\" addresses (NodePorts, ExternalIPs, and LoadBalancer IPs). If set to \"Local\", the proxy will configure the service in a way that assumes that external load balancers will take care of balancing the service traffic between nodes, and so each node will deliver traffic only to the node-local endpoints of the service, without masquerading the client source IP. (Traffic mistakenly sent to a node with no endpoints will be dropped.) The default value, \"Cluster\", uses the standard behavior of routing to all endpoints evenly (possibly modified by topology and other features). Note that traffic sent to an External IP or LoadBalancer IP from within the cluster will always get \"Cluster\" semantics, but clients sending to a NodePort from within the cluster may need to take traffic policy into account when picking a node.\n\nPossible enum values:\n - `\"Cluster\"`\n - `\"Local\"` preserves the source IP of the traffic by routing only to endpoints on the same node as the traffic was received on (dropping the traffic if there are no local endpoints).", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Cluster", "Cluster", "Local", "Local"}, + Enum: []interface{}{"Cluster", "Local"}, }, }, "healthCheckNodePort": { @@ -12401,6 +12404,7 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O Default: "", Type: []string{"string"}, Format: "", + Enum: []interface{}{"", "IPv4", "IPv6"}, }, }, }, diff --git a/config/crd/bases/metal.ironcore.dev_machineclaims.yaml b/config/crd/bases/metal.ironcore.dev_machineclaims.yaml index ad1f55bc..d9f77ade 100644 --- a/config/crd/bases/metal.ironcore.dev_machineclaims.yaml +++ b/config/crd/bases/metal.ironcore.dev_machineclaims.yaml @@ -136,6 +136,9 @@ spec: type: object type: array power: + enum: + - "On" + - "Off" type: string required: - image @@ -145,6 +148,9 @@ spec: description: MachineClaimStatus defines the observed state of MachineClaim properties: phase: + enum: + - Bound + - Unbound type: string type: object type: object diff --git a/config/crd/bases/metal.ironcore.dev_machines.yaml b/config/crd/bases/metal.ironcore.dev_machines.yaml index daa681b2..ab2a41f8 100644 --- a/config/crd/bases/metal.ironcore.dev_machines.yaml +++ b/config/crd/bases/metal.ironcore.dev_machines.yaml @@ -83,6 +83,10 @@ spec: type: object x-kubernetes-map-type: atomic locatorLED: + enum: + - "On" + - "Off" + - Blinking type: string loopbackAddressRef: description: |- @@ -172,6 +176,9 @@ spec: type: object x-kubernetes-map-type: atomic power: + enum: + - "On" + - "Off" type: string uuid: pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ @@ -253,6 +260,10 @@ spec: type: object type: array locatorLED: + enum: + - "On" + - "Off" + - Blinking type: string manufacturer: type: string @@ -296,6 +307,9 @@ spec: type: object type: array power: + enum: + - "On" + - "Off" type: string serialNumber: type: string @@ -305,6 +319,10 @@ spec: sku: type: string state: + enum: + - Ready + - Unready + - Error type: string type: object type: object diff --git a/config/crd/bases/metal.ironcore.dev_oobs.yaml b/config/crd/bases/metal.ironcore.dev_oobs.yaml index 75949da4..1c6b6511 100644 --- a/config/crd/bases/metal.ironcore.dev_oobs.yaml +++ b/config/crd/bases/metal.ironcore.dev_oobs.yaml @@ -207,8 +207,16 @@ spec: sku: type: string state: + enum: + - Ready + - Unready + - Error type: string type: + enum: + - Machine + - Router + - Switch type: string type: object type: object diff --git a/config/crd/bases/metal.ironcore.dev_oobsecrets.yaml b/config/crd/bases/metal.ironcore.dev_oobsecrets.yaml index b463a899..5862360b 100644 --- a/config/crd/bases/metal.ironcore.dev_oobsecrets.yaml +++ b/config/crd/bases/metal.ironcore.dev_oobsecrets.yaml @@ -46,7 +46,7 @@ spec: spec: description: OOBSecretSpec defines the desired state of OOBSecret properties: - expirationDate: + expirationTime: format: date-time type: string macAddress: diff --git a/internal/controller/machineclaim_controller.go b/internal/controller/machineclaim_controller.go index bbfc4f68..e62ab567 100644 --- a/internal/controller/machineclaim_controller.go +++ b/internal/controller/machineclaim_controller.go @@ -18,9 +18,9 @@ import ( metalv1alpha1 "github.com/ironcore-dev/metal/api/v1alpha1" metalv1alpha1apply "github.com/ironcore-dev/metal/client/applyconfiguration/api/v1alpha1" - "github.com/ironcore-dev/metal/internal" "github.com/ironcore-dev/metal/internal/log" "github.com/ironcore-dev/metal/internal/patch" + "github.com/ironcore-dev/metal/internal/util" ) //+kubebuilder:rbac:groups=metal.ironcore.dev,resources=machineclaims,verbs=get;list;watch;create;update;patch;delete @@ -48,16 +48,16 @@ type MachineClaimReconciler struct { // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. func (r *MachineClaimReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - claim := &metalv1alpha1.MachineClaim{} - err := r.Get(ctx, req.NamespacedName, claim) + var claim metalv1alpha1.MachineClaim + err := r.Get(ctx, req.NamespacedName, &claim) if err != nil { return ctrl.Result{}, client.IgnoreNotFound(fmt.Errorf("cannot get MachineClaim: %w", err)) } if !claim.DeletionTimestamp.IsZero() { - return ctrl.Result{}, r.finalize(ctx, claim) + return ctrl.Result{}, r.finalize(ctx, &claim) } - return r.reconcile(ctx, claim) + return r.reconcile(ctx, &claim) } func (r *MachineClaimReconciler) finalize(ctx context.Context, claim *metalv1alpha1.MachineClaim) error { @@ -74,8 +74,8 @@ func (r *MachineClaimReconciler) finalize(ctx context.Context, claim *metalv1alp ctx = log.WithValues(ctx, "machine", claim.Spec.MachineRef.Name) log.Debug(ctx, "Getting Machine") - machine := &metalv1alpha1.Machine{} - err := r.Get(ctx, client.ObjectKey{Name: claim.Spec.MachineRef.Name}, machine) + var machine metalv1alpha1.Machine + err := r.Get(ctx, client.ObjectKey{Name: claim.Spec.MachineRef.Name}, &machine) if err != nil { if errors.IsNotFound(err) { break @@ -91,7 +91,7 @@ func (r *MachineClaimReconciler) finalize(ctx context.Context, claim *metalv1alp log.Debug(ctx, "Updating Machine") machineApply := metalv1alpha1apply.Machine(machine.Name, machine.Namespace).WithFinalizers().WithSpec(metalv1alpha1apply.MachineSpec()) - err = r.Patch(ctx, machine, patch.Apply(machineApply), client.FieldOwner(MachineClaimFieldOwner), client.ForceOwnership) + err = r.Patch(ctx, &machine, patch.Apply(machineApply), client.FieldOwner(MachineClaimFieldOwner), client.ForceOwnership) if err != nil { return fmt.Errorf("cannot patch Machine: %w", err) } @@ -117,20 +117,20 @@ func (r *MachineClaimReconciler) reconcile(ctx context.Context, claim *metalv1al var machines []metalv1alpha1.Machine if claim.Spec.MachineRef != nil { log.Debug(ctx, "Getting referenced Machine") - machine := &metalv1alpha1.Machine{} - err := r.Get(ctx, client.ObjectKey{Name: claim.Spec.MachineRef.Name}, machine) + var machine metalv1alpha1.Machine + err := r.Get(ctx, client.ObjectKey{Name: claim.Spec.MachineRef.Name}, &machine) if err != nil && !errors.IsNotFound(err) { - return ctrl.Result{}, fmt.Errorf("cannot get Machine from MachineClaim ref: %w", err) + return ctrl.Result{}, fmt.Errorf("cannot get Machine: %w", err) } if !errors.IsNotFound(err) { - machines = append(machines, *machine) + machines = append(machines, machine) } } else if claim.Spec.MachineSelector != nil { log.Debug(ctx, "Listing Machines with matching labels") - machineList := &metalv1alpha1.MachineList{} - err := r.List(ctx, machineList, client.MatchingLabels(claim.Spec.MachineSelector.MatchLabels)) + var machineList metalv1alpha1.MachineList + err := r.List(ctx, &machineList, client.MatchingLabels(claim.Spec.MachineSelector.MatchLabels)) if err != nil { - return ctrl.Result{}, fmt.Errorf("cannot list Machines from MachineClaim selector: %w", err) + return ctrl.Result{}, fmt.Errorf("cannot list Machines: %w", err) } machines = machineList.Items } @@ -143,7 +143,7 @@ func (r *MachineClaimReconciler) reconcile(ctx context.Context, claim *metalv1al continue } - machine := &m + machine := m ctx = log.WithValues(ctx, "machine", machine.Name) machineApply := metalv1alpha1apply.Machine(machine.Name, machine.Namespace).WithFinalizers(MachineClaimFinalizer).WithSpec(metalv1alpha1apply.MachineSpec(). @@ -153,11 +153,11 @@ func (r *MachineClaimReconciler) reconcile(ctx context.Context, claim *metalv1al UID: claim.UID, }). WithPower(claim.Spec.Power)) - if !controllerutil.ContainsFinalizer(machine, MachineClaimFinalizer) || - !internal.NilOrEqual(machine.Spec.MachineClaimRef, machineApply.Spec.MachineClaimRef) || + if !controllerutil.ContainsFinalizer(&machine, MachineClaimFinalizer) || + !util.NilOrEqual(machine.Spec.MachineClaimRef, machineApply.Spec.MachineClaimRef) || machine.Spec.Power != *machineApply.Spec.Power { log.Debug(ctx, "Updating Machine") - err := r.Patch(ctx, machine, patch.Apply(machineApply), client.FieldOwner(MachineClaimFieldOwner), client.ForceOwnership) + err := r.Patch(ctx, &machine, patch.Apply(machineApply), client.FieldOwner(MachineClaimFieldOwner), client.ForceOwnership) if err != nil { return ctrl.Result{}, fmt.Errorf("cannot patch Machine: %w", err) } @@ -171,7 +171,7 @@ func (r *MachineClaimReconciler) reconcile(ctx context.Context, claim *metalv1al apply := metalv1alpha1apply.MachineClaim(claim.Name, claim.Namespace).WithFinalizers(MachineClaimFinalizer).WithSpec(applySpec) if !controllerutil.ContainsFinalizer(claim, MachineClaimFinalizer) || - !internal.NilOrEqual(claim.Spec.MachineRef, apply.Spec.MachineRef) { + !util.NilOrEqual(claim.Spec.MachineRef, apply.Spec.MachineRef) { log.Debug(ctx, "Updating") err := r.Patch(ctx, claim, patch.Apply(apply), client.FieldOwner(MachineClaimFieldOwner), client.ForceOwnership) if err != nil { @@ -207,7 +207,8 @@ func (r *MachineClaimReconciler) enqueueMachineClaimsFromMachine() handler.Event machine := obj.(*metalv1alpha1.Machine) claimList := &metalv1alpha1.MachineClaimList{} - if err := r.List(ctx, claimList, client.MatchingFields{MachineClaimSpecMachineRef: machine.Name}); err != nil { + err := r.List(ctx, claimList, client.MatchingFields{MachineClaimSpecMachineRef: machine.Name}) + if err != nil { log.Error(ctx, fmt.Errorf("cannot list MachineClaims: %w", err)) return nil } diff --git a/internal/utils.go b/internal/util/utils.go similarity index 93% rename from internal/utils.go rename to internal/util/utils.go index 57cb0702..b07e9d44 100644 --- a/internal/utils.go +++ b/internal/util/utils.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 -package internal +package util func NilOrEqual[T comparable](x, y *T) bool { return (x == nil && y == nil) || (x != nil && y != nil && *x == *y)