Skip to content

Commit baa408f

Browse files
feat: implement cluster reconciler (#6)
* first working version * do not override other infrastructure fields of Gateway * simplify install/uninstall operations * fix: apply helm namespace to target cluster
1 parent b877bb8 commit baa408f

31 files changed

+2837
-2
lines changed

.gitignore

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
3+
# Binaries for programs and plugins
4+
*.exe
5+
*.exe~
6+
*.dll
7+
*.so
8+
*.dylib
9+
bin/
10+
Dockerfile.cross
11+
12+
# Test binary, build with `go test -c`
13+
*.test
14+
15+
# Output of the go coverage tool, specifically when used with LiteIDE
16+
*.out
17+
18+
# Kubernetes Generated files - skip generated files, except for vendored files
19+
20+
!vendor/**/zz_generated.*
21+
22+
# editor and IDE paraphernalia
23+
.idea
24+
.vscode
25+
*.swp
26+
*.swo
27+
*~
28+
29+
tmp/
30+
go.work*
31+
components/
32+
!**/components/
33+
/**/cover.html
34+
/**/cover.*.html
35+
36+
*.tmp
37+
.task/

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "hack/common"]
2+
path = hack/common
3+
url = https://github.com/openmcp-project/build.git

.golangci.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
version: "2"
2+
run:
3+
allow-parallel-runners: true
4+
linters:
5+
default: none
6+
enable:
7+
- copyloopvar
8+
- dupl
9+
- errcheck
10+
- ginkgolinter
11+
- goconst
12+
- gocyclo
13+
- govet
14+
- ineffassign
15+
- misspell
16+
- nakedret
17+
- prealloc
18+
- revive
19+
- staticcheck
20+
- unconvert
21+
- unparam
22+
- unused
23+
settings:
24+
revive:
25+
rules:
26+
- name: comment-spacings
27+
exclusions:
28+
generated: lax
29+
rules:
30+
- linters:
31+
- dupl
32+
path: internal/*
33+
paths:
34+
- third_party$
35+
- builtin$
36+
- examples$
37+
formatters:
38+
enable:
39+
- gofmt
40+
- goimports
41+
exclusions:
42+
generated: lax
43+
paths:
44+
- third_party$
45+
- builtin$
46+
- examples$

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
./hack/common/Makefile

Taskfile.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
version: 3
2+
3+
includes:
4+
shared:
5+
taskfile: hack/common/Taskfile_controller.yaml
6+
flatten: true
7+
excludes: [] # put task names in here which are overwritten in this file
8+
vars:
9+
NESTED_MODULES: api
10+
API_DIRS: '{{.ROOT_DIR}}/api/...'
11+
MANIFEST_OUT: '{{.ROOT_DIR}}/api/crds/manifests'
12+
CODE_DIRS: '{{.ROOT_DIR}}/cmd/... {{.ROOT_DIR}}/internal/... {{.ROOT_DIR}}/api/...'
13+
COMPONENTS: platform-service-gateway
14+
REPO_URL: 'https://github.com/openmcp-project/platform-service-gateway'
15+
GENERATE_DOCS_INDEX: "false"
16+
CHART_COMPONENTS: "[]"
17+
CRDS_COMPONENTS: platform-service-gateway
18+
CRDS_PATH: '{{.ROOT_DIR}}/api/crds/manifests'

VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v0.0.0-dev

api/crds/crds.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package crds
2+
3+
import (
4+
"embed"
5+
6+
crdutil "github.com/openmcp-project/controller-utils/pkg/crds"
7+
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
8+
)
9+
10+
//go:embed manifests
11+
var CRDFS embed.FS
12+
13+
func CRDs() ([]*apiextv1.CustomResourceDefinition, error) {
14+
return crdutil.CRDsFromFileSystem(CRDFS, "manifests")
15+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
---
2+
apiVersion: apiextensions.k8s.io/v1
3+
kind: CustomResourceDefinition
4+
metadata:
5+
annotations:
6+
controller-gen.kubebuilder.io/version: v0.18.0
7+
labels:
8+
openmcp.cloud/cluster: platform
9+
name: gatewayserviceconfigs.gateway.openmcp.cloud
10+
spec:
11+
group: gateway.openmcp.cloud
12+
names:
13+
kind: GatewayServiceConfig
14+
listKind: GatewayServiceConfigList
15+
plural: gatewayserviceconfigs
16+
singular: gatewayserviceconfig
17+
scope: Cluster
18+
versions:
19+
- name: v1alpha1
20+
schema:
21+
openAPIV3Schema:
22+
description: GatewayServiceConfig is the Schema for the Gateway PlatformService
23+
configuration API
24+
properties:
25+
apiVersion:
26+
description: |-
27+
APIVersion defines the versioned schema of this representation of an object.
28+
Servers should convert recognized schemas to the latest internal value, and
29+
may reject unrecognized values.
30+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
31+
type: string
32+
kind:
33+
description: |-
34+
Kind is a string value representing the REST resource this object represents.
35+
Servers may infer this from the endpoint the client submits requests to.
36+
Cannot be updated.
37+
In CamelCase.
38+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
39+
type: string
40+
metadata:
41+
type: object
42+
spec:
43+
description: GatewayServiceConfigSpec defines the desired state of GatewayServiceConfig
44+
properties:
45+
clusters:
46+
description: Clusters that should be included in the gateway configuration.
47+
items:
48+
properties:
49+
clusterRef:
50+
description: ClusterRef can be used to reference a single cluster.
51+
properties:
52+
name:
53+
description: Name of the referenced Cluster.
54+
minLength: 1
55+
type: string
56+
namespace:
57+
default: default
58+
description: Namespace of the referenced Cluster.
59+
type: string
60+
required:
61+
- name
62+
- namespace
63+
type: object
64+
selector:
65+
description: Selector for multiple clusters using labels and
66+
purpose.
67+
properties:
68+
matchLabels:
69+
additionalProperties:
70+
type: string
71+
description: MatchLabels selects clusters based on labels.
72+
type: object
73+
matchPurpose:
74+
description: MatchPurpose selects clusters based on purpose.
75+
type: string
76+
type: object
77+
type: object
78+
type: array
79+
dns:
80+
description: DNS configuration.
81+
properties:
82+
baseDomain:
83+
description: 'BaseDomain is the domain from which subdomains will
84+
be derived. Example: dev.openmcp.example.com.'
85+
minLength: 1
86+
type: string
87+
required:
88+
- baseDomain
89+
type: object
90+
envoyGateway:
91+
description: EnvoyGateway configuration.
92+
properties:
93+
chart:
94+
description: Chart configuration for Envoy Gateway.
95+
properties:
96+
tag:
97+
description: 'Tag of the chart. Example: 1.5.4'
98+
minLength: 1
99+
type: string
100+
url:
101+
default: oci://docker.io/envoyproxy/gateway-helm
102+
description: 'URL to the chart. Default: oci://docker.io/envoyproxy/gateway-helm'
103+
type: string
104+
required:
105+
- tag
106+
- url
107+
type: object
108+
images:
109+
description: Images overrides container image locations for Envoy
110+
components.
111+
properties:
112+
gateway:
113+
description: 'EnvoyGateway image. Example: docker.io/envoyproxy/gateway:v1.5.1'
114+
type: string
115+
proxy:
116+
description: 'EnvoyProxy image. Example: docker.io/envoyproxy/envoy:distroless-v1.35.3'
117+
type: string
118+
rateLimit:
119+
description: 'Ratelimit image. Example: docker.io/envoyproxy/ratelimit:e74a664a'
120+
type: string
121+
required:
122+
- gateway
123+
- proxy
124+
- rateLimit
125+
type: object
126+
required:
127+
- chart
128+
type: object
129+
required:
130+
- dns
131+
- envoyGateway
132+
type: object
133+
type: object
134+
served: true
135+
storage: true
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package v1alpha1
2+
3+
import (
4+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5+
)
6+
7+
// GatewayServiceConfigSpec defines the desired state of GatewayServiceConfig
8+
type GatewayServiceConfigSpec struct {
9+
// EnvoyGateway configuration.
10+
EnvoyGateway EnvoyGatewayConfig `json:"envoyGateway"`
11+
12+
// Clusters that should be included in the gateway configuration.
13+
Clusters []ClusterTerm `json:"clusters,omitempty"`
14+
15+
// DNS configuration.
16+
DNS DNSConfig `json:"dns"`
17+
}
18+
19+
type ClusterTerm struct {
20+
// Selector for multiple clusters using labels and purpose.
21+
Selector *ClusterSelector `json:"selector,omitempty"`
22+
23+
// ClusterRef can be used to reference a single cluster.
24+
ClusterRef *ClusterRef `json:"clusterRef,omitempty"`
25+
}
26+
27+
type ClusterSelector struct {
28+
// MatchLabels selects clusters based on labels.
29+
MatchLabels map[string]string `json:"matchLabels,omitempty"`
30+
31+
// MatchPurpose selects clusters based on purpose.
32+
MatchPurpose string `json:"matchPurpose,omitempty"`
33+
}
34+
35+
type ClusterRef struct {
36+
// Name of the referenced Cluster.
37+
// +kubebuilder:validation:Required
38+
// +kubebuilder:validation:MinLength=1
39+
Name string `json:"name"`
40+
41+
// Namespace of the referenced Cluster.
42+
// +kubebuilder:default=default
43+
Namespace string `json:"namespace"`
44+
}
45+
46+
type EnvoyGatewayConfig struct {
47+
// Images overrides container image locations for Envoy components.
48+
Images *ImagesConfig `json:"images,omitempty"`
49+
50+
// Chart configuration for Envoy Gateway.
51+
Chart EnvoyGatewayChart `json:"chart"`
52+
}
53+
54+
type EnvoyGatewayChart struct {
55+
// URL to the chart. Default: oci://docker.io/envoyproxy/gateway-helm
56+
// +kubebuilder:default="oci://docker.io/envoyproxy/gateway-helm"
57+
URL string `json:"url"`
58+
59+
// Tag of the chart. Example: 1.5.4
60+
// +kubebuilder:validation:Required
61+
// +kubebuilder:validation:MinLength=1
62+
Tag string `json:"tag"`
63+
}
64+
65+
type ImagesConfig struct {
66+
// EnvoyProxy image. Example: docker.io/envoyproxy/envoy:distroless-v1.35.3
67+
EnvoyProxy string `json:"proxy"`
68+
69+
// EnvoyGateway image. Example: docker.io/envoyproxy/gateway:v1.5.1
70+
EnvoyGateway string `json:"gateway"`
71+
72+
// Ratelimit image. Example: docker.io/envoyproxy/ratelimit:e74a664a
73+
Ratelimit string `json:"rateLimit"`
74+
}
75+
76+
type DNSConfig struct {
77+
// BaseDomain is the domain from which subdomains will be derived. Example: dev.openmcp.example.com.
78+
// +kubebuilder:validation:Required
79+
// +kubebuilder:validation:MinLength=1
80+
BaseDomain string `json:"baseDomain"`
81+
82+
// SubdomainTemplate defines how subdomains for clusters will be generated.
83+
// +kubebuilder:default={{.Cluster.Name}}.{{.Cluster.Namespace}}
84+
// SubdomainTemplate string `json:"subdomainTemplate"`
85+
}
86+
87+
// +kubebuilder:object:root=true
88+
// +kubebuilder:metadata:labels="openmcp.cloud/cluster=platform"
89+
// +kubebuilder:resource:scope=Cluster
90+
91+
// GatewayServiceConfig is the Schema for the Gateway PlatformService configuration API
92+
type GatewayServiceConfig struct {
93+
metav1.TypeMeta `json:",inline"`
94+
metav1.ObjectMeta `json:"metadata,omitempty"`
95+
96+
Spec GatewayServiceConfigSpec `json:"spec,omitempty"`
97+
}
98+
99+
// +kubebuilder:object:root=true
100+
101+
// GatewayServiceConfigList contains a list of GatewayServiceConfig
102+
type GatewayServiceConfigList struct {
103+
metav1.TypeMeta `json:",inline"`
104+
metav1.ListMeta `json:"metadata,omitempty"`
105+
Items []GatewayServiceConfig `json:"items"`
106+
}
107+
108+
func init() {
109+
SchemeBuilder.Register(&GatewayServiceConfig{}, &GatewayServiceConfigList{})
110+
}

api/gateway/v1alpha1/constants.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package v1alpha1
2+
3+
import (
4+
openmcpconst "github.com/openmcp-project/openmcp-operator/api/constants"
5+
)
6+
7+
const (
8+
OperationAnnotation = "gateway." + openmcpconst.OperationAnnotation
9+
10+
GatewayFinalizerOnCluster = "platformservice." + openmcpconst.OpenMCPGroupName + "/gateway"
11+
)

0 commit comments

Comments
 (0)