2018-08-12 22:09:37 +00:00
|
|
|
import * as plugins from './qenv.plugins';
|
2017-05-12 16:17:22 +00:00
|
|
|
|
2019-01-12 23:00:32 +00:00
|
|
|
/**
|
|
|
|
* class Qenv
|
|
|
|
* allows to make assertions about the environments while being more flexibel in how to meet them
|
|
|
|
*/
|
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
|
|
|
|
|
|
|
// filePaths
|
|
|
|
public qenvFilePathAbsolute: string;
|
|
|
|
public envFilePathAbsolute: string;
|
|
|
|
|
2020-06-08 18:58:43 +00:00
|
|
|
constructor(qenvFileBasePathArg = process.cwd(), envFileBasePathArg, failOnMissing = true) {
|
2019-01-06 00:30:07 +00:00
|
|
|
// lets make sure paths are absolute
|
2019-01-12 23:00:32 +00:00
|
|
|
this.qenvFilePathAbsolute = plugins.path.join(
|
|
|
|
plugins.path.resolve(qenvFileBasePathArg),
|
|
|
|
'qenv.yml'
|
|
|
|
);
|
|
|
|
this.envFilePathAbsolute = plugins.path.join(
|
|
|
|
plugins.path.resolve(envFileBasePathArg),
|
2019-08-06 15:41:45 +00:00
|
|
|
'env.json'
|
2019-01-12 23:00:32 +00:00
|
|
|
);
|
2019-01-06 00:30:07 +00:00
|
|
|
|
|
|
|
this.getRequiredEnvVars();
|
|
|
|
this.getAvailableEnvVars();
|
|
|
|
|
|
|
|
this.missingEnvVars = this.getMissingEnvVars();
|
2017-05-12 16:17:22 +00:00
|
|
|
|
|
|
|
// handle missing variables
|
|
|
|
if (this.missingEnvVars.length > 0) {
|
2018-08-12 22:09:37 +00:00
|
|
|
console.info('Required Env Vars are:');
|
|
|
|
console.log(this.requiredEnvVars);
|
|
|
|
console.error('However some Env variables could not be resolved:');
|
|
|
|
console.log(this.missingEnvVars);
|
2017-05-12 16:17:22 +00:00
|
|
|
if (failOnMissing) {
|
2019-08-29 12:29:16 +00:00
|
|
|
this.logger.log('error', 'Exiting!');
|
2018-08-12 22:09:37 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-12 23:00:32 +00:00
|
|
|
/**
|
|
|
|
* only gets an environment variable if it is required within a read qenv.yml file
|
|
|
|
* @param envVarName
|
|
|
|
*/
|
|
|
|
public getEnvVarRequired(envVarName): string {
|
2019-01-15 22:54:29 +00:00
|
|
|
return this.keyValueObject[envVarName];
|
2017-05-12 16:17:22 +00:00
|
|
|
}
|
2019-01-06 00:30:07 +00:00
|
|
|
|
2019-01-12 23:00:32 +00:00
|
|
|
/**
|
|
|
|
* tries to get any env var even if it is not required
|
2019-09-13 09:20:47 +00:00
|
|
|
* @param wantedEnvVar
|
2019-01-12 23:00:32 +00:00
|
|
|
*/
|
2019-09-13 09:20:47 +00:00
|
|
|
public getEnvVarOnDemand(wantedEnvVar: string): string {
|
|
|
|
let envVarFromEnvironmentVariable: string;
|
|
|
|
let envVarFromEnvJsonFile: string;
|
|
|
|
let envVarFromDockerSecret: string;
|
2019-01-12 23:00:32 +00:00
|
|
|
let dockerSecretJson: string;
|
|
|
|
|
|
|
|
// env var check
|
2019-09-13 09:20:47 +00:00
|
|
|
if (process.env[wantedEnvVar]) {
|
|
|
|
this.availableEnvVars.push(wantedEnvVar);
|
|
|
|
envVarFromEnvironmentVariable = process.env[wantedEnvVar];
|
2019-01-12 23:00:32 +00:00
|
|
|
}
|
2019-01-06 00:30:07 +00:00
|
|
|
|
2019-01-12 23:00:32 +00:00
|
|
|
// env file check
|
2019-09-13 09:20:47 +00:00
|
|
|
// lets determine the actual env yml
|
|
|
|
let envJsonFileAsObject;
|
|
|
|
try {
|
|
|
|
envJsonFileAsObject = plugins.smartfile.fs.toObjectSync(this.envFilePathAbsolute);
|
|
|
|
} catch (err) {
|
|
|
|
envJsonFileAsObject = {};
|
|
|
|
}
|
|
|
|
if (envJsonFileAsObject.hasOwnProperty(wantedEnvVar)) {
|
|
|
|
envVarFromEnvJsonFile = envJsonFileAsObject[wantedEnvVar];
|
2019-01-12 23:00:32 +00:00
|
|
|
}
|
2019-01-06 00:30:07 +00:00
|
|
|
|
2019-01-12 23:00:32 +00:00
|
|
|
// docker secret check
|
|
|
|
if (
|
|
|
|
plugins.smartfile.fs.isDirectory('/run') &&
|
|
|
|
plugins.smartfile.fs.isDirectory('/run/secrets') &&
|
2019-09-13 09:20:47 +00:00
|
|
|
plugins.smartfile.fs.fileExistsSync(`/run/secrets/${wantedEnvVar}`)
|
2019-01-12 23:00:32 +00:00
|
|
|
) {
|
2019-09-13 09:20:47 +00:00
|
|
|
envVarFromDockerSecret = plugins.smartfile.fs.toStringSync(`/run/secrets/${wantedEnvVar}`);
|
2019-01-12 23:00:32 +00:00
|
|
|
}
|
2019-01-06 00:30:07 +00:00
|
|
|
|
2019-01-12 23:00:32 +00:00
|
|
|
// docker secret.json
|
|
|
|
if (
|
|
|
|
plugins.smartfile.fs.isDirectory('/run') &&
|
2019-01-14 00:54:04 +00:00
|
|
|
plugins.smartfile.fs.isDirectory('/run/secrets')
|
2019-01-12 23:00:32 +00:00
|
|
|
) {
|
2019-01-14 00:54:04 +00:00
|
|
|
const availableSecrets = plugins.smartfile.fs.listAllItemsSync('/run/secrets');
|
|
|
|
for (const secret of availableSecrets) {
|
2019-09-13 09:20:47 +00:00
|
|
|
if (secret.includes('secret.json') && !envVarFromDockerSecret) {
|
2019-01-14 21:42:24 +00:00
|
|
|
const secretObject = plugins.smartfile.fs.toObjectSync(`/run/secrets/${secret}`);
|
2019-09-13 09:20:47 +00:00
|
|
|
envVarFromDockerSecret = secretObject[wantedEnvVar];
|
2019-01-14 00:54:04 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-12 23:00:32 +00:00
|
|
|
}
|
2019-01-06 00:30:07 +00:00
|
|
|
|
2019-01-12 23:00:32 +00:00
|
|
|
// warn if there is more than one candidate
|
2019-09-13 09:20:47 +00:00
|
|
|
const availableCcandidates: any[] = [];
|
|
|
|
[
|
|
|
|
envVarFromEnvironmentVariable,
|
|
|
|
envVarFromEnvJsonFile,
|
|
|
|
envVarFromDockerSecret,
|
|
|
|
dockerSecretJson
|
|
|
|
].forEach(candidate => {
|
2019-01-12 23:00:32 +00:00
|
|
|
if (candidate) {
|
2019-09-13 09:20:47 +00:00
|
|
|
availableCcandidates.push(candidate);
|
2019-01-06 00:30:07 +00:00
|
|
|
}
|
2019-01-12 23:00:32 +00:00
|
|
|
});
|
2019-09-13 09:20:47 +00:00
|
|
|
if (availableCcandidates.length > 1) {
|
2019-01-12 23:00:32 +00:00
|
|
|
this.logger.log(
|
|
|
|
'warn',
|
2019-09-13 09:20:47 +00:00
|
|
|
`found multiple candidates for ${wantedEnvVar} Choosing in the order of envVar, envFileVar, dockerSecret, dockerSecretJson`
|
2019-01-12 23:00:32 +00:00
|
|
|
);
|
2019-09-13 09:20:47 +00:00
|
|
|
console.log(availableCcandidates);
|
2019-01-12 23:00:32 +00:00
|
|
|
}
|
|
|
|
|
2019-09-13 09:20:47 +00:00
|
|
|
switch (true) {
|
|
|
|
case !!envVarFromEnvironmentVariable:
|
|
|
|
this.logger.log('ok', `found ${wantedEnvVar} as environment variable`);
|
|
|
|
return envVarFromEnvironmentVariable;
|
|
|
|
case !!envVarFromEnvJsonFile:
|
|
|
|
this.logger.log('ok', `found ${wantedEnvVar} as env.json variable`);
|
|
|
|
return envVarFromEnvJsonFile;
|
|
|
|
case !!envVarFromDockerSecret:
|
|
|
|
this.logger.log('ok', `found ${wantedEnvVar} as docker secret`);
|
|
|
|
return envVarFromDockerSecret;
|
|
|
|
case !!dockerSecretJson:
|
|
|
|
this.logger.log('ok', `found ${wantedEnvVar} as docker secret.json`);
|
|
|
|
return dockerSecretJson;
|
|
|
|
default:
|
|
|
|
this.logger.log(
|
|
|
|
'warn',
|
|
|
|
`could not find the wanted environment variable ${wantedEnvVar} anywhere`
|
|
|
|
);
|
|
|
|
return;
|
2019-01-12 23:00:32 +00:00
|
|
|
}
|
2019-01-06 00:30:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gets the required env values
|
|
|
|
*/
|
|
|
|
private getRequiredEnvVars = () => {
|
2019-01-12 23:00:32 +00:00
|
|
|
let qenvFile: any = {};
|
|
|
|
if (plugins.smartfile.fs.fileExistsSync(this.qenvFilePathAbsolute)) {
|
2019-01-06 02:36:40 +00:00
|
|
|
qenvFile = plugins.smartfile.fs.toObjectSync(this.qenvFilePathAbsolute);
|
2019-01-06 00:30:07 +00:00
|
|
|
}
|
2019-01-06 02:36:40 +00:00
|
|
|
if (!qenvFile || !qenvFile.required || !Array.isArray(qenvFile.required)) {
|
2019-09-13 09:20:47 +00:00
|
|
|
this.logger.log(
|
|
|
|
'warn',
|
2019-10-01 10:32:39 +00:00
|
|
|
`qenv (promised environment): ./qenv.yml File does not contain a 'required' Array! This might be ok though.`
|
2019-09-13 09:20:47 +00:00
|
|
|
);
|
2019-01-06 02:36:40 +00:00
|
|
|
} else {
|
|
|
|
for (const keyArg of Object.keys(qenvFile.required)) {
|
|
|
|
this.requiredEnvVars.push(qenvFile.required[keyArg]);
|
|
|
|
}
|
2019-01-06 00:30:07 +00:00
|
|
|
}
|
2019-09-13 09:20:47 +00:00
|
|
|
};
|
2019-01-06 00:30:07 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* gets the available env vars
|
|
|
|
*/
|
|
|
|
private getAvailableEnvVars = () => {
|
|
|
|
for (const requiredEnvVar of this.requiredEnvVars) {
|
|
|
|
const chosenVar = this.getEnvVarOnDemand(requiredEnvVar);
|
|
|
|
if (chosenVar) {
|
|
|
|
this.availableEnvVars.push(requiredEnvVar);
|
2019-01-15 22:54:29 +00:00
|
|
|
this.keyValueObject[requiredEnvVar] = chosenVar;
|
2019-01-06 00:30:07 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-06 15:37:07 +00:00
|
|
|
};
|
2019-01-06 00:30:07 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* gets missing env vars
|
|
|
|
*/
|
|
|
|
private getMissingEnvVars = (): string[] => {
|
|
|
|
const missingEnvVars: string[] = [];
|
|
|
|
for (const envVar of this.requiredEnvVars) {
|
|
|
|
if (!this.availableEnvVars.includes(envVar)) {
|
|
|
|
missingEnvVars.push(envVar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return missingEnvVars;
|
2019-01-14 00:54:04 +00:00
|
|
|
};
|
2017-05-12 16:17:22 +00:00
|
|
|
}
|