Skip to content

Commit 9acd668

Browse files
committed
Defaulting to the latest tag if no tag was specified.
In the current code, we handle differently build/sign and deploying a pre-built kmod. This is the current behavior: * If a `build`/`sign` section is set in the module, and the image tag isn't specified, then we will return an error. * If there are no `build`/`sign` section, and the image tag isn't specified, then we will default to the `latest` tag. This change is adjusting the behavior of both workflow to always default to the `latest` image tag if it is not specified in the `Module`. Signed-off-by: Yoni Bettan <[email protected]>
1 parent 96a33d1 commit 9acd668

File tree

9 files changed

+449
-0
lines changed

9 files changed

+449
-0
lines changed

cmd/webhook-server/main.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ func main() {
8282
if err = webhook.NewModuleValidator(logger).SetupWebhookWithManager(mgr); err != nil {
8383
cmd.FatalError(setupLogger, err, "unable to create webhook", "webhook", "ModuleValidator")
8484
}
85+
86+
if err = webhook.NewModuleDefaulter(logger).SetupWebhookWithManager(mgr); err != nil {
87+
cmd.FatalError(setupLogger, err, "unable to create mutating webhook", "webhook", "ModuleDefaulter")
88+
}
8589
}
8690

8791
if enableManagedClusterModule {
@@ -90,6 +94,10 @@ func main() {
9094
if err = hub.NewManagedClusterModuleValidator(logger).SetupWebhookWithManager(mgr); err != nil {
9195
cmd.FatalError(setupLogger, err, "unable to create webhook", "webhook", "ManagedClusterModuleValidator")
9296
}
97+
98+
if err = hub.NewManagedClusterModuleDefaulter(logger).SetupWebhookWithManager(mgr); err != nil {
99+
cmd.FatalError(setupLogger, err, "unable to create mutating webhook", "webhook", "ManagedClusterModuleDefaulter")
100+
}
93101
}
94102

95103
if enableNamespaceDeletion {

config/webhook-hub/manifests.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
---
22
apiVersion: admissionregistration.k8s.io/v1
3+
kind: MutatingWebhookConfiguration
4+
metadata:
5+
name: mutating-webhook-configuration
6+
webhooks:
7+
- admissionReviewVersions:
8+
- v1
9+
clientConfig:
10+
service:
11+
name: webhook-service
12+
namespace: system
13+
path: /mutate-hub-kmm-sigs-x-k8s-io-v1beta1-managedclustermodule
14+
failurePolicy: Fail
15+
name: vmanageclustermodule.kb.io
16+
rules:
17+
- apiGroups:
18+
- hub.kmm.sigs.x-k8s.io
19+
apiVersions:
20+
- v1beta1
21+
operations:
22+
- CREATE
23+
- UPDATE
24+
resources:
25+
- managedclustermodules
26+
sideEffects: None
27+
---
28+
apiVersion: admissionregistration.k8s.io/v1
329
kind: ValidatingWebhookConfiguration
430
metadata:
531
name: validating-webhook-configuration

config/webhook/manifests.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
---
22
apiVersion: admissionregistration.k8s.io/v1
3+
kind: MutatingWebhookConfiguration
4+
metadata:
5+
name: mutating-webhook-configuration
6+
webhooks:
7+
- admissionReviewVersions:
8+
- v1
9+
clientConfig:
10+
service:
11+
name: webhook-service
12+
namespace: system
13+
path: /mutate-kmm-sigs-x-k8s-io-v1beta1-module
14+
failurePolicy: Fail
15+
name: vmodule.kb.io
16+
rules:
17+
- apiGroups:
18+
- kmm.sigs.x-k8s.io
19+
apiVersions:
20+
- v1beta1
21+
operations:
22+
- CREATE
23+
- UPDATE
24+
resources:
25+
- modules
26+
sideEffects: None
27+
---
28+
apiVersion: admissionregistration.k8s.io/v1
329
kind: ValidatingWebhookConfiguration
430
metadata:
531
name: validating-webhook-configuration
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
Copyright 2022.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package hub
18+
19+
import (
20+
"context"
21+
"fmt"
22+
23+
"github.com/go-logr/logr"
24+
"github.com/kubernetes-sigs/kernel-module-management/api-hub/v1beta1"
25+
kmmv1beta1 "github.com/kubernetes-sigs/kernel-module-management/api/v1beta1"
26+
"github.com/kubernetes-sigs/kernel-module-management/internal/webhook"
27+
"k8s.io/apimachinery/pkg/runtime"
28+
ctrl "sigs.k8s.io/controller-runtime"
29+
)
30+
31+
type ManagedClusterModuleDefaulter struct {
32+
logger logr.Logger
33+
moduleDefaulter *webhook.ModuleDefaulter
34+
}
35+
36+
func NewManagedClusterModuleDefaulter(logger logr.Logger) *ManagedClusterModuleDefaulter {
37+
return &ManagedClusterModuleDefaulter{
38+
logger: logger,
39+
moduleDefaulter: webhook.NewModuleDefaulter(logger),
40+
}
41+
}
42+
43+
func (mcmd *ManagedClusterModuleDefaulter) SetupWebhookWithManager(mgr ctrl.Manager) error {
44+
// controller-runtime will set the path to `mutate-<group>-<version>-<resource> so we
45+
// need to make sure it is set correctly in the +kubebuilder annotation below.
46+
return ctrl.NewWebhookManagedBy(mgr).
47+
For(&v1beta1.ManagedClusterModule{}).
48+
WithDefaulter(mcmd).
49+
Complete()
50+
}
51+
52+
//+kubebuilder:webhook:path=/mutate-hub-kmm-sigs-x-k8s-io-v1beta1-managedclustermodule,mutating=true,failurePolicy=fail,sideEffects=None,groups=hub.kmm.sigs.x-k8s.io,resources=managedclustermodules,verbs=create;update,versions=v1beta1,name=vmanageclustermodule.kb.io,admissionReviewVersions=v1
53+
54+
// Default implements webhook.Default so a webhook will be registered for the type
55+
func (mcmd *ManagedClusterModuleDefaulter) Default(ctx context.Context, obj runtime.Object) error {
56+
57+
mcm, ok := obj.(*v1beta1.ManagedClusterModule)
58+
if !ok {
59+
return fmt.Errorf("bad type for the object; expected %T, got %T", mcm, obj)
60+
}
61+
62+
mcmd.logger.Info("Mutating ManagedClusterModule creation", "name", mcm.Name, "namespace", mcm.Namespace)
63+
64+
mod := &kmmv1beta1.Module{
65+
Spec: mcm.Spec.ModuleSpec,
66+
}
67+
return mcmd.moduleDefaulter.Default(ctx, mod)
68+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package hub
2+
3+
import (
4+
"context"
5+
6+
kmmhub "github.com/kubernetes-sigs/kernel-module-management/api-hub/v1beta1"
7+
kmm "github.com/kubernetes-sigs/kernel-module-management/api/v1beta1"
8+
. "github.com/onsi/ginkgo/v2"
9+
. "github.com/onsi/gomega"
10+
)
11+
12+
var _ = FDescribe("Default", func() {
13+
14+
var (
15+
ctx context.Context
16+
mcmd *ManagedClusterModuleDefaulter
17+
)
18+
19+
BeforeEach(func() {
20+
21+
mcmd = NewManagedClusterModuleDefaulter(GinkgoLogr)
22+
})
23+
24+
It("should fail if it got the wrong type", func() {
25+
26+
err := mcmd.Default(ctx, nil)
27+
Expect(err).To(HaveOccurred())
28+
})
29+
30+
It("should default the container image tag to `latest`", func() {
31+
32+
mcm := kmmhub.ManagedClusterModule{
33+
Spec: kmmhub.ManagedClusterModuleSpec{
34+
ModuleSpec: kmm.ModuleSpec{
35+
ModuleLoader: kmm.ModuleLoaderSpec{
36+
Container: kmm.ModuleLoaderContainerSpec{
37+
ContainerImage: "myregistry.com/org/image",
38+
},
39+
},
40+
},
41+
},
42+
}
43+
44+
err := mcmd.Default(ctx, &mcm)
45+
Expect(err).NotTo(HaveOccurred())
46+
Expect(mcm.Spec.ModuleSpec.ModuleLoader.Container.ContainerImage).To(Equal("myregistry.com/org/image:latest"))
47+
})
48+
49+
//It("should not default the container image tag to `latest` if a sha is speciied", func() {
50+
51+
// mod := kmmv1beta1.Module{
52+
// Spec: kmmv1beta1.ModuleSpec{
53+
// ModuleLoader: kmmv1beta1.ModuleLoaderSpec{
54+
// Container: kmmv1beta1.ModuleLoaderContainerSpec{
55+
// ContainerImage: "myregistry.com/org/image@99999",
56+
// },
57+
// },
58+
// },
59+
// }
60+
61+
// err := mcmd.Default(ctx, &mod)
62+
// Expect(err).NotTo(HaveOccurred())
63+
// Expect(mod.Spec.ModuleLoader.Container.ContainerImage).To(Equal("myregistry.com/org/image@99999"))
64+
//})
65+
66+
//It("should not default the container image tag to `latest` if a tag is speciied", func() {
67+
68+
// mod := kmmv1beta1.Module{
69+
// Spec: kmmv1beta1.ModuleSpec{
70+
// ModuleLoader: kmmv1beta1.ModuleLoaderSpec{
71+
// Container: kmmv1beta1.ModuleLoaderContainerSpec{
72+
// ContainerImage: "myregistry.com/org/image:mytag",
73+
// },
74+
// },
75+
// },
76+
// }
77+
78+
// err := mcmd.Default(ctx, &mod)
79+
// Expect(err).NotTo(HaveOccurred())
80+
// Expect(mod.Spec.ModuleLoader.Container.ContainerImage).To(Equal("myregistry.com/org/image:mytag"))
81+
//})
82+
83+
//It("should default the kernel-mappings image tags to `latest`", func() {
84+
85+
// mod := kmmv1beta1.Module{
86+
// Spec: kmmv1beta1.ModuleSpec{
87+
// ModuleLoader: kmmv1beta1.ModuleLoaderSpec{
88+
// Container: kmmv1beta1.ModuleLoaderContainerSpec{
89+
// KernelMappings: []kmmv1beta1.KernelMapping{
90+
// {
91+
// ContainerImage: "myregistry.com/org/image",
92+
// },
93+
// },
94+
// },
95+
// },
96+
// },
97+
// }
98+
99+
// err := mcmd.Default(ctx, &mod)
100+
// Expect(err).NotTo(HaveOccurred())
101+
// Expect(mod.Spec.ModuleLoader.Container.KernelMappings[0].ContainerImage).To(Equal("myregistry.com/org/image:latest"))
102+
//})
103+
})

internal/webhook/hub/suite_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package hub
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/onsi/ginkgo/v2"
7+
. "github.com/onsi/gomega"
8+
)
9+
10+
func TestSuite(t *testing.T) {
11+
RegisterFailHandler(Fail)
12+
RunSpecs(t, "Webhook-Hub Suite")
13+
}

internal/webhook/module_mutator.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
Copyright 2022.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package webhook
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"strings"
23+
24+
"github.com/go-logr/logr"
25+
kmmv1beta1 "github.com/kubernetes-sigs/kernel-module-management/api/v1beta1"
26+
"k8s.io/apimachinery/pkg/runtime"
27+
ctrl "sigs.k8s.io/controller-runtime"
28+
)
29+
30+
const defaultTag = "latest"
31+
32+
type ModuleDefaulter struct {
33+
logger logr.Logger
34+
}
35+
36+
func NewModuleDefaulter(logger logr.Logger) *ModuleDefaulter {
37+
return &ModuleDefaulter{logger: logger}
38+
}
39+
40+
func (md *ModuleDefaulter) SetupWebhookWithManager(mgr ctrl.Manager) error {
41+
// controller-runtime will set the path to `mutate-<group>-<version>-<resource> so we
42+
// need to make sure it is set correctly in the +kubebuilder annotation below.
43+
return ctrl.NewWebhookManagedBy(mgr).
44+
For(&kmmv1beta1.Module{}).
45+
WithDefaulter(md).
46+
Complete()
47+
}
48+
49+
//+kubebuilder:webhook:path=/mutate-kmm-sigs-x-k8s-io-v1beta1-module,mutating=true,failurePolicy=fail,sideEffects=None,groups=kmm.sigs.x-k8s.io,resources=modules,verbs=create;update,versions=v1beta1,name=vmodule.kb.io,admissionReviewVersions=v1
50+
51+
// Default implements webhook.Default so a webhook will be registered for the type
52+
func (md *ModuleDefaulter) Default(ctx context.Context, obj runtime.Object) error {
53+
54+
mod, ok := obj.(*kmmv1beta1.Module)
55+
if !ok {
56+
return fmt.Errorf("bad type for the object; expected %T, got %T", mod, obj)
57+
}
58+
59+
md.logger.Info("Mutating Module creation", "name", mod.Name, "namespace", mod.Namespace)
60+
61+
setDefaultContainerImageTagIfNeeded(mod)
62+
setDefaultKernelMappingTagsIfNeeded(mod)
63+
64+
return nil
65+
}
66+
67+
func setDefaultContainerImageTagIfNeeded(mod *kmmv1beta1.Module) {
68+
69+
setDefaultTagIfNeeded(&mod.Spec.ModuleLoader.Container.ContainerImage)
70+
}
71+
72+
func setDefaultKernelMappingTagsIfNeeded(mod *kmmv1beta1.Module) {
73+
74+
for i := range mod.Spec.ModuleLoader.Container.KernelMappings {
75+
setDefaultTagIfNeeded(&mod.Spec.ModuleLoader.Container.KernelMappings[i].ContainerImage)
76+
}
77+
}
78+
79+
func setDefaultTagIfNeeded(image *string) {
80+
81+
if *image == "" {
82+
return
83+
}
84+
85+
if !strings.Contains(*image, ":") && !strings.Contains(*image, "@") {
86+
*image = fmt.Sprintf("%s:%s", *image, defaultTag)
87+
}
88+
}

0 commit comments

Comments
 (0)