Skip to content

Commit d410f83

Browse files
committed
feat: add support for using KonnectGatewayControlPlane object of type group with KonnectExtension
1 parent 0047fdf commit d410f83

File tree

9 files changed

+162
-4
lines changed

9 files changed

+162
-4
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@
9393
- Added `managed-by:kong-operator` tag to all Konnect entities to allow
9494
filtering resources managed by Kong Operator in Konnect.
9595
[#3609](https://github.com/Kong/kong-operator/pull/3609)
96+
- Added support for using `KonnectGatewayControlPlane` of type group with `KonnectExtension`s.
97+
[#3711](https://github.com/Kong/kong-operator/pull/3711)
9698

9799
### Changed
98100

api/konnect/v1alpha2/konnect_extension_types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ const (
221221
ClusterTypeControlPlane KonnectExtensionClusterType = "ControlPlane"
222222
// ClusterTypeK8sIngressController is the type of the Kubernetes Control Plane.
223223
ClusterTypeK8sIngressController KonnectExtensionClusterType = "K8SIngressController"
224+
// ClusterTypeControlPlaneGroup is the type of the Control Plane Group.
225+
ClusterTypeControlPlaneGroup KonnectExtensionClusterType = "ControlPlaneGroup"
224226
)
225227

226228
// KonnectEndpoints defines the Konnect endpoints for the control plane.
@@ -249,7 +251,7 @@ type KonnectExtensionControlPlaneStatus struct {
249251
// ClusterType is the type of the Konnect Control Plane.
250252
//
251253
// +required
252-
// +kubebuilder:validation:Enum=ControlPlane;K8SIngressController
254+
// +kubebuilder:validation:Enum=ControlPlane;K8SIngressController;ControlPlaneGroup
253255
ClusterType KonnectExtensionClusterType `json:"clusterType"`
254256

255257
// Endpoints defines the Konnect endpoints for the control plane.

config/crd/kong-operator/konnect.konghq.com_konnectextensions.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,7 @@ spec:
763763
enum:
764764
- ControlPlane
765765
- K8SIngressController
766+
- ControlPlaneGroup
766767
type: string
767768
controlPlaneID:
768769
description: ControlPlaneID is the Konnect ID of the ControlPlane

controller/konnect/konnectextension_controller_utils.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,8 @@ func konnectClusterTypeToCRDClusterType(clusterType sdkkonnectcomp.ControlPlaneC
319319
return konnectv1alpha2.ClusterTypeControlPlane
320320
case sdkkonnectcomp.ControlPlaneClusterTypeClusterTypeK8SIngressController:
321321
return konnectv1alpha2.ClusterTypeK8sIngressController
322+
case sdkkonnectcomp.ControlPlaneClusterTypeClusterTypeControlPlaneGroup:
323+
return konnectv1alpha2.ClusterTypeControlPlaneGroup
322324
default:
323325
// default never happens as the validation is at the CRD level
324326
return ""

controller/konnect/reconciler_controlplaneref.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,12 @@ func handleControlPlaneRef[T constraints.SupportedKonnectEntityType, TEnt constr
7474
// The configuration in control plane group type are read only so they are unsupported to attach entities to them:
7575
// https://docs.konghq.com/konnect/gateway-manager/control-plane-groups/#limitations
7676
if cp.GetKonnectClusterType() != nil &&
77-
*cp.GetKonnectClusterType() == sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlaneGroup {
77+
(*cp.GetKonnectClusterType() == sdkkonnectcomp.CreateControlPlaneRequestClusterTypeClusterTypeControlPlaneGroup &&
78+
// We don't allow attaching to control plane group type as they are read only
79+
// and don't have the configuration that can be used by the entities,
80+
// but we want to allow attaching KongDataPlaneClientCertificate to them
81+
// as they are used for CP/DP mTLS.
82+
ent.GetObjectKind().GroupVersionKind().GroupKind().Kind != "KongDataPlaneClientCertificate") {
7883
if res, errStatus := patch.StatusWithCondition(
7984
ctx, cl, ent,
8085
konnectv1alpha1.ControlPlaneRefValidConditionType,

controller/pkg/extensions/konnect/controlplane.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ func kicInKonnectDefaults(ctx context.Context, cl client.Client, konnectExtensio
107107
KonnectConfig: &konnectConfig,
108108
}, nil
109109

110-
case konnectv1alpha2.ClusterTypeControlPlane:
110+
case konnectv1alpha2.ClusterTypeControlPlane, konnectv1alpha2.ClusterTypeControlPlaneGroup:
111111
return nil, fmt.Errorf("unsupported Konnect cluster type: %s", konnectExtension.Status.Konnect.ClusterType)
112112
default:
113113
// default never happens as the validation is at the CRD level

internal/utils/config/dataplane.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func KongInKonnectDefaults(
8181
var template map[string]string
8282

8383
switch konnectExtensionStatus.Konnect.ClusterType {
84-
case konnectv1alpha2.ClusterTypeControlPlane:
84+
case konnectv1alpha2.ClusterTypeControlPlane, konnectv1alpha2.ClusterTypeControlPlaneGroup:
8585
template = kongInKonnectClusterTypeControlPlane
8686
case konnectv1alpha2.ClusterTypeK8sIngressController:
8787
template = kongInKonnectClusterTypeIngressController

test/crdsvalidation/common/testcase.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,16 @@ type TestCase[T client.Object] struct {
7171
// ExpectedUpdateErrorMessage is the expected error message when updating the object.
7272
ExpectedUpdateErrorMessage *string
7373

74+
// ExpectedStatusUpdateErrorMessage is the expected error message when updating the object status.
75+
ExpectedStatusUpdateErrorMessage *string
76+
7477
// Update is a function that updates the object in the test case after it's created.
7578
// It can be used to verify CEL rules that verify the previous object's version against the new one.
7679
Update func(T)
7780

81+
// StatusUpdate is a function that updates the status of the object in the test case after it's created.
82+
StatusUpdate func(T)
83+
7884
// WarningCollector (optional) collects API server warnings emitted during operations.
7985
// If set together with ExpectedWarningMessage, the test will assert that a warning containing the
8086
// expected message substring was produced.
@@ -228,6 +234,28 @@ func (tc *TestCase[T]) RunWithConfig(t *testing.T, cfg *rest.Config, scheme *run
228234
require.NoError(c, err)
229235
}, timeout, period)
230236
}
237+
238+
// If the StatusUpdate function was defined, update the object status
239+
// and check if the update is allowed.
240+
if tc.StatusUpdate != nil {
241+
require.EventuallyWithT(t, func(c *assert.CollectT) {
242+
err := cl.Get(ctx, client.ObjectKeyFromObject(tc.TestObject), tc.TestObject)
243+
require.NoError(c, err)
244+
// Update the object status and push the update to the server.
245+
tc.StatusUpdate(tc.TestObject)
246+
err = cl.Status().Update(ctx, tc.TestObject)
247+
248+
// If the expected status update error message is defined,
249+
// check if the error message contains the expected message
250+
// and return. Otherwise, expect no error.
251+
if tc.ExpectedStatusUpdateErrorMessage != nil {
252+
require.Error(c, err)
253+
assert.Contains(c, err.Error(), *tc.ExpectedStatusUpdateErrorMessage)
254+
return
255+
}
256+
require.NoError(c, err)
257+
}, timeout, period)
258+
}
231259
})
232260
}
233261

test/crdsvalidation/konnect.konghq.com/konnectextension_test.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,124 @@ func TestKonnectExtension(t *testing.T) {
142142
}.
143143
RunWithConfig(t, cfg, scheme)
144144
})
145+
t.Run("status clusterType", func(t *testing.T) {
146+
common.TestCasesGroup[*konnectv1alpha2.KonnectExtension]{
147+
{
148+
Name: "status clusterType ControlPlane",
149+
TestObject: &konnectv1alpha2.KonnectExtension{
150+
ObjectMeta: common.CommonObjectMeta(ns.Name),
151+
Spec: konnectv1alpha2.KonnectExtensionSpec{
152+
Konnect: konnectv1alpha2.KonnectExtensionKonnectSpec{
153+
ControlPlane: konnectv1alpha2.KonnectExtensionControlPlane{
154+
Ref: commonv1alpha1.KonnectExtensionControlPlaneRef{
155+
Type: configurationv1alpha1.ControlPlaneRefKonnectNamespacedRef,
156+
KonnectNamespacedRef: &commonv1alpha1.KonnectNamespacedRef{
157+
Name: "test-konnect-control-plane",
158+
},
159+
},
160+
},
161+
},
162+
},
163+
},
164+
StatusUpdate: func(ke *konnectv1alpha2.KonnectExtension) {
165+
ke.Status.Konnect = &konnectv1alpha2.KonnectExtensionControlPlaneStatus{
166+
ControlPlaneID: "cp-id",
167+
ClusterType: konnectv1alpha2.ClusterTypeControlPlane,
168+
Endpoints: konnectv1alpha2.KonnectEndpoints{
169+
TelemetryEndpoint: "telemetry.example.com",
170+
ControlPlaneEndpoint: "cp.example.com",
171+
},
172+
}
173+
},
174+
},
175+
{
176+
Name: "status clusterType K8SIngressController",
177+
TestObject: &konnectv1alpha2.KonnectExtension{
178+
ObjectMeta: common.CommonObjectMeta(ns.Name),
179+
Spec: konnectv1alpha2.KonnectExtensionSpec{
180+
Konnect: konnectv1alpha2.KonnectExtensionKonnectSpec{
181+
ControlPlane: konnectv1alpha2.KonnectExtensionControlPlane{
182+
Ref: commonv1alpha1.KonnectExtensionControlPlaneRef{
183+
Type: configurationv1alpha1.ControlPlaneRefKonnectNamespacedRef,
184+
KonnectNamespacedRef: &commonv1alpha1.KonnectNamespacedRef{
185+
Name: "test-konnect-control-plane",
186+
},
187+
},
188+
},
189+
},
190+
},
191+
},
192+
StatusUpdate: func(ke *konnectv1alpha2.KonnectExtension) {
193+
ke.Status.Konnect = &konnectv1alpha2.KonnectExtensionControlPlaneStatus{
194+
ControlPlaneID: "cp-id",
195+
ClusterType: konnectv1alpha2.ClusterTypeK8sIngressController,
196+
Endpoints: konnectv1alpha2.KonnectEndpoints{
197+
TelemetryEndpoint: "telemetry.example.com",
198+
ControlPlaneEndpoint: "cp.example.com",
199+
},
200+
}
201+
},
202+
},
203+
{
204+
Name: "status clusterType ControlPlaneGroup",
205+
TestObject: &konnectv1alpha2.KonnectExtension{
206+
ObjectMeta: common.CommonObjectMeta(ns.Name),
207+
Spec: konnectv1alpha2.KonnectExtensionSpec{
208+
Konnect: konnectv1alpha2.KonnectExtensionKonnectSpec{
209+
ControlPlane: konnectv1alpha2.KonnectExtensionControlPlane{
210+
Ref: commonv1alpha1.KonnectExtensionControlPlaneRef{
211+
Type: configurationv1alpha1.ControlPlaneRefKonnectNamespacedRef,
212+
KonnectNamespacedRef: &commonv1alpha1.KonnectNamespacedRef{
213+
Name: "test-konnect-control-plane",
214+
},
215+
},
216+
},
217+
},
218+
},
219+
},
220+
StatusUpdate: func(ke *konnectv1alpha2.KonnectExtension) {
221+
ke.Status.Konnect = &konnectv1alpha2.KonnectExtensionControlPlaneStatus{
222+
ControlPlaneID: "cp-id",
223+
ClusterType: konnectv1alpha2.ClusterTypeControlPlaneGroup,
224+
Endpoints: konnectv1alpha2.KonnectEndpoints{
225+
TelemetryEndpoint: "telemetry.example.com",
226+
ControlPlaneEndpoint: "cp.example.com",
227+
},
228+
}
229+
},
230+
},
231+
{
232+
Name: "status clusterType invalid",
233+
TestObject: &konnectv1alpha2.KonnectExtension{
234+
ObjectMeta: common.CommonObjectMeta(ns.Name),
235+
Spec: konnectv1alpha2.KonnectExtensionSpec{
236+
Konnect: konnectv1alpha2.KonnectExtensionKonnectSpec{
237+
ControlPlane: konnectv1alpha2.KonnectExtensionControlPlane{
238+
Ref: commonv1alpha1.KonnectExtensionControlPlaneRef{
239+
Type: configurationv1alpha1.ControlPlaneRefKonnectNamespacedRef,
240+
KonnectNamespacedRef: &commonv1alpha1.KonnectNamespacedRef{
241+
Name: "test-konnect-control-plane",
242+
},
243+
},
244+
},
245+
},
246+
},
247+
},
248+
StatusUpdate: func(ke *konnectv1alpha2.KonnectExtension) {
249+
ke.Status.Konnect = &konnectv1alpha2.KonnectExtensionControlPlaneStatus{
250+
ControlPlaneID: "cp-id",
251+
ClusterType: konnectv1alpha2.KonnectExtensionClusterType("InvalidType"),
252+
Endpoints: konnectv1alpha2.KonnectEndpoints{
253+
TelemetryEndpoint: "telemetry.example.com",
254+
ControlPlaneEndpoint: "cp.example.com",
255+
},
256+
}
257+
},
258+
ExpectedStatusUpdateErrorMessage: new(`Unsupported value: "InvalidType"`),
259+
},
260+
}.
261+
RunWithConfig(t, cfg, scheme)
262+
})
145263
t.Run("dataPlane labels", func(t *testing.T) {
146264
common.TestCasesGroup[*konnectv1alpha2.KonnectExtension]{
147265
{

0 commit comments

Comments
 (0)