lenv-cli
v2.1.4
Published
![](./cover.png)
Downloads
4
Readme
Install
NPM
$ npm install --global lenv-cli
YARN
$ yarn global add lenv-cli
Run
$ lenv
What is LENV?
LENV is a CLI tool which allows to configure and build docker-compose file from modules, secrets and automation artifacts.
What is module?
Module is a small piece of configuration. It may contain multiple configuration variants. For example local, staging and production. End user of LENV CLI has to select which modules to run and configuration variant for each module. LENV will resolve dependencies and use all required modules to build docker-compose file.
How to create a module?
Modules are built from multiple files. At least two files are required:
- Module declaration file
./modules/MODULE_DIR/*.module.js
- Module configuration variant
./modules/MODULE_DIR/configs/*.js
Module declaration file has only two fields:
module.exports = {
name: "mongodb", // module name
defaultConfig: "local", // default configuration variant
};
Module configuration variant:
module.exports = {
name: "local", // variant name
requires: [
/*
Array of dependencies.
Values are names of other modules.
(optional)
*/
],
jobs: [
/*
Array of jobs required for this configuration.
Values are names of other modules.
(optional)
*/
],
output: {
/*
Object with exported variables
which other modules may use
(optional)
*/
},
docker: {
/*
This object will be merged into the final
docker-compose file
(optional)
*/
},
};
How to share variables between modules?
There are to steps.
- Export values from one module
- Import values in another
How to export values?
Add them into the output section
module.exports = {
name: "local", // variant name
output: {
host: "mongodb"
},
};
How to import values?
We can use values from other modules inside two sections:
- output
- docker
There is a function getVar
. Input of the function is a string MODULE_NAME.VARIABLE_NAME
. Output is a Promise.
Example of usage:
module.exports = {
name: "local", // variant name
requires: [
"mongodb",
],
docker: {
services: {
api: {
/* ....... */
environment: {
DB_HOST: ({ getVar }) => getVar("mongodb.host")
}
/* ....... */
}
}
},
};
If some transformations to the value are required there are two options to implement them:
- Promise
.then
- async/await
Important!
Don’t forget to add module into the requires section.
When to use dependencies?
There are two main reasons to add module as a dependency:
- To be able to use exported variables (output) from another module.
- To enable module and to include it into the final docker-compose file.
How to add custom logic?
All configurations are unique and sometimes there is a requirement to add custom logic into the configuration process. There are two options to do this:
- Jobs
- Custom functions
What are Jobs?
During build process LENV CLI runs some code which is grouped into the Jobs. Jobs are grouped into the Stages.
Out of the box there are two stages:
- build
- run
And two jobs:
- docker-compose
- docker-compose up One job in one stage.
LENV runs all jobs in one stage simultaneously. LENV will not continue to the next stage in case not all of the jobs from the current stage have Success state.
A few examples for jobs:
- Check that code repository is cloned
- Check that
/etc/hosts
contains required records - There is a dynamic configuration which requires user input or manual actions
How to add Stages?
LENV checks for stages inside lenv.config.js
.
module.exports={
runStages:[
"prepare",
"build",
"run"
]
}
In case file doesn’t exist the default fallback is:
module.exports={
runStages:[
"build",
"run"
]
}
Note
It is possible to completely replace list of stages, but:
- if
build
stage doesn’t exist LENV will not create docker-compose file - if
run
stage doesn’t exist LENV will not run containers automatically
How to add Jobs?
LENV looks for jobs at ./jobs/*.job.js
module.exports = {
name: "check-sources", // job name
stage: "prepare", // stage to run the job
requires: [
/*
Array of dependencies.
Values are names of other modules.
(optional)
*/
],
jobs: [
/*
Array of jobs required for this configuration.
Values are names of other modules.
(optional)
*/
],
body: (params) => {
// code to be executed inside JS function
}
};
requires
and jobs
sections are identical to the same sections in modules. More information here
body
is a simple JS function which receives object with parameters:
interface Params {
/*
log, error and info allows to log message to the job's
output with different level
*/
log: (msg: string) => void,
error: (msg: string) => void,
info: (msg: string) => void,
/*
adds log to the job's output and updates job status to
'success'
*/
success: (msg?: string) => void,
/*
adds log to the job's output and updates job status to
'failed'
*/
fail: (msg?: string) => void,
/*
updates job status to 'waiting'
user has to enter string to continue
*/
textInput: () => Promise<string>,
/*
array of all parameters passed to the job
*/
args: any[]
/*
get and set artifacts
*/
getArtifacts: () => Record<string, any>,
updateArtifacts: (data: Record<string, any>) => void,
}
Artifacts
Artifacts are persistent storage for the jobs. They may be used in modules similar to outputs with getArtifact
function.
module.exports = {
jobs: [
"get-user-token",
{ target: "SERIVCE_NAME" }
],
docker: {
services: {
api: {
/* ....... */
environment: {
SERVICE_TOKEN: ({ getArtifact }) => getArtifact("get-user-token.artifactNameForTheToken")
}
/* ....... */
}
}
},
};
Job example
module.exports = {
name: "get-token",
stage: "prepare",
body: async ({ textInput, updateArtifacts, success }) => {
const token = await textInput();
updateArtifacts({ token });
success();
}
};
More job examples here (TBD)
What are custom functions?
TBD
How does LENV resolve dependencies (requires, jobs)?
TBD