qenv/ts/qenv.classes.qenv.ts

194 lines
6.2 KiB
TypeScript
Raw Normal View History

2023-08-09 15:47:20 +00:00
import { ConfigVaultAdapter } from './qenv.classes.configvaultadapter.js';
2022-07-28 08:09:01 +00:00
import * as plugins from './qenv.plugins.js';
2017-05-12 16:17:22 +00:00
2023-10-20 15:21:51 +00:00
export type TEnvVarRef = string | (() => Promise<string>);
2017-05-12 16:17:22 +00:00
export class Qenv {
2019-01-06 00:30:07 +00:00
public requiredEnvVars: string[] = [];
public availableEnvVars: string[] = [];
public missingEnvVars: string[] = [];
2019-08-06 15:37:07 +00:00
public keyValueObject: { [key: string]: any } = {};
2020-06-08 18:57:22 +00:00
public logger = new plugins.smartlog.ConsoleLog();
2019-01-06 00:30:07 +00:00
2023-08-09 15:47:20 +00:00
public configVaultAdapter: ConfigVaultAdapter;
2019-01-06 00:30:07 +00:00
public qenvFilePathAbsolute: string;
public envFilePathAbsolute: string;
2023-08-09 10:49:52 +00:00
constructor(
qenvFileBasePathArg: string = process.cwd(),
envFileBasePathArg: string,
failOnMissing: boolean = true
) {
2023-08-09 15:47:20 +00:00
this.configVaultAdapter = new ConfigVaultAdapter();
2023-08-09 10:49:52 +00:00
this.initializeFilePaths(qenvFileBasePathArg, envFileBasePathArg);
this.loadRequiredEnvVars();
this.loadAvailableEnvVars();
this.checkForMissingEnvVars(failOnMissing);
}
private initializeFilePaths(qenvFileBasePathArg: string, envFileBasePathArg: string) {
2023-08-09 12:50:32 +00:00
this.qenvFilePathAbsolute = plugins.path.join(
plugins.path.resolve(qenvFileBasePathArg),
'qenv.yml'
);
this.envFilePathAbsolute = plugins.path.join(
plugins.path.resolve(envFileBasePathArg),
'env.json'
);
2023-08-09 10:49:52 +00:00
}
private loadRequiredEnvVars() {
if (plugins.smartfile.fs.fileExistsSync(this.qenvFilePathAbsolute)) {
const qenvFile = plugins.smartfile.fs.toObjectSync(this.qenvFilePathAbsolute);
if (qenvFile?.required && Array.isArray(qenvFile.required)) {
this.requiredEnvVars.push(...qenvFile.required);
} else {
this.logger.log('warn', 'qenv.yml does not contain a "required" Array!');
}
}
}
2019-01-06 00:30:07 +00:00
2023-08-09 10:49:52 +00:00
private loadAvailableEnvVars() {
for (const envVar of this.requiredEnvVars) {
const value = this.getEnvVarOnDemand(envVar);
if (value) {
this.availableEnvVars.push(envVar);
this.keyValueObject[envVar] = value;
}
}
}
2019-01-06 00:30:07 +00:00
2023-08-09 10:49:52 +00:00
private checkForMissingEnvVars(failOnMissing: boolean) {
2023-08-09 12:50:32 +00:00
this.missingEnvVars = this.requiredEnvVars.filter(
(envVar) => !this.availableEnvVars.includes(envVar)
);
2017-05-12 16:17:22 +00:00
if (this.missingEnvVars.length > 0) {
2023-08-09 10:49:52 +00:00
console.info('Required Env Vars are:', this.requiredEnvVars);
console.error('Missing Env Vars:', this.missingEnvVars);
2017-05-12 16:17:22 +00:00
if (failOnMissing) {
2023-08-09 10:49:52 +00:00
this.logger.log('error', 'Exiting due to missing env vars!');
process.exit(1);
2019-08-29 12:19:15 +00:00
} else {
2019-08-29 12:29:16 +00:00
this.logger.log('warn', 'qenv is not set to fail on missing environment variables');
2017-05-12 16:17:22 +00:00
}
}
}
2023-08-09 12:50:32 +00:00
public async getEnvVarOnDemand(
2023-10-20 15:21:51 +00:00
envVarNameOrNames: TEnvVarRef | TEnvVarRef[]
2023-08-09 12:50:32 +00:00
): Promise<string | undefined> {
if (Array.isArray(envVarNameOrNames)) {
for (const envVarName of envVarNameOrNames) {
const value = await this.tryGetEnvVar(envVarName);
if (value) {
return value;
}
}
return undefined;
} else {
return await this.tryGetEnvVar(envVarNameOrNames);
}
}
public getEnvVarOnDemandSync(envVarNameOrNames: string | string[]): string | undefined {
console.warn('requesting env var sync leaves out potentially important async env sources.');
if (Array.isArray(envVarNameOrNames)) {
for (const envVarName of envVarNameOrNames) {
const value = this.tryGetEnvVarSync(envVarName);
if (value) {
return value;
}
}
return undefined;
} else {
return this.tryGetEnvVarSync(envVarNameOrNames);
}
}
public async getEnvVarOnDemandAsObject(envVarNameOrNames: string | string[]): Promise<any> {
const rawValue = await this.getEnvVarOnDemand(envVarNameOrNames);
if (rawValue && rawValue.startsWith('base64Object:')) {
const base64Part = rawValue.split('base64Object:')[1];
return this.decodeBase64(base64Part);
}
return rawValue;
}
2023-10-20 15:21:51 +00:00
private async tryGetEnvVar(envVarRefArg: TEnvVarRef): Promise<string | undefined> {
if (typeof envVarRefArg === 'function') {
return await envVarRefArg();
}
2023-08-09 10:49:52 +00:00
return (
2023-10-20 15:21:51 +00:00
this.getFromEnvironmentVariable(envVarRefArg) ||
this.getFromEnvJsonFile(envVarRefArg) ||
this.getFromDockerSecret(envVarRefArg) ||
this.getFromDockerSecretJson(envVarRefArg)
2023-08-09 10:49:52 +00:00
);
2017-05-12 16:17:22 +00:00
}
2019-01-06 00:30:07 +00:00
2023-08-09 12:50:32 +00:00
private tryGetEnvVarSync(envVarName: string): string | undefined {
2023-08-09 11:24:49 +00:00
return (
this.getFromEnvironmentVariable(envVarName) ||
this.getFromEnvJsonFile(envVarName) ||
this.getFromDockerSecret(envVarName) ||
this.getFromDockerSecretJson(envVarName)
);
}
2023-08-09 10:49:52 +00:00
private getFromEnvironmentVariable(envVarName: string): string | undefined {
return process.env[envVarName];
}
private getFromEnvJsonFile(envVarName: string): string | undefined {
2019-09-13 09:20:47 +00:00
try {
2023-08-09 10:49:52 +00:00
const envJson = plugins.smartfile.fs.toObjectSync(this.envFilePathAbsolute);
const value = envJson[envVarName];
if (typeof value === 'object') {
return 'base64Object:' + this.encodeBase64(value);
}
return value;
} catch (error) {
return undefined;
2019-01-12 23:00:32 +00:00
}
2023-08-09 10:49:52 +00:00
}
2019-01-06 00:30:07 +00:00
2023-08-09 10:49:52 +00:00
private getFromDockerSecret(envVarName: string): string | undefined {
const secretPath = `/run/secrets/${envVarName}`;
if (plugins.smartfile.fs.fileExistsSync(secretPath)) {
return plugins.smartfile.fs.toStringSync(secretPath);
2019-01-12 23:00:32 +00:00
}
2023-08-09 10:49:52 +00:00
return undefined;
}
2019-01-06 00:30:07 +00:00
2023-08-09 10:49:52 +00:00
private getFromDockerSecretJson(envVarName: string): string | undefined {
if (plugins.smartfile.fs.isDirectory('/run/secrets')) {
const availableSecrets = plugins.smartfile.fs.listAllItemsSync('/run/secrets');
for (const secret of availableSecrets) {
2023-08-09 10:49:52 +00:00
if (secret.includes('secret.json')) {
2019-01-14 21:42:24 +00:00
const secretObject = plugins.smartfile.fs.toObjectSync(`/run/secrets/${secret}`);
2023-08-09 10:49:52 +00:00
const value = secretObject[envVarName];
if (typeof value === 'object') {
return 'base64Object:' + this.encodeBase64(value);
}
return value;
}
}
2019-01-12 23:00:32 +00:00
}
2023-08-09 10:49:52 +00:00
return undefined;
2019-01-06 00:30:07 +00:00
}
2023-08-09 10:49:52 +00:00
private encodeBase64(data: any): string {
const jsonString = JSON.stringify(data);
return Buffer.from(jsonString).toString('base64');
}
2019-01-06 00:30:07 +00:00
2023-08-09 10:49:52 +00:00
private decodeBase64(encodedString: string): any {
const decodedString = Buffer.from(encodedString, 'base64').toString('utf-8');
return JSON.parse(decodedString);
}
2017-05-12 16:17:22 +00:00
}