Currently I'm trying to create a docker image that will setup some things in our environment.
If the user pass the --interactive parameter the idea is to spin up the container and show an interactive sheel to select which options you want to run, for example
Ex:
- Run Full Setup
- Create Database
- Create Database User
I've made the logic to check if is interactive mode or not, but when is interactive I'm not able to pass the desired option.
Even when I run the container in attached mode.
The only way I'm able to do that is connect to the container throught Docker Desktop terminal and run the script by hand using the function runInteractiveSetupUserNeedsToConnectToContainer
Is there anyway that i could run the interactive menu when user is connected to docker container terminal?
I mean, this command do the job
docker exec -it setup node /app/interactive.js
But I wanted the same behavior without needing to pass node /app/interactive.js
Commands that I've already tried to use
docker-compose up --attach setup
docker-compose up
docker exec -it setup node /app/interactive.js #this way works but i need to pass the command to run
I'll attach here a simpler version of the code that I'm using the function
FROM node
WORKDIR /app
COPY ./package.json .
COPY ./interactive.js .
WORKDIR /app/modules
COPY ./modules .
WORKDIR /app
RUN apt update && apt install -y curl jq iputils-ping traceroute lsb-release && \
npm install && \
ln -sf /bin/bash /bin/sh]
ENTRYPOINT ["node","/app/modules/main.js"]
CMD [ "$*" ]
version: "3.9"
services:
setup:
image: setup
build:
context: .
dockerfile: Dockerfile
command: --interactive
volumes:
- ./interactive.js:/app/interactive.js
- ./package.json:/app/package.json
- ./modules:/app/modules
stdin_open: true
tty: true
modules
interactive menu
function createAndStartMenu(){
const menu = require('node-menu');
const setup = require('/app/modules/setup.js');
menu.addDelimiter('-', 40, 'Setup')
menu.addItem('Run Full Setup',setup.runFullSetup);
menu.addItem('Create Database',setup.createDatabase);
menu.addItem('Create Database User',setup.createDatabaseUser);
menu.addItem('Stop Setup',async ()=>{
menu.stop();
});
menu.addItem('Finish Interactive Setup Successfully', async ()=>{
console.log("Finishing interactive setup...");
console.log("The application will shutdown with exit code 0, it may take a few seconds...")
process.exit(0);
})
menu.addItem('Finish Interactive Setup With Errors',
async ()=>{
console.log("Finishing interactive setup with errors...");
console.log("The application will shutdown with exit code 1, it may take a few seconds...")
process.exit(1);
}
);
menu.start();
}
module.exports = {
createAndStartMenu
}
main
async function runInteractiveSetupUserNeedsToConnectToContainer(){
console.log("Running interactive setup...");
console.log("To exit press CTRL+C");
console.log("To cancel press CTRL+C twice");
console.log("As you started the application in interactive mode, you may need to take some actions...")
console.log("You can attach to the running container with the following command:")
console.log("docker exec -it <container_name> /bin/bash")
console.log("Or you can connect throught the docker integrated terminal, if so you may need to call the following command:")
console.log("node interactive.js")
let cancellationToken =false;
process.on('SIGINT', function () {
console.log("Cancellation token set to true throught SIGINT...")
cancellationToken = true;
});
setInterval(()=>{
if(cancellationToken) return process.exit(0);
console.log("Waiting for cancellation token...");
},1000);
}
async function runInteractiveSetupWithoutNeedToConnectToContainer(){
console.log("Running interactive setup...");
const interactiveMenu = require('/app/modules/interactiveMenu.js');
interactiveMenu.createAndStartMenu();
}
async function runNonInteractiveSetup(){
console.log("Running non-interactive setup...");
const setup = require('/app/modules/setup.js');
await setup.runFullSetup();
}
async function run(){
const commandLineArgs = require('command-line-args')
const optionsDefinitions=[
{name:'interactive',alias:"i", type:Boolean,defaultOption:false}
];
const options = commandLineArgs(optionsDefinitions)
const interactive = options.interactive;
if(interactive) await runInteractiveSetupUserNeedsToConnectToContainer();
else await runNonInteractiveSetup();
}
run().then(()=>console.log("Setup finished with no errors...")).catch((err)=>console.log(`Setup finished with errors: ${err}`));
setup
async function runFullSetup(){
await createDatabase();
await createDatabaseUser();
}
async function createDatabase(){
console.log('creating database');
};
async function createDatabaseUser(){
console.log('creating user');
};
module.exports= {
runFullSetup,
createDatabase,
createDatabaseUser
}
interactive
const { createAndStartMenu } = require('/app/modules/interactiveMenu.js');
createAndStartMenu();
package.json
{
"dependencies": {
"axios": "^1.4.0",
"command-line-args": "^5.2.1",
"install": "^0.13.0",
"mongodb": "^5.7.0",
"mysql": "^2.18.1",
"node-menu": "^1.3.2",
"npm": "^9.8.0",
"pg": "^8.11.1"
}
}