Skip to content

Commit 75a38d2

Browse files
authored
Merge pull request #2919 from k8s-infra-cherrypick-robot/cherry-pick-2893-to-release-0.18
[release-0.18] 🐛 Recreate watcher if the file unlinked and replaced
2 parents 9fe6db5 + 27793ff commit 75a38d2

File tree

3 files changed

+43
-8
lines changed

3 files changed

+43
-8
lines changed

pkg/certwatcher/certwatcher.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -173,14 +173,14 @@ func (cw *CertWatcher) ReadCertificate() error {
173173

174174
func (cw *CertWatcher) handleEvent(event fsnotify.Event) {
175175
// Only care about events which may modify the contents of the file.
176-
if !(isWrite(event) || isRemove(event) || isCreate(event)) {
176+
if !(isWrite(event) || isRemove(event) || isCreate(event) || isChmod(event)) {
177177
return
178178
}
179179

180180
log.V(1).Info("certificate event", "event", event)
181181

182-
// If the file was removed, re-add the watch.
183-
if isRemove(event) {
182+
// If the file was removed or renamed, re-add the watch to the previous name
183+
if isRemove(event) || isChmod(event) {
184184
if err := cw.watcher.Add(event.Name); err != nil {
185185
log.Error(err, "error re-watching file")
186186
}
@@ -202,3 +202,7 @@ func isCreate(event fsnotify.Event) bool {
202202
func isRemove(event fsnotify.Event) bool {
203203
return event.Op.Has(fsnotify.Remove)
204204
}
205+
206+
func isChmod(event fsnotify.Event) bool {
207+
return event.Op.Has(fsnotify.Chmod)
208+
}

pkg/certwatcher/certwatcher_suite_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ var _ = BeforeSuite(func() {
4141
})
4242

4343
var _ = AfterSuite(func() {
44-
for _, file := range []string{certPath, keyPath} {
44+
for _, file := range []string{certPath, keyPath, certPath + ".new", keyPath + ".new", certPath + ".old", keyPath + ".old"} {
4545
_ = os.Remove(file)
4646
}
4747
})

pkg/certwatcher/certwatcher_test.go

+35-4
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,36 @@ var _ = Describe("CertWatcher", func() {
121121
Expect(called.Load()).To(BeNumerically(">=", 1))
122122
})
123123

124+
It("should reload currentCert when changed with rename", func() {
125+
doneCh := startWatcher()
126+
called := atomic.Int64{}
127+
watcher.RegisterCallback(func(crt tls.Certificate) {
128+
called.Add(1)
129+
Expect(crt.Certificate).ToNot(BeEmpty())
130+
})
131+
132+
firstcert, _ := watcher.GetCertificate(nil)
133+
134+
err := writeCerts(certPath+".new", keyPath+".new", "192.168.0.2")
135+
Expect(err).ToNot(HaveOccurred())
136+
137+
Expect(os.Link(certPath, certPath+".old")).To(Succeed())
138+
Expect(os.Rename(certPath+".new", certPath)).To(Succeed())
139+
140+
Expect(os.Link(keyPath, keyPath+".old")).To(Succeed())
141+
Expect(os.Rename(keyPath+".new", keyPath)).To(Succeed())
142+
143+
Eventually(func() bool {
144+
secondcert, _ := watcher.GetCertificate(nil)
145+
first := firstcert.PrivateKey.(*rsa.PrivateKey)
146+
return first.Equal(secondcert.PrivateKey)
147+
}).ShouldNot(BeTrue())
148+
149+
ctxCancel()
150+
Eventually(doneCh, "4s").Should(BeClosed())
151+
Expect(called.Load()).To(BeNumerically(">=", 1))
152+
})
153+
124154
Context("prometheus metric read_certificate_total", func() {
125155
var readCertificateTotalBefore float64
126156
var readCertificateErrorsBefore float64
@@ -159,17 +189,18 @@ var _ = Describe("CertWatcher", func() {
159189

160190
Expect(os.Remove(keyPath)).To(Succeed())
161191

192+
// Note, we are checking two errors here, because os.Remove generates two fsnotify events: Chmod + Remove
162193
Eventually(func() error {
163194
readCertificateTotalAfter := testutil.ToFloat64(metrics.ReadCertificateTotal)
164-
if readCertificateTotalAfter != readCertificateTotalBefore+1.0 {
165-
return fmt.Errorf("metric read certificate total expected: %v and got: %v", readCertificateTotalBefore+1.0, readCertificateTotalAfter)
195+
if readCertificateTotalAfter != readCertificateTotalBefore+2.0 {
196+
return fmt.Errorf("metric read certificate total expected: %v and got: %v", readCertificateTotalBefore+2.0, readCertificateTotalAfter)
166197
}
167198
return nil
168199
}, "4s").Should(Succeed())
169200
Eventually(func() error {
170201
readCertificateErrorsAfter := testutil.ToFloat64(metrics.ReadCertificateErrors)
171-
if readCertificateErrorsAfter != readCertificateErrorsBefore+1.0 {
172-
return fmt.Errorf("metric read certificate errors expected: %v and got: %v", readCertificateErrorsBefore+1.0, readCertificateErrorsAfter)
202+
if readCertificateErrorsAfter != readCertificateErrorsBefore+2.0 {
203+
return fmt.Errorf("metric read certificate errors expected: %v and got: %v", readCertificateErrorsBefore+2.0, readCertificateErrorsAfter)
173204
}
174205
return nil
175206
}, "4s").Should(Succeed())

0 commit comments

Comments
 (0)