Skip to content

Commit 5cd64e2

Browse files
author
Mengqi Yu
committed
support gen-manifests and disable-installer
1 parent c06cec4 commit 5cd64e2

File tree

11 files changed

+194
-106
lines changed

11 files changed

+194
-106
lines changed

example/main.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,26 @@ import (
3939
var log = logf.Log.WithName("example-controller")
4040

4141
func main() {
42+
var genManifests, disableInstaller bool
43+
flag.BoolVar(&genManifests, "generate-manifests", false,
44+
"generate manifests for webhook related resources")
45+
flag.BoolVar(&disableInstaller, "disable-installer", false,
46+
"disable the installer in the webhook server, so it won't install webhook related resources during bootstrapping")
47+
4248
flag.Parse()
4349
logf.SetLogger(logf.ZapLogger(false))
4450
entryLog := log.WithName("entrypoint")
4551

4652
// Setup a Manager
53+
entryLog.Info("setting up manager")
4754
mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{})
4855
if err != nil {
4956
entryLog.Error(err, "unable to set up overall controller manager")
5057
os.Exit(1)
5158
}
5259

5360
// Setup a new controller to Reconciler ReplicaSets
61+
entryLog.Info("Setting up controller")
5462
c, err := controller.New("foo-controller", mgr, controller.Options{
5563
Reconciler: &reconcileReplicaSet{client: mgr.GetClient(), log: log.WithName("reconciler")},
5664
})
@@ -73,6 +81,7 @@ func main() {
7381
}
7482

7583
// Setup webhooks
84+
entryLog.Info("setting up webhooks")
7685
mutatingWebhook, err := builder.NewWebhookBuilder().
7786
Name("mutating.k8s.io").
7887
Mutating().
@@ -99,9 +108,12 @@ func main() {
99108
os.Exit(1)
100109
}
101110

111+
entryLog.Info("setting up webhook server")
102112
as, err := webhook.NewServer("foo-admission-server", mgr, webhook.ServerOptions{
103-
Port: 9876,
104-
CertDir: "/tmp/cert",
113+
Port: 9876,
114+
CertDir: "/tmp/cert",
115+
GenerateManifests: genManifests,
116+
DisableInstaller: disableInstaller,
105117
BootstrapOptions: &webhook.BootstrapOptions{
106118
Secret: &apitypes.NamespacedName{
107119
Namespace: "default",
@@ -122,12 +134,15 @@ func main() {
122134
entryLog.Error(err, "unable to create a new webhook server")
123135
os.Exit(1)
124136
}
137+
138+
entryLog.Info("registering webhooks to the webhook server")
125139
err = as.Register(mutatingWebhook, validatingWebhook)
126140
if err != nil {
127141
entryLog.Error(err, "unable to register webhooks in the admission server")
128142
os.Exit(1)
129143
}
130144

145+
entryLog.Info("starting manager")
131146
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
132147
entryLog.Error(err, "unable to run manager")
133148
os.Exit(1)

pkg/webhook/bootstrap.go

Lines changed: 119 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ import (
2626
"path"
2727
"strconv"
2828

29-
"github.com/ghodss/yaml"
30-
3129
"k8s.io/api/admissionregistration/v1beta1"
3230
admissionregistration "k8s.io/api/admissionregistration/v1beta1"
31+
appsv1 "k8s.io/api/apps/v1"
3332
corev1 "k8s.io/api/core/v1"
3433
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3534
"k8s.io/apimachinery/pkg/runtime"
@@ -93,6 +92,15 @@ func (s *Server) setBootstrappingDefault() {
9392
s.Host = &varString
9493
}
9594

95+
if s.Writer == nil {
96+
s.Writer = os.Stdout
97+
}
98+
if s.GenerateManifests {
99+
s.Client = &writerClient{
100+
writer: s.Writer,
101+
}
102+
}
103+
96104
var certWriter writer.CertWriter
97105
var err error
98106
if s.Secret != nil {
@@ -114,12 +122,10 @@ func (s *Server) setBootstrappingDefault() {
114122
s.certProvisioner = &cert.Provisioner{
115123
CertWriter: certWriter,
116124
}
117-
if s.Writer == nil {
118-
s.Writer = os.Stdout
119-
}
120125
}
121126

122-
// installWebhookConfig writes the configuration of admissionWebhookConfiguration in yaml format if dryrun is true.
127+
// installWebhookConfig writes the configuration of admissionWebhookConfiguration in yaml format
128+
// if GenerateManifests is true.
123129
// Otherwise, it creates the the admissionWebhookConfiguration objects and service if any.
124130
// It also provisions the certificate for the admission server.
125131
func (s *Server) installWebhookConfig() error {
@@ -129,6 +135,14 @@ func (s *Server) installWebhookConfig() error {
129135
return s.err
130136
}
131137

138+
if !s.GenerateManifests && s.DisableInstaller {
139+
log.Info("webhook installer is disabled")
140+
return nil
141+
}
142+
if s.GenerateManifests {
143+
log.Info("generating webhook related manifests")
144+
}
145+
132146
var err error
133147
s.webhookConfigurations, err = s.whConfigs()
134148
if err != nil {
@@ -145,40 +159,18 @@ func (s *Server) installWebhookConfig() error {
145159
_, err = s.certProvisioner.Provision(cert.Options{
146160
ClientConfig: cc,
147161
Objects: s.webhookConfigurations,
148-
Dryrun: s.Dryrun,
149162
})
150163
if err != nil {
151164
return err
152165
}
153166

154-
if s.Dryrun {
155-
// TODO: print here
156-
// if dryrun, return the AdmissionWebhookConfiguration in yaml format.
157-
return s.genYamlConfig(objects)
167+
if s.GenerateManifests {
168+
objects = append(objects, s.deployment())
158169
}
159170

160171
return batchCreateOrReplace(s.Client, objects...)
161172
}
162173

163-
// genYamlConfig generates yaml config for admissionWebhookConfiguration
164-
func (s *Server) genYamlConfig(objs []runtime.Object) error {
165-
for _, obj := range objs {
166-
_, err := s.Writer.Write([]byte("---"))
167-
if err != nil {
168-
return err
169-
}
170-
b, err := yaml.Marshal(obj)
171-
if err != nil {
172-
return err
173-
}
174-
_, err = s.Writer.Write(b)
175-
if err != nil {
176-
return err
177-
}
178-
}
179-
return nil
180-
}
181-
182174
func (s *Server) getClientConfig() (*admissionregistration.WebhookClientConfig, error) {
183175
if s.Host != nil && s.Service != nil {
184176
return nil, errors.New("URL and Service can't be set at the same time")
@@ -360,3 +352,100 @@ func (s *Server) service() runtime.Object {
360352
}
361353
return svc
362354
}
355+
356+
func (s *Server) deployment() runtime.Object {
357+
namespace := "default"
358+
if s.Secret != nil {
359+
namespace = s.Secret.Namespace
360+
}
361+
362+
labels := map[string]string{
363+
"app": "webhook-server",
364+
}
365+
if s.Service != nil {
366+
for k, v := range s.Service.Selectors {
367+
labels[k] = v
368+
}
369+
}
370+
371+
image := "webhook-server:latest"
372+
if len(os.Getenv("IMG")) != 0 {
373+
image = os.Getenv("IMG")
374+
}
375+
376+
readOnly := false
377+
if s.Service != nil {
378+
readOnly = true
379+
}
380+
381+
var volumeSource corev1.VolumeSource
382+
if s.Secret != nil {
383+
var mode int32 = 420
384+
volumeSource = corev1.VolumeSource{
385+
Secret: &corev1.SecretVolumeSource{
386+
DefaultMode: &mode,
387+
SecretName: s.Secret.Name,
388+
},
389+
}
390+
} else {
391+
volumeSource = corev1.VolumeSource{
392+
EmptyDir: &corev1.EmptyDirVolumeSource{},
393+
}
394+
}
395+
396+
return &appsv1.Deployment{
397+
TypeMeta: metav1.TypeMeta{
398+
APIVersion: "apps/v1",
399+
Kind: "Deployment",
400+
},
401+
ObjectMeta: metav1.ObjectMeta{
402+
Name: "webhook-server",
403+
Namespace: namespace,
404+
Labels: labels,
405+
},
406+
Spec: appsv1.DeploymentSpec{
407+
Selector: &metav1.LabelSelector{
408+
MatchLabels: labels,
409+
},
410+
Template: corev1.PodTemplateSpec{
411+
ObjectMeta: metav1.ObjectMeta{
412+
Labels: labels,
413+
},
414+
Spec: corev1.PodSpec{
415+
Containers: []corev1.Container{
416+
{
417+
Name: "webhook-server-container",
418+
Image: image,
419+
ImagePullPolicy: corev1.PullAlways,
420+
Command: []string{
421+
"/bin/sh",
422+
"-c",
423+
"exec ./manager --disable-installer",
424+
},
425+
Ports: []corev1.ContainerPort{
426+
{
427+
Name: "webhook-server",
428+
Protocol: corev1.ProtocolTCP,
429+
ContainerPort: s.Port,
430+
},
431+
},
432+
VolumeMounts: []corev1.VolumeMount{
433+
{
434+
Name: "cert",
435+
MountPath: s.CertDir,
436+
ReadOnly: readOnly,
437+
},
438+
},
439+
},
440+
},
441+
Volumes: []corev1.Volume{
442+
{
443+
Name: "cert",
444+
VolumeSource: volumeSource,
445+
},
446+
},
447+
},
448+
},
449+
},
450+
}
451+
}

pkg/webhook/internal/cert/provisioner.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ type Options struct {
4646
ClientConfig *admissionregistrationv1beta1.WebhookClientConfig
4747
// Objects are the objects that will use the ClientConfig above.
4848
Objects []runtime.Object
49-
// Dryrun controls if the objects are sent to the API server or write to io.Writer
50-
Dryrun bool
5149
}
5250

5351
// Provision provisions certificates for for the WebhookClientConfig.
@@ -68,7 +66,7 @@ func (cp *Provisioner) Provision(options Options) (bool, error) {
6866
return false, err
6967
}
7068

71-
certs, changed, err := cp.CertWriter.EnsureCert(dnsName, options.Dryrun)
69+
certs, changed, err := cp.CertWriter.EnsureCert(dnsName)
7270
if err != nil {
7371
return false, err
7472
}

pkg/webhook/internal/cert/provisioner_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ type fakeCertWriter struct {
211211

212212
var _ writer.CertWriter = &fakeCertWriter{}
213213

214-
func (f *fakeCertWriter) EnsureCert(dnsName string, dryrun bool) (*generator.Artifacts, bool, error) {
214+
func (f *fakeCertWriter) EnsureCert(dnsName string) (*generator.Artifacts, bool, error) {
215215
f.invokedEnsureCert = true
216216
return &generator.Artifacts{}, true, nil
217217
}

pkg/webhook/internal/cert/writer/certwriter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const (
4141
// CertWriter provides method to handle webhooks.
4242
type CertWriter interface {
4343
// EnsureCert provisions the cert for the webhookClientConfig.
44-
EnsureCert(dnsName string, dryrun bool) (*generator.Artifacts, bool, error)
44+
EnsureCert(dnsName string) (*generator.Artifacts, bool, error)
4545
// Inject injects the necessary information given the objects.
4646
// It supports MutatingWebhookConfiguration and ValidatingWebhookConfiguration.
4747
Inject(objs ...runtime.Object) error

pkg/webhook/internal/cert/writer/fs.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,7 @@ func NewFSCertWriter(ops FSCertWriterOptions) (CertWriter, error) {
7272
}
7373

7474
// EnsureCert provisions certificates for a webhookClientConfig by writing the certificates in the filesystem.
75-
// fsCertWriter doesn't support dryrun.
76-
func (f *fsCertWriter) EnsureCert(dnsName string, _ bool) (*generator.Artifacts, bool, error) {
75+
func (f *fsCertWriter) EnsureCert(dnsName string) (*generator.Artifacts, bool, error) {
7776
// create or refresh cert and write it to fs
7877
f.dnsName = dnsName
7978
return handleCommon(f.dnsName, f)

pkg/webhook/internal/cert/writer/fs_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ var _ = Describe("fsCertWriter", func() {
6060
Context("Failed to EnsureCert", func() {
6161
Describe("empty DNS name", func() {
6262
It("should return error", func() {
63-
_, _, err := certWriter.EnsureCert("", false)
63+
_, _, err := certWriter.EnsureCert("")
6464
Expect(err).To(MatchError("dnsName should not be empty"))
6565
})
6666
})
@@ -69,15 +69,15 @@ var _ = Describe("fsCertWriter", func() {
6969
Context("Succeeded to EnsureCert", func() {
7070
Context("CertGenerator is not set", func() {
7171
It("should default it and return no error", func() {
72-
_, _, err := certWriter.EnsureCert(dnsName, false)
72+
_, _, err := certWriter.EnsureCert(dnsName)
7373
Expect(err).NotTo(HaveOccurred())
7474

7575
})
7676
})
7777

7878
Context("no existing certificate files", func() {
7979
It("should create new certificate files", func() {
80-
_, _, err := certWriter.EnsureCert(dnsName, false)
80+
_, _, err := certWriter.EnsureCert(dnsName)
8181
Expect(err).NotTo(HaveOccurred())
8282
caBytes, err := ioutil.ReadFile(path.Join(testingDir, CACertName))
8383
Expect(err).NotTo(HaveOccurred())
@@ -102,7 +102,7 @@ var _ = Describe("fsCertWriter", func() {
102102
})
103103

104104
It("should replace with new certs", func() {
105-
_, _, err := certWriter.EnsureCert(dnsName, false)
105+
_, _, err := certWriter.EnsureCert(dnsName)
106106
Expect(err).NotTo(HaveOccurred())
107107
caBytes, err := ioutil.ReadFile(path.Join(testingDir, CACertName))
108108
Expect(err).NotTo(HaveOccurred())
@@ -131,7 +131,7 @@ var _ = Describe("fsCertWriter", func() {
131131
})
132132

133133
It("should replace with new certs", func() {
134-
_, _, err := certWriter.EnsureCert(dnsName, false)
134+
_, _, err := certWriter.EnsureCert(dnsName)
135135
Expect(err).NotTo(HaveOccurred())
136136
caBytes, err := ioutil.ReadFile(path.Join(testingDir, CACertName))
137137
Expect(err).NotTo(HaveOccurred())
@@ -156,7 +156,7 @@ var _ = Describe("fsCertWriter", func() {
156156
})
157157

158158
It("should replace with new certs", func() {
159-
_, _, err := certWriter.EnsureCert(dnsName, false)
159+
_, _, err := certWriter.EnsureCert(dnsName)
160160
Expect(err).NotTo(HaveOccurred())
161161
caBytes, err := ioutil.ReadFile(path.Join(testingDir, CACertName))
162162
Expect(err).NotTo(HaveOccurred())
@@ -191,7 +191,7 @@ var _ = Describe("fsCertWriter", func() {
191191
})
192192

193193
It("should replace with new certs", func() {
194-
_, _, err := certWriter.EnsureCert(dnsName, false)
194+
_, _, err := certWriter.EnsureCert(dnsName)
195195
Expect(err).NotTo(HaveOccurred())
196196
caBytes, err := ioutil.ReadFile(path.Join(testingDir, CACertName))
197197
Expect(err).NotTo(HaveOccurred())
@@ -220,7 +220,7 @@ var _ = Describe("fsCertWriter", func() {
220220
close(done)
221221
})
222222
It("should keep the secret", func() {
223-
_, _, err := certWriter.EnsureCert(dnsName, false)
223+
_, _, err := certWriter.EnsureCert(dnsName)
224224
Expect(err).NotTo(HaveOccurred())
225225
caBytes, err := ioutil.ReadFile(path.Join(testingDir, CACertName))
226226
Expect(err).NotTo(HaveOccurred())

0 commit comments

Comments
 (0)