Skip to content

Commit 6159e4f

Browse files
committed
MAJOR: crd: add job for custom resource definition handling
CRDs are not properly handled with external tools, Helm and similar options cannot handle upgrading of custom resource definitions
1 parent 802a499 commit 6159e4f

18 files changed

+348
-22
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ kubernetes-ingress
44
dist/
55
.code-generator/
66
bin/golangci-lint
7+
.local/*

crs/definition/embed.go

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package definition
2+
3+
import _ "embed"
4+
5+
//go:embed defaults.core.haproxy.org.yaml
6+
var DefaultsV1alpha2 []byte
7+
8+
//go:embed globals.core.haproxy.org.yaml
9+
var GlobalsV1alpha2 []byte
10+
11+
//go:embed backends.core.haproxy.org.yaml
12+
var BackendsV1alpha2 []byte
13+
14+
//go:embed upgrade/defaults.core.haproxy.org.yaml
15+
var DefaultsV1alpha1V1alpha2 []byte
16+
17+
//go:embed upgrade/globals.core.haproxy.org.yaml
18+
var GlobalsV1alpha1V1alpha2 []byte
19+
20+
//go:embed upgrade/backends.core.haproxy.org.yaml
21+
var BackendsV1alpha1V1alpha2 []byte
22+
23+
func GetCRDs() map[string][]byte {
24+
return map[string][]byte{
25+
"defaults.core.haproxy.org": DefaultsV1alpha2,
26+
"globals.core.haproxy.org": GlobalsV1alpha2,
27+
"backends.core.haproxy.org": BackendsV1alpha2,
28+
}
29+
}
30+
31+
func GetCRDsUpgrade() map[string][]byte {
32+
return map[string][]byte{
33+
"defaults.core.haproxy.org": DefaultsV1alpha1V1alpha2,
34+
"globals.core.haproxy.org": GlobalsV1alpha1V1alpha2,
35+
"backends.core.haproxy.org": BackendsV1alpha1V1alpha2,
36+
}
37+
}

deploy/tests/config/crd/job-crd.yaml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apiVersion: batch/v1
2+
kind: Job
3+
metadata:
4+
name: haproxy-ingress-crd # each deploymnent should have a unique name, in example we always recreate the custer
5+
namespace: haproxy-controller
6+
spec:
7+
template:
8+
spec:
9+
serviceAccountName: haproxy-kubernetes-ingress-crd
10+
containers:
11+
- name: haproxy-ingress-crd
12+
image: haproxytech/kubernetes-ingress:latest
13+
imagePullPolicy: Never
14+
command: ["./haproxy-ingress-controller","--job-check-crd"]
15+
restartPolicy: Never
16+
backoffLimit: 0

deploy/tests/config/crd/rbac.yaml

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
apiVersion: v1
3+
kind: ServiceAccount
4+
metadata:
5+
name: haproxy-kubernetes-ingress-crd
6+
namespace: haproxy-controller
7+
---
8+
kind: ClusterRole
9+
apiVersion: rbac.authorization.k8s.io/v1
10+
metadata:
11+
name: haproxy-kubernetes-ingress-crd
12+
rules:
13+
- apiGroups:
14+
- "apiextensions.k8s.io"
15+
resources:
16+
- customresourcedefinitions
17+
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
18+
---
19+
kind: ClusterRoleBinding
20+
apiVersion: rbac.authorization.k8s.io/v1
21+
metadata:
22+
name: haproxy-kubernetes-ingress-crd
23+
namespace: haproxy-controller
24+
roleRef:
25+
apiGroup: rbac.authorization.k8s.io
26+
kind: ClusterRole
27+
name: haproxy-kubernetes-ingress-crd
28+
subjects:
29+
- kind: ServiceAccount
30+
name: haproxy-kubernetes-ingress-crd
31+
namespace: haproxy-controller

deploy/tests/create.sh

+7-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ if [ -n "${CI_ENV}" ]; then
1111
echo "building image for ingress controller"
1212
if [ -n "${GITLAB_CI}" ]; then
1313
echo "haproxytech/kubernetes-ingress image already available from previous stage"
14-
#docker build --build-arg TARGETPLATFORM="linux/amd64" -t haproxytech/kubernetes-ingress -f build/Dockerfile .
1514
else
1615
docker build --build-arg TARGETPLATFORM="linux/amd64" -t haproxytech/kubernetes-ingress -f build/Dockerfile .
1716
fi
@@ -44,13 +43,16 @@ fi
4443
echo "loading image http-echo in kind"
4544
kind load docker-image haproxytech/http-echo:latest --name=$clustername
4645

46+
printf %80s |tr " " "="; echo ""
47+
echo "Create HAProxy namespace ..."
48+
kubectl apply -f $DIR/config/0.namespace.yaml
49+
printf %80s |tr " " "="; echo ""
4750
echo "Install custom resource definitions ..."
48-
kubectl apply -f $DIR/../../crs/definition/backend.yaml
49-
kubectl apply -f $DIR/../../crs/definition/defaults.yaml
50-
kubectl apply -f $DIR/../../crs/definition/global.yaml
51+
kubectl apply -f $DIR/../../deploy/tests/config/crd/rbac.yaml
52+
kubectl apply -f $DIR/../../deploy/tests/config/crd/job-crd.yaml
53+
kubectl wait --for=condition=complete --timeout=60s job/haproxy-ingress-crd -n haproxy-controller
5154

5255
echo "deploying Ingress Controller ..."
53-
kubectl apply -f $DIR/config/0.namespace.yaml
5456
kubectl apply -f $DIR/config/1.rbac.yaml
5557
kubectl apply -f $DIR/config/2.configmap.yaml
5658
kubectl apply -f $DIR/config/3.ingress-controller.yaml

go.mod

+4-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ require (
1616
github.com/valyala/fasthttp v1.50.0
1717
go.uber.org/automaxprocs v1.5.3
1818
k8s.io/api v0.25.2
19+
k8s.io/apiextensions-apiserver v0.25.2
1920
k8s.io/apimachinery v0.25.2
2021
k8s.io/client-go v0.25.2
22+
sigs.k8s.io/yaml v1.4.0
2123
)
2224

2325
require (
@@ -58,6 +60,8 @@ require (
5860
github.com/modern-go/reflect2 v1.0.2 // indirect
5961
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
6062
github.com/oklog/ulid v1.3.1 // indirect
63+
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
64+
github.com/onsi/gomega v1.27.10 // indirect
6165
github.com/pkg/errors v0.9.1 // indirect
6266
github.com/pmezard/go-difflib v1.0.0 // indirect
6367
github.com/prometheus/client_model v0.5.0 // indirect
@@ -83,5 +87,4 @@ require (
8387
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect
8488
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
8589
sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect
86-
sigs.k8s.io/yaml v1.3.0 // indirect
8790
)

go.sum

+14-6
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9F
127127
github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
128128
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
129129
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
130+
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
131+
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
130132
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
131133
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
132134
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
@@ -186,6 +188,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
186188
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
187189
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
188190
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
191+
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
192+
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
189193
github.com/google/renameio v1.0.1 h1:Lh/jXZmvZxb0BBeSY5VKEfidcbcbenKjZFzM/q0fSeU=
190194
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
191195
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -266,10 +270,10 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
266270
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
267271
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
268272
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
269-
github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU=
270-
github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
271-
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
272-
github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
273+
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
274+
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
275+
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
276+
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
273277
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
274278
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
275279
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
@@ -457,6 +461,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
457461
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
458462
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
459463
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
464+
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
465+
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
460466
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
461467
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
462468
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -509,6 +515,8 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
509515
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
510516
k8s.io/api v0.25.2 h1:v6G8RyFcwf0HR5jQGIAYlvtRNrxMJQG1xJzaSeVnIS8=
511517
k8s.io/api v0.25.2/go.mod h1:qP1Rn4sCVFwx/xIhe+we2cwBLTXNcheRyYXwajonhy0=
518+
k8s.io/apiextensions-apiserver v0.25.2 h1:8uOQX17RE7XL02ngtnh3TgifY7EhekpK+/piwzQNnBo=
519+
k8s.io/apiextensions-apiserver v0.25.2/go.mod h1:iRwwRDlWPfaHhuBfQ0WMa5skdQfrE18QXJaJvIDLvE8=
512520
k8s.io/apimachinery v0.25.2 h1:WbxfAjCx+AeN8Ilp9joWnyJ6xu9OMeS/fsfjK/5zaQs=
513521
k8s.io/apimachinery v0.25.2/go.mod h1:hqqA1X0bsgsxI6dXsJ4HnNTBOmJNxyPp8dw3u2fSHwA=
514522
k8s.io/client-go v0.25.2 h1:SUPp9p5CwM0yXGQrwYurw9LWz+YtMwhWd0GqOsSiefo=
@@ -524,5 +532,5 @@ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMm
524532
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
525533
sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk=
526534
sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
527-
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
528-
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
535+
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
536+
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

main.go

+16
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434

3535
"github.com/haproxytech/kubernetes-ingress/pkg/annotations"
3636
"github.com/haproxytech/kubernetes-ingress/pkg/controller"
37+
"github.com/haproxytech/kubernetes-ingress/pkg/job"
3738
"github.com/haproxytech/kubernetes-ingress/pkg/k8s"
3839
"github.com/haproxytech/kubernetes-ingress/pkg/store"
3940
"github.com/haproxytech/kubernetes-ingress/pkg/utils"
@@ -70,6 +71,21 @@ func main() {
7071
parser.WriteHelp(os.Stdout)
7172
return
7273
}
74+
if osArgs.JobCheckCRD {
75+
logger.Print(IngressControllerInfo)
76+
logger.Print(job.IngressControllerCRDUpdater)
77+
logger.Infof("HAProxy Ingress Controller CRD Updater %s %s%s", GitTag, GitCommit, GitDirty)
78+
logger.Infof("Build from: %s", GitRepo)
79+
80+
err := job.CRDRefresh(logger, osArgs)
81+
if err != nil {
82+
logger.Error(err)
83+
os.Exit(1) //nolint:gocritic
84+
}
85+
// exit, this is just a job
86+
os.Exit(0)
87+
}
88+
7389
logger.ShowFilename(false)
7490
exit := logInfo(logger, osArgs)
7591
if exit {

pkg/job/crd-check.go

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright 2023 HAProxy Technologies LLC
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+
package job
15+
16+
import (
17+
"context"
18+
19+
"github.com/haproxytech/kubernetes-ingress/crs/definition"
20+
"github.com/haproxytech/kubernetes-ingress/pkg/k8s"
21+
"github.com/haproxytech/kubernetes-ingress/pkg/utils"
22+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
23+
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
24+
apiError "k8s.io/apimachinery/pkg/api/errors"
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
"sigs.k8s.io/yaml"
27+
)
28+
29+
func CRDRefresh(log utils.Logger, osArgs utils.OSArgs) error {
30+
log.Info("checking CRDS")
31+
config, err := k8s.GetRestConfig(osArgs)
32+
if err != nil {
33+
return err
34+
}
35+
36+
// Create a new clientset for the apiextensions API group
37+
clientset := apiextensionsclientset.NewForConfigOrDie(config)
38+
39+
// Check if the CRD exists
40+
crds := definition.GetCRDs()
41+
crdsUpgrade := definition.GetCRDsUpgrade()
42+
for crdName, crdDef := range crds {
43+
// CustomResourceDefinition object
44+
var crd apiextensionsv1.CustomResourceDefinition
45+
err = yaml.Unmarshal(crdDef, &crd)
46+
if err != nil {
47+
return err
48+
}
49+
log.Info("")
50+
log.Infof("checking CRD %s", crdName)
51+
52+
existingVersion, err := clientset.ApiextensionsV1().CustomResourceDefinitions().Get(context.Background(), crdName, metav1.GetOptions{})
53+
if err != nil {
54+
if !apiError.IsNotFound(err) {
55+
return err
56+
}
57+
log.Infof("CRD %s does not exist", crdName)
58+
// Create the CRD
59+
_, err = clientset.ApiextensionsV1().CustomResourceDefinitions().Create(context.Background(), &crd, metav1.CreateOptions{})
60+
if err != nil {
61+
return err
62+
}
63+
log.Infof("CRD %s created", crdName)
64+
continue
65+
}
66+
log.Infof("CRD %s exists", crdName)
67+
versions := existingVersion.Spec.Versions
68+
if len(versions) == 2 {
69+
log.Infof("CRD %s exists as v1alpha1 and v1alpha2, nothing to do", crdName)
70+
continue
71+
}
72+
// check if we have alpha 2 or we need to upgrade for alpha2
73+
crd.ObjectMeta.ResourceVersion = existingVersion.ObjectMeta.ResourceVersion
74+
if versions[0].Name == "v1alpha2" {
75+
log.Infof("CRD %s exists as v1alpha2, nothing to do", crdName)
76+
continue
77+
}
78+
err = yaml.Unmarshal(crdsUpgrade[crdName], &crd)
79+
if err != nil {
80+
return err
81+
}
82+
// Upgrade the CRDl
83+
_, err = clientset.ApiextensionsV1().CustomResourceDefinitions().Update(context.Background(), &crd, metav1.UpdateOptions{})
84+
if err != nil {
85+
return err
86+
}
87+
}
88+
89+
log.Info("")
90+
log.Info("CRD update done")
91+
return nil
92+
}
93+
94+
// IngressControllerCRDUpdater console pretty print
95+
const IngressControllerCRDUpdater = `
96+
____ ____ ____ _ _ _ _
97+
/ ___| _ \| _ \ | | | |_ __ __| | __ _| |_ ___ _ __
98+
| | | |_) | | | | | | | | '_ \ / _` + "`" + ` |/ _` + "`" + ` | __/ _ \ '__|
99+
| |___| _ <| |_| | | |_| | |_) | (_| | (_| | || __/ |
100+
\____|_| \_\____/ \___/| .__/ \__,_|\__,_|\__\___|_|
101+
|_|
102+
103+
`

0 commit comments

Comments
 (0)