Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ generate.clientsets: client-gen
--input incubator/v1alpha1 \
--input gateway-operator/v1alpha1 \
--input gateway-operator/v1beta1 \
--input gateway-operator/v2alpha1 \
--output-dir pkg/ \
--output-pkg $(REPO_URL)/pkg/

Expand Down
1 change: 1 addition & 0 deletions api/gateway-operator/v1beta1/controlplane_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func init() {
// ControlPlane is the Schema for the controlplanes API
//
// +genclient
// +kubebuilder:storageversion
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
Expand Down
303 changes: 303 additions & 0 deletions api/gateway-operator/v2alpha1/controlplane_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,303 @@
/*
Copyright 2025 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.
*/

package v2alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

commonv1alpha1 "github.com/kong/kubernetes-configuration/api/common/v1alpha1"
operatorv1beta1 "github.com/kong/kubernetes-configuration/api/gateway-operator/v1beta1"
)

func init() {
SchemeBuilder.Register(&ControlPlane{}, &ControlPlaneList{})
}

// ControlPlane is the Schema for the controlplanes API
//
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:shortName=kocp,categories=kong;all
// +kubebuilder:printcolumn:name="Ready",description="The Resource is ready",type=string,JSONPath=`.status.conditions[?(@.type=='Ready')].status`
// +apireference:kgo:include
// +kong:channels=gateway-operator
type ControlPlane struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec ControlPlaneSpec `json:"spec,omitempty"`
Status ControlPlaneStatus `json:"status,omitempty"`
}

// ControlPlaneList contains a list of ControlPlane
//
// +kubebuilder:object:root=true
// +apireference:kgo:include
type ControlPlaneList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ControlPlane `json:"items"`
}

// ControlPlaneSpec defines the desired state of ControlPlane
//
// +apireference:kgo:include
type ControlPlaneSpec struct {
ControlPlaneOptions `json:",inline"`

// IngressClass enables support for the older Ingress resource and indicates
// which Ingress resources this ControlPlane should be responsible for.
//
// If omitted, Ingress resources will not be supported by the ControlPlane.
//
// +optional
IngressClass *string `json:"ingressClass,omitempty"`
}

// ControlPlaneOptions indicates the specific information needed to
// deploy and connect a ControlPlane to a DataPlane object.
//
// +apireference:kgo:include
// +kubebuilder:validation:XValidation:message="Extension not allowed for ControlPlane",rule="has(self.extensions) ? self.extensions.all(e, (e.group == 'konnect.konghq.com' && e.kind == 'KonnectExtension') || (e.group == 'gateway-operator.konghq.com' && e.kind == 'DataPlaneMetricsExtension')) : true"
type ControlPlaneOptions struct {
// DataPlane designates the target data plane to configure.
//
// It can be either a URL to an externally managed DataPlane (e.g. installed
// independently with Helm) or a name of a DataPlane resource that is
// managed by the operator.
//
// +required
DataPlane ControlPlaneDataPlaneTarget `json:"dataplane"`

// Extensions provide additional or replacement features for the ControlPlane
// resources to influence or enhance functionality.
//
// +optional
// +kubebuilder:validation:MaxItems=2
Extensions []commonv1alpha1.ExtensionRef `json:"extensions,omitempty"`

// WatchNamespaces indicates the namespaces to watch for resources.
//
// +optional
// +kubebuilder:default={type: all}
WatchNamespaces *operatorv1beta1.WatchNamespaces `json:"watchNamespaces,omitempty"`

// FeatureGates is a list of feature gates that are enabled for this ControlPlane.
//
// +optional
// +listType=map
// +listMapKey=name
// +kubebuilder:validation:MaxItems=32
FeatureGates []ControlPlaneFeatureGate `json:"featureGates,omitempty"`

// Controllers defines the controllers that are enabled for this ControlPlane.
//
// +optional
// +listType=map
// +listMapKey=name
// +kubebuilder:validation:MaxItems=32
Controllers []ControlPlaneController `json:"controllers,omitempty"`

// AdminAPI defines the configuration for the Kong Admin API.
//
// +optional
AdminAPI *ControlPlaneAdminAPI `json:"adminAPI,omitempty"`
}

// ControlPlaneDataPlaneTarget defines the target for the DataPlane that the ControlPlane
// is responsible for configuring.
//
// +kubebuilder:validation:XValidation:message="External has to be provided when type is set to external",rule="self.type != 'external' || has(self.external)"
// +kubebuilder:validation:XValidation:message="External cannot be provided when type is set to managedByOwner",rule="self.type != 'managedByOwner' || !has(self.external)"
// +kubebuilder:validation:XValidation:message="External cannot be provided when type is set to ref",rule="self.type != 'ref' || !has(self.external)"
// +kubebuilder:validation:XValidation:message="Ref has to be provided when type is set to ref",rule="self.type != 'ref' || has(self.ref)"
// +kubebuilder:validation:XValidation:message="Ref cannot be provided when type is set to managedByOwner",rule="self.type != 'managedByOwner' || !has(self.ref)"
// +kubebuilder:validation:XValidation:message="Ref cannot be provided when type is set to external",rule="self.type != 'external' || !has(self.ref)"
type ControlPlaneDataPlaneTarget struct {
// Type indicates the type of the DataPlane target.
//
// +required
// +kubebuilder:validation:Enum=external;ref;managedByOwner
Type ControlPlaneDataPlaneTargetType `json:"type"`

// External is the External of the DataPlane target. This is used for configuring
// externally managed DataPlanes like those installed independently with Helm.
//
// +optional
External *ControlPlaneDataPlaneTargetExternal `json:"external,omitempty"`

// Ref is the name of the DataPlane to configure.
//
// +optional
Ref *ControlPlaneDataPlaneTargetRef `json:"ref,omitempty"`
}

// ControlPlaneDataPlaneTargetType defines the type of the DataPlane target
// that the ControlPlane is responsible for configuring.
type ControlPlaneDataPlaneTargetType string

const (
// ControlPlaneDataPlaneTargetExternalType indicates that the DataPlane target is external.
// This is used for configuring externally managed DataPlanes like those
// installed independently with Helm.
ControlPlaneDataPlaneTargetExternalType ControlPlaneDataPlaneTargetType = "external"

// ControlPlaneDataPlaneTargetRefType indicates that the DataPlane target is a ref
// of a DataPlane resource managed by the operator.
// This is used for configuring DataPlanes that are managed by the operator.
ControlPlaneDataPlaneTargetRefType ControlPlaneDataPlaneTargetType = "ref"

// ControlPlaneDataPlaneTargetManagedByType indicates that the DataPlane target
// is managed by the owner of the ControlPlane.
// This is the case when using a Gateway resource to manage the DataPlane
// and the ControlPlane is responsible for configuring it.
ControlPlaneDataPlaneTargetManagedByType ControlPlaneDataPlaneTargetType = "managedByOwner"
Comment on lines +166 to +170
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried constraining the created ControlPlane with this target type to ensure that it has an owner set but CEL doesn't allow it for some reason:

The CustomResourceDefinition "controlplanes.gateway-operator.konghq.com" is invalid: spec.versions[1].schema.openAPIV3Schema.x-kubernetes-validations[0].rule: Invalid value: apiextensions.ValidationRule{Rule:"self.spec.dataplane.type != 'managedByOwner' || self.ownerReferences[0].kind == 'Gateway'", Message:"X", MessageExpression:"", Reason:(*apiextensions.FieldValueErrorReason)(nil), FieldPath:"", OptionalOldSelf:(*bool)(nil)}: compilation failed: ERROR: <input>:1:53: undefined field 'ownerReferences'
 | self.spec.dataplane.type != 'managedByOwner' || self.ownerReferences[0].kind == 'Gateway'
 | ....................................................^

slack thread asking about the reason and the comprehensive list of allowed metadata fields to use in CEL: https://kubernetes.slack.com/archives/C0EG7JC6T/p1749212565802129

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is explained in https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/

The apiVersion, kind, metadata.name and metadata.generateName are always accessible from the root of the object and from any x-kubernetes-embedded-resource annotated objects. No other metadata properties are accessible.

So we can't do this validation (at this moment) via CEL.

)

// ControlPlaneDataPlaneTargetExternal defines the configuration for an external DataPlane
// that the ControlPlane is responsible for configuring.
type ControlPlaneDataPlaneTargetExternal struct {
// URL is the URL of the external DataPlane to configure.
//
// +required
// +kubebuilder:validation:XValidation:message="URL has to be a valid URL",rule="isURL(self)"
URL string `json:"url"`

// TODO: add additional fields for authenticating with the external DataPlane.
// ref: https://github.com/Kong/gateway-operator/issues/1366
}

// ControlPlaneDataPlaneTargetRef defines the reference to a DataPlane resource
// that the ControlPlane is responsible for configuring.
type ControlPlaneDataPlaneTargetRef struct {
// Ref is the name of the DataPlane to configure.
//
// +required
Name string `json:"name"`
}

// ControlPlaneAdminAPI defines the configuration for the DataPlane Kong Admin API.
type ControlPlaneAdminAPI struct {
// Workspace indicates the Kong Workspace to use for the ControlPlane.
// If left empty then no Kong workspace will be used.
//
// +optional
Workspace string `json:"workspace,omitempty"`
}

// ControllerState defines the state of a feature gate.
type ControllerState string

const (
// ControllerStateEnabled indicates that the feature gate is enabled.
ControllerStateEnabled ControllerState = "enabled"
// ControllerStateDisabled indicates that the feature gate is disabled.
ControllerStateDisabled ControllerState = "disabled"
)

// ControlPlaneController defines a controller state for the ControlPlane.
// It overrides the default behavior as defined in the deployed operator version.
//
// +apireference:kgo:include
type ControlPlaneController struct {
// Name is the name of the controller.
//
// +required
// +kubebuilder:validation:MinLength=1
Name string `json:"name"`

// State indicates whether the feature gate is enabled or disabled.
//
// +required
// +kubebuilder:validation:Enum=enabled;disabled
State ControllerState `json:"state"`
}

// FeatureGateState defines the state of a feature gate.
type FeatureGateState string

const (
// FeatureGateStateEnabled indicates that the feature gate is enabled.
FeatureGateStateEnabled FeatureGateState = "enabled"
// FeatureGateStateDisabled indicates that the feature gate is disabled.
FeatureGateStateDisabled FeatureGateState = "disabled"
)

// ControlPlaneFeatureGate defines a feature gate state for the ControlPlane.
// It overrides the default behavior as defined in the deployed operator version.
//
// +apireference:kgo:include
type ControlPlaneFeatureGate struct {
// Name is the name of the feature gate.
//
// +required
// +kubebuilder:validation:MinLength=1
Name string `json:"name"`

// State indicates whether the feature gate is enabled or disabled.
//
// +required
// +kubebuilder:validation:Enum=enabled;disabled
State FeatureGateState `json:"state"`
}

// ControlPlaneStatus defines the observed state of ControlPlane
//
// +apireference:kgo:include
type ControlPlaneStatus struct {
// Conditions describe the current conditions of the Gateway.
//
// +optional
// +listType=map
// +listMapKey=type
// +kubebuilder:validation:MaxItems=8
// +kubebuilder:default={{type: "Scheduled", status: "Unknown", reason:"NotReconciled", message:"Waiting for controller", lastTransitionTime: "1970-01-01T00:00:00Z"}}
Conditions []metav1.Condition `json:"conditions,omitempty"`

// FeatureGates is a list of effective feature gates for this ControlPlane.
//
// +optional
// +listType=map
// +listMapKey=name
// +kubebuilder:validation:MaxItems=32
FeatureGates []ControlPlaneFeatureGate `json:"featureGates,omitempty"`

// Controllers is a list of enabled and disabled controllers for this ControlPlane.
//
// +optional
// +listType=map
// +listMapKey=name
// +kubebuilder:validation:MaxItems=32
Controllers []ControlPlaneController `json:"controllers,omitempty"`
}

// GetConditions returns the ControlPlane Status Conditions
func (c *ControlPlane) GetConditions() []metav1.Condition {
return c.Status.Conditions
}

// SetConditions sets the ControlPlane Status Conditions
func (c *ControlPlane) SetConditions(conditions []metav1.Condition) {
c.Status.Conditions = conditions
}

// GetExtensions retrieves the ControlPlane Extensions
func (c *ControlPlane) GetExtensions() []commonv1alpha1.ExtensionRef {
return c.Spec.Extensions
}
21 changes: 21 additions & 0 deletions api/gateway-operator/v2alpha1/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
Copyright 2025 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.
*/

// Package v2alpha1 contains API Schema definitions for the gateway-operator.konghq.com v2alpha1 API group.
// +kubebuilder:object:generate=true
// +groupName=gateway-operator.konghq.com
// +groupGoName=GatewayOperator
package v2alpha1
36 changes: 36 additions & 0 deletions api/gateway-operator/v2alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
Copyright 2025 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.
*/

// Package v2alpha1 contains API Schema definitions for the gateway-operator.konghq.com v2alpha1 API group
// +kubebuilder:object:generate=true
// +groupName=gateway-operator.konghq.com
package v2alpha1

import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)

var (
// SchemeGroupVersion is group version used to register these objects
SchemeGroupVersion = schema.GroupVersion{Group: "gateway-operator.konghq.com", Version: "v2alpha1"}

// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}

// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)
12 changes: 12 additions & 0 deletions api/gateway-operator/v2alpha1/gvrs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package v2alpha1

import "k8s.io/apimachinery/pkg/runtime/schema"

// ControlPlaneGVR returns current package ControlPlane GVR.
func ControlPlaneGVR() schema.GroupVersionResource {
return schema.GroupVersionResource{
Group: SchemeGroupVersion.Group,
Version: SchemeGroupVersion.Version,
Resource: "controlplanes",
}
}
Loading