Skip to content

Commit

Permalink
feat: event switch
Browse files Browse the repository at this point in the history
  • Loading branch information
ElderMatt committed Aug 21, 2024
1 parent a480b23 commit 98a458f
Showing 1 changed file with 73 additions and 123 deletions.
196 changes: 73 additions & 123 deletions src/operator/secrets.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as k8s from '@kubernetes/client-node'
import { KubeConfig } from '@kubernetes/client-node'
import { KubernetesObject } from '@kubernetes/client-node/dist'
import Operator, { ResourceEventType } from '@linode/apl-k8s-operator'
import Operator, { ResourceEvent, ResourceEventType } from '@linode/apl-k8s-operator'

// added the type property which was missing in the original KubernetesObject
interface CustomKubernetesObject extends KubernetesObject {
Expand All @@ -12,10 +12,11 @@ async function createNamespacedSecret(
metadata: k8s.V1ObjectMeta | undefined,
targetNamespace: string,
secretType: string,
secretName: string,
) {
if (!metadata) return
const simpleSecret = new k8s.V1Secret()
simpleSecret.metadata = { name: `copy-${metadata?.namespace}-${metadata?.name}`, namespace: targetNamespace }
simpleSecret.metadata = { name: secretName, namespace: targetNamespace }
simpleSecret.type = secretType
try {
try {
Expand All @@ -32,6 +33,72 @@ async function createNamespacedSecret(
}
}

async function EventSwitch(
resourceEvent: ResourceEvent,
metadata: k8s.V1ObjectMeta,
targetNamespace: string,
type: string,
namePrefix?: string,
) {
const secretName = namePrefix ? `${namePrefix}-${metadata?.name}` : `copy-${metadata?.namespace}-${metadata?.name}`
switch (resourceEvent.type) {
case ResourceEventType.Deleted: {
try {
await k8sApi.deleteNamespacedSecret(secretName, targetNamespace)
console.debug(`Secret '${secretName}' successfully deleted in namespace '${targetNamespace}'`)
} catch (err) {
console.debug(
`Error deleting copied secret: statuscode: ${err.response.body.code} - message: ${err.response.body.message}`,
)
}
break
}
case ResourceEventType.Modified: {
const simpleSecret = new k8s.V1Secret()
simpleSecret.metadata = {
name: secretName,
namespace: targetNamespace,
}
simpleSecret.type = type
try {
const headers = { 'content-type': 'application/strategic-merge-patch+json' }
try {
simpleSecret.data = (await k8sApi.readNamespacedSecret(metadata.name!, metadata.namespace!)).body.data
} catch (error) {
console.debug(`Secret '${metadata.name!}' cannot be found in namespace '${metadata.namespace!}'`)
}
await k8sApi.patchNamespacedSecret(
simpleSecret.metadata.name!,
targetNamespace,
simpleSecret,
undefined,
undefined,
undefined,
undefined,
{ headers },
)
console.debug(`Secret '${simpleSecret.metadata.name!}' successfully patched in namespace '${targetNamespace}'`)
break
} catch (err) {
console.debug(
`Error patching copied secret: statuscode: ${err.response.body.code} - message: ${err.response.body.message}`,
)
// we know 404 indicates that a secret does not exist, in this case we recreate a new one because otherwise it will not create a copy
if (err.response.body.code !== 404) break
console.debug('Recreating a copy of the secret')
await createNamespacedSecret(metadata, targetNamespace, type, secretName)
break
}
}
case ResourceEventType.Added: {
await createNamespacedSecret(metadata, targetNamespace, type, secretName)
break
}
default:
break
}
}

const kc = new KubeConfig()
kc.loadFromDefault()
const k8sApi = kc.makeApiClient(k8s.CoreV1Api)
Expand All @@ -42,144 +109,27 @@ export default class MyOperator extends Operator {
const { object } = e
const { metadata, type } = object as CustomKubernetesObject
if (metadata && metadata.namespace?.startsWith('monitoring')) {
if (metadata && metadata.name !== 'thanos-objectstore') return
if (type !== 'Opaque') return
// Get all team namespaces
const namespaces = await k8sApi.listNamespace()

// Filter namespaces that start with the given prefix
const teamNamespaces = namespaces.body.items
.map((ns) => ns.metadata?.name)
.filter((name) => name && name.startsWith('team-'))
.filter((name) => name && name.startsWith('team-') && name !== 'team-admin')

// Loop through all of them and add or delete it
if (teamNamespaces.length === 0) return
// eslint-disable-next-line @typescript-eslint/no-misused-promises
teamNamespaces.forEach(async (targetNamespace: string) => {
switch (e.type) {
case ResourceEventType.Deleted: {
try {
await k8sApi.deleteNamespacedSecret(`copy-${metadata?.namespace}-${metadata?.name}`, targetNamespace)
console.debug(
`Secret 'copy-${metadata?.namespace}-${metadata?.name}' successfully deleted in namespace '${targetNamespace}'`,
)
} catch (err) {
console.debug(
`Error deleting copied secret: statuscode: ${err.response.body.code} - message: ${err.response.body.message}`,
)
}
break
}
case ResourceEventType.Modified: {
const simpleSecret = new k8s.V1Secret()
simpleSecret.metadata = {
name: `copy-${metadata?.namespace}-${metadata?.name}`,
namespace: targetNamespace,
}
simpleSecret.type = type
try {
const headers = { 'content-type': 'application/strategic-merge-patch+json' }
try {
simpleSecret.data = (await k8sApi.readNamespacedSecret(metadata.name!, metadata.namespace!)).body.data
} catch (error) {
console.debug(`Secret '${metadata.name!}' cannot be found in namespace '${metadata.namespace!}'`)
}
await k8sApi.patchNamespacedSecret(
simpleSecret.metadata.name!,
targetNamespace,
simpleSecret,
undefined,
undefined,
undefined,
undefined,
{ headers },
)
console.debug(
`Secret '${simpleSecret.metadata.name!}' successfully patched in namespace '${targetNamespace}'`,
)
break
} catch (err) {
console.debug(
`Error patching copied secret: statuscode: ${err.response.body.code} - message: ${err.response.body.message}`,
)
// we know 404 indicates that a secret does not exist, in this case we recreate a new one because otherwise it will not create a copy
if (err.response.body.code !== 404) break
console.debug('Recreating a copy of the secret')
await createNamespacedSecret(metadata, targetNamespace, type)
break
}
}
case ResourceEventType.Added: {
await createNamespacedSecret(metadata, targetNamespace, type)
break
}
default:
break
}
await EventSwitch(e, metadata, targetNamespace, type, 'copy')
})
}
if (metadata && metadata.namespace?.startsWith('team-')) {
if (type !== 'kubernetes.io/dockerconfigjson' && type !== 'kubernetes.io/tls') return
const targetNamespace = type === 'kubernetes.io/dockerconfigjson' ? 'argocd' : 'istio-system'
switch (e.type) {
case ResourceEventType.Deleted: {
try {
await k8sApi.deleteNamespacedSecret(`copy-${metadata?.namespace}-${metadata?.name}`, targetNamespace)
console.debug(
`Secret 'copy-${metadata?.namespace}-${metadata?.name}' successfully deleted in namespace '${targetNamespace}'`,
)
} catch (err) {
console.debug(
`Error deleting copied secret: statuscode: ${err.response.body.code} - message: ${err.response.body.message}`,
)
}
break
}
case ResourceEventType.Modified: {
const simpleSecret = new k8s.V1Secret()
simpleSecret.metadata = {
name: `copy-${metadata?.namespace}-${metadata?.name}`,
namespace: targetNamespace,
}
simpleSecret.type = type
try {
const headers = { 'content-type': 'application/strategic-merge-patch+json' }
try {
simpleSecret.data = (await k8sApi.readNamespacedSecret(metadata.name!, metadata.namespace)).body.data
} catch (error) {
console.debug(`Secret '${metadata.name!}' cannot be found in namespace '${metadata.namespace}'`)
}
await k8sApi.patchNamespacedSecret(
simpleSecret.metadata.name!,
targetNamespace,
simpleSecret,
undefined,
undefined,
undefined,
undefined,
{ headers },
)
console.debug(
`Secret '${simpleSecret.metadata.name!}' successfully patched in namespace '${targetNamespace}'`,
)
break
} catch (err) {
console.debug(
`Error patching copied secret: statuscode: ${err.response.body.code} - message: ${err.response.body.message}`,
)
// we know 404 indicates that a secret does not exist, in this case we recreate a new one because otherwise it will not create a copy
if (err.response.body.code !== 404) break
console.debug('Recreating a copy of the secret')
await createNamespacedSecret(metadata, targetNamespace, type)
break
}
}
case ResourceEventType.Added: {
await createNamespacedSecret(metadata, targetNamespace, type)
break
}
default:
break
}
await EventSwitch(e, metadata, targetNamespace, type)
}
})
}
Expand Down

0 comments on commit 98a458f

Please sign in to comment.