diff --git a/CHANGELOG.md b/CHANGELOG.md index eca9ae25..4fec9d20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,16 @@ Adding a new version? You'll need three changes: - [v1.0.2](#v102) - [v1.0.0](#v100) +## Unreleased + +### Breaking Changes + +- `KonnectGatewayControlPlane v1alpha2` has been introduced. + The `CreateControlPlaneRequest` fields (`name, description, clusterType, authType, cloudGateway, proxyUrls, labels`) have been moved from the top level of `spec` into a new structured field: `spec.createControlPlaneRequest`. The old flat field layout is no longer supported in `v1alpha2`. + *Action required*: + - Update any manifests or code that reference these fields to use the new nested structure. + [#502](https://github.com/Kong/kubernetes-configuration/pull/502) + ## [v2.0.0-alpha.0] [v2.0.0-alpha.0]: https://github.com/Kong/kubernetes-configuration/compare/v1.5.2...v2.0.0-alpha.0 diff --git a/api/konnect/v1alpha1/konnect_gateway_controlplane_types.go b/api/konnect/v1alpha1/konnect_gateway_controlplane_types.go index ca9187f4..f1f1c614 100644 --- a/api/konnect/v1alpha1/konnect_gateway_controlplane_types.go +++ b/api/konnect/v1alpha1/konnect_gateway_controlplane_types.go @@ -16,6 +16,7 @@ func init() { // KonnectGatewayControlPlane is the Schema for the KonnectGatewayControlplanes API. // // +genclient +// +kubebuilder:deprecatedversion:warning="This API version has been deprecated in favor of v1alpha2 and it will be removed in the future." // +kubebuilder:resource:scope=Namespaced // +kubebuilder:resource:categories=kong // +kubebuilder:object:root=true diff --git a/api/konnect/v1alpha2/konnect_apiauthconfiguration_ref.go b/api/konnect/v1alpha2/konnect_apiauthconfiguration_ref.go new file mode 100644 index 00000000..da0ef885 --- /dev/null +++ b/api/konnect/v1alpha2/konnect_apiauthconfiguration_ref.go @@ -0,0 +1,9 @@ +package v1alpha2 + +// KonnectAPIAuthConfigurationRef is a reference to a KonnectAPIAuthConfiguration resource. +// +apireference:kgo:include +type KonnectAPIAuthConfigurationRef struct { + // Name is the name of the KonnectAPIAuthConfiguration resource. + // +required + Name string `json:"name"` +} diff --git a/api/konnect/v1alpha2/konnect_configuration.go b/api/konnect/v1alpha2/konnect_configuration.go new file mode 100644 index 00000000..8d25287b --- /dev/null +++ b/api/konnect/v1alpha2/konnect_configuration.go @@ -0,0 +1,16 @@ +package v1alpha2 + +// KonnectConfiguration is the Schema for the KonnectConfiguration API. +// +kubebuilder:object:generate=false +// +apireference:kgo:include +type KonnectConfiguration struct { + // APIAuthConfigurationRef is the reference to the API Auth Configuration + // that should be used for this Konnect Configuration. + // + // +required + APIAuthConfigurationRef KonnectAPIAuthConfigurationRef `json:"authRef"` + + // NOTE: Place for extending the KonnectConfiguration object. + // This is a good place to add fields like "class" which could reference a cluster-wide + // configuration for Konnect (similar to what Gateway API's GatewayClass). +} diff --git a/api/konnect/v1alpha2/konnect_gateway_controlplane_types.go b/api/konnect/v1alpha2/konnect_gateway_controlplane_types.go new file mode 100644 index 00000000..00653326 --- /dev/null +++ b/api/konnect/v1alpha2/konnect_gateway_controlplane_types.go @@ -0,0 +1,264 @@ +package v1alpha2 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + sdkkonnectcomp "github.com/Kong/sdk-konnect-go/models/components" + + commonv1alpha1 "github.com/kong/kubernetes-configuration/v2/api/common/v1alpha1" + konnectv1alpha1 "github.com/kong/kubernetes-configuration/v2/api/konnect/v1alpha1" +) + +func init() { + SchemeBuilder.Register(&KonnectGatewayControlPlane{}, &KonnectGatewayControlPlaneList{}) +} + +// KonnectGatewayControlPlane is the Schema for the KonnectGatewayControlplanes API. +// +// +genclient +// +kubebuilder:resource:scope=Namespaced +// +kubebuilder:resource:categories=kong +// +kubebuilder:object:root=true +// +kubebuilder:object:generate=true +// +kubebuilder:subresource:status +// +kubebuilder:storageversion +// +kubebuilder:printcolumn:name="Programmed",description="The Resource is Programmed on Konnect",type=string,JSONPath=`.status.conditions[?(@.type=='Programmed')].status` +// +kubebuilder:printcolumn:name="ID",description="Konnect ID",type=string,JSONPath=`.status.id` +// +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" +// +apireference:kgo:include +// +kong:channels=gateway-operator +type KonnectGatewayControlPlane struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of KonnectGatewayControlPlane. + Spec KonnectGatewayControlPlaneSpec `json:"spec,omitempty"` + + // Status defines the observed state of KonnectGatewayControlPlane. + // + // +optional + Status KonnectGatewayControlPlaneStatus `json:"status,omitempty"` +} + +// KonnectGatewayControlPlaneSpec defines the desired state of KonnectGatewayControlPlane. +// +// +kubebuilder:validation:XValidation:message="spec.createControlPlaneRequest.labels must not have more than 40 entries", rule="has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.labels) ? size(self.createControlPlaneRequest.labels) <= 40 : true" +// +kubebuilder:validation:XValidation:message="spec.createControlPlaneRequest.labels keys must be of length 1-63 characters", rule="has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.labels) ? self.createControlPlaneRequest.labels.all(key, size(key) >= 1 && size(key) <= 63) : true" +// +kubebuilder:validation:XValidation:message="spec.createControlPlaneRequest.labels values must be of length 1-63 characters", rule="has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.labels) ? self.createControlPlaneRequest.labels.all(key, size(self.createControlPlaneRequest.labels[key]) >= 1 && size(self.createControlPlaneRequest.labels[key]) <= 63) : true" +// +kubebuilder:validation:XValidation:message="spec.createControlPlaneRequest.labels keys must not start with 'k8s', 'kong', 'konnect', 'mesh', 'kic', 'insomnia' or '_'", rule="has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.labels) ? self.createControlPlaneRequest.labels.all(key, !key.startsWith('k8s') && !key.startsWith('kong') && !key.startsWith('konnect') && !key.startsWith('mesh') && !key.startsWith('kic') && !key.startsWith('_') && !key.startsWith('insomnia')) : true" +// +kubebuilder:validation:XValidation:message="spec.createControlPlaneRequest.labels keys must satisfy the '^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$' pattern", rule="has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.labels) ? self.createControlPlaneRequest.labels.all(key, key.matches('^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$')) : true" +// +kubebuilder:validation:XValidation:message="spec.members is only applicable for ControlPlanes that are created as groups", rule="(has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.cluster_type) && self.createControlPlaneRequest.cluster_type != 'CLUSTER_TYPE_CONTROL_PLANE_GROUP') ? !has(self.members) : true" +// +kubebuilder:validation:XValidation:message="when specified, spec.createControlPlaneRequest.cluster_type must be one of 'CLUSTER_TYPE_CONTROL_PLANE_GROUP', 'CLUSTER_TYPE_CONTROL_PLANE' or 'CLUSTER_TYPE_K8S_INGRESS_CONTROLLER'", rule="!has(self.createControlPlaneRequest) || !has(self.createControlPlaneRequest.cluster_type) ? true : ['CLUSTER_TYPE_CONTROL_PLANE_GROUP', 'CLUSTER_TYPE_CONTROL_PLANE', 'CLUSTER_TYPE_K8S_INGRESS_CONTROLLER'].exists(ct, ct == self.createControlPlaneRequest.cluster_type)" +// +kubebuilder:validation:XValidation:message="spec.createControlPlaneRequest.cluster_type is immutable", rule="!has(self.createControlPlaneRequest) && !has(oldSelf.createControlPlaneRequest) ? true : (has(self.createControlPlaneRequest) && has(oldSelf.createControlPlaneRequest) && (!has(self.createControlPlaneRequest.cluster_type) ? !has(oldSelf.createControlPlaneRequest.cluster_type) : self.createControlPlaneRequest.cluster_type == oldSelf.createControlPlaneRequest.cluster_type))" +// +kubebuilder:validation:XValidation:message="spec.createControlPlaneRequest.cloud_gateway cannot be set for spec.createControlPlaneRequest.cluster_type 'CLUSTER_TYPE_K8S_INGRESS_CONTROLLER'", rule="has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.cluster_type) && self.createControlPlaneRequest.cluster_type == 'CLUSTER_TYPE_K8S_INGRESS_CONTROLLER' ? !has(self.createControlPlaneRequest.cloud_gateway) : true" +// +kubebuilder:validation:XValidation:message="createControlPlaneRequest fields cannot be set for type Mirror", rule="has(self.source) && self.source == 'Mirror' ? !has(self.createControlPlaneRequest) : true" +// +kubebuilder:validation:XValidation:message="spec.source is immutable", rule="!has(self.source) && !has(oldSelf.source) ? true : self.source == oldSelf.source" +// +kubebuilder:validation:XValidation:message="mirror field must be set for type Mirror", rule="self.source == 'Mirror' ? has(self.mirror) : true" +// +kubebuilder:validation:XValidation:message="mirror field cannot be set for type Origin", rule="self.source == 'Origin' ? !has(self.mirror) : true" +// +kubebuilder:validation:XValidation:message="spec.createControlPlaneRequest must be set for type Origin", rule="self.source == 'Origin' ? has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.name) : true" +// +apireference:kgo:include +type KonnectGatewayControlPlaneSpec struct { + // CreateControlPlaneRequest is the request to create a Konnect Control Plane. + // + // +optional + CreateControlPlaneRequest *sdkkonnectcomp.CreateControlPlaneRequest `json:"createControlPlaneRequest,omitempty"` + + // Mirror is the Konnect Mirror configuration. + // It is only applicable for ControlPlanes that are created as Mirrors. + // + // +optional + Mirror *MirrorSpec `json:"mirror,omitempty"` + + // Source represents the source type of the Konnect entity. + // + // +kubebuilder:validation:Enum=Origin;Mirror + // +optional + // +kubebuilder:default=Origin + Source *commonv1alpha1.EntitySource `json:"source,omitempty"` + + // Members is a list of references to the KonnectGatewayControlPlaneMembers that are part of this control plane group. + // Only applicable for ControlPlanes that are created as groups. + // + // +optional + Members []corev1.LocalObjectReference `json:"members,omitempty"` + + // KonnectConfiguration contains the Konnect configuration for the control plane. + // + // +optional + KonnectConfiguration konnectv1alpha1.KonnectConfiguration `json:"konnect,omitempty"` +} + +// MirrorSpec contains the Konnect Mirror configuration. +type MirrorSpec struct { + // Konnect contains the KonnectID of the KonnectGatewayControlPlane that + // is mirrored. + // + // +required + Konnect MirrorKonnect `json:"konnect"` +} + +// MirrorKonnect contains the Konnect Mirror configuration. +type MirrorKonnect struct { + // ID is the ID of the Konnect entity. It can be set only in case + // the ControlPlane type is Mirror. + // + // +required + ID commonv1alpha1.KonnectIDType `json:"id"` +} + +// KonnectGatewayControlPlaneStatus defines the observed state of KonnectGatewayControlPlane. +// +apireference:kgo:include +type KonnectGatewayControlPlaneStatus struct { + konnectv1alpha1.KonnectEntityStatus `json:",inline"` + + // Endpoints defines the Konnect endpoints for the control plane. + // They are required by the DataPlane to be properly configured in + // Konnect and connect to the control plane. + // + // +optional + Endpoints *KonnectEndpoints `json:"konnectEndpoints,omitempty"` + + // Conditions describe the current conditions of the KonnectGatewayControlPlane. + // + // Known condition types are: + // + // * "Programmed" + // + // +listType=map + // +listMapKey=type + // +kubebuilder:validation:MaxItems=8 + // +kubebuilder:default={{type: "Programmed", status: "Unknown", reason:"Pending", message:"Waiting for controller", lastTransitionTime: "1970-01-01T00:00:00Z"}} + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// GetKonnectLabels gets the Konnect Labels from object's spec. +func (c *KonnectGatewayControlPlane) GetKonnectLabels() map[string]string { + if c.Spec.CreateControlPlaneRequest == nil { + return nil + } + + return c.Spec.CreateControlPlaneRequest.Labels +} + +// SetKonnectLabels sets the Konnect Labels in object's spec. +func (c *KonnectGatewayControlPlane) SetKonnectLabels(labels map[string]string) { + if c.Spec.CreateControlPlaneRequest == nil { + c.Spec.CreateControlPlaneRequest = &sdkkonnectcomp.CreateControlPlaneRequest{} + } + c.Spec.CreateControlPlaneRequest.Labels = labels +} + +// GetKonnectName gets the Name from CreateControlPlaneRequest. +func (c *KonnectGatewayControlPlane) GetKonnectName() string { + if c.Spec.CreateControlPlaneRequest == nil { + return "" + } + return c.Spec.CreateControlPlaneRequest.Name +} + +// SetKonnectName sets the Name in CreateControlPlaneRequest. +func (c *KonnectGatewayControlPlane) SetKonnectName(name string) { + if c.Spec.CreateControlPlaneRequest == nil { + c.Spec.CreateControlPlaneRequest = &sdkkonnectcomp.CreateControlPlaneRequest{} + } + c.Spec.CreateControlPlaneRequest.Name = name +} + +// GetKonnectClusterType gets the ClusterType from CreateControlPlaneRequest. +func (c *KonnectGatewayControlPlane) GetKonnectClusterType() *sdkkonnectcomp.CreateControlPlaneRequestClusterType { + if c.Spec.CreateControlPlaneRequest == nil { + return nil + } + return c.Spec.CreateControlPlaneRequest.ClusterType +} + +// SetKonnectClusterType sets the ClusterType in CreateControlPlaneRequest. +func (c *KonnectGatewayControlPlane) SetKonnectClusterType(clusterType *sdkkonnectcomp.CreateControlPlaneRequestClusterType) { + if c.Spec.CreateControlPlaneRequest == nil { + c.Spec.CreateControlPlaneRequest = &sdkkonnectcomp.CreateControlPlaneRequest{} + } + c.Spec.CreateControlPlaneRequest.ClusterType = clusterType +} + +// GetKonnectCloudGateway gets the CloudGateway from CreateControlPlaneRequest. +func (c *KonnectGatewayControlPlane) GetKonnectCloudGateway() *bool { + if c.Spec.CreateControlPlaneRequest == nil { + return nil + } + return c.Spec.CreateControlPlaneRequest.CloudGateway +} + +// SetKonnectCloudGateway sets the CloudGateway in CreateControlPlaneRequest. +func (c *KonnectGatewayControlPlane) SetKonnectCloudGateway(cloudGateway *bool) { + if c.Spec.CreateControlPlaneRequest == nil { + c.Spec.CreateControlPlaneRequest = &sdkkonnectcomp.CreateControlPlaneRequest{} + } + c.Spec.CreateControlPlaneRequest.CloudGateway = cloudGateway +} + +// GetKonnectAuthType gets the AuthType from CreateControlPlaneRequest. +func (c *KonnectGatewayControlPlane) GetKonnectAuthType() *sdkkonnectcomp.AuthType { + if c.Spec.CreateControlPlaneRequest == nil { + return nil + } + return c.Spec.CreateControlPlaneRequest.AuthType +} + +// SetKonnectAuthType sets the AuthType in CreateControlPlaneRequest. +func (c *KonnectGatewayControlPlane) SetKonnectAuthType(authType *sdkkonnectcomp.AuthType) { + if c.Spec.CreateControlPlaneRequest == nil { + c.Spec.CreateControlPlaneRequest = &sdkkonnectcomp.CreateControlPlaneRequest{} + } + c.Spec.CreateControlPlaneRequest.AuthType = authType +} + +// GetKonnectProxyURLs gets the ProxyUrls from CreateControlPlaneRequest. +func (c *KonnectGatewayControlPlane) GetKonnectProxyURLs() []sdkkonnectcomp.ProxyURL { + if c.Spec.CreateControlPlaneRequest == nil { + return nil + } + return c.Spec.CreateControlPlaneRequest.ProxyUrls +} + +// SetKonnectProxyURLs sets the ProxyUrls in CreateControlPlaneRequest. +func (c *KonnectGatewayControlPlane) SetKonnectProxyURLs(proxyURLs []sdkkonnectcomp.ProxyURL) { + if c.Spec.CreateControlPlaneRequest == nil { + c.Spec.CreateControlPlaneRequest = &sdkkonnectcomp.CreateControlPlaneRequest{} + } + c.Spec.CreateControlPlaneRequest.ProxyUrls = proxyURLs +} + +// GetKonnectDescription gets the Description from CreateControlPlaneRequest. +func (c *KonnectGatewayControlPlane) GetKonnectDescription() *string { + if c.Spec.CreateControlPlaneRequest == nil { + return nil + } + return c.Spec.CreateControlPlaneRequest.Description +} + +// SetKonnectDescription sets the Description in CreateControlPlaneRequest. +func (c *KonnectGatewayControlPlane) SetKonnectDescription(description *string) { + if c.Spec.CreateControlPlaneRequest == nil { + c.Spec.CreateControlPlaneRequest = &sdkkonnectcomp.CreateControlPlaneRequest{} + } + c.Spec.CreateControlPlaneRequest.Description = description +} + +// GetKonnectAPIAuthConfigurationRef returns the Konnect API Auth Configuration Ref. +func (c *KonnectGatewayControlPlane) GetKonnectAPIAuthConfigurationRef() konnectv1alpha1.KonnectAPIAuthConfigurationRef { + return c.Spec.KonnectConfiguration.APIAuthConfigurationRef +} + +// KonnectGatewayControlPlaneList contains a list of KonnectGatewayControlPlane. +// +kubebuilder:object:root=true +// +apireference:kgo:include +type KonnectGatewayControlPlaneList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + + Items []KonnectGatewayControlPlane `json:"items"` +} diff --git a/api/konnect/v1alpha2/zz_generated.deepcopy.go b/api/konnect/v1alpha2/zz_generated.deepcopy.go index 39c76a77..ca4f5c75 100644 --- a/api/konnect/v1alpha2/zz_generated.deepcopy.go +++ b/api/konnect/v1alpha2/zz_generated.deepcopy.go @@ -21,7 +21,9 @@ limitations under the License. package v1alpha2 import ( + "github.com/Kong/sdk-konnect-go/models/components" "github.com/kong/kubernetes-configuration/v2/api/common/v1alpha1" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -71,6 +73,21 @@ func (in *DataPlaneClientAuthStatus) DeepCopy() *DataPlaneClientAuthStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KonnectAPIAuthConfigurationRef) DeepCopyInto(out *KonnectAPIAuthConfigurationRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KonnectAPIAuthConfigurationRef. +func (in *KonnectAPIAuthConfigurationRef) DeepCopy() *KonnectAPIAuthConfigurationRef { + if in == nil { + return nil + } + out := new(KonnectAPIAuthConfigurationRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KonnectEndpoints) DeepCopyInto(out *KonnectEndpoints) { *out = *in @@ -303,6 +320,160 @@ func (in *KonnectExtensionStatus) DeepCopy() *KonnectExtensionStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KonnectGatewayControlPlane) DeepCopyInto(out *KonnectGatewayControlPlane) { + *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 KonnectGatewayControlPlane. +func (in *KonnectGatewayControlPlane) DeepCopy() *KonnectGatewayControlPlane { + if in == nil { + return nil + } + out := new(KonnectGatewayControlPlane) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KonnectGatewayControlPlane) 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 *KonnectGatewayControlPlaneList) DeepCopyInto(out *KonnectGatewayControlPlaneList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]KonnectGatewayControlPlane, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KonnectGatewayControlPlaneList. +func (in *KonnectGatewayControlPlaneList) DeepCopy() *KonnectGatewayControlPlaneList { + if in == nil { + return nil + } + out := new(KonnectGatewayControlPlaneList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KonnectGatewayControlPlaneList) 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 *KonnectGatewayControlPlaneSpec) DeepCopyInto(out *KonnectGatewayControlPlaneSpec) { + *out = *in + if in.CreateControlPlaneRequest != nil { + in, out := &in.CreateControlPlaneRequest, &out.CreateControlPlaneRequest + *out = new(components.CreateControlPlaneRequest) + (*in).DeepCopyInto(*out) + } + if in.Mirror != nil { + in, out := &in.Mirror, &out.Mirror + *out = new(MirrorSpec) + **out = **in + } + if in.Source != nil { + in, out := &in.Source, &out.Source + *out = new(v1alpha1.EntitySource) + **out = **in + } + if in.Members != nil { + in, out := &in.Members, &out.Members + *out = make([]corev1.LocalObjectReference, len(*in)) + copy(*out, *in) + } + out.KonnectConfiguration = in.KonnectConfiguration +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KonnectGatewayControlPlaneSpec. +func (in *KonnectGatewayControlPlaneSpec) DeepCopy() *KonnectGatewayControlPlaneSpec { + if in == nil { + return nil + } + out := new(KonnectGatewayControlPlaneSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KonnectGatewayControlPlaneStatus) DeepCopyInto(out *KonnectGatewayControlPlaneStatus) { + *out = *in + out.KonnectEntityStatus = in.KonnectEntityStatus + if in.Endpoints != nil { + in, out := &in.Endpoints, &out.Endpoints + *out = new(KonnectEndpoints) + **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 KonnectGatewayControlPlaneStatus. +func (in *KonnectGatewayControlPlaneStatus) DeepCopy() *KonnectGatewayControlPlaneStatus { + if in == nil { + return nil + } + out := new(KonnectGatewayControlPlaneStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MirrorKonnect) DeepCopyInto(out *MirrorKonnect) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MirrorKonnect. +func (in *MirrorKonnect) DeepCopy() *MirrorKonnect { + if in == nil { + return nil + } + out := new(MirrorKonnect) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MirrorSpec) DeepCopyInto(out *MirrorSpec) { + *out = *in + out.Konnect = in.Konnect +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MirrorSpec. +func (in *MirrorSpec) DeepCopy() *MirrorSpec { + if in == nil { + return nil + } + out := new(MirrorSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SecretRef) DeepCopyInto(out *SecretRef) { *out = *in diff --git a/api/konnect/v1alpha2/zz_generated_funcs_standalone.go b/api/konnect/v1alpha2/zz_generated_funcs_standalone.go new file mode 100644 index 00000000..4c613d8e --- /dev/null +++ b/api/konnect/v1alpha2/zz_generated_funcs_standalone.go @@ -0,0 +1,37 @@ +package v1alpha2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + konnectv1alpha1 "github.com/kong/kubernetes-configuration/v2/api/konnect/v1alpha1" +) + +// Code generated by scripts/apitypes-funcs/main.go; DO NOT EDIT. + +// GetKonnectStatus returns the Konnect status contained in the KonnectGatewayControlPlane status. +func (obj *KonnectGatewayControlPlane) GetKonnectStatus() *konnectv1alpha1.KonnectEntityStatus { + return &obj.Status.KonnectEntityStatus +} + +// GetKonnectID returns the Konnect ID in the KonnectGatewayControlPlane status. +func (obj *KonnectGatewayControlPlane) GetKonnectID() string { + return obj.Status.ID +} + +// SetKonnectID sets the Konnect ID in the KonnectGatewayControlPlane status. +func (obj *KonnectGatewayControlPlane) SetKonnectID(id string) { + obj.Status.ID = id +} +// GetTypeName returns the KonnectGatewayControlPlane Kind name +func (obj KonnectGatewayControlPlane) GetTypeName() string { + return "KonnectGatewayControlPlane" +} + +// GetConditions returns the Status Conditions +func (obj *KonnectGatewayControlPlane) GetConditions() []metav1.Condition { + return obj.Status.Conditions +} + +// SetConditions sets the Status Conditions +func (obj *KonnectGatewayControlPlane) SetConditions(conditions []metav1.Condition) { + obj.Status.Conditions = conditions +} diff --git a/api/konnect/v1alpha2/zz_generated_list_funcs.go b/api/konnect/v1alpha2/zz_generated_list_funcs.go index 28e70f13..5af0bf89 100644 --- a/api/konnect/v1alpha2/zz_generated_list_funcs.go +++ b/api/konnect/v1alpha2/zz_generated_list_funcs.go @@ -2,6 +2,11 @@ package v1alpha2 // Code generated by scripts/apitypes-funcs/main.go; DO NOT EDIT. +// GetItems returns the list of KonnectGatewayControlPlane items. +func (obj KonnectGatewayControlPlaneList) GetItems() []KonnectGatewayControlPlane { + return obj.Items +} + // GetItems returns the list of KonnectExtension items. func (obj KonnectExtensionList) GetItems() []KonnectExtension { return obj.Items diff --git a/config/crd/gateway-operator/konnect.konghq.com_konnectgatewaycontrolplanes.yaml b/config/crd/gateway-operator/konnect.konghq.com_konnectgatewaycontrolplanes.yaml index f8b74238..525d571b 100644 --- a/config/crd/gateway-operator/konnect.konghq.com_konnectgatewaycontrolplanes.yaml +++ b/config/crd/gateway-operator/konnect.konghq.com_konnectgatewaycontrolplanes.yaml @@ -30,6 +30,9 @@ spec: jsonPath: .status.organizationID name: OrgID type: string + deprecated: true + deprecationWarning: This API version has been deprecated in favor of v1alpha2 + and it will be removed in the future. name: v1alpha1 schema: openAPIV3Schema: @@ -336,6 +339,351 @@ spec: rule: '!self.status.conditions.exists(c, c.type == ''APIAuthValid'' && c.status == ''True'') ? true : self.spec.konnect.authRef == oldSelf.spec.konnect.authRef' served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: The Resource is Programmed on Konnect + jsonPath: .status.conditions[?(@.type=='Programmed')].status + name: Programmed + type: string + - description: Konnect ID + jsonPath: .status.id + name: ID + type: string + - description: Konnect Organization ID this resource belongs to. + jsonPath: .status.organizationID + name: OrgID + type: string + name: v1alpha2 + schema: + openAPIV3Schema: + description: KonnectGatewayControlPlane is the Schema for the KonnectGatewayControlplanes + API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of KonnectGatewayControlPlane. + properties: + createControlPlaneRequest: + description: CreateControlPlaneRequest is the request to create a + Konnect Control Plane. + properties: + auth_type: + description: The auth type value of the cluster associated with + the Runtime Group. + type: string + cloud_gateway: + description: Whether this control-plane can be used for cloud-gateways. + type: boolean + cluster_type: + description: The ClusterType value of the cluster associated with + the Control Plane. + type: string + description: + description: The description of the control plane in Konnect. + type: string + labels: + additionalProperties: + type: string + description: |- + Labels store metadata of an entity that can be used for filtering an entity list or for searching across entity types. + + Keys must be of length 1-63 characters, and cannot start with "kong", "konnect", "mesh", "kic", or "_". + type: object + name: + description: The name of the control plane. + type: string + proxy_urls: + description: Array of proxy URLs associated with reaching the + data-planes connected to a control-plane. + items: + description: ProxyURL - Proxy URL associated with reaching the + data-planes connected to a control-plane. + properties: + host: + description: Hostname of the proxy URL. + type: string + port: + description: Port of the proxy URL. + format: int64 + type: integer + protocol: + description: Protocol of the proxy URL. + type: string + required: + - host + - port + - protocol + type: object + type: array + required: + - name + type: object + konnect: + description: KonnectConfiguration contains the Konnect configuration + for the control plane. + properties: + authRef: + description: |- + APIAuthConfigurationRef is the reference to the API Auth Configuration + that should be used for this Konnect Configuration. + properties: + name: + description: Name is the name of the KonnectAPIAuthConfiguration + resource. + type: string + required: + - name + type: object + required: + - authRef + type: object + members: + description: |- + Members is a list of references to the KonnectGatewayControlPlaneMembers that are part of this control plane group. + Only applicable for ControlPlanes that are created as groups. + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: array + mirror: + description: |- + Mirror is the Konnect Mirror configuration. + It is only applicable for ControlPlanes that are created as Mirrors. + properties: + konnect: + description: |- + Konnect contains the KonnectID of the KonnectGatewayControlPlane that + is mirrored. + properties: + id: + description: |- + ID is the ID of the Konnect entity. It can be set only in case + the ControlPlane type is Mirror. + pattern: ^[0-9a-f]{8}(?:\-[0-9a-f]{4}){3}-[0-9a-f]{12}$ + type: string + required: + - id + type: object + required: + - konnect + type: object + source: + default: Origin + description: Source represents the source type of the Konnect entity. + enum: + - Origin + - Mirror + type: string + type: object + x-kubernetes-validations: + - message: spec.createControlPlaneRequest.labels must not have more than + 40 entries + rule: 'has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.labels) + ? size(self.createControlPlaneRequest.labels) <= 40 : true' + - message: spec.createControlPlaneRequest.labels keys must be of length + 1-63 characters + rule: 'has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.labels) + ? self.createControlPlaneRequest.labels.all(key, size(key) >= 1 && + size(key) <= 63) : true' + - message: spec.createControlPlaneRequest.labels values must be of length + 1-63 characters + rule: 'has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.labels) + ? self.createControlPlaneRequest.labels.all(key, size(self.createControlPlaneRequest.labels[key]) + >= 1 && size(self.createControlPlaneRequest.labels[key]) <= 63) : + true' + - message: spec.createControlPlaneRequest.labels keys must not start with + 'k8s', 'kong', 'konnect', 'mesh', 'kic', 'insomnia' or '_' + rule: 'has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.labels) + ? self.createControlPlaneRequest.labels.all(key, !key.startsWith(''k8s'') + && !key.startsWith(''kong'') && !key.startsWith(''konnect'') && !key.startsWith(''mesh'') + && !key.startsWith(''kic'') && !key.startsWith(''_'') && !key.startsWith(''insomnia'')) + : true' + - message: spec.createControlPlaneRequest.labels keys must satisfy the + '^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$' pattern + rule: 'has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.labels) + ? self.createControlPlaneRequest.labels.all(key, key.matches(''^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$'')) + : true' + - message: spec.members is only applicable for ControlPlanes that are + created as groups + rule: '(has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.cluster_type) + && self.createControlPlaneRequest.cluster_type != ''CLUSTER_TYPE_CONTROL_PLANE_GROUP'') + ? !has(self.members) : true' + - message: when specified, spec.createControlPlaneRequest.cluster_type + must be one of 'CLUSTER_TYPE_CONTROL_PLANE_GROUP', 'CLUSTER_TYPE_CONTROL_PLANE' + or 'CLUSTER_TYPE_K8S_INGRESS_CONTROLLER' + rule: '!has(self.createControlPlaneRequest) || !has(self.createControlPlaneRequest.cluster_type) + ? true : [''CLUSTER_TYPE_CONTROL_PLANE_GROUP'', ''CLUSTER_TYPE_CONTROL_PLANE'', + ''CLUSTER_TYPE_K8S_INGRESS_CONTROLLER''].exists(ct, ct == self.createControlPlaneRequest.cluster_type)' + - message: spec.createControlPlaneRequest.cluster_type is immutable + rule: '!has(self.createControlPlaneRequest) && !has(oldSelf.createControlPlaneRequest) + ? true : (has(self.createControlPlaneRequest) && has(oldSelf.createControlPlaneRequest) + && (!has(self.createControlPlaneRequest.cluster_type) ? !has(oldSelf.createControlPlaneRequest.cluster_type) + : self.createControlPlaneRequest.cluster_type == oldSelf.createControlPlaneRequest.cluster_type))' + - message: spec.createControlPlaneRequest.cloud_gateway cannot be set + for spec.createControlPlaneRequest.cluster_type 'CLUSTER_TYPE_K8S_INGRESS_CONTROLLER' + rule: 'has(self.createControlPlaneRequest) && has(self.createControlPlaneRequest.cluster_type) + && self.createControlPlaneRequest.cluster_type == ''CLUSTER_TYPE_K8S_INGRESS_CONTROLLER'' + ? !has(self.createControlPlaneRequest.cloud_gateway) : true' + - message: createControlPlaneRequest fields cannot be set for type Mirror + rule: 'has(self.source) && self.source == ''Mirror'' ? !has(self.createControlPlaneRequest) + : true' + - message: spec.source is immutable + rule: '!has(self.source) && !has(oldSelf.source) ? true : self.source + == oldSelf.source' + - message: mirror field must be set for type Mirror + rule: 'self.source == ''Mirror'' ? has(self.mirror) : true' + - message: mirror field cannot be set for type Origin + rule: 'self.source == ''Origin'' ? !has(self.mirror) : true' + - message: spec.createControlPlaneRequest must be set for type Origin + rule: 'self.source == ''Origin'' ? has(self.createControlPlaneRequest) + && has(self.createControlPlaneRequest.name) : true' + status: + description: Status defines the observed state of KonnectGatewayControlPlane. + properties: + conditions: + default: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Pending + status: Unknown + type: Programmed + description: |- + Conditions describe the current conditions of the KonnectGatewayControlPlane. + + Known condition types are: + + * "Programmed" + 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 + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + description: |- + 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 + konnectEndpoints: + description: |- + Endpoints defines the Konnect endpoints for the control plane. + They are required by the DataPlane to be properly configured in + Konnect and connect to the control plane. + properties: + controlPlane: + description: ControlPlaneEndpoint is the endpoint for the control + plane. + type: string + telemetry: + description: TelemetryEndpoint is the endpoint for telemetry. + type: string + required: + - controlPlane + - telemetry + type: object + organizationID: + description: OrgID is ID of Konnect Org that this entity has been + created in. + type: string + serverURL: + description: ServerURL is the URL of the Konnect server in which the + entity exists. + type: string + type: object + type: object + x-kubernetes-validations: + - 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' + - 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' + served: true storage: true subresources: status: {} diff --git a/config/samples/konnect_gateway_controlplane.yaml b/config/samples/konnect_gateway_controlplane_v1alpha2.yaml similarity index 63% rename from config/samples/konnect_gateway_controlplane.yaml rename to config/samples/konnect_gateway_controlplane_v1alpha2.yaml index 4303ee21..3e5c3614 100644 --- a/config/samples/konnect_gateway_controlplane.yaml +++ b/config/samples/konnect_gateway_controlplane_v1alpha2.yaml @@ -1,28 +1,30 @@ kind: KonnectGatewayControlPlane -apiVersion: konnect.konghq.com/v1alpha1 +apiVersion: konnect.konghq.com/v1alpha2 metadata: name: group1 namespace: default spec: - name: group1 - cluster_type: CLUSTER_TYPE_CONTROL_PLANE_GROUP - labels: - app: group1 - key1: group1 + createControlPlaneRequest: + name: group1 + cluster_type: CLUSTER_TYPE_CONTROL_PLANE_GROUP + labels: + app: group1 + key1: group1 konnect: authRef: name: konnect-api-auth-dev-1 --- kind: KonnectGatewayControlPlane -apiVersion: konnect.konghq.com/v1alpha1 +apiVersion: konnect.konghq.com/v1alpha2 metadata: name: test1 namespace: default spec: - name: test1 - labels: - app: test1 - key1: test1 + createControlPlaneRequest: + name: test1 + labels: + app: test1 + key1: test1 konnect: authRef: name: konnect-api-auth-dev-1 diff --git a/docs/all-api-reference.md b/docs/all-api-reference.md index 78c95182..e1d2d7be 100644 --- a/docs/all-api-reference.md +++ b/docs/all-api-reference.md @@ -4379,6 +4379,7 @@ _Appears in:_ - [KonnectCloudGatewayNetworkSpec](#konnectcloudgatewaynetworkspec) - [KonnectExtensionKonnectSpec](#konnectextensionkonnectspec) - [KonnectGatewayControlPlaneSpec](#konnectgatewaycontrolplanespec) +- [KonnectGatewayControlPlaneSpec](#konnectgatewaycontrolplanespec) #### KonnectConfigurationDataPlaneGroup @@ -4442,6 +4443,7 @@ _Appears in:_ - [KonnectEntityStatusWithControlPlaneRef](#konnectentitystatuswithcontrolplaneref) - [KonnectEntityStatusWithNetworkRef](#konnectentitystatuswithnetworkref) - [KonnectGatewayControlPlaneStatus](#konnectgatewaycontrolplanestatus) +- [KonnectGatewayControlPlaneStatus](#konnectgatewaycontrolplanestatus) #### KonnectEntityStatusWithControlPlaneAndCertificateRefs @@ -4838,6 +4840,7 @@ _Appears in:_ Package v1alpha2 contains API Schema definitions for the konnect.konghq.com v1alpha2 API group. - [KonnectExtension](#konnectextension) +- [KonnectGatewayControlPlane](#konnectgatewaycontrolplane) ### KonnectExtension @@ -4857,6 +4860,22 @@ deployment(s) spec gets customized to include the konnect-related configuration. +### KonnectGatewayControlPlane + + +KonnectGatewayControlPlane is the Schema for the KonnectGatewayControlplanes API. + + + +| Field | Description | +| --- | --- | +| `apiVersion` _string_ | `konnect.konghq.com/v1alpha2` +| `kind` _string_ | `KonnectGatewayControlPlane` +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.33/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | +| `spec` _[KonnectGatewayControlPlaneSpec](#konnectgatewaycontrolplanespec)_ | Spec defines the desired state of KonnectGatewayControlPlane. | + + + ### Types In this section you will find types that the CRDs rely on. @@ -4903,6 +4922,23 @@ DataPlaneLabelValue is the type that defines the value of a label that will be a _Appears in:_ - [KonnectExtensionDataPlane](#konnectextensiondataplane) +#### KonnectAPIAuthConfigurationRef + + +KonnectAPIAuthConfigurationRef is a reference to a KonnectAPIAuthConfiguration resource. + + + +| Field | Description | +| --- | --- | +| `name` _string_ | Name is the name of the KonnectAPIAuthConfiguration resource. | + + +_Appears in:_ +- [KonnectConfiguration](#konnectconfiguration) + + + #### KonnectEndpoints @@ -4918,6 +4954,7 @@ KonnectEndpoints defines the Konnect endpoints for the control plane. _Appears in:_ - [KonnectExtensionControlPlaneStatus](#konnectextensioncontrolplanestatus) +- [KonnectGatewayControlPlaneStatus](#konnectgatewaycontrolplanestatus) #### KonnectExtensionClientAuth @@ -5029,6 +5066,57 @@ _Appears in:_ +#### KonnectGatewayControlPlaneSpec + + +KonnectGatewayControlPlaneSpec defines the desired state of KonnectGatewayControlPlane. + + + +| Field | Description | +| --- | --- | +| `createControlPlaneRequest` _[CreateControlPlaneRequest](#createcontrolplanerequest)_ | CreateControlPlaneRequest is the request to create a Konnect Control Plane. | +| `mirror` _[MirrorSpec](#mirrorspec)_ | Mirror is the Konnect Mirror configuration. It is only applicable for ControlPlanes that are created as Mirrors. | +| `source` _[EntitySource](#entitysource)_ | Source represents the source type of the Konnect entity. | +| `members` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.33/#localobjectreference-v1-core) array_ | Members is a list of references to the KonnectGatewayControlPlaneMembers that are part of this control plane group. Only applicable for ControlPlanes that are created as groups. | +| `konnect` _[KonnectConfiguration](#konnectconfiguration)_ | KonnectConfiguration contains the Konnect configuration for the control plane. | + + +_Appears in:_ +- [KonnectGatewayControlPlane](#konnectgatewaycontrolplane) + + + +#### MirrorKonnect + + +MirrorKonnect contains the Konnect Mirror configuration. + + + +| Field | Description | +| --- | --- | +| `id` _[KonnectIDType](#konnectidtype)_ | ID is the ID of the Konnect entity. It can be set only in case the ControlPlane type is Mirror. | + + +_Appears in:_ +- [MirrorSpec](#mirrorspec) + +#### MirrorSpec + + +MirrorSpec contains the Konnect Mirror configuration. + + + +| Field | Description | +| --- | --- | +| `konnect` _[MirrorKonnect](#mirrorkonnect)_ | Konnect contains the KonnectID of the KonnectGatewayControlPlane that is mirrored. | + + +_Appears in:_ +- [KonnectGatewayControlPlaneSpec](#konnectgatewaycontrolplanespec) + #### ProvisioningMethod _Underlying type:_ `string` diff --git a/docs/konnect-api-reference.md b/docs/konnect-api-reference.md index 09ee0155..61a82856 100644 --- a/docs/konnect-api-reference.md +++ b/docs/konnect-api-reference.md @@ -478,6 +478,7 @@ _Appears in:_ - [KonnectCloudGatewayNetworkSpec](#konnectcloudgatewaynetworkspec) - [KonnectExtensionKonnectSpec](#konnectextensionkonnectspec) - [KonnectGatewayControlPlaneSpec](#konnectgatewaycontrolplanespec) +- [KonnectGatewayControlPlaneSpec](#konnectgatewaycontrolplanespec) #### KonnectConfigurationDataPlaneGroup @@ -541,6 +542,7 @@ _Appears in:_ - [KonnectEntityStatusWithControlPlaneRef](#konnectentitystatuswithcontrolplaneref) - [KonnectEntityStatusWithNetworkRef](#konnectentitystatuswithnetworkref) - [KonnectGatewayControlPlaneStatus](#konnectgatewaycontrolplanestatus) +- [KonnectGatewayControlPlaneStatus](#konnectgatewaycontrolplanestatus) @@ -838,6 +840,7 @@ _Appears in:_ Package v1alpha2 contains API Schema definitions for the konnect.konghq.com v1alpha2 API group. - [KonnectExtension](#konnectextension) +- [KonnectGatewayControlPlane](#konnectgatewaycontrolplane) ### KonnectExtension @@ -857,6 +860,22 @@ deployment(s) spec gets customized to include the konnect-related configuration. +### KonnectGatewayControlPlane + + +KonnectGatewayControlPlane is the Schema for the KonnectGatewayControlplanes API. + + + +| Field | Description | +| --- | --- | +| `apiVersion` _string_ | `konnect.konghq.com/v1alpha2` +| `kind` _string_ | `KonnectGatewayControlPlane` +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.33/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | +| `spec` _[KonnectGatewayControlPlaneSpec](#konnectgatewaycontrolplanespec)_ | Spec defines the desired state of KonnectGatewayControlPlane. | + + + ### Types In this section you will find types that the CRDs rely on. @@ -903,6 +922,23 @@ DataPlaneLabelValue is the type that defines the value of a label that will be a _Appears in:_ - [KonnectExtensionDataPlane](#konnectextensiondataplane) +#### KonnectAPIAuthConfigurationRef + + +KonnectAPIAuthConfigurationRef is a reference to a KonnectAPIAuthConfiguration resource. + + + +| Field | Description | +| --- | --- | +| `name` _string_ | Name is the name of the KonnectAPIAuthConfiguration resource. | + + +_Appears in:_ +- [KonnectConfiguration](#konnectconfiguration) + + + #### KonnectEndpoints @@ -918,6 +954,7 @@ KonnectEndpoints defines the Konnect endpoints for the control plane. _Appears in:_ - [KonnectExtensionControlPlaneStatus](#konnectextensioncontrolplanestatus) +- [KonnectGatewayControlPlaneStatus](#konnectgatewaycontrolplanestatus) #### KonnectExtensionClientAuth @@ -1029,6 +1066,57 @@ _Appears in:_ +#### KonnectGatewayControlPlaneSpec + + +KonnectGatewayControlPlaneSpec defines the desired state of KonnectGatewayControlPlane. + + + +| Field | Description | +| --- | --- | +| `createControlPlaneRequest` _[CreateControlPlaneRequest](#createcontrolplanerequest)_ | CreateControlPlaneRequest is the request to create a Konnect Control Plane. | +| `mirror` _[MirrorSpec](#mirrorspec)_ | Mirror is the Konnect Mirror configuration. It is only applicable for ControlPlanes that are created as Mirrors. | +| `source` _[EntitySource](#entitysource)_ | Source represents the source type of the Konnect entity. | +| `members` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.33/#localobjectreference-v1-core) array_ | Members is a list of references to the KonnectGatewayControlPlaneMembers that are part of this control plane group. Only applicable for ControlPlanes that are created as groups. | +| `konnect` _[KonnectConfiguration](#konnectconfiguration)_ | KonnectConfiguration contains the Konnect configuration for the control plane. | + + +_Appears in:_ +- [KonnectGatewayControlPlane](#konnectgatewaycontrolplane) + + + +#### MirrorKonnect + + +MirrorKonnect contains the Konnect Mirror configuration. + + + +| Field | Description | +| --- | --- | +| `id` _[KonnectIDType](#konnectidtype)_ | ID is the ID of the Konnect entity. It can be set only in case the ControlPlane type is Mirror. | + + +_Appears in:_ +- [MirrorSpec](#mirrorspec) + +#### MirrorSpec + + +MirrorSpec contains the Konnect Mirror configuration. + + + +| Field | Description | +| --- | --- | +| `konnect` _[MirrorKonnect](#mirrorkonnect)_ | Konnect contains the KonnectID of the KonnectGatewayControlPlane that is mirrored. | + + +_Appears in:_ +- [KonnectGatewayControlPlaneSpec](#konnectgatewaycontrolplanespec) + #### ProvisioningMethod _Underlying type:_ `string` diff --git a/pkg/clientset/typed/konnect/v1alpha2/fake/fake_konnect_client.go b/pkg/clientset/typed/konnect/v1alpha2/fake/fake_konnect_client.go index 524ab4bd..f1b32774 100644 --- a/pkg/clientset/typed/konnect/v1alpha2/fake/fake_konnect_client.go +++ b/pkg/clientset/typed/konnect/v1alpha2/fake/fake_konnect_client.go @@ -32,6 +32,10 @@ func (c *FakeKonnectV1alpha2) KonnectExtensions(namespace string) v1alpha2.Konne return newFakeKonnectExtensions(c, namespace) } +func (c *FakeKonnectV1alpha2) KonnectGatewayControlPlanes(namespace string) v1alpha2.KonnectGatewayControlPlaneInterface { + return newFakeKonnectGatewayControlPlanes(c, namespace) +} + // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakeKonnectV1alpha2) RESTClient() rest.Interface { diff --git a/pkg/clientset/typed/konnect/v1alpha2/fake/fake_konnectgatewaycontrolplane.go b/pkg/clientset/typed/konnect/v1alpha2/fake/fake_konnectgatewaycontrolplane.go new file mode 100644 index 00000000..ae04ccd5 --- /dev/null +++ b/pkg/clientset/typed/konnect/v1alpha2/fake/fake_konnectgatewaycontrolplane.go @@ -0,0 +1,52 @@ +/* +Copyright 2021 Kong, Inc. + +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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha2 "github.com/kong/kubernetes-configuration/v2/api/konnect/v1alpha2" + konnectv1alpha2 "github.com/kong/kubernetes-configuration/v2/pkg/clientset/typed/konnect/v1alpha2" + gentype "k8s.io/client-go/gentype" +) + +// fakeKonnectGatewayControlPlanes implements KonnectGatewayControlPlaneInterface +type fakeKonnectGatewayControlPlanes struct { + *gentype.FakeClientWithList[*v1alpha2.KonnectGatewayControlPlane, *v1alpha2.KonnectGatewayControlPlaneList] + Fake *FakeKonnectV1alpha2 +} + +func newFakeKonnectGatewayControlPlanes(fake *FakeKonnectV1alpha2, namespace string) konnectv1alpha2.KonnectGatewayControlPlaneInterface { + return &fakeKonnectGatewayControlPlanes{ + gentype.NewFakeClientWithList[*v1alpha2.KonnectGatewayControlPlane, *v1alpha2.KonnectGatewayControlPlaneList]( + fake.Fake, + namespace, + v1alpha2.SchemeGroupVersion.WithResource("konnectgatewaycontrolplanes"), + v1alpha2.SchemeGroupVersion.WithKind("KonnectGatewayControlPlane"), + func() *v1alpha2.KonnectGatewayControlPlane { return &v1alpha2.KonnectGatewayControlPlane{} }, + func() *v1alpha2.KonnectGatewayControlPlaneList { return &v1alpha2.KonnectGatewayControlPlaneList{} }, + func(dst, src *v1alpha2.KonnectGatewayControlPlaneList) { dst.ListMeta = src.ListMeta }, + func(list *v1alpha2.KonnectGatewayControlPlaneList) []*v1alpha2.KonnectGatewayControlPlane { + return gentype.ToPointerSlice(list.Items) + }, + func(list *v1alpha2.KonnectGatewayControlPlaneList, items []*v1alpha2.KonnectGatewayControlPlane) { + list.Items = gentype.FromPointerSlice(items) + }, + ), + fake, + } +} diff --git a/pkg/clientset/typed/konnect/v1alpha2/generated_expansion.go b/pkg/clientset/typed/konnect/v1alpha2/generated_expansion.go index af88613b..5a698396 100644 --- a/pkg/clientset/typed/konnect/v1alpha2/generated_expansion.go +++ b/pkg/clientset/typed/konnect/v1alpha2/generated_expansion.go @@ -19,3 +19,5 @@ limitations under the License. package v1alpha2 type KonnectExtensionExpansion interface{} + +type KonnectGatewayControlPlaneExpansion interface{} diff --git a/pkg/clientset/typed/konnect/v1alpha2/konnect_client.go b/pkg/clientset/typed/konnect/v1alpha2/konnect_client.go index 42db50b7..d811a482 100644 --- a/pkg/clientset/typed/konnect/v1alpha2/konnect_client.go +++ b/pkg/clientset/typed/konnect/v1alpha2/konnect_client.go @@ -29,6 +29,7 @@ import ( type KonnectV1alpha2Interface interface { RESTClient() rest.Interface KonnectExtensionsGetter + KonnectGatewayControlPlanesGetter } // KonnectV1alpha2Client is used to interact with features provided by the konnect.konghq.com group. @@ -40,6 +41,10 @@ func (c *KonnectV1alpha2Client) KonnectExtensions(namespace string) KonnectExten return newKonnectExtensions(c, namespace) } +func (c *KonnectV1alpha2Client) KonnectGatewayControlPlanes(namespace string) KonnectGatewayControlPlaneInterface { + return newKonnectGatewayControlPlanes(c, namespace) +} + // NewForConfig creates a new KonnectV1alpha2Client for the given config. // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), // where httpClient was generated with rest.HTTPClientFor(c). diff --git a/pkg/clientset/typed/konnect/v1alpha2/konnectgatewaycontrolplane.go b/pkg/clientset/typed/konnect/v1alpha2/konnectgatewaycontrolplane.go new file mode 100644 index 00000000..7a766f88 --- /dev/null +++ b/pkg/clientset/typed/konnect/v1alpha2/konnectgatewaycontrolplane.go @@ -0,0 +1,74 @@ +/* +Copyright 2021 Kong, Inc. + +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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + context "context" + + konnectv1alpha2 "github.com/kong/kubernetes-configuration/v2/api/konnect/v1alpha2" + scheme "github.com/kong/kubernetes-configuration/v2/pkg/clientset/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// KonnectGatewayControlPlanesGetter has a method to return a KonnectGatewayControlPlaneInterface. +// A group's client should implement this interface. +type KonnectGatewayControlPlanesGetter interface { + KonnectGatewayControlPlanes(namespace string) KonnectGatewayControlPlaneInterface +} + +// KonnectGatewayControlPlaneInterface has methods to work with KonnectGatewayControlPlane resources. +type KonnectGatewayControlPlaneInterface interface { + Create(ctx context.Context, konnectGatewayControlPlane *konnectv1alpha2.KonnectGatewayControlPlane, opts v1.CreateOptions) (*konnectv1alpha2.KonnectGatewayControlPlane, error) + Update(ctx context.Context, konnectGatewayControlPlane *konnectv1alpha2.KonnectGatewayControlPlane, opts v1.UpdateOptions) (*konnectv1alpha2.KonnectGatewayControlPlane, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, konnectGatewayControlPlane *konnectv1alpha2.KonnectGatewayControlPlane, opts v1.UpdateOptions) (*konnectv1alpha2.KonnectGatewayControlPlane, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*konnectv1alpha2.KonnectGatewayControlPlane, error) + List(ctx context.Context, opts v1.ListOptions) (*konnectv1alpha2.KonnectGatewayControlPlaneList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *konnectv1alpha2.KonnectGatewayControlPlane, err error) + KonnectGatewayControlPlaneExpansion +} + +// konnectGatewayControlPlanes implements KonnectGatewayControlPlaneInterface +type konnectGatewayControlPlanes struct { + *gentype.ClientWithList[*konnectv1alpha2.KonnectGatewayControlPlane, *konnectv1alpha2.KonnectGatewayControlPlaneList] +} + +// newKonnectGatewayControlPlanes returns a KonnectGatewayControlPlanes +func newKonnectGatewayControlPlanes(c *KonnectV1alpha2Client, namespace string) *konnectGatewayControlPlanes { + return &konnectGatewayControlPlanes{ + gentype.NewClientWithList[*konnectv1alpha2.KonnectGatewayControlPlane, *konnectv1alpha2.KonnectGatewayControlPlaneList]( + "konnectgatewaycontrolplanes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *konnectv1alpha2.KonnectGatewayControlPlane { + return &konnectv1alpha2.KonnectGatewayControlPlane{} + }, + func() *konnectv1alpha2.KonnectGatewayControlPlaneList { + return &konnectv1alpha2.KonnectGatewayControlPlaneList{} + }, + ), + } +} diff --git a/scripts/apitypes-funcs/supportedtypes.go b/scripts/apitypes-funcs/supportedtypes.go index d153e03e..5b61c2da 100644 --- a/scripts/apitypes-funcs/supportedtypes.go +++ b/scripts/apitypes-funcs/supportedtypes.go @@ -183,18 +183,32 @@ var supportedKonnectTypesStandalone = []supportedTypesT{ Types: []templateDataT{ { Type: "KonnectGatewayControlPlane", - KonnectStatusType: "*KonnectEntityStatus", + KonnectStatusType: "KonnectEntityStatus", KonnectStatusEmbedded: true, - GetKonnectStatusReturnType: "KonnectEntityStatus", + GetKonnectStatusReturnType: "*KonnectEntityStatus", }, { Type: "KonnectAPIAuthConfiguration", }, { Type: "KonnectCloudGatewayNetwork", - KonnectStatusType: "*KonnectEntityStatus", + KonnectStatusType: "KonnectEntityStatus", KonnectStatusEmbedded: true, - GetKonnectStatusReturnType: "KonnectEntityStatus", + GetKonnectStatusReturnType: "*KonnectEntityStatus", + }, + }, + }, + { + PackageVersion: "v1alpha2", + AdditionalImports: []string{ + `konnectv1alpha1 "github.com/kong/kubernetes-configuration/v2/api/konnect/v1alpha1"`, + }, + Types: []templateDataT{ + { + Type: "KonnectGatewayControlPlane", + KonnectStatusType: "KonnectEntityStatus", + KonnectStatusEmbedded: true, + GetKonnectStatusReturnType: "*konnectv1alpha1.KonnectEntityStatus", }, }, }, diff --git a/scripts/apitypes-funcs/templates.go b/scripts/apitypes-funcs/templates.go index 81ede814..1c0ce0ad 100644 --- a/scripts/apitypes-funcs/templates.go +++ b/scripts/apitypes-funcs/templates.go @@ -173,6 +173,10 @@ func (obj *{{ .Type }}) GetConsumerRefName() string { import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +{{- range .AdditionalImports }} + {{ . }} +{{- end }} ) // Code generated by scripts/apitypes-funcs/main.go; DO NOT EDIT. @@ -180,7 +184,7 @@ import ( {{- range .Types }} {{ if .KonnectStatusType }} // GetKonnectStatus returns the Konnect status contained in the {{ .Type }} status. -func (obj *{{ .Type }}) GetKonnectStatus() {{ .KonnectStatusType }} { +func (obj *{{ .Type }}) GetKonnectStatus() {{ .GetKonnectStatusReturnType }} { return &obj.Status.{{ trimPrefix "*" .KonnectStatusType }} } diff --git a/test/crdsvalidation/konnect.konghq.com/konnectgatewaycontrolplane_test.go b/test/crdsvalidation/konnect.konghq.com/konnectgatewaycontrolplane_test.go index 557d5041..f3778dda 100644 --- a/test/crdsvalidation/konnect.konghq.com/konnectgatewaycontrolplane_test.go +++ b/test/crdsvalidation/konnect.konghq.com/konnectgatewaycontrolplane_test.go @@ -116,6 +116,8 @@ func TestKonnectGatewayControlPlane(t *testing.T) { common.TestCasesGroup[*konnectv1alpha1.KonnectGatewayControlPlane]{ { Name: "konnect.authRef change is not allowed for Programmed=True", + // Tracking issue: https://github.com/Kong/kubernetes-configuration/issues/504 + SkipReason: "Fails when v1alpha2 is the storage version due to missing conversion logic. This test could be re-enabled by implementing conversion logic using a conversion webhook: https://github.com/Kong/kubernetes-configuration/issues/504", TestObject: &konnectv1alpha1.KonnectGatewayControlPlane{ ObjectMeta: common.CommonObjectMeta, Spec: konnectv1alpha1.KonnectGatewayControlPlaneSpec{ @@ -147,6 +149,8 @@ func TestKonnectGatewayControlPlane(t *testing.T) { }, { Name: "konnect.authRef change is not allowed for APIAuthValid=True", + // Tracking issue: https://github.com/Kong/kubernetes-configuration/issues/504 + SkipReason: "Fails when v1alpha2 is the storage version due to missing conversion logic. This test could be re-enabled by implementing conversion logic using a conversion webhook: https://github.com/Kong/kubernetes-configuration/issues/504", TestObject: &konnectv1alpha1.KonnectGatewayControlPlane{ ObjectMeta: common.CommonObjectMeta, Spec: konnectv1alpha1.KonnectGatewayControlPlaneSpec{ @@ -178,6 +182,8 @@ func TestKonnectGatewayControlPlane(t *testing.T) { }, { Name: "konnect.authRef change is allowed when cp is not Programmed=True nor APIAuthValid=True", + // Tracking issue: https://github.com/Kong/kubernetes-configuration/issues/504 + SkipReason: "Fails when v1alpha2 is the storage version due to missing conversion logic. This test could be re-enabled by implementing conversion logic using a conversion webhook: https://github.com/Kong/kubernetes-configuration/issues/504", TestObject: &konnectv1alpha1.KonnectGatewayControlPlane{ ObjectMeta: common.CommonObjectMeta, Spec: konnectv1alpha1.KonnectGatewayControlPlaneSpec{ @@ -665,6 +671,8 @@ func TestKonnectGatewayControlPlane(t *testing.T) { }, { Name: "cluster type is immutable when having it set and then trying to unset it", + // Tracking issue: https://github.com/Kong/kubernetes-configuration/issues/504 + SkipReason: "Fails when v1alpha2 is the storage version due to missing conversion logic. This test could be re-enabled by implementing conversion logic using a conversion webhook: https://github.com/Kong/kubernetes-configuration/issues/504", TestObject: &konnectv1alpha1.KonnectGatewayControlPlane{ ObjectMeta: common.CommonObjectMeta, Spec: konnectv1alpha1.KonnectGatewayControlPlaneSpec{ diff --git a/test/crdsvalidation/konnect.konghq.com/konnectgatewaycontrolplane_v1alpha2_test.go b/test/crdsvalidation/konnect.konghq.com/konnectgatewaycontrolplane_v1alpha2_test.go new file mode 100644 index 00000000..2afbff71 --- /dev/null +++ b/test/crdsvalidation/konnect.konghq.com/konnectgatewaycontrolplane_v1alpha2_test.go @@ -0,0 +1,933 @@ +package crdsvalidation_test + +import ( + "fmt" + "testing" + + "github.com/samber/lo" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + sdkkonnectcomp "github.com/Kong/sdk-konnect-go/models/components" + + commonv1alpha1 "github.com/kong/kubernetes-configuration/v2/api/common/v1alpha1" + konnectv1alpha1 "github.com/kong/kubernetes-configuration/v2/api/konnect/v1alpha1" + konnectv1alpha2 "github.com/kong/kubernetes-configuration/v2/api/konnect/v1alpha2" + common "github.com/kong/kubernetes-configuration/v2/test/crdsvalidation/common" +) + +func TestKonnectGatewayControlPlaneV1alpha2(t *testing.T) { + t.Run("members can only be set on groups", func(t *testing.T) { + common.TestCasesGroup[*konnectv1alpha2.KonnectGatewayControlPlane]{ + { + Name: "members can be set on control-plane group", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cpg-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlaneGroup), + }, + Members: []corev1.LocalObjectReference{ + { + Name: "cp-1", + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + }, + { + Name: "members cannot be set on regular control-planes", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cpg-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + }, + Members: []corev1.LocalObjectReference{ + { + Name: "cp-1", + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.members is only applicable for ControlPlanes that are created as groups"), + }, + { + Name: "members cannot be set on a KIC control-planes", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cpg-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeK8SIngressController), + }, + Members: []corev1.LocalObjectReference{ + { + Name: "cp-1", + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.members is only applicable for ControlPlanes that are created as groups"), + }, + { + Name: "members cannot be set on serverless control-planes", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cpg-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeServerless), + }, + Members: []corev1.LocalObjectReference{ + { + Name: "cp-1", + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.members is only applicable for ControlPlanes that are created as groups"), + }, + }.Run(t) + }) + + t.Run("updates not allowed for status conditions", func(t *testing.T) { + common.TestCasesGroup[*konnectv1alpha2.KonnectGatewayControlPlane]{ + { + Name: "konnect.authRef change is not allowed for Programmed=True", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + Status: konnectv1alpha2.KonnectGatewayControlPlaneStatus{ + Conditions: []metav1.Condition{ + { + Type: "Programmed", + Status: metav1.ConditionTrue, + Reason: "Valid", + LastTransitionTime: metav1.Now(), + }, + }, + }, + }, + Update: func(kcp *konnectv1alpha2.KonnectGatewayControlPlane) { + kcp.Spec.KonnectConfiguration.APIAuthConfigurationRef.Name = "name-2" + }, + ExpectedUpdateErrorMessage: lo.ToPtr("spec.konnect.authRef is immutable when an entity is already Programme"), + }, + { + Name: "konnect.authRef change is not allowed for APIAuthValid=True", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + Status: konnectv1alpha2.KonnectGatewayControlPlaneStatus{ + Conditions: []metav1.Condition{ + { + Type: "APIAuthValid", + Status: metav1.ConditionTrue, + Reason: "Valid", + LastTransitionTime: metav1.Now(), + }, + }, + }, + }, + Update: func(kcp *konnectv1alpha2.KonnectGatewayControlPlane) { + kcp.Spec.KonnectConfiguration.APIAuthConfigurationRef.Name = "name-2" + }, + ExpectedUpdateErrorMessage: lo.ToPtr("spec.konnect.authRef is immutable when an entity refers to a Valid API Auth Configuration"), + }, + { + Name: "konnect.authRef change is allowed when cp is not Programmed=True nor APIAuthValid=True", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + Status: konnectv1alpha2.KonnectGatewayControlPlaneStatus{ + Conditions: []metav1.Condition{ + { + Type: "APIAuthValid", + Status: metav1.ConditionFalse, + Reason: "Invalid", + LastTransitionTime: metav1.Now(), + }, + { + Type: "Programmed", + Status: metav1.ConditionFalse, + Reason: "NotProgrammed", + LastTransitionTime: metav1.Now(), + }, + }, + }, + }, + Update: func(kcp *konnectv1alpha2.KonnectGatewayControlPlane) { + kcp.Spec.KonnectConfiguration.APIAuthConfigurationRef.Name = "name-2" + }, + }, + { + Name: "spec.createControlPlaneRequest.cluster_type change is not allowed", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + Update: func(kcp *konnectv1alpha2.KonnectGatewayControlPlane) { + kcp.Spec.CreateControlPlaneRequest.ClusterType = sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlaneGroup.ToPointer() + }, + ExpectedUpdateErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.cluster_type is immutable"), + }, + }.Run(t) + }) + + t.Run("labels constraints", func(t *testing.T) { + common.TestCasesGroup[*konnectv1alpha2.KonnectGatewayControlPlane]{ + { + Name: "spec.createControlPlaneRequest.labels of length 40 is allowed", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + Labels: func() map[string]string { + labels := make(map[string]string) + for i := range 40 { + labels[fmt.Sprintf("key-%d", i)] = fmt.Sprintf("value-%d", i) + } + return labels + }(), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + }, + { + Name: "spec.createControlPlaneRequest.labels length must not be greater than 40", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + Labels: func() map[string]string { + labels := make(map[string]string) + for i := range 41 { + labels[fmt.Sprintf("key-%d", i)] = fmt.Sprintf("value-%d", i) + } + return labels + }(), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.labels must not have more than 40 entries"), + }, + { + Name: "spec.createControlPlaneRequest.labels keys' length must not be greater than 63", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + Labels: map[string]string{ + lo.RandomString(64, lo.AllCharset): "value", + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.labels keys must be of length 1-63 characters"), + }, + { + Name: "spec.createControlPlaneRequest.labels keys' length must at least 1 character long", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + Labels: map[string]string{ + "": "value", + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.labels keys must be of length 1-63 characters"), + }, + // + { + Name: "spec.createControlPlaneRequest.labels values' length must not be greater than 63", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + Labels: map[string]string{ + "key": lo.RandomString(64, lo.AllCharset), + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.labels values must be of length 1-63 characters"), + }, + { + Name: "spec.createControlPlaneRequest.labels values' length must at least 1 character long", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + Labels: map[string]string{ + "key": "", + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.labels values must be of length 1-63 characters"), + }, + { + Name: "spec.createControlPlaneRequest.labels keys must not start with k8s", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + Labels: map[string]string{ + "k8s_key": "value", + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.labels keys must not start with 'k8s', 'kong', 'konnect', 'mesh', 'kic', 'insomnia' or '_'"), + }, + { + Name: "spec.createControlPlaneRequest.labels keys must not start with kong", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + Labels: map[string]string{ + "kong_key": "value", + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.labels keys must not start with 'k8s', 'kong', 'konnect', 'mesh', 'kic', 'insomnia' or '_'"), + }, + { + Name: "spec.createControlPlaneRequest.labels keys must not start with konnect", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + Labels: map[string]string{ + "konnect_key": "value", + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.labels keys must not start with 'k8s', 'kong', 'konnect', 'mesh', 'kic', 'insomnia' or '_'"), + }, + { + Name: "spec.createControlPlaneRequest.labels keys must not start with mesh", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + Labels: map[string]string{ + "mesh_key": "value", + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.labels keys must not start with 'k8s', 'kong', 'konnect', 'mesh', 'kic', 'insomnia' or '_'"), + }, + { + Name: "spec.createControlPlaneRequest.labels keys must not start with kic", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + Labels: map[string]string{ + "kic_key": "value", + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.labels keys must not start with 'k8s', 'kong', 'konnect', 'mesh', 'kic', 'insomnia' or '_'"), + }, + { + Name: "spec.createControlPlaneRequest.labels keys must not start with insomnia", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + Labels: map[string]string{ + "insomnia_key": "value", + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.labels keys must not start with 'k8s', 'kong', 'konnect', 'mesh', 'kic', 'insomnia' or '_'"), + }, + { + Name: "spec.createControlPlaneRequest.labels keys must not start with underscore", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + Labels: map[string]string{ + "_key": "value", + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.labels keys must not start with 'k8s', 'kong', 'konnect', 'mesh', 'kic', 'insomnia' or '_'"), + }, + { + Name: "spec.createControlPlaneRequest.labels keys must satisfy the '^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$' pattern", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: lo.ToPtr(sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane), + Labels: map[string]string{ + "key-": "value", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.labels keys must satisfy the '^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$' pattern"), + }, + }.Run(t) + }) + + t.Run("restriction on cluster types", func(t *testing.T) { + common.TestCasesGroup[*konnectv1alpha2.KonnectGatewayControlPlane]{ + { + Name: "unspecified cluster type (defaulting to CLUSTR_TYPE_CONTROL_PLANE) is allowed", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + }, + { + Name: "CLUSTER_TYPE_CONTROL_PLANE_GROUP is supported", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlaneGroup.ToPointer(), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + }, + { + Name: "CLUSTER_TYPE_CONTROL_PLANE is supported", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane.ToPointer(), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + }, + { + Name: "CLUSTER_TYPE_K8S_INGRESS_CONTROLLER is supported", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeK8SIngressController.ToPointer(), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + }, + { + Name: "CLUSTER_TYPE_SERVERLESS is not supported", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeServerless.ToPointer(), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.cluster_type must be one of 'CLUSTER_TYPE_CONTROL_PLANE_GROUP', 'CLUSTER_TYPE_CONTROL_PLANE' or 'CLUSTER_TYPE_K8S_INGRESS_CONTROLLER'"), + }, + { + Name: "CLUSTER_TYPE_CUSTOM is not supported", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: sdkkonnectcomp.CreateControlPlaneRequestClusterType("CLUSTER_TYPE_CUSTOM").ToPointer(), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.cluster_type must be one of 'CLUSTER_TYPE_CONTROL_PLANE_GROUP', 'CLUSTER_TYPE_CONTROL_PLANE' or 'CLUSTER_TYPE_K8S_INGRESS_CONTROLLER'"), + }, + { + Name: "cluster type is immutable", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + Update: func(cp *konnectv1alpha2.KonnectGatewayControlPlane) { + cp.Spec.CreateControlPlaneRequest.ClusterType = sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlaneGroup.ToPointer() + }, + ExpectedUpdateErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.cluster_type is immutable"), + }, + { + Name: "cluster type is immutable when having it set and then trying to unset it", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane.ToPointer(), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + Update: func(cp *konnectv1alpha2.KonnectGatewayControlPlane) { + cp.Spec.CreateControlPlaneRequest.ClusterType = nil + }, + ExpectedUpdateErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.cluster_type is immutable"), + }, + { + Name: "cannot set spec.createControlPlaneRequest.cloud_gateway to true for spec.createControlPlaneRequest.cluster_type CLUSTER_TYPE_K8S_INGRESS_CONTROLLER", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeK8SIngressController.ToPointer(), + CloudGateway: lo.ToPtr(true), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.cloud_gateway cannot be set for spec.createControlPlaneRequest.cluster_type 'CLUSTER_TYPE_K8S_INGRESS_CONTROLLER'"), + }, + { + Name: "cannot set spec.createControlPlaneRequest.cloud_gateway to false for spec.createControlPlaneRequest.cluster_type CLUSTER_TYPE_K8S_INGRESS_CONTROLLER", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeK8SIngressController.ToPointer(), + CloudGateway: lo.ToPtr(false), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest.cloud_gateway cannot be set for spec.createControlPlaneRequest.cluster_type 'CLUSTER_TYPE_K8S_INGRESS_CONTROLLER'"), + }, + { + Name: "not setting spec.createControlPlaneRequest.cloud_gateway for spec.createControlPlaneRequest.cluster_type CLUSTER_TYPE_K8S_INGRESS_CONTROLLER passes", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + ClusterType: sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeK8SIngressController.ToPointer(), + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + }, + { + Name: "update status with CreateControlPlaneRequest nil, validation should pass", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: nil, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + Source: lo.ToPtr(commonv1alpha1.EntitySourceMirror), + Mirror: &konnectv1alpha2.MirrorSpec{ + Konnect: konnectv1alpha2.MirrorKonnect{ + ID: commonv1alpha1.KonnectIDType("8ae65120-cdec-4310-84c1-4b19caf67967"), + }, + }, + }, + Status: konnectv1alpha2.KonnectGatewayControlPlaneStatus{ + Conditions: []metav1.Condition{ + { + Type: "Programmed", + Status: metav1.ConditionTrue, + Reason: "Valid", + LastTransitionTime: metav1.Now(), + }, + }, + }, + }, + Update: func(cp *konnectv1alpha2.KonnectGatewayControlPlane) { + cp.Status.Conditions = append(cp.Status.Conditions, metav1.Condition{ + Type: "APIAuthValid", + Status: metav1.ConditionTrue, + Reason: "Valid", + LastTransitionTime: metav1.Now(), + }) + }, + }, + }.Run(t) + }) + + t.Run("controlPlane types", func(t *testing.T) { + common.TestCasesGroup[*konnectv1alpha2.KonnectGatewayControlPlane]{ + { + Name: "no type specificed, no KonnectID specified", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + }, + { + Name: "mirror type, no KonnectID specified", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + Source: lo.ToPtr(commonv1alpha1.EntitySourceMirror), + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("mirror field must be set for type Mirror"), + }, + { + Name: "mirror type, well-formed KonnectID specified", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + Source: lo.ToPtr(commonv1alpha1.EntitySourceMirror), + Mirror: &konnectv1alpha2.MirrorSpec{ + Konnect: konnectv1alpha2.MirrorKonnect{ + ID: commonv1alpha1.KonnectIDType("8ae65120-cdec-4310-84c1-4b19caf67967"), + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + }, + { + Name: "mirror type, malformed KonnectID specified", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + Source: lo.ToPtr(commonv1alpha1.EntitySourceMirror), + Mirror: &konnectv1alpha2.MirrorSpec{ + Konnect: konnectv1alpha2.MirrorKonnect{ + ID: commonv1alpha1.KonnectIDType("malformed-id"), + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.mirror.konnect.id in body should match '^[0-9a-f]{8}(?:\\-[0-9a-f]{4}){3}-[0-9a-f]{12}$'"), + }, + { + Name: "mirror type, KonnectID specified, controlPlane spec specified", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + Source: lo.ToPtr(commonv1alpha1.EntitySourceMirror), + Mirror: &konnectv1alpha2.MirrorSpec{ + Konnect: konnectv1alpha2.MirrorKonnect{ + ID: commonv1alpha1.KonnectIDType("8ae65120-cdec-4310-84c1-4b19caf67967"), + }, + }, + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("createControlPlaneRequest fields cannot be set for type Mirror"), + }, + { + Name: "origin type, KonnectID specified", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + Source: lo.ToPtr(commonv1alpha1.EntitySourceOrigin), + Mirror: &konnectv1alpha2.MirrorSpec{ + Konnect: konnectv1alpha2.MirrorKonnect{ + ID: commonv1alpha1.KonnectIDType("8ae65120-cdec-4310-84c1-4b19caf67967"), + }, + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("mirror field cannot be set for type Origin"), + }, + { + Name: "origin type, no KonnectID specified, empty controlPlane spec", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + Source: lo.ToPtr(commonv1alpha1.EntitySourceOrigin), + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + ExpectedErrorMessage: lo.ToPtr("spec.createControlPlaneRequest must be set for type Origin"), + }, + { + Name: "origin type, no KonnectID specified, with controlPlane name", + TestObject: &konnectv1alpha2.KonnectGatewayControlPlane{ + ObjectMeta: common.CommonObjectMeta, + Spec: konnectv1alpha2.KonnectGatewayControlPlaneSpec{ + Source: lo.ToPtr(commonv1alpha1.EntitySourceOrigin), + CreateControlPlaneRequest: &sdkkonnectcomp.CreateControlPlaneRequest{ + Name: "cp-1", + }, + KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{ + APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{ + Name: "name-1", + }, + }, + }, + }, + }, + }.Run(t) + }) +}