Skip to content

Commit 7fdb8b1

Browse files
author
Mengqi Yu
committed
cleanup tests
1 parent 2ecd6e3 commit 7fdb8b1

File tree

10 files changed

+653
-840
lines changed

10 files changed

+653
-840
lines changed

pkg/webhook/internal/cert/provisioner.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ func (cp *Provisioner) Provision(options Options) (bool, error) {
5757
if cp.CertWriter == nil {
5858
return false, errors.New("CertWriter need to be set")
5959
}
60+
// If the objects need to be updated, just be lazy and return.
61+
if len(options.Objects) == 0 {
62+
return false, nil
63+
}
6064

6165
dnsName, err := dnsNameFromClientConfig(options.ClientConfig)
6266
if err != nil {
@@ -70,6 +74,8 @@ func (cp *Provisioner) Provision(options Options) (bool, error) {
7074

7175
caBundle := options.ClientConfig.CABundle
7276
caCert := certs.CACert
77+
// TODO(mengqiy): limit the size of the CABundle by GC the old CA certificate
78+
// this is important since the max record size in etcd is 1MB (latest version is 1.5MB).
7379
if !bytes.Contains(caBundle, caCert) {
7480
// Ensure the CA bundle in the webhook configuration has the signing CA.
7581
options.ClientConfig.CABundle = append(caBundle, caCert...)
@@ -90,6 +96,9 @@ func (cp *Provisioner) inject(cc *admissionregistrationv1beta1.WebhookClientConf
9096
injectForEachWebhook(cc, typed.Webhooks)
9197
case *admissionregistrationv1beta1.ValidatingWebhookConfiguration:
9298
injectForEachWebhook(cc, typed.Webhooks)
99+
default:
100+
return fmt.Errorf("%#v is not supported for injecting a webhookClientConfig",
101+
objs[i].GetObjectKind().GroupVersionKind())
93102
}
94103
}
95104
return cp.CertWriter.Inject(objs...)
@@ -105,6 +114,9 @@ func injectForEachWebhook(
105114
}
106115

107116
func dnsNameFromClientConfig(config *admissionregistrationv1beta1.WebhookClientConfig) (string, error) {
117+
if config == nil {
118+
return "", errors.New("clientConfig should not be empty")
119+
}
108120
if config.Service != nil && config.URL != nil {
109121
return "", fmt.Errorf("service and URL can't be set at the same time in a webhook: %v", config)
110122
}
@@ -114,9 +126,6 @@ func dnsNameFromClientConfig(config *admissionregistrationv1beta1.WebhookClientC
114126
if config.Service != nil {
115127
return generator.ServiceToCommonName(config.Service.Namespace, config.Service.Name), nil
116128
}
117-
118-
// TODO
119-
// config.URL != nil
120129
u, err := url.Parse(*config.URL)
121130
return u.Host, err
122131
}

pkg/webhook/internal/cert/provisioner_test.go

Lines changed: 189 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
66
You may obtain a copy of the License at
77
8-
http://www.apache.org/licenses/LICENSE-2.0
8+
http://www.apache.org/licenses/LICENSE-2.0
99
1010
Unless required by applicable law or agreed to in writing, software
1111
distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,20 +17,196 @@ limitations under the License.
1717
package cert
1818

1919
import (
20-
"testing"
20+
. "github.com/onsi/ginkgo"
21+
. "github.com/onsi/gomega"
2122

22-
"k8s.io/api/admissionregistration/v1beta1"
23-
"sigs.k8s.io/controller-runtime/pkg/client/fake"
23+
admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
24+
corev1 "k8s.io/api/core/v1"
25+
"k8s.io/apimachinery/pkg/runtime"
26+
"sigs.k8s.io/controller-runtime/pkg/webhook/internal/cert/generator"
27+
"sigs.k8s.io/controller-runtime/pkg/webhook/internal/cert/writer"
2428
)
2529

26-
func TestCertProvisionerInit(t *testing.T) {
27-
p := &Provisioner{
28-
Client: fake.NewFakeClient(),
29-
}
30-
config := &v1beta1.MutatingWebhookConfiguration{}
30+
var _ = Describe("provisioner", func() {
31+
Context("Invalid Provisioner", func() {
32+
It("should return error", func() {
33+
p := Provisioner{}
34+
_, err := p.Provision(Options{})
35+
Expect(err).To(MatchError("CertWriter need to be set"))
36+
})
37+
})
3138

32-
err := p.Sync(config)
33-
if err != nil {
34-
t.Fatalf("expect nil; got %q", err)
35-
}
39+
Context("No objects in the options", func() {
40+
It("should return no error", func() {
41+
fcw := &fakeCertWriter{}
42+
p := Provisioner{CertWriter: fcw}
43+
changed, err := p.Provision(Options{})
44+
Expect(err).NotTo(HaveOccurred())
45+
Expect(changed).To(BeFalse())
46+
Expect(fcw.invokedEnsureCert).To(BeFalse())
47+
Expect(fcw.invokedInject).To(BeFalse())
48+
})
49+
})
50+
51+
Context("WebhookClientConfig is missing in the options", func() {
52+
It("should return error", func() {
53+
p := Provisioner{CertWriter: &fakeCertWriter{}}
54+
_, err := p.Provision(Options{
55+
Objects: []runtime.Object{
56+
&corev1.Pod{},
57+
},
58+
})
59+
Expect(err).To(MatchError("clientConfig should not be empty"))
60+
})
61+
})
62+
63+
Context("object is not support for injecting webhookClientConfig", func() {
64+
It("should return no error", func() {
65+
p := Provisioner{CertWriter: &fakeCertWriter{}}
66+
_, err := p.Provision(Options{
67+
ClientConfig: &admissionregistrationv1beta1.WebhookClientConfig{
68+
Service: &admissionregistrationv1beta1.ServiceReference{
69+
Namespace: "test-svc-namespace",
70+
Name: "test-service",
71+
},
72+
},
73+
Objects: []runtime.Object{
74+
&corev1.Pod{},
75+
},
76+
})
77+
Expect(err.Error()).To(ContainSubstring("not supported for injecting a webhookClientConfig"))
78+
})
79+
})
80+
81+
Context("webhookConfig has 0 webhook", func() {
82+
It("should return no error", func() {
83+
fcw := &fakeCertWriter{}
84+
p := Provisioner{CertWriter: fcw}
85+
_, err := p.Provision(Options{
86+
ClientConfig: &admissionregistrationv1beta1.WebhookClientConfig{
87+
Service: &admissionregistrationv1beta1.ServiceReference{
88+
Namespace: "test-svc-namespace",
89+
Name: "test-service",
90+
},
91+
},
92+
Objects: []runtime.Object{
93+
&admissionregistrationv1beta1.MutatingWebhookConfiguration{},
94+
},
95+
})
96+
Expect(err).To(BeNil())
97+
Expect(fcw.invokedEnsureCert).To(BeTrue())
98+
Expect(fcw.invokedInject).To(BeTrue())
99+
})
100+
})
101+
102+
Context("happy path", func() {
103+
It("should return no error", func() {
104+
fcw := &fakeCertWriter{}
105+
mwc := &admissionregistrationv1beta1.MutatingWebhookConfiguration{
106+
Webhooks: []admissionregistrationv1beta1.Webhook{
107+
{
108+
Name: "foo-webhook",
109+
},
110+
},
111+
}
112+
vwc := &admissionregistrationv1beta1.ValidatingWebhookConfiguration{
113+
Webhooks: []admissionregistrationv1beta1.Webhook{
114+
{
115+
Name: "foo-webhook",
116+
},
117+
},
118+
}
119+
p := Provisioner{CertWriter: fcw}
120+
_, err := p.Provision(Options{
121+
ClientConfig: &admissionregistrationv1beta1.WebhookClientConfig{
122+
Service: &admissionregistrationv1beta1.ServiceReference{
123+
Namespace: "test-svc-namespace",
124+
Name: "test-service",
125+
},
126+
},
127+
Objects: []runtime.Object{mwc, vwc},
128+
})
129+
Expect(err).To(BeNil())
130+
Expect(fcw.invokedEnsureCert).To(BeTrue())
131+
Expect(fcw.invokedInject).To(BeTrue())
132+
})
133+
})
134+
})
135+
136+
var _ = Describe("dnsNameFromClientConfig", func() {
137+
Context("Invalid WebhookClientConfig", func() {
138+
It("should return error", func() {
139+
_, err := dnsNameFromClientConfig(nil)
140+
Expect(err).To(MatchError("clientConfig should not be empty"))
141+
})
142+
})
143+
144+
Context("Neither Service nor URL is set", func() {
145+
It("should return error", func() {
146+
urlStr := "foo.example.com"
147+
cc := &admissionregistrationv1beta1.WebhookClientConfig{
148+
Service: &admissionregistrationv1beta1.ServiceReference{},
149+
URL: &urlStr,
150+
}
151+
_, err := dnsNameFromClientConfig(cc)
152+
Expect(err.Error()).To(ContainSubstring("service and URL can't be set at the same time in a webhook"))
153+
})
154+
})
155+
156+
Context("Both Service and URL are set", func() {
157+
It("should return error", func() {
158+
urlStr := "https://foo.example.com"
159+
cc := &admissionregistrationv1beta1.WebhookClientConfig{
160+
Service: &admissionregistrationv1beta1.ServiceReference{},
161+
URL: &urlStr,
162+
}
163+
_, err := dnsNameFromClientConfig(cc)
164+
Expect(err.Error()).To(ContainSubstring("service and URL can't be set at the same time in a webhook"))
165+
})
166+
})
167+
168+
Context("Only service is set", func() {
169+
It("should return a DNS name", func() {
170+
path := "somepath"
171+
cc := &admissionregistrationv1beta1.WebhookClientConfig{
172+
Service: &admissionregistrationv1beta1.ServiceReference{
173+
Namespace: "test-svc-namespace",
174+
Name: "test-service",
175+
Path: &path,
176+
},
177+
}
178+
dnsName, err := dnsNameFromClientConfig(cc)
179+
Expect(err).NotTo(HaveOccurred())
180+
Expect(dnsName).To(Equal("test-service.test-svc-namespace.svc"))
181+
})
182+
})
183+
184+
Context("Only URL is set", func() {
185+
It("should return a DNS name", func() {
186+
urlStr := "https://foo.example.com/webhookendpoint"
187+
cc := &admissionregistrationv1beta1.WebhookClientConfig{
188+
URL: &urlStr,
189+
}
190+
dnsName, err := dnsNameFromClientConfig(cc)
191+
Expect(err).NotTo(HaveOccurred())
192+
Expect(dnsName).To(Equal("foo.example.com"))
193+
})
194+
})
195+
})
196+
197+
type fakeCertWriter struct {
198+
invokedEnsureCert bool
199+
invokedInject bool
200+
}
201+
202+
var _ writer.CertWriter = &fakeCertWriter{}
203+
204+
func (f *fakeCertWriter) EnsureCert(dnsName string, dryrun bool) (*generator.Artifacts, bool, error) {
205+
f.invokedEnsureCert = true
206+
return &generator.Artifacts{}, true, nil
207+
}
208+
209+
func (f *fakeCertWriter) Inject(objs ...runtime.Object) error {
210+
f.invokedInject = true
211+
return nil
36212
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
Copyright 2018 The Kubernetes Authors.
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 cert
18+
19+
import (
20+
"testing"
21+
22+
. "github.com/onsi/ginkgo"
23+
. "github.com/onsi/gomega"
24+
25+
"sigs.k8s.io/controller-runtime/pkg/envtest"
26+
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
27+
)
28+
29+
func TestSource(t *testing.T) {
30+
RegisterFailHandler(Fail)
31+
RunSpecsWithDefaultAndCustomReporters(t, "Cert Provisioner Test Suite", []Reporter{envtest.NewlineReporter{}})
32+
}
33+
34+
var _ = BeforeSuite(func(done Done) {
35+
logf.SetLogger(logf.ZapLoggerTo(GinkgoWriter, true))
36+
close(done)
37+
}, 60)

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

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,18 @@ type CertWriter interface {
4848
// handleCommon ensures the given webhook has a proper certificate.
4949
// It uses the given certReadWriter to read and (or) write the certificate.
5050
func handleCommon(dnsName string, ch certReadWriter) (*generator.Artifacts, bool, error) {
51+
if len(dnsName) == 0 {
52+
return nil, false, errors.New("dnsName should not be empty")
53+
}
5154
if ch == nil {
5255
return nil, false, errors.New("certReaderWriter should not be nil")
5356
}
5457

55-
certs, err := createIfNotExists(ch)
58+
certs, changed, err := createIfNotExists(ch)
5659
if err != nil {
57-
return nil, false, err
60+
return nil, changed, err
5861
}
5962

60-
updated := false
6163
// Recreate the cert if it's invalid.
6264
valid := validCert(certs, dnsName)
6365
if !valid {
@@ -66,12 +68,12 @@ func handleCommon(dnsName string, ch certReadWriter) (*generator.Artifacts, bool
6668
if err != nil {
6769
return nil, false, err
6870
}
69-
updated = true
71+
changed = true
7072
}
71-
return certs, updated, nil
73+
return certs, changed, nil
7274
}
7375

74-
func createIfNotExists(ch certReadWriter) (*generator.Artifacts, error) {
76+
func createIfNotExists(ch certReadWriter) (*generator.Artifacts, bool, error) {
7577
// Try to read first
7678
certs, err := ch.read()
7779
if isNotFound(err) {
@@ -81,16 +83,12 @@ func createIfNotExists(ch certReadWriter) (*generator.Artifacts, error) {
8183
// This may happen if there is another racer.
8284
case isAlreadyExists(err):
8385
certs, err = ch.read()
84-
if err != nil {
85-
return certs, err
86-
}
87-
case err != nil:
88-
return certs, err
86+
return certs, true, err
87+
default:
88+
return certs, true, err
8989
}
90-
} else if err != nil {
91-
return certs, err
9290
}
93-
return certs, nil
91+
return certs, false, err
9492
}
9593

9694
// certReadWriter provides methods for reading and writing certificates.

0 commit comments

Comments
 (0)