Skip to content

Commit 5449f90

Browse files
committed
MAJOR: add support for CRD v3
Keep support for CRD v1 that are migrated internally to v3
1 parent 5086a84 commit 5449f90

File tree

273 files changed

+18569
-3495
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

273 files changed

+18569
-3495
lines changed

.gitlab-ci.yml

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ stages:
77
- e2e_k8s_30
88
- e2e_k8s_31
99
- e2e_k8s_32
10+
- e2e_crd_versions
1011
variables:
1112
KIND: v0.26.0
1213
DOCKER_HOST: tcp://docker:2375
@@ -202,8 +203,6 @@ docker-build:
202203
- echo "running make -f Makefile.ci ci-e2e-$TEST_PART tests" && make -f Makefile.ci ci-e2e-$TEST_PART
203204
.kind_deployment_schedules:
204205
extends: .kind_deployment
205-
rules:
206-
- if: $CI_PIPELINE_SOURCE == "schedule"
207206
allow_failure: true
208207
e2e_k8s_30:
209208
stage: e2e_k8s_30
@@ -213,6 +212,8 @@ e2e_k8s_30:
213212
KUBEADM_VER: v1beta3
214213
KUBECTL: v1.30.4
215214
extends: .kind_deployment_schedules
215+
rules:
216+
- if: $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULE_TYPE == 'weekly' && $SCHEDULE_DAY == 'monday'
216217
e2e_k8s_31:
217218
stage: e2e_k8s_31
218219
needs: ["docker-build"]
@@ -221,6 +222,8 @@ e2e_k8s_31:
221222
KUBEADM_VER: v1beta3
222223
KUBECTL: v1.31.0
223224
extends: .kind_deployment_schedules
225+
rules:
226+
- if: $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULE_TYPE == 'weekly' && $SCHEDULE_DAY == 'tuesday'
224227
e2e_k8s_32:
225228
stage: e2e_k8s_32
226229
needs: ["docker-build"]
@@ -229,3 +232,16 @@ e2e_k8s_32:
229232
KUBEADM_VER: v1beta3
230233
KUBECTL: v1.31.0
231234
extends: .kind_deployment
235+
rules:
236+
- if: $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULE_TYPE == 'weekly' && $SCHEDULE_DAY == 'wednesday'
237+
e2e_crd_v1:
238+
stage: e2e_crd_versions
239+
needs: ["docker-build"]
240+
variables:
241+
K8S_VERSION: v1.32.0
242+
KUBEADM_VER: v1beta3
243+
KUBECTL: v1.31.0
244+
CRD_VERSION: v1
245+
extends: .kind_deployment_schedules
246+
rules:
247+
- if: $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULE_TYPE == 'weekly' && $SCHEDULE_DAY == 'thursday'

Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ e2e:
1515
go test ./... --tags=e2e_parallel,e2e_https
1616
go test ./... -p 1 --tags=e2e_sequential
1717

18+
.PHONY: e2e_crd_v1
19+
e2e_crd_v1:
20+
go clean -testcache
21+
CRD_VERSION=v1 go test ./... --tags=e2e_parallel,e2e_https
22+
CRD_VERSION=v1 go test ./... -p 1 --tags=e2e_sequential
23+
24+
1825
.PHONY: tidy
1926
tidy:
2027
go mod tidy
@@ -79,7 +86,7 @@ build-pebble:
7986
### Can be used for example to use `go replace` and build with a local library,
8087
.PHONY: build-dev
8188
build-dev:
82-
GOOS=$(GOSS) GOARCH=$(GOARCH) CGO_ENABLED='0' go build .
89+
GOOS=$(GOOS) GOARCH=$(GOARCH) CGO_ENABLED='0' go build .
8390
docker build -t haproxytech/kubernetes-ingress --build-arg TARGETPLATFORM=$(TARGETPLATFORM) -f build/Dockerfile.dev .
8491

8592
.PHONY: publish

crs/README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ crs
3737

3838
### GoLang Type
3939

40-
In this guide the API group is `ingress.v1.haproxy.org` (this group is used for any resource dealing with haproxy configuration) and the API version is `v1`.
40+
In this guide the API group is `ingress.v3.haproxy.org` (this group is used for any resource dealing with haproxy configuration) and the API version is `v3`.
4141
So to follow the */crs/api/<group>/<version>/* convention, the GoLang Type describing the `Global` CR should be in *crs/api/ingress/v1/global.go* with the following content:
4242

4343
```go
44-
package v1
44+
package v3
4545

4646
import (
47-
"github.com/haproxytech/client-native/v5/models"
47+
"github.com/haproxytech/client-native/v6/models"
4848
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4949
)
5050

@@ -101,14 +101,14 @@ The tool we are using is [k8s.io/code-generator](https://github.com/kubernetes/c
101101
- lister-gen: generates lister methods which provide a read-only caching layer for GET and LIST requests.
102102

103103
Before generating code, some global tags need to be set in the package of the versioned API group which should be in *crs/api/<group>/<version>/* directory.
104-
Usually this goes into the package's doc.go, so in this case it would be in *crs/api/ingress/v1/doc.go* with the following content:
104+
Usually this goes into the package's doc.go, so in this case it would be in *crs/api/ingress/v3/doc.go* with the following content:
105105

106106
```yml
107-
// Package v1 contains the core v1 API group
107+
// Package v3 contains the core v3 API group
108108
//
109109
// +k8s:deepcopy-gen=package
110-
// +groupName=ingress.v1.haproxy.org
111-
package v1
110+
// +groupName=ingress.v3.haproxy.org
111+
package v3
112112
```
113113

114114
In addition to including a number of global code generation tags, "doc.go" is used to describe the API group's purpose.

crs/api/core/v1alpha2/doc.go

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,16 @@
1313
// limitations under the License.
1414
//
1515

16-
package v1alpha2
16+
package v3
1717

1818
import (
19-
"github.com/haproxytech/client-native/v3/models"
19+
"github.com/haproxytech/client-native/v6/models"
2020
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2121
)
2222

2323
// +genclient
2424
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
25+
// +kubebuilder:metadata:annotations="haproxy.org/client-native=v6.0.7-0.20250113083507-df8f78bea9bb"
2526

2627
// Backend is a specification for a Backend resource
2728
type Backend struct {
@@ -32,16 +33,13 @@ type Backend struct {
3233

3334
// BackendSpec defines the desired state of Backend
3435
type BackendSpec struct {
35-
Config *models.Backend `json:"config"`
36+
models.Backend `json:",inline"`
3637
}
3738

3839
// DeepCopyInto deepcopying the receiver into out. in must be non-nil.
3940
func (in *BackendSpec) DeepCopyInto(out *BackendSpec) {
40-
*out = *in
41-
if in.Config != nil {
42-
b, _ := in.Config.MarshalBinary()
43-
_ = out.Config.UnmarshalBinary(b)
44-
}
41+
b, _ := in.MarshalBinary()
42+
_ = out.Backend.UnmarshalBinary(b)
4543
}
4644

4745
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,16 @@
1313
// limitations under the License.
1414
//
1515

16-
package v1alpha2
16+
package v3
1717

1818
import (
19-
"github.com/haproxytech/client-native/v3/models"
19+
"github.com/haproxytech/client-native/v6/models"
2020
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2121
)
2222

2323
// +genclient
2424
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
25+
// +kubebuilder:metadata:annotations="haproxy.org/client-native=v6.0.7-0.20250113083507-df8f78bea9bb"
2526

2627
// Defaults is a specification for a Defaults resource
2728
type Defaults struct {
@@ -32,16 +33,13 @@ type Defaults struct {
3233

3334
// DefaultsSpec defines the desired state of Defaults
3435
type DefaultsSpec struct {
35-
Config *models.Defaults `json:"config"`
36+
models.Defaults `json:",inline"`
3637
}
3738

3839
// DeepCopyInto deepcopying the receiver into out. in must be non-nil.
3940
func (in *DefaultsSpec) DeepCopyInto(out *DefaultsSpec) {
40-
*out = *in
41-
if in.Config != nil {
42-
b, _ := in.Config.MarshalBinary()
43-
_ = out.Config.UnmarshalBinary(b)
44-
}
41+
b, _ := in.MarshalBinary()
42+
_ = out.Defaults.UnmarshalBinary(b)
4543
}
4644

4745
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

crs/api/ingress/v3/doc.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Package v3 contains the core v3 API group
2+
//
3+
// +k8s:deepcopy-gen=package
4+
// +groupName=ingress.v3.haproxy.org
5+
package v3
Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,20 @@
1313
// limitations under the License.
1414
//
1515

16-
package v1alpha2
16+
package v3
1717

1818
import (
19-
"github.com/haproxytech/client-native/v3/models"
19+
"github.com/haproxytech/client-native/v6/models"
2020
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2121
)
2222

2323
// +genclient
2424
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
25+
// +kubebuilder:metadata:annotations="haproxy.org/client-native=v6.0.7-0.20250113083507-df8f78bea9bb"
26+
// +kubebuilder:validation:XValidation:rule="!has(self.spec.default_path)", message="spec.config.default_path is set by ingress controller internally"
27+
// +kubebuilder:validation:XValidation:rule="!has(self.spec.master__dash__worker)", message="spec.config.master-worker is set by ingress controller internally"
28+
// +kubebuilder:validation:XValidation:rule="!has(self.spec.pidfile)", message="spec.config.pidfile is set by ingress controller internally"
29+
// +kubebuilder:validation:XValidation:rule="!has(self.spec.localpeer)", message="spec.config.localpeer is set by ingress controller internally"
2530

2631
// Global is a specification for a Global resource
2732
type Global struct {
@@ -33,24 +38,13 @@ type Global struct {
3338

3439
// GlobalSpec defines the desired state of Global
3540
type GlobalSpec struct {
36-
Config *models.Global `json:"config"`
37-
LogTargets models.LogTargets `json:"log_targets"` //nolint:tagliatelle
41+
models.Global `json:",inline"`
3842
}
3943

4044
// DeepCopyInto deepcopying the receiver into out. in must be non-nil.
4145
func (in *GlobalSpec) DeepCopyInto(out *GlobalSpec) {
42-
if in.Config != nil {
43-
b, _ := in.Config.MarshalBinary()
44-
_ = out.Config.UnmarshalBinary(b)
45-
}
46-
if in.LogTargets != nil {
47-
out.LogTargets = make([]*models.LogTarget, len(in.LogTargets))
48-
for i, v := range in.LogTargets {
49-
b, _ := v.MarshalBinary()
50-
out.LogTargets[i] = &models.LogTarget{}
51-
_ = out.LogTargets[i].UnmarshalBinary(b)
52-
}
53-
}
46+
b, _ := in.MarshalBinary()
47+
_ = out.Global.UnmarshalBinary(b)
5448
}
5549

5650
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

crs/api/ingress/v3/tcp.go

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// Copyright 2024 HAProxy Technologies
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
16+
package v3
17+
18+
import (
19+
"github.com/go-openapi/swag"
20+
"github.com/haproxytech/client-native/v6/models"
21+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+
)
23+
24+
// +genclient
25+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
26+
// +kubebuilder:metadata:annotations="haproxy.org/client-native=v6.0.7-0.20250113083507-df8f78bea9bb"
27+
28+
// TCP is a specification for a TCP resource
29+
type TCP struct {
30+
Spec TCPSpec `json:"spec"`
31+
metav1.TypeMeta `json:",inline"`
32+
metav1.ObjectMeta `json:"metadata,omitempty"`
33+
}
34+
35+
type TCPService struct {
36+
Name string `json:"name"`
37+
// +kubebuilder:validation:Maximum=65535
38+
// +kubebuilder:validation:Minimum=1
39+
Port int `json:"port"`
40+
}
41+
42+
type TCPModel struct {
43+
// +kubebuilder:validation:Required
44+
Name string `json:"name"`
45+
Frontend models.Frontend `json:"frontend"`
46+
// Service defines the name of the default service (default_backend)
47+
Service TCPService `json:"service"`
48+
// Services defines additional services for additional backends
49+
Services TCPServices `json:"services,omitempty"`
50+
}
51+
52+
type TCPServices []*TCPService
53+
54+
// TCPSpec defines the desired state of a TCPService
55+
type TCPSpec []TCPModel
56+
57+
// DeepCopyInto deepcopying the receiver into out. in must be non-nil.
58+
func (a *TCPModel) DeepCopyInto(out *TCPModel) {
59+
*out = *a
60+
61+
f, _ := a.Frontend.MarshalBinary()
62+
out.Frontend = models.Frontend{}
63+
_ = out.Frontend.UnmarshalBinary(f)
64+
65+
s, _ := a.Service.MarshalBinary()
66+
out.Service = TCPService{}
67+
_ = out.Service.UnmarshalBinary(s)
68+
69+
if a.Services != nil {
70+
out.Services = make(TCPServices, len(a.Services))
71+
a.Services.DeepCopyInto(&out.Services)
72+
}
73+
}
74+
75+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
76+
77+
// TCPList is a list of TCP resources
78+
type TCPList struct {
79+
metav1.TypeMeta `json:",inline"`
80+
metav1.ListMeta `json:"metadata"`
81+
82+
Items []TCP `json:"items"`
83+
}
84+
85+
// MarshalBinary interface implementation
86+
func (s *TCPService) MarshalBinary() ([]byte, error) {
87+
if s == nil {
88+
return nil, nil
89+
}
90+
return swag.WriteJSON(s)
91+
}
92+
93+
// UnmarshalBinary interface implementation
94+
func (s *TCPService) UnmarshalBinary(b []byte) error {
95+
var res TCPService
96+
if err := swag.ReadJSON(b, &res); err != nil {
97+
return err
98+
}
99+
*s = res
100+
return nil
101+
}
102+
103+
func (a TCPModel) Equal(b TCPModel, opt ...models.Options) bool {
104+
if a.Name != b.Name {
105+
return false
106+
}
107+
if !a.Frontend.Equal(b.Frontend, opt...) {
108+
return false
109+
}
110+
111+
if !a.Service.Equal(b.Service, opt...) {
112+
return false
113+
}
114+
115+
if (a.Services == nil && b.Services != nil) || (a.Services != nil && b.Services == nil) {
116+
return false
117+
}
118+
if a.Services != nil && b.Services != nil {
119+
if len(a.Services) != len(b.Services) {
120+
return false
121+
}
122+
for i, value := range a.Services {
123+
if (value == nil && b.Services[i] != nil) || (value != nil && b.Services[i] == nil) {
124+
return false
125+
}
126+
if value != nil &&
127+
b.Services[i] != nil &&
128+
!value.Equal(*b.Services[i], opt...) {
129+
return false
130+
}
131+
}
132+
}
133+
134+
return true
135+
}
136+
137+
func (s TCPService) Equal(b TCPService, opt ...models.Options) bool {
138+
return s.Name == b.Name && s.Port == b.Port
139+
}

0 commit comments

Comments
 (0)