diff --git a/api/konnect/v1alpha1/konnect_gateway_controlplane_types.go b/api/konnect/v1alpha1/konnect_gateway_controlplane_types.go index 894d9e4..fb4a26c 100644 --- a/api/konnect/v1alpha1/konnect_gateway_controlplane_types.go +++ b/api/konnect/v1alpha1/konnect_gateway_controlplane_types.go @@ -23,6 +23,7 @@ func init() { // +kubebuilder:printcolumn:name="OrgID",description="Konnect Organization ID this resource belongs to.",type=string,JSONPath=`.status.organizationID` // +kubebuilder:validation:XValidation:message="spec.konnect.authRef is immutable when an entity is already Programmed", rule="!self.status.conditions.exists(c, c.type == 'Programmed' && c.status == 'True') ? true : self.spec.konnect.authRef == oldSelf.spec.konnect.authRef" // +kubebuilder:validation:XValidation:message="spec.konnect.authRef is immutable when an entity refers to a Valid API Auth Configuration", rule="!self.status.conditions.exists(c, c.type == 'APIAuthValid' && c.status == 'True') ? true : self.spec.konnect.authRef == oldSelf.spec.konnect.authRef" +// +kubebuilder:validation:XValidation:message="status.members is only applicable for ControlPlanes that are created as groups", rule="(has(self.spec.cluster_type) && self.spec.cluster_type != 'CLUSTER_TYPE_CONTROL_PLANE_GROUP') ? (!has(self.status) || !has(self.status.members)) : true" // +apireference:kgo:include type KonnectGatewayControlPlane struct { metav1.TypeMeta `json:",inline"` @@ -71,6 +72,10 @@ type KonnectGatewayControlPlaneStatus struct { // +kubebuilder:validation:MaxItems=8 // +kubebuilder:default={{type: "Programmed", status: "Unknown", reason:"Pending", message:"Waiting for controller", lastTransitionTime: "1970-01-01T00:00:00Z"}} Conditions []metav1.Condition `json:"conditions,omitempty"` + + // MemberStatus is the status of each member in the control plane group. + // This field is only applicable for control planes with spec.cluster_type = CLUSTER_TYPE_CONTROL_PLANE_GROUP. + MemberStatus map[string][]metav1.Condition `json:"members,omitempty"` } // GetKonnectLabels gets the Konnect Labels from object's spec. @@ -88,6 +93,18 @@ func (c *KonnectGatewayControlPlane) GetKonnectAPIAuthConfigurationRef() Konnect return c.Spec.KonnectConfiguration.APIAuthConfigurationRef } +// SetMemberStatus sets conditions of a member of the control plane group in status. +// REVIEW: is it better to replace it with `SetMemberCondition` to set a single condition of a member? +func (c *KonnectGatewayControlPlane) SetMemberStatus(name string, conditions []metav1.Condition) { + if c.Status.MemberStatus == nil { + c.Status.MemberStatus = map[string][]metav1.Condition{ + name: conditions, + } + } + + c.Status.MemberStatus[name] = conditions +} + // KonnectGatewayControlPlaneList contains a list of KonnectGatewayControlPlane. // +kubebuilder:object:root=true // +apireference:kgo:include diff --git a/api/konnect/v1alpha1/zz_generated.deepcopy.go b/api/konnect/v1alpha1/zz_generated.deepcopy.go index cd77a0b..4ff30e4 100644 --- a/api/konnect/v1alpha1/zz_generated.deepcopy.go +++ b/api/konnect/v1alpha1/zz_generated.deepcopy.go @@ -345,6 +345,24 @@ func (in *KonnectGatewayControlPlaneStatus) DeepCopyInto(out *KonnectGatewayCont (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.MemberStatus != nil { + in, out := &in.MemberStatus, &out.MemberStatus + *out = make(map[string][]metav1.Condition, len(*in)) + for key, val := range *in { + var outVal []metav1.Condition + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + (*out)[key] = outVal + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KonnectGatewayControlPlaneStatus. diff --git a/config/crd/bases/konnect.konghq.com_konnectgatewaycontrolplanes.yaml b/config/crd/bases/konnect.konghq.com_konnectgatewaycontrolplanes.yaml index 9dd3843..15b1ff1 100644 --- a/config/crd/bases/konnect.konghq.com_konnectgatewaycontrolplanes.yaml +++ b/config/crd/bases/konnect.konghq.com_konnectgatewaycontrolplanes.yaml @@ -255,6 +255,68 @@ spec: ID is the unique identifier of the Konnect entity as assigned by Konnect API. If it's unset (empty string), it means the Konnect entity hasn't been created yet. type: string + members: + additionalProperties: + items: + description: Condition contains details for one aspect of the + current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + description: |- + MemberStatus is the status of each member in the control plane group. + This field is only applicable for control planes with spec.cluster_type = CLUSTER_TYPE_CONTROL_PLANE_GROUP. + type: object organizationID: description: OrgID is ID of Konnect Org that this entity has been created in. @@ -273,6 +335,10 @@ spec: API Auth Configuration rule: '!self.status.conditions.exists(c, c.type == ''APIAuthValid'' && c.status == ''True'') ? true : self.spec.konnect.authRef == oldSelf.spec.konnect.authRef' + - message: status.members is only applicable for ControlPlanes that are created + as groups + rule: '(has(self.spec.cluster_type) && self.spec.cluster_type != ''CLUSTER_TYPE_CONTROL_PLANE_GROUP'') + ? (!has(self.status) || !has(self.status.members)) : true' served: true storage: true subresources: diff --git a/test/crdsvalidation/konnectgatewaycontrolplane_test.go b/test/crdsvalidation/konnectgatewaycontrolplane_test.go index 425fe8c..1a91456 100644 --- a/test/crdsvalidation/konnectgatewaycontrolplane_test.go +++ b/test/crdsvalidation/konnectgatewaycontrolplane_test.go @@ -350,7 +350,6 @@ func TestKonnectGatewayControlPlane(t *testing.T) { }, ExpectedErrorMessage: lo.ToPtr("spec.labels keys must be of length 1-63 characters"), }, - // { Name: "spec.labels values' length must not be greater than 63", TestObject: &konnectv1alpha1.KonnectGatewayControlPlane{