diff --git a/api/configuration/v1alpha1/kongservice_types.go b/api/configuration/v1alpha1/kongservice_types.go
index afa9e1a7..ced3d399 100644
--- a/api/configuration/v1alpha1/kongservice_types.go
+++ b/api/configuration/v1alpha1/kongservice_types.go
@@ -39,6 +39,8 @@ import (
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.spec.controlPlaneRef) || has(self.spec.controlPlaneRef)", message="controlPlaneRef is required once set"
// +kubebuilder:validation:XValidation:rule="(!has(self.spec.controlPlaneRef) || !has(self.spec.controlPlaneRef.konnectNamespacedRef)) ? true : !has(self.spec.controlPlaneRef.konnectNamespacedRef.__namespace__)", message="spec.controlPlaneRef cannot specify namespace for namespaced resource"
// +kubebuilder:validation:XValidation:rule="(!has(self.spec.controlPlaneRef)) ? true : (!has(self.status) || !self.status.conditions.exists(c, c.type == 'Programmed' && c.status == 'True')) ? true : oldSelf.spec.controlPlaneRef == self.spec.controlPlaneRef", message="spec.controlPlaneRef is immutable when an entity is already Programmed"
+// +kubebuilder:validation:XValidation:rule="(!has(self.status) || !self.status.conditions.exists(c, c.type == 'Programmed' && c.status == 'True')) ? true : !has(self.spec.konnect) || !has(self.spec.konnect.adopt) || (has(oldSelf.spec.konnect) && has(oldSelf.spec.konnect.adopt))", message="Cannot add spec.konnect.adopt when an entity is already programmed"
+// +kubebuilder:validation:XValidation:rule="(!has(self.spec.konnect) || !has(self.spec.konnect.adopt) || !has(oldSelf.spec.konnect) || !has(oldSelf.spec.konnect.adopt)) ? true : (!has(self.status) || !self.status.conditions.exists(c, c.type == 'Programmed' && c.status == 'True')) ? true : oldSelf.spec.konnect.adopt == self.spec.konnect.adopt", message="spec.konnect.adopt is immutable when an entity is already Programmed"
// +apireference:kgo:include
// +kong:channels=gateway-operator
type KongService struct {
@@ -53,12 +55,17 @@ type KongService struct {
// KongServiceSpec defines specification of a Kong Service.
// +kubebuilder:validation:XValidation:rule="!has(self.controlPlaneRef) ? true : self.controlPlaneRef.type != 'kic'", message="KIC is not supported as control plane"
+// +kubebuilder:validation:XValidation:rule="(has(self.controlPlaneRef) && (self.controlPlaneRef.type == 'konnectNamespacedRef' || self.controlPlaneRef.type == 'konnectID')) ? true : !has(self.konnect)", message="Cannot specify Konnect specific options when control plane is not Konnect"
// +apireference:kgo:include
type KongServiceSpec struct {
// ControlPlaneRef is a reference to a ControlPlane this KongService is associated with.
// +kubebuilder:validation:Required
ControlPlaneRef *ControlPlaneRef `json:"controlPlaneRef"`
+ // KonnectOptions includes options specific to Konnect.
+ // Only used when we manage the KongService by Konnect entity controller.
+ KonnectOptions *konnectv1alpha1.KonnectEntityOptions `json:"konnect,omitempty"`
+
KongServiceAPISpec `json:",inline"`
}
diff --git a/api/configuration/v1alpha1/zz_generated.deepcopy.go b/api/configuration/v1alpha1/zz_generated.deepcopy.go
index 7e8fd5be..268b55f2 100644
--- a/api/configuration/v1alpha1/zz_generated.deepcopy.go
+++ b/api/configuration/v1alpha1/zz_generated.deepcopy.go
@@ -2350,6 +2350,11 @@ func (in *KongServiceSpec) DeepCopyInto(out *KongServiceSpec) {
*out = new(ControlPlaneRef)
(*in).DeepCopyInto(*out)
}
+ if in.KonnectOptions != nil {
+ in, out := &in.KonnectOptions, &out.KonnectOptions
+ *out = new(konnectv1alpha1.KonnectEntityOptions)
+ (*in).DeepCopyInto(*out)
+ }
in.KongServiceAPISpec.DeepCopyInto(&out.KongServiceAPISpec)
}
diff --git a/api/konnect/v1alpha1/konnect_configuration.go b/api/konnect/v1alpha1/konnect_configuration.go
index f5e05975..82600d94 100644
--- a/api/konnect/v1alpha1/konnect_configuration.go
+++ b/api/konnect/v1alpha1/konnect_configuration.go
@@ -14,3 +14,15 @@ type KonnectConfiguration struct {
// 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).
}
+
+// KonnectEntityOptions stores the options of entities specific to Konnect.
+// +apireference:kgo:include
+type KonnectEntityOptions struct {
+ Adopt *KonnectAdoptOptions `json:"adopt,omitempty"`
+}
+
+// KonnectAdoptOptions stores the options for adopting existing Konnect entities.
+// +apireference:kgo:include
+type KonnectAdoptOptions struct {
+ ID string `json:"id"`
+}
diff --git a/api/konnect/v1alpha1/konnect_gateway_controlplane_types.go b/api/konnect/v1alpha1/konnect_gateway_controlplane_types.go
index cc8517c9..5c4e08f8 100644
--- a/api/konnect/v1alpha1/konnect_gateway_controlplane_types.go
+++ b/api/konnect/v1alpha1/konnect_gateway_controlplane_types.go
@@ -23,6 +23,8 @@ func init() {
// +kubebuilder:printcolumn:name="OrgID",description="Konnect Organization ID this resource belongs to.",type=string,JSONPath=`.status.organizationID`
// +kubebuilder:validation:XValidation:message="spec.konnect.authRef is immutable when an entity is already Programmed", rule="!self.status.conditions.exists(c, c.type == 'Programmed' && c.status == 'True') ? true : self.spec.konnect.authRef == oldSelf.spec.konnect.authRef"
// +kubebuilder:validation:XValidation:message="spec.konnect.authRef is immutable when an entity refers to a Valid API Auth Configuration", rule="!self.status.conditions.exists(c, c.type == 'APIAuthValid' && c.status == 'True') ? true : self.spec.konnect.authRef == oldSelf.spec.konnect.authRef"
+// +kubebuilder:validation:XValidation:message="Cannot add spec.adopt when an entitiy is already Programmed", rule="!self.status.conditions.exists(c, c.type == 'Programmed' && c.status == 'True') ? true : (!has(self.spec.adopt) || has(oldSelf.spec.adopt))"
+// +kubebuilder:validation:XValidation:message="spec.adopt is immutable when an entitiy is already Programmed", rule="!self.status.conditions.exists(c, c.type == 'Programmed' && c.status == 'True') ? true : ((!has(self.spec.adopt) || !has(oldSelf.spec.adopt)) ? true : self.spec.adopt == oldSelf.spec.adopt)"
// +apireference:kgo:include
// +kong:channels=gateway-operator
type KonnectGatewayControlPlane struct {
@@ -53,6 +55,8 @@ type KonnectGatewayControlPlaneSpec struct {
// Only applicable for ControlPlanes that are created as groups.
Members []corev1.LocalObjectReference `json:"members,omitempty"`
+ Adopt *KonnectAdoptOptions `json:"adopt,omitempty"`
+
KonnectConfiguration KonnectConfiguration `json:"konnect,omitempty"`
}
diff --git a/api/konnect/v1alpha1/zz_generated.deepcopy.go b/api/konnect/v1alpha1/zz_generated.deepcopy.go
index cd77a0b5..7f364f83 100644
--- a/api/konnect/v1alpha1/zz_generated.deepcopy.go
+++ b/api/konnect/v1alpha1/zz_generated.deepcopy.go
@@ -142,6 +142,41 @@ func (in *KonnectAPIAuthConfigurationStatus) DeepCopy() *KonnectAPIAuthConfigura
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *KonnectAdoptOptions) DeepCopyInto(out *KonnectAdoptOptions) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KonnectAdoptOptions.
+func (in *KonnectAdoptOptions) DeepCopy() *KonnectAdoptOptions {
+ if in == nil {
+ return nil
+ }
+ out := new(KonnectAdoptOptions)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *KonnectEntityOptions) DeepCopyInto(out *KonnectEntityOptions) {
+ *out = *in
+ if in.Adopt != nil {
+ in, out := &in.Adopt, &out.Adopt
+ *out = new(KonnectAdoptOptions)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KonnectEntityOptions.
+func (in *KonnectEntityOptions) DeepCopy() *KonnectEntityOptions {
+ if in == nil {
+ return nil
+ }
+ out := new(KonnectEntityOptions)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KonnectEntityStatus) DeepCopyInto(out *KonnectEntityStatus) {
*out = *in
@@ -321,6 +356,11 @@ func (in *KonnectGatewayControlPlaneSpec) DeepCopyInto(out *KonnectGatewayContro
*out = make([]v1.LocalObjectReference, len(*in))
copy(*out, *in)
}
+ if in.Adopt != nil {
+ in, out := &in.Adopt, &out.Adopt
+ *out = new(KonnectAdoptOptions)
+ **out = **in
+ }
out.KonnectConfiguration = in.KonnectConfiguration
}
diff --git a/config/crd/gateway-operator/configuration.konghq.com_kongservices.yaml b/config/crd/gateway-operator/configuration.konghq.com_kongservices.yaml
index 90fdd6c2..aa17e6c8 100644
--- a/config/crd/gateway-operator/configuration.konghq.com_kongservices.yaml
+++ b/config/crd/gateway-operator/configuration.konghq.com_kongservices.yaml
@@ -135,6 +135,21 @@ spec:
description: The host of the upstream server. Note that the host value
is case sensitive.
type: string
+ konnect:
+ description: |-
+ KonnectOptions includes options specific to Konnect.
+ Only used when we manage the KongService by Konnect entity controller.
+ properties:
+ adopt:
+ description: KonnectAdoptOptions stores the options for adopting
+ existing Konnect entities.
+ properties:
+ id:
+ type: string
+ required:
+ - id
+ type: object
+ type: object
name:
description: The Service name.
type: string
@@ -193,6 +208,10 @@ spec:
- message: KIC is not supported as control plane
rule: '!has(self.controlPlaneRef) ? true : self.controlPlaneRef.type
!= ''kic'''
+ - message: Cannot specify Konnect specific options when control plane
+ is not Konnect
+ rule: '(has(self.controlPlaneRef) && (self.controlPlaneRef.type == ''konnectNamespacedRef''
+ || self.controlPlaneRef.type == ''konnectID'')) ? true : !has(self.konnect)'
status:
default:
conditions:
@@ -301,6 +320,15 @@ spec:
rule: '(!has(self.spec.controlPlaneRef)) ? true : (!has(self.status) ||
!self.status.conditions.exists(c, c.type == ''Programmed'' && c.status
== ''True'')) ? true : oldSelf.spec.controlPlaneRef == self.spec.controlPlaneRef'
+ - message: Cannot add spec.konnect.adopt when an entity is already programmed
+ rule: '(!has(self.status) || !self.status.conditions.exists(c, c.type ==
+ ''Programmed'' && c.status == ''True'')) ? true : !has(self.spec.konnect)
+ || !has(self.spec.konnect.adopt) || (has(oldSelf.spec.konnect) && has(oldSelf.spec.konnect.adopt))'
+ - message: spec.konnect.adopt is immutable when an entity is already Programmed
+ rule: '(!has(self.spec.konnect) || !has(self.spec.konnect.adopt) || !has(oldSelf.spec.konnect)
+ || !has(oldSelf.spec.konnect.adopt)) ? true : (!has(self.status) || !self.status.conditions.exists(c,
+ c.type == ''Programmed'' && c.status == ''True'')) ? true : oldSelf.spec.konnect.adopt
+ == self.spec.konnect.adopt'
served: true
storage: true
subresources:
diff --git a/config/crd/gateway-operator/konnect.konghq.com_konnectgatewaycontrolplanes.yaml b/config/crd/gateway-operator/konnect.konghq.com_konnectgatewaycontrolplanes.yaml
index c3cb8259..58a55802 100644
--- a/config/crd/gateway-operator/konnect.konghq.com_konnectgatewaycontrolplanes.yaml
+++ b/config/crd/gateway-operator/konnect.konghq.com_konnectgatewaycontrolplanes.yaml
@@ -54,6 +54,15 @@ spec:
spec:
description: Spec defines the desired state of KonnectGatewayControlPlane.
properties:
+ adopt:
+ description: KonnectAdoptOptions stores the options for adopting existing
+ Konnect entities.
+ properties:
+ id:
+ type: string
+ required:
+ - id
+ type: object
auth_type:
description: The auth type value of the cluster associated with the
Runtime Group.
@@ -274,6 +283,13 @@ spec:
API Auth Configuration
rule: '!self.status.conditions.exists(c, c.type == ''APIAuthValid'' && c.status
== ''True'') ? true : self.spec.konnect.authRef == oldSelf.spec.konnect.authRef'
+ - message: Cannot add spec.adopt when an entitiy is already Programmed
+ rule: '!self.status.conditions.exists(c, c.type == ''Programmed'' && c.status
+ == ''True'') ? true : (!has(self.spec.adopt) || has(oldSelf.spec.adopt))'
+ - message: spec.adopt is immutable when an entitiy is already Programmed
+ rule: '!self.status.conditions.exists(c, c.type == ''Programmed'' && c.status
+ == ''True'') ? true : ((!has(self.spec.adopt) || !has(oldSelf.spec.adopt))
+ ? true : self.spec.adopt == oldSelf.spec.adopt)'
served: true
storage: true
subresources:
diff --git a/docs/api-reference.md b/docs/api-reference.md
index 0b8a531d..4bcac659 100644
--- a/docs/api-reference.md
+++ b/docs/api-reference.md
@@ -1435,6 +1435,7 @@ KongServiceSpec defines specification of a Kong Service.
| Field | Description |
| --- | --- |
| `controlPlaneRef` _[ControlPlaneRef](#controlplaneref)_ | ControlPlaneRef is a reference to a ControlPlane this KongService is associated with. |
+| `konnect` _[KonnectEntityOptions](#konnectentityoptions)_ | KonnectOptions includes options specific to Konnect. Only used when we manage the KongService by Konnect entity controller. |
| `url` _string_ | Helper field to set `protocol`, `host`, `port` and `path` using a URL. This field is write-only and is not returned in responses. |
| `connect_timeout` _integer_ | The timeout in milliseconds for establishing a connection to the upstream server. |
| `enabled` _boolean_ | Whether the Service is active. If set to `false`, the proxy behavior will be as if any routes attached to it do not exist (404). Default: `true`. |
diff --git a/docs/konnect-api-reference.md b/docs/konnect-api-reference.md
index 03e7fafa..acfa19de 100644
--- a/docs/konnect-api-reference.md
+++ b/docs/konnect-api-reference.md
@@ -92,6 +92,22 @@ KonnectAPIAuthType is the type of authentication used to authenticate with the K
_Appears in:_
- [KonnectAPIAuthConfigurationSpec](#konnectapiauthconfigurationspec)
+#### KonnectAdoptOptions
+
+
+KonnectAdoptOptions stores the options for adopting existing Konnect entities.
+
+
+
+| Field | Description |
+| --- | --- |
+| `id` _string_ | |
+
+
+_Appears in:_
+- [KonnectEntityOptions](#konnectentityoptions)
+- [KonnectGatewayControlPlaneSpec](#konnectgatewaycontrolplanespec)
+
#### KonnectConfiguration
@@ -107,6 +123,8 @@ KonnectConfiguration is the Schema for the KonnectConfiguration API.
_Appears in:_
- [KonnectGatewayControlPlaneSpec](#konnectgatewaycontrolplanespec)
+
+
#### KonnectEntityStatus
@@ -159,6 +177,7 @@ KonnectGatewayControlPlaneSpec defines the desired state of KonnectGatewayContro
| `proxy_urls` _[ProxyURL](#proxyurl) array_ | Array of proxy URLs associated with reaching the data-planes connected to a control-plane. |
| `labels` _object (keys:string, values:string)_ | 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 "_". |
| `members` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#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. |
+| `adopt` _[KonnectAdoptOptions](#konnectadoptoptions)_ | |
| `konnect` _[KonnectConfiguration](#konnectconfiguration)_ | |
diff --git a/test/crdsvalidation/kongservice_test.go b/test/crdsvalidation/kongservice_test.go
index f320ecb3..43ea0b04 100644
--- a/test/crdsvalidation/kongservice_test.go
+++ b/test/crdsvalidation/kongservice_test.go
@@ -8,6 +8,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
configurationv1alpha1 "github.com/kong/kubernetes-configuration/api/configuration/v1alpha1"
+ konnectv1alpha1 "github.com/kong/kubernetes-configuration/api/konnect/v1alpha1"
"github.com/kong/kubernetes-configuration/test/crdsvalidation"
)
@@ -28,6 +29,168 @@ func TestKongService(t *testing.T) {
NewCRDValidationTestCasesGroupCPRefChangeKICUnsupportedTypes(t, obj, EmptyControlPlaneRefNotAllowed).Run(t)
})
+ t.Run("konnect adopt", func(t *testing.T) {
+ crdsvalidation.TestCasesGroup[*configurationv1alpha1.KongService]{
+ {
+ Name: "konnect adopt can be changed before getting programmed",
+ TestObject: &configurationv1alpha1.KongService{
+ ObjectMeta: commonObjectMeta,
+ Spec: configurationv1alpha1.KongServiceSpec{
+ ControlPlaneRef: &configurationv1alpha1.ControlPlaneRef{
+ Type: configurationv1alpha1.ControlPlaneRefKonnectNamespacedRef,
+ KonnectNamespacedRef: &configurationv1alpha1.KonnectNamespacedRef{
+ Name: "test-konnect-control-plane",
+ },
+ },
+ KonnectOptions: &konnectv1alpha1.KonnectEntityOptions{
+ Adopt: &konnectv1alpha1.KonnectAdoptOptions{
+ ID: "abcddcba-0000-1111-9999-0123456789ab",
+ },
+ },
+ KongServiceAPISpec: configurationv1alpha1.KongServiceAPISpec{
+ Host: "example.com",
+ },
+ },
+ },
+ Update: func(ks *configurationv1alpha1.KongService) {
+ ks.Spec.KonnectOptions = &konnectv1alpha1.KonnectEntityOptions{
+ Adopt: &konnectv1alpha1.KonnectAdoptOptions{
+ ID: "abcddcba-0000-1111-9999-0123456789ac",
+ },
+ }
+ },
+ },
+ {
+ Name: "konnect adopt cannot be changed after programmed",
+ TestObject: &configurationv1alpha1.KongService{
+ ObjectMeta: commonObjectMeta,
+ Spec: configurationv1alpha1.KongServiceSpec{
+ ControlPlaneRef: &configurationv1alpha1.ControlPlaneRef{
+ Type: configurationv1alpha1.ControlPlaneRefKonnectNamespacedRef,
+ KonnectNamespacedRef: &configurationv1alpha1.KonnectNamespacedRef{
+ Name: "test-konnect-control-plane",
+ },
+ },
+ KonnectOptions: &konnectv1alpha1.KonnectEntityOptions{
+ Adopt: &konnectv1alpha1.KonnectAdoptOptions{
+ ID: "abcddcba-0000-1111-9999-0123456789ab",
+ },
+ },
+ KongServiceAPISpec: configurationv1alpha1.KongServiceAPISpec{
+ Host: "example.com",
+ },
+ },
+ Status: configurationv1alpha1.KongServiceStatus{
+ Konnect: &konnectv1alpha1.KonnectEntityStatusWithControlPlaneRef{
+ KonnectEntityStatus: konnectv1alpha1.KonnectEntityStatus{
+ ID: "abcddcba-0000-1111-9999-0123456789ac",
+ },
+ ControlPlaneID: "cp-1",
+ },
+ Conditions: []metav1.Condition{
+ {
+ Type: "Programmed",
+ Status: metav1.ConditionTrue,
+ Reason: "Valid",
+ LastTransitionTime: metav1.Now(),
+ },
+ },
+ },
+ },
+ Update: func(ks *configurationv1alpha1.KongService) {
+ ks.Spec.KonnectOptions = &konnectv1alpha1.KonnectEntityOptions{
+ Adopt: &konnectv1alpha1.KonnectAdoptOptions{
+ ID: "abcddcba-0000-1111-9999-fd9876543211",
+ },
+ }
+ },
+ ExpectedUpdateErrorMessage: lo.ToPtr("spec.konnect.adopt is immutable when an entity is already Programmed"),
+ },
+ {
+ Name: "Cannot set konnect adopt after programmed",
+ TestObject: &configurationv1alpha1.KongService{
+ ObjectMeta: commonObjectMeta,
+ Spec: configurationv1alpha1.KongServiceSpec{
+ ControlPlaneRef: &configurationv1alpha1.ControlPlaneRef{
+ Type: configurationv1alpha1.ControlPlaneRefKonnectNamespacedRef,
+ KonnectNamespacedRef: &configurationv1alpha1.KonnectNamespacedRef{
+ Name: "test-konnect-control-plane",
+ },
+ },
+ KongServiceAPISpec: configurationv1alpha1.KongServiceAPISpec{
+ Host: "example.com",
+ },
+ },
+ Status: configurationv1alpha1.KongServiceStatus{
+ Konnect: &konnectv1alpha1.KonnectEntityStatusWithControlPlaneRef{
+ KonnectEntityStatus: konnectv1alpha1.KonnectEntityStatus{
+ ID: "abcddcba-0000-1111-9999-fdecba987654",
+ },
+ ControlPlaneID: "cp-1",
+ },
+ Conditions: []metav1.Condition{
+ {
+ Type: "Programmed",
+ Status: metav1.ConditionTrue,
+ Reason: "Valid",
+ LastTransitionTime: metav1.Now(),
+ },
+ },
+ },
+ },
+ Update: func(ks *configurationv1alpha1.KongService) {
+ ks.Spec.KonnectOptions = &konnectv1alpha1.KonnectEntityOptions{
+ Adopt: &konnectv1alpha1.KonnectAdoptOptions{
+ ID: "abcddcba-0000-1111-9999-1234567890ab",
+ },
+ }
+ },
+ ExpectedUpdateErrorMessage: lo.ToPtr("Cannot add spec.konnect.adopt when an entity is already programmed"),
+ },
+ {
+ Name: "konnect adopt can be removed after programmed",
+ TestObject: &configurationv1alpha1.KongService{
+ ObjectMeta: commonObjectMeta,
+ Spec: configurationv1alpha1.KongServiceSpec{
+ ControlPlaneRef: &configurationv1alpha1.ControlPlaneRef{
+ Type: configurationv1alpha1.ControlPlaneRefKonnectNamespacedRef,
+ KonnectNamespacedRef: &configurationv1alpha1.KonnectNamespacedRef{
+ Name: "test-konnect-control-plane",
+ },
+ },
+ KonnectOptions: &konnectv1alpha1.KonnectEntityOptions{
+ Adopt: &konnectv1alpha1.KonnectAdoptOptions{
+ ID: "abcddcba-0000-1111-9999-0123456789ab",
+ },
+ },
+ KongServiceAPISpec: configurationv1alpha1.KongServiceAPISpec{
+ Host: "example.com",
+ },
+ },
+ Status: configurationv1alpha1.KongServiceStatus{
+ Konnect: &konnectv1alpha1.KonnectEntityStatusWithControlPlaneRef{
+ KonnectEntityStatus: konnectv1alpha1.KonnectEntityStatus{
+ ID: "abcddcba-0000-1111-9999-fdecba987654",
+ },
+ ControlPlaneID: "cp-1",
+ },
+ Conditions: []metav1.Condition{
+ {
+ Type: "Programmed",
+ Status: metav1.ConditionTrue,
+ Reason: "Valid",
+ LastTransitionTime: metav1.Now(),
+ },
+ },
+ },
+ },
+ Update: func(ks *configurationv1alpha1.KongService) {
+ ks.Spec.KonnectOptions.Adopt = nil
+ },
+ },
+ }.Run(t)
+ })
+
t.Run("tags validation", func(t *testing.T) {
crdsvalidation.TestCasesGroup[*configurationv1alpha1.KongService]{
{
diff --git a/test/crdsvalidation/konnectgatewaycontrolplane_test.go b/test/crdsvalidation/konnectgatewaycontrolplane_test.go
index 579eae79..4cb75db1 100644
--- a/test/crdsvalidation/konnectgatewaycontrolplane_test.go
+++ b/test/crdsvalidation/konnectgatewaycontrolplane_test.go
@@ -685,4 +685,155 @@ func TestKonnectGatewayControlPlane(t *testing.T) {
},
}.Run(t)
})
+
+ t.Run("constraint on adopt options", func(t *testing.T) {
+ crdsvalidation.TestCasesGroup[*konnectv1alpha1.KonnectGatewayControlPlane]{
+ {
+ Name: "Can update adopt options before programmed",
+ TestObject: &konnectv1alpha1.KonnectGatewayControlPlane{
+ ObjectMeta: commonObjectMeta,
+ Spec: konnectv1alpha1.KonnectGatewayControlPlaneSpec{
+ Adopt: &konnectv1alpha1.KonnectAdoptOptions{
+ ID: "abcddcba-1234-5678-abcd-0123456789ab",
+ },
+ CreateControlPlaneRequest: sdkkonnectcomp.CreateControlPlaneRequest{
+ Name: "cp-1",
+ ClusterType: sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane.ToPointer(),
+ },
+ KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{
+ APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{
+ Name: "name-1",
+ },
+ },
+ },
+ Status: konnectv1alpha1.KonnectGatewayControlPlaneStatus{
+ Conditions: []metav1.Condition{
+ {
+ Type: "Programmed",
+ Status: metav1.ConditionUnknown,
+ Reason: "Pending",
+ LastTransitionTime: metav1.Now(),
+ },
+ },
+ },
+ },
+ Update: func(kgcp *konnectv1alpha1.KonnectGatewayControlPlane) {
+ kgcp.Spec.Adopt = &konnectv1alpha1.KonnectAdoptOptions{
+ ID: "abcddcba-1234-5678-abcd-0123456789ac",
+ }
+ },
+ },
+ {
+ Name: "Cannot update adopt options after programmed",
+ TestObject: &konnectv1alpha1.KonnectGatewayControlPlane{
+ ObjectMeta: commonObjectMeta,
+ Spec: konnectv1alpha1.KonnectGatewayControlPlaneSpec{
+ Adopt: &konnectv1alpha1.KonnectAdoptOptions{
+ ID: "abcddcba-1234-5678-abcd-0123456789ab",
+ },
+ CreateControlPlaneRequest: sdkkonnectcomp.CreateControlPlaneRequest{
+ Name: "cp-1",
+ ClusterType: sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane.ToPointer(),
+ },
+ KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{
+ APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{
+ Name: "name-1",
+ },
+ },
+ },
+ Status: konnectv1alpha1.KonnectGatewayControlPlaneStatus{
+ KonnectEntityStatus: konnectv1alpha1.KonnectEntityStatus{
+ ID: "abcddcba-1234-5678-abcd-0123456789ab",
+ },
+ Conditions: []metav1.Condition{
+ {
+ Type: "Programmed",
+ Status: metav1.ConditionTrue,
+ Reason: "Programmed",
+ LastTransitionTime: metav1.Now(),
+ },
+ },
+ },
+ },
+ Update: func(kgcp *konnectv1alpha1.KonnectGatewayControlPlane) {
+ kgcp.Spec.Adopt = &konnectv1alpha1.KonnectAdoptOptions{
+ ID: "abcddcba-1234-5678-abcd-0123456789ac",
+ }
+ },
+ ExpectedUpdateErrorMessage: lo.ToPtr("spec.adopt is immutable when an entitiy is already Programmed"),
+ },
+ {
+ Name: "Cannot add adopt options after programmed",
+ TestObject: &konnectv1alpha1.KonnectGatewayControlPlane{
+ ObjectMeta: commonObjectMeta,
+ Spec: konnectv1alpha1.KonnectGatewayControlPlaneSpec{
+ CreateControlPlaneRequest: sdkkonnectcomp.CreateControlPlaneRequest{
+ Name: "cp-1",
+ ClusterType: sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane.ToPointer(),
+ },
+ KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{
+ APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{
+ Name: "name-1",
+ },
+ },
+ },
+ Status: konnectv1alpha1.KonnectGatewayControlPlaneStatus{
+ KonnectEntityStatus: konnectv1alpha1.KonnectEntityStatus{
+ ID: "abcddcba-1234-5678-abcd-0123456789ab",
+ },
+ Conditions: []metav1.Condition{
+ {
+ Type: "Programmed",
+ Status: metav1.ConditionTrue,
+ Reason: "Programmed",
+ LastTransitionTime: metav1.Now(),
+ },
+ },
+ },
+ },
+ Update: func(kgcp *konnectv1alpha1.KonnectGatewayControlPlane) {
+ kgcp.Spec.Adopt = &konnectv1alpha1.KonnectAdoptOptions{
+ ID: "abcddcba-1234-5678-abcd-0123456789ac",
+ }
+ },
+ ExpectedUpdateErrorMessage: lo.ToPtr("Cannot add spec.adopt when an entitiy is already Programmed"),
+ },
+ {
+ Name: "can delete adopt options after programmed",
+ TestObject: &konnectv1alpha1.KonnectGatewayControlPlane{
+ ObjectMeta: commonObjectMeta,
+ Spec: konnectv1alpha1.KonnectGatewayControlPlaneSpec{
+ Adopt: &konnectv1alpha1.KonnectAdoptOptions{
+ ID: "abcddcba-1234-5678-abcd-0123456789ab",
+ },
+ CreateControlPlaneRequest: sdkkonnectcomp.CreateControlPlaneRequest{
+ Name: "cp-1",
+ ClusterType: sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlane.ToPointer(),
+ },
+ KonnectConfiguration: konnectv1alpha1.KonnectConfiguration{
+ APIAuthConfigurationRef: konnectv1alpha1.KonnectAPIAuthConfigurationRef{
+ Name: "name-1",
+ },
+ },
+ },
+ Status: konnectv1alpha1.KonnectGatewayControlPlaneStatus{
+ KonnectEntityStatus: konnectv1alpha1.KonnectEntityStatus{
+ ID: "abcddcba-1234-5678-abcd-0123456789ab",
+ },
+ Conditions: []metav1.Condition{
+ {
+ Type: "Programmed",
+ Status: metav1.ConditionTrue,
+ Reason: "Programmed",
+ LastTransitionTime: metav1.Now(),
+ },
+ },
+ },
+ },
+ Update: func(kgcp *konnectv1alpha1.KonnectGatewayControlPlane) {
+ kgcp.Spec.Adopt = nil
+ },
+ },
+ }.Run(t)
+ })
}