UNPKG

kubricate

Version:

A TypeScript framework for building reusable, type-safe Kubernetes infrastructure — without the YAML mess.

80 lines 2.86 kB
import { createHash } from 'node:crypto'; import { cloneDeep } from 'lodash-es'; import { LABELS } from './constants.js'; export class MetadataInjector { options; constructor(options) { this.options = options; } inject(resource) { if (typeof resource !== 'object' || resource == null) { return resource; } const metadata = this.ensureMetadata(resource); metadata.labels ??= {}; metadata.annotations ??= {}; metadata.labels[LABELS.kubricate] = 'true'; if (this.options.type === 'stack') { metadata.labels[LABELS.stackId] = this.options.stackId; metadata.annotations[LABELS.stackName] = this.options.stackName; metadata.labels[LABELS.resourceId] = this.options.resourceId; } else if (this.options.type === 'secret') { metadata.labels[LABELS.secretManagerId] = this.options.secretManagerId; metadata.annotations[LABELS.secretManagerName] = this.options.secretManagerName; } if (this.options.inject?.version) { metadata.annotations[LABELS.version] = this.options.kubricateVersion; } if (this.options.inject?.resourceHash) { metadata.annotations[LABELS.resourceHash] = this.calculateHash(resource); } if (this.options.inject?.managedAt) { metadata.annotations[LABELS.managedAt] = this.options.managedAt ?? new Date().toISOString(); } return resource; } ensureMetadata(resource) { if (!('metadata' in resource)) { resource.metadata = {}; } // eslint-disable-next-line @typescript-eslint/no-explicit-any const metadata = resource.metadata; metadata.labels ??= {}; metadata.annotations ??= {}; return metadata; } calculateHash(resource) { const cleaned = this.cleanForHash(resource); const sorted = this.sortKeysRecursively(cleaned); const serialized = JSON.stringify(sorted); return createHash('sha256').update(serialized).digest('hex'); } cleanForHash(resource) { const clone = cloneDeep(resource); if (clone.metadata && typeof clone.metadata === 'object') { const metadata = clone.metadata; delete metadata.creationTimestamp; delete metadata.resourceVersion; delete metadata.uid; delete metadata.selfLink; delete metadata.generation; delete metadata.managedFields; } return clone; } sortKeysRecursively(obj) { if (Array.isArray(obj)) { return obj.map(item => this.sortKeysRecursively(item)); } if (obj && typeof obj === 'object') { return Object.keys(obj).sort().reduce((acc, key) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any acc[key] = this.sortKeysRecursively(obj[key]); return acc; // eslint-disable-next-line @typescript-eslint/no-explicit-any }, {}); } return obj; } } //# sourceMappingURL=MetadataInjector.js.map