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

feat: restart watcher if no events seen for specified period #532

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions bin/daemon.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ const {
pollingDisabled,
rolePermittedAnnotation,
namingPermittedAnnotation,
enforceNamespaceAnnotation
enforceNamespaceAnnotation,
watchTimeout
} = require('../config')

async function main () {
Expand All @@ -37,7 +38,8 @@ async function main () {
const externalSecretEvents = getExternalSecretEvents({
kubeClient,
customResourceManifest,
logger
logger,
watchTimeout
})

const registry = Prometheus.register
Expand Down
1 change: 1 addition & 0 deletions charts/kubernetes-external-secrets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ The following table lists the configurable parameters of the `kubernetes-externa
| `env.POLLER_INTERVAL_MILLISECONDS` | Set POLLER_INTERVAL_MILLISECONDS in Deployment Pod | `10000` |
| `env.VAULT_ADDR` | Endpoint for the Vault backend, if using Vault | `http://127.0.0.1:8200` |
| `env.DISABLE_POLLING` | Disables backend polling and only updates secrets when ExternalSecret is modified, setting this to any value will disable polling | `nil` |
| `env.WATCH_TIMEOUT` | Restarts the external secrets resource watcher if no events have been seen in this time period (miliseconds) | `60000` |
| `envVarsFromSecret.AWS_ACCESS_KEY_ID` | Set AWS_ACCESS_KEY_ID (from a secret) in Deployment Pod | |
| `envVarsFromSecret.AWS_SECRET_ACCESS_KEY` | Set AWS_SECRET_ACCESS_KEY (from a secret) in Deployment Pod | |
| `envVarsFromSecret.AZURE_TENANT_ID` | Set AZURE_TENANT_ID (from a secret) in Deployment Pod | |
Expand Down
1 change: 1 addition & 0 deletions charts/kubernetes-external-secrets/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ env:
AWS_REGION: us-west-2
AWS_DEFAULT_REGION: us-west-2
POLLER_INTERVAL_MILLISECONDS: 10000 # Caution, setting this frequency may incur additional charges on some platforms
WATCH_TIMEOUT: 60000
LOG_LEVEL: info
LOG_MESSAGE_KEY: 'msg'
# Print logs level as string ("info") rather than integer (30)
Expand Down
4 changes: 3 additions & 1 deletion config/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const enforceNamespaceAnnotation = 'ENFORCE_NAMESPACE_ANNOTATIONS' in process.en
const metricsPort = process.env.METRICS_PORT || 3001

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

module.exports = {
vaultEndpoint,
Expand All @@ -52,5 +53,6 @@ module.exports = {
logLevel,
customResourceManagerDisabled,
useHumanReadableLogLevels,
logMessageKey
logMessageKey,
watchTimeout
}
34 changes: 28 additions & 6 deletions lib/external-secret.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ async function startWatcher ({
kubeClient,
customResourceManifest,
logger,
eventQueue
eventQueue,
watchTimeout
}) {
const deathQueue = createEventQueue()

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

jsonStream.on('data', eventQueue.put)
let timeout
const restartTimeout = () => {
if (timeout) {
clearTimeout(timeout)
}

const timeMs = watchTimeout
timeout = setTimeout(() => {
logger.info(`No watch event for ${timeMs} ms, restarting watcher`)
stream.abort()
}, timeMs)
timeout.unref()
}

jsonStream.on('data', (evt) => {
eventQueue.put(evt)
restartTimeout()
})

jsonStream.on('error', (err) => {
logger.warn(err, 'Got error on stream')
deathQueue.put('ERROR')
clearTimeout(timeout)
})

jsonStream.on('end', () => {
deathQueue.put('END')
clearTimeout(timeout)
})

await deathQueue.take()
const deathEvent = await deathQueue.take()

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

stream.abort()
Expand All @@ -75,7 +95,8 @@ async function startWatcher ({
function getExternalSecretEvents ({
kubeClient,
customResourceManifest,
logger
logger,
watchTimeout
}) {
return (async function * () {
const eventQueue = createEventQueue()
Expand All @@ -84,7 +105,8 @@ function getExternalSecretEvents ({
kubeClient,
customResourceManifest,
logger,
eventQueue
eventQueue,
watchTimeout
})

while (true) {
Expand Down
4 changes: 3 additions & 1 deletion lib/external-secret.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe('getExternalSecretEvents', () => {

mockedStream = new Readable()
mockedStream._read = () => {}
mockedStream.abort = () => {}

externalSecretsApiMock.get = sinon.stub()
kubeClientMock = sinon.mock()
Expand Down Expand Up @@ -60,7 +61,8 @@ describe('getExternalSecretEvents', () => {
const events = getExternalSecretEvents({
kubeClient: kubeClientMock,
customResourceManifest: fakeCustomResourceManifest,
logger: loggerMock
logger: loggerMock,
watchTimeout: 5000
})

mockedStream.push(`${JSON.stringify({
Expand Down