Skip to content

Commit 133561f

Browse files
authored
Merge pull request #7 from cybozu-go/add-imageprefetch-webhook
Create a template for the ImagePrefetch webhook
2 parents 6833453 + b7b5ddf commit 133561f

21 files changed

+583
-105
lines changed

PROJECT

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ resources:
1313
kind: ImagePrefetch
1414
path: github.com/cybozu-go/ofen/api/v1
1515
version: v1
16+
webhooks:
17+
defaulting: true
18+
validation: true
19+
webhookVersion: v1
1620
- api:
1721
crdVersion: v1
1822
controller: true

api/v1/imageprefetch_webhook.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package v1
2+
3+
import (
4+
"k8s.io/apimachinery/pkg/runtime"
5+
ctrl "sigs.k8s.io/controller-runtime"
6+
logf "sigs.k8s.io/controller-runtime/pkg/log"
7+
"sigs.k8s.io/controller-runtime/pkg/webhook"
8+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
9+
)
10+
11+
// log is for logging in this package.
12+
var imageprefetchlog = logf.Log.WithName("imageprefetch-resource")
13+
14+
// SetupWebhookWithManager will setup the manager to manage the webhooks
15+
func (r *ImagePrefetch) SetupWebhookWithManager(mgr ctrl.Manager) error {
16+
return ctrl.NewWebhookManagedBy(mgr).
17+
For(r).
18+
Complete()
19+
}
20+
21+
// TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
22+
23+
// +kubebuilder:webhook:path=/mutate-ofen-cybozu-io-v1-imageprefetch,mutating=true,failurePolicy=fail,sideEffects=None,groups=ofen.cybozu.io,resources=imageprefetches,verbs=create;update,versions=v1,name=mimageprefetch.kb.io,admissionReviewVersions=v1
24+
25+
var _ webhook.Defaulter = &ImagePrefetch{}
26+
27+
// Default implements webhook.Defaulter so a webhook will be registered for the type
28+
func (r *ImagePrefetch) Default() {
29+
imageprefetchlog.Info("default", "name", r.Name)
30+
31+
// TODO(user): fill in your defaulting logic.
32+
}
33+
34+
// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
35+
// NOTE: The 'path' attribute must follow a specific pattern and should not be modified directly here.
36+
// Modifying the path for an invalid path can cause API server errors; failing to locate the webhook.
37+
// +kubebuilder:webhook:path=/validate-ofen-cybozu-io-v1-imageprefetch,mutating=false,failurePolicy=fail,sideEffects=None,groups=ofen.cybozu.io,resources=imageprefetches,verbs=create;update,versions=v1,name=vimageprefetch.kb.io,admissionReviewVersions=v1
38+
39+
var _ webhook.Validator = &ImagePrefetch{}
40+
41+
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
42+
func (r *ImagePrefetch) ValidateCreate() (admission.Warnings, error) {
43+
imageprefetchlog.Info("validate create", "name", r.Name)
44+
45+
// TODO(user): fill in your validation logic upon object creation.
46+
return nil, nil
47+
}
48+
49+
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
50+
func (r *ImagePrefetch) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
51+
imageprefetchlog.Info("validate update", "name", r.Name)
52+
53+
// TODO(user): fill in your validation logic upon object update.
54+
return nil, nil
55+
}
56+
57+
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
58+
func (r *ImagePrefetch) ValidateDelete() (admission.Warnings, error) {
59+
imageprefetchlog.Info("validate delete", "name", r.Name)
60+
61+
// TODO(user): fill in your validation logic upon object deletion.
62+
return nil, nil
63+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package v1
2+
3+
import (
4+
. "github.com/onsi/ginkgo/v2"
5+
)
6+
7+
var _ = Describe("ImagePrefetch Webhook", func() {
8+
9+
Context("When creating ImagePrefetch under Defaulting Webhook", func() {
10+
It("Should fill in the default value if a required field is empty", func() {
11+
12+
// TODO(user): Add your logic here
13+
14+
})
15+
})
16+
17+
Context("When creating ImagePrefetch under Validating Webhook", func() {
18+
It("Should deny if a required field is empty", func() {
19+
20+
// TODO(user): Add your logic here
21+
22+
})
23+
24+
It("Should admit if all required fields are provided", func() {
25+
26+
// TODO(user): Add your logic here
27+
28+
})
29+
})
30+
31+
})

api/v1/webhook_suite_test.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package v1
2+
3+
import (
4+
"context"
5+
"crypto/tls"
6+
"fmt"
7+
"net"
8+
"path/filepath"
9+
"runtime"
10+
"testing"
11+
"time"
12+
13+
. "github.com/onsi/ginkgo/v2"
14+
. "github.com/onsi/gomega"
15+
16+
admissionv1 "k8s.io/api/admission/v1"
17+
// +kubebuilder:scaffold:imports
18+
apimachineryruntime "k8s.io/apimachinery/pkg/runtime"
19+
"k8s.io/client-go/rest"
20+
ctrl "sigs.k8s.io/controller-runtime"
21+
"sigs.k8s.io/controller-runtime/pkg/client"
22+
"sigs.k8s.io/controller-runtime/pkg/envtest"
23+
logf "sigs.k8s.io/controller-runtime/pkg/log"
24+
"sigs.k8s.io/controller-runtime/pkg/log/zap"
25+
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
26+
"sigs.k8s.io/controller-runtime/pkg/webhook"
27+
)
28+
29+
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
30+
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
31+
32+
var cfg *rest.Config
33+
var k8sClient client.Client
34+
var testEnv *envtest.Environment
35+
var ctx context.Context
36+
var cancel context.CancelFunc
37+
38+
func TestAPIs(t *testing.T) {
39+
RegisterFailHandler(Fail)
40+
41+
RunSpecs(t, "Webhook Suite")
42+
}
43+
44+
var _ = BeforeSuite(func() {
45+
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
46+
47+
ctx, cancel = context.WithCancel(context.TODO())
48+
49+
By("bootstrapping test environment")
50+
testEnv = &envtest.Environment{
51+
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
52+
ErrorIfCRDPathMissing: false,
53+
54+
// The BinaryAssetsDirectory is only required if you want to run the tests directly
55+
// without call the makefile target test. If not informed it will look for the
56+
// default path defined in controller-runtime which is /usr/local/kubebuilder/.
57+
// Note that you must have the required binaries setup under the bin directory to perform
58+
// the tests directly. When we run make test it will be setup and used automatically.
59+
BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s",
60+
fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)),
61+
62+
WebhookInstallOptions: envtest.WebhookInstallOptions{
63+
Paths: []string{filepath.Join("..", "..", "config", "webhook")},
64+
},
65+
}
66+
67+
var err error
68+
// cfg is defined in this file globally.
69+
cfg, err = testEnv.Start()
70+
Expect(err).NotTo(HaveOccurred())
71+
Expect(cfg).NotTo(BeNil())
72+
73+
scheme := apimachineryruntime.NewScheme()
74+
err = AddToScheme(scheme)
75+
Expect(err).NotTo(HaveOccurred())
76+
77+
err = admissionv1.AddToScheme(scheme)
78+
Expect(err).NotTo(HaveOccurred())
79+
80+
// +kubebuilder:scaffold:scheme
81+
82+
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme})
83+
Expect(err).NotTo(HaveOccurred())
84+
Expect(k8sClient).NotTo(BeNil())
85+
86+
// start webhook server using Manager
87+
webhookInstallOptions := &testEnv.WebhookInstallOptions
88+
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
89+
Scheme: scheme,
90+
WebhookServer: webhook.NewServer(webhook.Options{
91+
Host: webhookInstallOptions.LocalServingHost,
92+
Port: webhookInstallOptions.LocalServingPort,
93+
CertDir: webhookInstallOptions.LocalServingCertDir,
94+
}),
95+
LeaderElection: false,
96+
Metrics: metricsserver.Options{BindAddress: "0"},
97+
})
98+
Expect(err).NotTo(HaveOccurred())
99+
100+
err = (&ImagePrefetch{}).SetupWebhookWithManager(mgr)
101+
Expect(err).NotTo(HaveOccurred())
102+
103+
// +kubebuilder:scaffold:webhook
104+
105+
go func() {
106+
defer GinkgoRecover()
107+
err = mgr.Start(ctx)
108+
Expect(err).NotTo(HaveOccurred())
109+
}()
110+
111+
// wait for the webhook server to get ready
112+
dialer := &net.Dialer{Timeout: time.Second}
113+
addrPort := fmt.Sprintf("%s:%d", webhookInstallOptions.LocalServingHost, webhookInstallOptions.LocalServingPort)
114+
Eventually(func() error {
115+
conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, &tls.Config{InsecureSkipVerify: true})
116+
if err != nil {
117+
return err
118+
}
119+
return conn.Close()
120+
}).Should(Succeed())
121+
122+
})
123+
124+
var _ = AfterSuite(func() {
125+
By("tearing down the test environment")
126+
cancel()
127+
err := testEnv.Stop()
128+
Expect(err).NotTo(HaveOccurred())
129+
})

api/v1/zz_generated.deepcopy.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ func main() {
140140
setupLog.Error(err, "unable to create controller", "controller", "NodeImageSet")
141141
os.Exit(1)
142142
}
143+
if os.Getenv("ENABLE_WEBHOOKS") != "false" {
144+
if err = (&ofenv1.ImagePrefetch{}).SetupWebhookWithManager(mgr); err != nil {
145+
setupLog.Error(err, "unable to create webhook", "webhook", "ImagePrefetch")
146+
os.Exit(1)
147+
}
148+
}
143149
// +kubebuilder:scaffold:builder
144150

145151
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# The following manifests contain a self-signed issuer CR and a certificate CR.
2+
# More document can be found at https://docs.cert-manager.io
3+
# WARNING: Targets CertManager v1.0. Check https://cert-manager.io/docs/installation/upgrading/ for breaking changes.
4+
apiVersion: cert-manager.io/v1
5+
kind: Issuer
6+
metadata:
7+
labels:
8+
app.kubernetes.io/name: ofen
9+
app.kubernetes.io/managed-by: kustomize
10+
name: selfsigned-issuer
11+
namespace: system
12+
spec:
13+
selfSigned: {}
14+
---
15+
apiVersion: cert-manager.io/v1
16+
kind: Certificate
17+
metadata:
18+
labels:
19+
app.kubernetes.io/name: certificate
20+
app.kubernetes.io/instance: serving-cert
21+
app.kubernetes.io/component: certificate
22+
app.kubernetes.io/created-by: ofen
23+
app.kubernetes.io/part-of: ofen
24+
app.kubernetes.io/managed-by: kustomize
25+
name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml
26+
namespace: system
27+
spec:
28+
# SERVICE_NAME and SERVICE_NAMESPACE will be substituted by kustomize
29+
dnsNames:
30+
- SERVICE_NAME.SERVICE_NAMESPACE.svc
31+
- SERVICE_NAME.SERVICE_NAMESPACE.svc.cluster.local
32+
issuerRef:
33+
kind: Issuer
34+
name: selfsigned-issuer
35+
secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
resources:
2+
- certificate.yaml
3+
4+
configurations:
5+
- kustomizeconfig.yaml
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# This configuration is for teaching kustomize how to update name ref substitution
2+
nameReference:
3+
- kind: Issuer
4+
group: cert-manager.io
5+
fieldSpecs:
6+
- kind: Certificate
7+
group: cert-manager.io
8+
path: spec/issuerRef/name

config/crd/kustomization.yaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,17 @@ resources:
99
patches:
1010
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
1111
# patches here are for enabling the conversion webhook for each CRD
12+
- path: patches/webhook_in_imageprefetches.yaml
1213
# +kubebuilder:scaffold:crdkustomizewebhookpatch
1314

1415
# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix.
1516
# patches here are for enabling the CA injection for each CRD
16-
#- path: patches/cainjection_in_imageprefetches.yaml
17+
- path: patches/cainjection_in_imageprefetches.yaml
1718
#- path: patches/cainjection_in_nodeimagesets.yaml
1819
# +kubebuilder:scaffold:crdkustomizecainjectionpatch
1920

2021
# [WEBHOOK] To enable webhook, uncomment the following section
2122
# the following config is for teaching kustomize how to do kustomization for CRDs.
2223

23-
#configurations:
24-
#- kustomizeconfig.yaml
24+
configurations:
25+
- kustomizeconfig.yaml

0 commit comments

Comments
 (0)