|
|
@ -5,6 +5,10 @@ export interface IKeyValueObject {
|
|
|
|
value: string;
|
|
|
|
value: string;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* class Qenv
|
|
|
|
|
|
|
|
* allows to make assertions about the environments while being more flexibel in how to meet them
|
|
|
|
|
|
|
|
*/
|
|
|
|
export class Qenv {
|
|
|
|
export class Qenv {
|
|
|
|
public requiredEnvVars: string[] = [];
|
|
|
|
public requiredEnvVars: string[] = [];
|
|
|
|
public availableEnvVars: string[] = [];
|
|
|
|
public availableEnvVars: string[] = [];
|
|
|
@ -25,8 +29,14 @@ export class Qenv {
|
|
|
|
this.logger = loggerArg;
|
|
|
|
this.logger = loggerArg;
|
|
|
|
|
|
|
|
|
|
|
|
// lets make sure paths are absolute
|
|
|
|
// lets make sure paths are absolute
|
|
|
|
this.qenvFilePathAbsolute = plugins.path.join(plugins.path.resolve(qenvFileBasePathArg), 'qenv.yml');
|
|
|
|
this.qenvFilePathAbsolute = plugins.path.join(
|
|
|
|
this.envFilePathAbsolute = plugins.path.join(plugins.path.resolve(envFileBasePathArg), 'env.yml');
|
|
|
|
plugins.path.resolve(qenvFileBasePathArg),
|
|
|
|
|
|
|
|
'qenv.yml'
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
this.envFilePathAbsolute = plugins.path.join(
|
|
|
|
|
|
|
|
plugins.path.resolve(envFileBasePathArg),
|
|
|
|
|
|
|
|
'env.yml'
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
this.getRequiredEnvVars();
|
|
|
|
this.getRequiredEnvVars();
|
|
|
|
this.getAvailableEnvVars();
|
|
|
|
this.getAvailableEnvVars();
|
|
|
@ -46,22 +56,30 @@ export class Qenv {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public getEnvVar(envVarName): string {
|
|
|
|
/**
|
|
|
|
|
|
|
|
* only gets an environment variable if it is required within a read qenv.yml file
|
|
|
|
|
|
|
|
* @param envVarName
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public getEnvVarRequired(envVarName): string {
|
|
|
|
return process.env[envVarName];
|
|
|
|
return process.env[envVarName];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* tries to get any env var even if it is not required
|
|
|
|
|
|
|
|
* @param requiredEnvVar
|
|
|
|
|
|
|
|
*/
|
|
|
|
public getEnvVarOnDemand(requiredEnvVar: string): string {
|
|
|
|
public getEnvVarOnDemand(requiredEnvVar: string): string {
|
|
|
|
// lets determine the actual env yml
|
|
|
|
// lets determine the actual env yml
|
|
|
|
let envYml;
|
|
|
|
let envYml;
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
envYml = plugins.smartfile.fs.toObjectSync(this.envFilePathAbsolute);
|
|
|
|
envYml = plugins.smartfile.fs.toObjectSync(this.envFilePathAbsolute);
|
|
|
|
} catch (err) {
|
|
|
|
} catch (err) {
|
|
|
|
console.log("env file couldn't be found at " + this.envFilePathAbsolute);
|
|
|
|
|
|
|
|
envYml = {};
|
|
|
|
envYml = {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let envVar: string;
|
|
|
|
let envVar: string;
|
|
|
|
let envFileVar: string;
|
|
|
|
let envFileVar: string;
|
|
|
|
let dockerSecret: string;
|
|
|
|
let dockerSecret: string;
|
|
|
|
|
|
|
|
let dockerSecretJson: string;
|
|
|
|
|
|
|
|
|
|
|
|
// env var check
|
|
|
|
// env var check
|
|
|
|
if (process.env[requiredEnvVar]) {
|
|
|
|
if (process.env[requiredEnvVar]) {
|
|
|
@ -74,28 +92,53 @@ export class Qenv {
|
|
|
|
envFileVar = envYml[requiredEnvVar];
|
|
|
|
envFileVar = envYml[requiredEnvVar];
|
|
|
|
this.availableEnvVars.push(requiredEnvVar);
|
|
|
|
this.availableEnvVars.push(requiredEnvVar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// docker secret check
|
|
|
|
if (
|
|
|
|
if (
|
|
|
|
plugins.smartfile.fs.isDirectory('/run') &&
|
|
|
|
plugins.smartfile.fs.isDirectory('/run') &&
|
|
|
|
plugins.smartfile.fs.isDirectory('/run/secrets') &&
|
|
|
|
plugins.smartfile.fs.isDirectory('/run/secrets') &&
|
|
|
|
plugins.smartfile.fs.fileExists(`/run/secrets/${requiredEnvVar}`)
|
|
|
|
plugins.smartfile.fs.fileExistsSync(`/run/secrets/${requiredEnvVar}`)
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
dockerSecret = plugins.smartfile.fs.toStringSync(`/run/secrets/${requiredEnvVar}`);
|
|
|
|
dockerSecret = plugins.smartfile.fs.toStringSync(`/run/secrets/${requiredEnvVar}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ((envVar && envFileVar) || (envVar && dockerSecret) || (envFileVar && dockerSecret)) {
|
|
|
|
// docker secret.json
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
|
|
|
plugins.smartfile.fs.isDirectory('/run') &&
|
|
|
|
|
|
|
|
plugins.smartfile.fs.isDirectory('/run/secrets') &&
|
|
|
|
|
|
|
|
plugins.smartfile.fs.fileExistsSync(`/run/secrets/secret.json`)
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
const secretObject = plugins.smartfile.fs.toObjectSync('/run/secrets/secret.json');
|
|
|
|
|
|
|
|
dockerSecret = secretObject[requiredEnvVar];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// warn if there is more than one candidate
|
|
|
|
|
|
|
|
let candidatesCounter = 0;
|
|
|
|
|
|
|
|
[envVar, envFileVar, dockerSecret, dockerSecretJson].forEach(candidate => {
|
|
|
|
|
|
|
|
if (candidate) {
|
|
|
|
|
|
|
|
candidatesCounter++;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
if (candidatesCounter > 1) {
|
|
|
|
this.logger.log(
|
|
|
|
this.logger.log(
|
|
|
|
'warn',
|
|
|
|
'warn',
|
|
|
|
`found multiple candidates for ${requiredEnvVar} Choosing in the order of envVar, envFileVar, dockerSecret`
|
|
|
|
`found multiple candidates for ${requiredEnvVar} Choosing in the order of envVar, envFileVar, dockerSecret, dockerSecretJson`
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let chosenVar: string = null;
|
|
|
|
let chosenVar: string = null;
|
|
|
|
if (envVar) {
|
|
|
|
if (envVar) {
|
|
|
|
|
|
|
|
this.logger.log('ok', `found ${requiredEnvVar} as environment variable`);
|
|
|
|
chosenVar = envVar;
|
|
|
|
chosenVar = envVar;
|
|
|
|
} else if (envFileVar) {
|
|
|
|
} else if (envFileVar) {
|
|
|
|
|
|
|
|
this.logger.log('ok', `found ${requiredEnvVar} as env.yml variable`);
|
|
|
|
chosenVar = envFileVar;
|
|
|
|
chosenVar = envFileVar;
|
|
|
|
} else if (dockerSecret) {
|
|
|
|
} else if (dockerSecret) {
|
|
|
|
|
|
|
|
this.logger.log('ok', `found ${requiredEnvVar} as docker secret`);
|
|
|
|
chosenVar = dockerSecret;
|
|
|
|
chosenVar = dockerSecret;
|
|
|
|
|
|
|
|
} else if (dockerSecretJson) {
|
|
|
|
|
|
|
|
this.logger.log('ok', `found ${requiredEnvVar} as docker secret.json`);
|
|
|
|
|
|
|
|
chosenVar = dockerSecretJson;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return chosenVar;
|
|
|
|
return chosenVar;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -115,13 +158,12 @@ export class Qenv {
|
|
|
|
this.requiredEnvVars.push(qenvFile.required[keyArg]);
|
|
|
|
this.requiredEnvVars.push(qenvFile.required[keyArg]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* gets the available env vars
|
|
|
|
* gets the available env vars
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private getAvailableEnvVars = () => {
|
|
|
|
private getAvailableEnvVars = () => {
|
|
|
|
|
|
|
|
|
|
|
|
for (const requiredEnvVar of this.requiredEnvVars) {
|
|
|
|
for (const requiredEnvVar of this.requiredEnvVars) {
|
|
|
|
const chosenVar = this.getEnvVarOnDemand(requiredEnvVar);
|
|
|
|
const chosenVar = this.getEnvVarOnDemand(requiredEnvVar);
|
|
|
|
if (chosenVar) {
|
|
|
|
if (chosenVar) {
|
|
|
@ -133,7 +175,7 @@ export class Qenv {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* gets missing env vars
|
|
|
|
* gets missing env vars
|
|
|
@ -146,5 +188,5 @@ export class Qenv {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return missingEnvVars;
|
|
|
|
return missingEnvVars;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|