Skip to content
This repository was archived by the owner on Jul 26, 2022. It is now read-only.

Commit bb1ed9e

Browse files
authored
feat: restart watcher if no events seen for specified period (default 60 sec) (#532)
1 parent b7da57f commit bb1ed9e

File tree

6 files changed

+40
-10
lines changed

6 files changed

+40
-10
lines changed

bin/daemon.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ const {
2525
pollingDisabled,
2626
rolePermittedAnnotation,
2727
namingPermittedAnnotation,
28-
enforceNamespaceAnnotation
28+
enforceNamespaceAnnotation,
29+
watchTimeout
2930
} = require('../config')
3031

3132
async function main () {
@@ -37,7 +38,8 @@ async function main () {
3738
const externalSecretEvents = getExternalSecretEvents({
3839
kubeClient,
3940
customResourceManifest,
40-
logger
41+
logger,
42+
watchTimeout
4143
})
4244

4345
const registry = Prometheus.register

charts/kubernetes-external-secrets/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ The following table lists the configurable parameters of the `kubernetes-externa
8383
| `env.POLLER_INTERVAL_MILLISECONDS` | Set POLLER_INTERVAL_MILLISECONDS in Deployment Pod | `10000` |
8484
| `env.VAULT_ADDR` | Endpoint for the Vault backend, if using Vault | `http://127.0.0.1:8200` |
8585
| `env.DISABLE_POLLING` | Disables backend polling and only updates secrets when ExternalSecret is modified, setting this to any value will disable polling | `nil` |
86+
| `env.WATCH_TIMEOUT` | Restarts the external secrets resource watcher if no events have been seen in this time period (miliseconds) | `60000` |
8687
| `envVarsFromSecret.AWS_ACCESS_KEY_ID` | Set AWS_ACCESS_KEY_ID (from a secret) in Deployment Pod | |
8788
| `envVarsFromSecret.AWS_SECRET_ACCESS_KEY` | Set AWS_SECRET_ACCESS_KEY (from a secret) in Deployment Pod | |
8889
| `envVarsFromSecret.AZURE_TENANT_ID` | Set AZURE_TENANT_ID (from a secret) in Deployment Pod | |

charts/kubernetes-external-secrets/values.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ env:
1515
AWS_REGION: us-west-2
1616
AWS_DEFAULT_REGION: us-west-2
1717
POLLER_INTERVAL_MILLISECONDS: 10000 # Caution, setting this frequency may incur additional charges on some platforms
18+
WATCH_TIMEOUT: 60000
1819
LOG_LEVEL: info
1920
LOG_MESSAGE_KEY: 'msg'
2021
# Print logs level as string ("info") rather than integer (30)

config/environment.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const enforceNamespaceAnnotation = 'ENFORCE_NAMESPACE_ANNOTATIONS' in process.en
3939
const metricsPort = process.env.METRICS_PORT || 3001
4040

4141
const customResourceManagerDisabled = 'DISABLE_CUSTOM_RESOURCE_MANAGER' in process.env
42+
const watchTimeout = process.env.WATCH_TIMEOUT ? parseInt(process.env.WATCH_TIMEOUT) : 60000
4243

4344
module.exports = {
4445
vaultEndpoint,
@@ -56,5 +57,6 @@ module.exports = {
5657
logLevel,
5758
customResourceManagerDisabled,
5859
useHumanReadableLogLevels,
59-
logMessageKey
60+
logMessageKey,
61+
watchTimeout
6062
}

lib/external-secret.js

+28-6
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ async function startWatcher ({
2626
kubeClient,
2727
customResourceManifest,
2828
logger,
29-
eventQueue
29+
eventQueue,
30+
watchTimeout
3031
}) {
3132
const deathQueue = createEventQueue()
3233

@@ -42,20 +43,39 @@ async function startWatcher ({
4243
const jsonStream = new JSONStream()
4344
stream.pipe(jsonStream)
4445

45-
jsonStream.on('data', eventQueue.put)
46+
let timeout
47+
const restartTimeout = () => {
48+
if (timeout) {
49+
clearTimeout(timeout)
50+
}
51+
52+
const timeMs = watchTimeout
53+
timeout = setTimeout(() => {
54+
logger.info(`No watch event for ${timeMs} ms, restarting watcher`)
55+
stream.abort()
56+
}, timeMs)
57+
timeout.unref()
58+
}
59+
60+
jsonStream.on('data', (evt) => {
61+
eventQueue.put(evt)
62+
restartTimeout()
63+
})
4664

4765
jsonStream.on('error', (err) => {
4866
logger.warn(err, 'Got error on stream')
4967
deathQueue.put('ERROR')
68+
clearTimeout(timeout)
5069
})
5170

5271
jsonStream.on('end', () => {
5372
deathQueue.put('END')
73+
clearTimeout(timeout)
5474
})
5575

56-
await deathQueue.take()
76+
const deathEvent = await deathQueue.take()
5777

58-
logger.debug('Stopping watch stream')
78+
logger.info('Stopping watch stream due to event: %s', deathEvent)
5979
eventQueue.put({ type: 'DELETED_ALL' })
6080

6181
stream.abort()
@@ -75,7 +95,8 @@ async function startWatcher ({
7595
function getExternalSecretEvents ({
7696
kubeClient,
7797
customResourceManifest,
78-
logger
98+
logger,
99+
watchTimeout
79100
}) {
80101
return (async function * () {
81102
const eventQueue = createEventQueue()
@@ -84,7 +105,8 @@ function getExternalSecretEvents ({
84105
kubeClient,
85106
customResourceManifest,
86107
logger,
87-
eventQueue
108+
eventQueue,
109+
watchTimeout
88110
})
89111

90112
while (true) {

lib/external-secret.test.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ describe('getExternalSecretEvents', () => {
2727

2828
mockedStream = new Readable()
2929
mockedStream._read = () => {}
30+
mockedStream.abort = () => {}
3031

3132
externalSecretsApiMock.get = sinon.stub()
3233
kubeClientMock = sinon.mock()
@@ -60,7 +61,8 @@ describe('getExternalSecretEvents', () => {
6061
const events = getExternalSecretEvents({
6162
kubeClient: kubeClientMock,
6263
customResourceManifest: fakeCustomResourceManifest,
63-
logger: loggerMock
64+
logger: loggerMock,
65+
watchTimeout: 5000
6466
})
6567

6668
mockedStream.push(`${JSON.stringify({

0 commit comments

Comments
 (0)