kubricate
Version:
A TypeScript framework for building reusable, type-safe Kubernetes infrastructure — without the YAML mess.
161 lines • 5.44 kB
JavaScript
import { SecretsInjectionContext } from '../secret/index.js';
import { ResourceComposer } from './ResourceComposer.js';
/**
* BaseStack is the base class for all stacks.
*
* @note BaseStack fields and methods need to be public, type inference is not working with private fields when using with `createSt`
*/
export class BaseStack {
_composer;
_secretManagers = {};
_targetInjects = [];
_defaultSecretManagerId = 'default';
logger;
/**
* The name of the stack.
* This is used to identify the stack, generally used with Stack.
*/
_name;
/**
* Registers a secret injection to be processed during stack build/render.
*/
registerSecretInjection(inject) {
this._targetInjects.push(inject);
}
/**
* Retrieves all registered secret injections.
*/
getTargetInjects() {
return this._targetInjects;
}
useSecrets(secretManager, builder) {
if (!secretManager) {
throw new Error(`Cannot BaseStack.useSecrets, secret manager is not provided.`);
}
const secretManagerNextId = Object.keys(this._secretManagers).length;
this._secretManagers[secretManagerNextId] = secretManager;
const ctx = new SecretsInjectionContext(this, secretManager, secretManagerNextId);
builder(ctx); // invoke builder
ctx.resolveAll();
return this;
}
/**
* Get the secret manager instance.
* @param id The ID of the secret manager. defaults to 'default'.
* @returns The secret manager instance.
*/
getSecretManager(id) {
if (!this._secretManagers[id]) {
throw new Error(`Secret manager with ID ${id} is not defined. Make sure to use the 'useSecrets' method to define it, and call before 'from' method in the stack.`);
}
return this._secretManagers[id];
}
/**
* Get all secret managers in the stack.
* @returns The secret managers in the stack.
*/
getSecretManagers() {
return this._secretManagers;
}
override(data) {
this._composer.override(data);
return this;
}
/**
* Build the stack and return the resources.
* @returns The resources in the stack.
*/
build() {
this.logger?.debug('BaseStack.build: Starting to build the stack.');
const injectGroups = new Map();
for (const inject of this._targetInjects) {
const key = `${inject.providerId}:${inject.resourceId}:${inject.path}`;
if (!injectGroups.has(key)) {
injectGroups.set(key, {
providerId: inject.providerId,
provider: inject.provider,
resourceId: inject.resourceId,
path: inject.path,
injects: []
});
}
injectGroups.get(key).injects.push(inject);
}
for (const {
providerId,
provider,
resourceId,
path,
injects
} of injectGroups.values()) {
const payload = provider.getInjectionPayload(injects);
this.logger?.debug(`BaseStack.build: Injecting value into resource:`);
this.logger?.debug(JSON.stringify({
providerId,
resourceId,
path,
payload
}, null, 2));
this._composer.inject(resourceId, path, payload);
this.logger?.debug(`BaseStack.build: Injected secrets from provider "${providerId}" into resource "${resourceId}" at path "${path}".`);
}
return this._composer.build();
// for (const targetInject of this._targetInjects) {
// const provider = targetInject.provider;
// const injectsForProvider = this._targetInjects.filter(i => i.provider === provider);
// const targetValue = provider.getInjectionPayload(injectsForProvider);
// this.logger?.debug(`BaseStack.build: Injecting value: ${JSON.stringify(targetValue, null, 2)}`);
// this._composer.inject(targetInject.resourceId, targetInject.path, targetValue);
// this.logger?.debug(`
// BaseStack.build: Injected secrets into provider "${provider.constructor.name}" with ID "${targetInject.resourceId}" at path: ${targetInject.path}.`);
// }
// return this._composer.build();
}
setComposer(composer) {
this._composer = composer;
}
getComposer() {
return this._composer;
}
/**
* Get the resources from the composer.
* @returns The resources from the composer.
*/
get resources() {
return this._composer;
}
getName() {
return this._name;
}
setName(name) {
this._name = name;
}
/**
* @internal
* This method is used to inject the logger into the stack.
* It is called by the orchestrator to inject the logger into all components of the stack.
*
* Inject a logger instance into all components of the stack e.g. secret managers, connector, providers, etc.
* This is useful for logging purposes and debugging.
* @param logger The logger instance to be injected.
*/
injectLogger(logger) {
this.logger = logger;
if (typeof this.getSecretManagers === 'function') {
const managers = this.getSecretManagers();
for (const secretManager of Object.values(managers)) {
// Inject into SecretManager
secretManager.logger = logger;
// Inject into each connector
for (const connector of Object.values(secretManager.getConnectors())) {
connector.logger = logger;
}
// Inject into each provider
for (const provider of Object.values(secretManager.getProviders())) {
provider.logger = logger;
}
}
}
}
}
//# sourceMappingURL=BaseStack.js.map