Skip to content

Commit

Permalink
feat: introduce CRD channels (#153)
Browse files Browse the repository at this point in the history
  • Loading branch information
czeslavo authored Nov 13, 2024
1 parent 3a7ba72 commit e16b985
Show file tree
Hide file tree
Showing 77 changed files with 1,674 additions and 87 deletions.
13 changes: 9 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ generate.apitypes-funcs:

.PHONY: generate.crds
generate.crds: controller-gen ## Generate WebhookConfiguration and CustomResourceDefinition objects.
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=kong-ingress webhook paths="$(CRD_INCUBATOR_GEN_PATHS)" output:crd:artifacts:config=config/crd/incubator
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=kong-ingress webhook paths="$(CRD_GEN_PATHS)" output:crd:artifacts:config=config/crd/bases
# Use gotypesalias=0 as a workaround for https://github.com/kubernetes-sigs/controller-tools/issues/1088.
GODEBUG=gotypesalias=0 go run ./scripts/crds-generator

.PHONY: generate.deepcopy
generate.deepcopy: controller-gen
Expand Down Expand Up @@ -178,10 +178,15 @@ generate.apidocs: crd-ref-docs
# generate.cli-arguments-docs:
# go run ./scripts/cli-arguments-docs-gen/main.go > ./docs/cli-arguments.md

# Install CRDs into the K8s cluster specified in ~/.kube/config.
# Define a constant list of channels
CHANNELS := ingress-controller ingress-controller-incubator gateway-operator

# Install all CRDs into the K8s cluster specified in ~/.kube/config.
.PHONY: install
install: generate.crds kustomize
$(KUSTOMIZE) build config/crd | kubectl apply -f -
@for channel in $(CHANNELS); do \
$(KUSTOMIZE) build config/crd/$$channel | kubectl apply -f -; \
done

GOLANGCI_LINT_CONFIG ?= $(PROJECT_DIR)/.golangci.yaml
.PHONY: lint
Expand Down
57 changes: 46 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ This repository holds the API definitions for Kong's Kubernetes configuration.
- [`api/`][api] directory contains Go types that are the source for generating
- [`pkg/clientset`][clientset]: Go clientsets for users who want to interact
with Kong's Kubernetes configuration in Go
- [`config/crd`][crd]: Kubernetes CRDs for Kong configuration
- [`config/crd`][crd]: Kubernetes CRDs for all supported [channels]
- [`test/`][test] directory contains Go tests
- [`test/crdsvalidation`][testcrdsvalidation] directory contains Go tests which
perform operations against a live Kubernetes cluster, testing [CEL][cel] rules
Expand All @@ -29,13 +29,37 @@ This repository holds the API definitions for Kong's Kubernetes configuration.
[testcrdsvalidation]: ./test/crdsvalidation
[testunit]: ./test/unit
[cel]: https://kubernetes.io/docs/reference/using-api/cel/
[channels]: #channels

## Channels

This repository supports multiple _channels_ of CRDs. Each channel is an independent collection
of CRDs that is meant to be used by a designated product or project. Manifests for each channel
are stored in a separate directory under `config/crd/<channel>` (each has a generated `kustomize.yaml` file as well).

The following channels are supported:
- `ingress-controller` - CRDs for [Kong Ingress Controller][kic]
- `ingress-controller-incubator` - experimental CRDs for [Kong Ingress Controller][kic]
- `gateway-operator` - CRDs for [Kong Gateway Operator][kgo]

A single CRD can be included in multiple channels. See [available custom markers](#available-custom-markers) for more details.

[kic]: https://github.com/kong/kubernetes-ingress-controller
[kgo]: https://github.com/kong/gateway-operator

## Install CRDs

In order to install the CRDs from this repo:
In order to install the CRDs from this repo, you can use the following command, replacing
`<channel>` with one of the supported [channel names](#channels).

```terminal
kustomize build github.com/kong/kubernetes-configuration/config/crd/<channel> | kubectl apply -f -
```

For example, to install the CRDs for the Kong Ingress Controller, you can run:

```terminal
kustomize build github.com/kong/kubernetes-configuration/config/crd | kubectl apply -f -
kustomize build github.com/kong/kubernetes-configuration/config/crd/ingress-controller | kubectl apply -f -
```

## Generate code
Expand All @@ -46,7 +70,7 @@ In order to run code generation in this repo you can use `make generate`.

When you add a new CRD make sure to

- Add it to CRD [kustomization.yaml][crd_kustomization]
- Annotate the CRD with `+kong:channels` marker to specify the channels that the CRD should be published to.
- Add unit tests in [`test/unit`][testunit]
- Add CRD validation tests in [`test/crdsvalidation`][testcrdsvalidation]
- If you want `GetItems() []T` helper to be generated for your type,
Expand All @@ -62,17 +86,28 @@ When you add a new CRD make sure to

## How to release?

Currently in order to make a new release/tag available for users to use is to
Currently, in order to make a new release/tag available for users to use is to
create a new tag and push it to the repository.

## Available custom markers

| Name | Applies to | Meaning |
|-----------------------------|------------|---------------------------------------------------------------------------------------------------------------|
| `+apireference:kgo:exclude` | Fields | Any field annotated with this marker will be excluded from the [KGO's generated CRDs reference][kgo-crd-ref]. |
| `+apireference:kgo:include` | Types | Any type annotated with this marker will be included in the [KGO's generated CRDs reference][kgo-crd-ref]. |
| `+apireference:kic:exclude` | Fields | Any type annotated with this marker will be excluded from the [KIC's generated CRDs reference][kic-crd-ref]. |
| `+apireference:kic:include` | Types | Any type annotated with this marker will be included in the [KIC's generated CRDs reference][kic-crd-ref]. |
| Name | Applies to | Meaning |
|-----------------------------|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `+kong:channels` | Types | Any root object type annotated with this marker will be included in a [CRD channel](#channels) passed as a marker value (e.g. `+kong:channels=ingress-controller;gateway-operator` will include the CRD both in `ingress-controller` and `gateway-operator` channels). |
| `+apireference:kgo:exclude` | Fields | Any field annotated with this marker will be excluded from the [KGO's generated CRDs reference][kgo-crd-ref]. |
| `+apireference:kgo:include` | Types | Any type annotated with this marker will be included in the [KGO's generated CRDs reference][kgo-crd-ref]. |
| `+apireference:kic:exclude` | Fields | Any type annotated with this marker will be excluded from the [KIC's generated CRDs reference][kic-crd-ref]. |
| `+apireference:kic:include` | Types | Any type annotated with this marker will be included in the [KIC's generated CRDs reference][kic-crd-ref]. |

### Why do we need separate markers for API reference and channels?

Channels are used to group CRDs into logical sets that are meant to be used by a specific product or project.
API reference markers are used to control which types and fields are included in the generated API reference documentation.
While the channels are enough to be defined on a root object type, the API reference markers need to be defined on
each type or field that should be included/excluded in the generated API reference documentation.

Currently, we don't have a way to automatically generate API reference documentation based only on channels,
so we need separate markers for this purpose.

[kgo-crd-ref]: https://github.com/Kong/gateway-operator/blob/main/docs/api-reference.md
[kic-crd-ref]: https://github.com/kong/kubernetes-ingress-controller/blob/main/docs/api-reference.md
1 change: 1 addition & 0 deletions api/configuration/v1/kongclusterplugin_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (

// KongClusterPlugin is the Schema for the kongclusterplugins API.
// +apireference:kic:include
// +kong:channels=ingress-controller
type KongClusterPlugin struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions api/configuration/v1/kongconsumer_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
// +kubebuilder:validation:XValidation:rule="(!has(self.spec) || !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"
// +apireference:kgo:include
// +apireference:kic:include
// +kong:channels=ingress-controller;gateway-operator
type KongConsumer struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions api/configuration/v1/kongingress_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (

// KongIngress is the Schema for the kongingresses API.
// +apireference:kic:include
// +kong:channels=ingress-controller
type KongIngress struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions api/configuration/v1/kongplugin_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (
// +kubebuilder:validation:XValidation:rule="self.plugin == oldSelf.plugin", message="The plugin field is immutable"
// +apireference:kgo:include
// +apireference:kic:include
// +kong:channels=ingress-controller;gateway-operator
type KongPlugin struct {
metav1.TypeMeta `json:",inline"`
// Setting a `global` label to `true` will apply the plugin to every request proxied by the Kong.
Expand Down
1 change: 1 addition & 0 deletions api/configuration/v1alpha1/ingress_class_param_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type IngressClassParametersList struct {

// IngressClassParameters is the Schema for the IngressClassParameters API.
// +apireference:kic:include
// +kong:channels=ingress-controller
type IngressClassParameters struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions api/configuration/v1alpha1/key_set_ref.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (
// +kubebuilder:validation:XValidation:rule="self.type == 'namespacedRef' ? has(self.namespacedRef) : true", message="when type is namespacedRef, namespacedRef must be set"
// +kubebuilder:validation:XValidation:rule="self.type == 'konnectID' ? has(self.konnectID) : true", message="when type is konnectID, konnectID must be set"
// +apireference:kgo:include
// +kong:channels=gateway-operator
type KeySetRef struct {
// Type defines type of the KeySet object reference. It can be one of:
// - konnectID
Expand Down
1 change: 1 addition & 0 deletions api/configuration/v1alpha1/kong_ca_certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
// +kubebuilder:validation:XValidation:rule="!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="(!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"
// +apireference:kgo:include
// +kong:channels=gateway-operator
type KongCACertificate struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions api/configuration/v1alpha1/kong_certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.spec.controlPlaneRef) || has(self.spec.controlPlaneRef)", message="controlPlaneRef is required once set"
// +kubebuilder:validation:XValidation:rule="(!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"
// +apireference:kgo:include
// +kong:channels=gateway-operator
type KongCertificate struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
5 changes: 4 additions & 1 deletion api/configuration/v1alpha1/kong_custom_entity_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ const (
type KongEntityScope string

// KongCustomEntity defines a "custom" Kong entity that KIC cannot support the entity type directly.
//
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:object:root=true
Expand All @@ -27,6 +26,7 @@ type KongEntityScope string
// +kubebuilder:validation:XValidation:rule="self.spec.type == oldSelf.spec.type",message="The spec.type field is immutable"
// +kubebuilder:validation:XValidation:rule="!(self.spec.type in ['services','routes','upstreams','targets','plugins','consumers','consumer_groups'])",message="The spec.type field cannot be known Kong entity types"
// +apireference:kic:include
// +kong:channels=ingress-controller
type KongCustomEntity struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand All @@ -38,6 +38,7 @@ type KongCustomEntity struct {
}

// KongCustomEntitySpec defines the specification of the KongCustomEntity.
// +apireference:kic:include
type KongCustomEntitySpec struct {
// EntityType is the type of the Kong entity. The type is used in generating declarative configuration.
EntityType string `json:"type"`
Expand All @@ -53,6 +54,7 @@ type KongCustomEntitySpec struct {
}

// ObjectReference defines reference of a kubernetes object.
// +apireference:kic:include
type ObjectReference struct {
Group *string `json:"group,omitempty"`
Kind *string `json:"kind,omitempty"`
Expand All @@ -62,6 +64,7 @@ type ObjectReference struct {
}

// KongCustomEntityStatus defines the status of the KongCustomEntity.
// +apireference:kic:include
type KongCustomEntityStatus struct {
// Conditions describe the current conditions of the KongCustomEntityStatus.
//
Expand Down
2 changes: 2 additions & 0 deletions api/configuration/v1alpha1/kong_license_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
// +kubebuilder:printcolumn:name="Enabled",type=boolean,JSONPath=`.enabled`,description="Enabled to configure on Kong gateway instances"
// +apireference:kic:include
// +apireference:kgo:include
// +apireference:kic:include
// +kong:channels=ingress-controller;gateway-operator
type KongLicense struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions api/configuration/v1alpha1/kong_target_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
// +kubebuilder:printcolumn:name="Programmed",description="The Resource is Programmed on Konnect",type=string,JSONPath=`.status.conditions[?(@.type=='Programmed')].status`
// +kubebuilder:validation:XValidation:rule="oldSelf.spec.upstreamRef == self.spec.upstreamRef", message="spec.upstreamRef is immutable"
// +apireference:kgo:include
// +kong:channels=gateway-operator
type KongTarget struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions api/configuration/v1alpha1/kong_vault_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const (
// +kubebuilder:validation:XValidation:rule="(!has(self.status) || !self.status.conditions.exists(c, c.type == 'Programmed' && c.status == 'True') || !has(self.spec.controlPlaneRef)) ? true : oldSelf.spec.controlPlaneRef == self.spec.controlPlaneRef", message="spec.controlPlaneRef is immutable when an entity is already Programmed"
// +apireference:kgo:include
// +apireference:kic:include
// +kong:channels=ingress-controller;gateway-operator
type KongVault struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions api/configuration/v1alpha1/kongcredential_acl_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
// +kubebuilder:printcolumn:name="Programmed",description="The Resource is Programmed on Konnect",type=string,JSONPath=`.status.conditions[?(@.type=='Programmed')].status`
// +kubebuilder:validation:XValidation:rule="(!self.status.conditions.exists(c, c.type == 'Programmed' && c.status == 'True')) ? true : oldSelf.spec.consumerRef == self.spec.consumerRef",message="spec.consumerRef is immutable when an entity is already Programmed"
// +apireference:kgo:include
// +kong:channels=gateway-operator
type KongCredentialACL struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions api/configuration/v1alpha1/kongcredential_apikey_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
// +kubebuilder:printcolumn:name="Programmed",description="The Resource is Programmed on Konnect",type=string,JSONPath=`.status.conditions[?(@.type=='Programmed')].status`
// +kubebuilder:validation:XValidation:rule="(!self.status.conditions.exists(c, c.type == 'Programmed' && c.status == 'True')) ? true : oldSelf.spec.consumerRef == self.spec.consumerRef",message="spec.consumerRef is immutable when an entity is already Programmed"
// +apireference:kgo:include
// +kong:channels=gateway-operator
type KongCredentialAPIKey struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
// +kubebuilder:printcolumn:name="Programmed",description="The Resource is Programmed on Konnect",type=string,JSONPath=`.status.conditions[?(@.type=='Programmed')].status`
// +kubebuilder:validation:XValidation:rule="(!self.status.conditions.exists(c, c.type == 'Programmed' && c.status == 'True')) ? true : oldSelf.spec.consumerRef == self.spec.consumerRef",message="spec.consumerRef is immutable when an entity is already Programmed"
// +apireference:kgo:include
// +kong:channels=gateway-operator
type KongCredentialBasicAuth struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions api/configuration/v1alpha1/kongcredential_hmac_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
// +kubebuilder:printcolumn:name="Programmed",description="The Resource is Programmed on Konnect",type=string,JSONPath=`.status.conditions[?(@.type=='Programmed')].status`
// +kubebuilder:validation:XValidation:rule="(!self.status.conditions.exists(c, c.type == 'Programmed' && c.status == 'True')) ? true : oldSelf.spec.consumerRef == self.spec.consumerRef",message="spec.consumerRef is immutable when an entity is already Programmed"
// +apireference:kgo:include
// +kong:channels=gateway-operator
type KongCredentialHMAC struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions api/configuration/v1alpha1/kongcredential_jwt_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
// +kubebuilder:validation:XValidation:rule="(!self.status.conditions.exists(c, c.type == 'Programmed' && c.status == 'True')) ? true : oldSelf.spec.consumerRef == self.spec.consumerRef",message="spec.consumerRef is immutable when an entity is already Programmed"
// +kubebuilder:validation:XValidation:rule="self.spec.algorithm in [ 'RS256','RS384','RS512','ES256','ES384','ES512','PS256','PS384','PS512','EdDSA', ] ? has(self.spec.rsa_public_key) : true",message="spec.rsa_public_key is required when algorithm is RS*, ES*, PS* or EdDSA*"
// +apireference:kgo:include
// +kong:channels=gateway-operator
type KongCredentialJWT struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
// +kubebuilder:validation:XValidation:rule="(!self.status.conditions.exists(c, c.type == 'Programmed' && c.status == 'True')) ? true : oldSelf.spec.cert == self.spec.cert", message="spec.cert is immutable when an entity is already Programmed"
// +kubebuilder:validation:XValidation:rule="!has(self.spec.controlPlaneRef) ? true : !has(self.spec.controlPlaneRef.konnectNamespacedRef) ? true : !has(self.spec.controlPlaneRef.konnectNamespacedRef.__namespace__)", message="spec.controlPlaneRef cannot specify namespace for namespaced resource - it's not supported yet"
// +apireference:kgo:include
// +kong:channels=gateway-operator
type KongDataPlaneClientCertificate struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
Loading

0 comments on commit e16b985

Please sign in to comment.