| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- #!/usr/bin/env node
- const { createClient } = require('../lib/client')
- const getConfig = require('microservice-config')
- const passwordPrompt = require('password-prompt')
- const asTable = require('as-table')
- const Vorpal = require('vorpal')
- const main = async() => {
- const vorpal = new Vorpal()
- function log(...args) { vorpal.activeCommand.log(...args) }
- const fillModel = async model => {
- if (!model.options) model.options = {}
- model.options.username = model.options.username || process.env.PORTAINER_USERNAME
- if (!model.options.username) throw new Error('Username is required.')
- model.options.password = model.options.password || process.env.PORTAINER_PASSWORD || await passwordPrompt('Password: ', {method: 'hide'})
- if (!model.options.password) throw new Error('Password is required.')
- model.options.url = model.options.url || process.env.PORTAINER_URL
- if (!model.options.url) throw new Error('URL is required.')
- if (model.options.verbose) {
- log('options', JSON.stringify({
- ...model,
- options: {
- ...model.options,
- password: '******'
- }
- }, null, 4))
- }
- }
-
- const command = commandSpec => vorpal.command(commandSpec)
- .option('-v, --verbose', 'Enable verbose logging')
- .option('-u, --username <username>', 'Portainer username. Defaults to environment variable PORTAINER_USERNAME.')
- .option('-p, --password <password>', 'Portainer password. Defaults to environment variable PORTAINER_PASSWORD.')
- .option('-r, --url <url>', 'Portainer URL, such as http://server:9000. Defaults to environment variable PORTAINER_URL.')
- .option('-k, --insecure', 'Ignore certificate errors.')
- .option('-j, --json', 'Format JSON.')
- const action = handler => async function(model, cb) {
- try {
- await fillModel(model)
- if (model.options.insecure) {
- process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0
- }
- const client = createClient({
- log,
- ...model.options
- })
- const result = await handler(client, model)
- if (result) {
- if (!model.options.json) {
- if (Array.isArray(result)) {
- log(asTable(result))
- } else {
- log(asTable([result]))
- }
- } else {
- log(JSON.stringify(result))
- }
- }
- cb()
- } catch (err) {
- console.warn(err.message || err)
- process.exit(1)
- }
- }
- command('stack deploy <name>', 'Creates or updates a stack.')
- .option('-c, --compose-file <compose_file>', 'Path to docker-compose.yml file. Defaults to ./docker-compose.yml.')
- .option('-P, --prune', 'Prune obsolete or orphaned containers. Defaults to true.')
- .option('-W, --warning', 'Add warning message to head of yaml. Defaults to true.')
- .action(action(async (client, model) => {
- if (model.options.prune === undefined) model.options.prune = true
- if (model.options.warning === undefined) model.options.warning = true
- if (model.options['compose-file'] === undefined) model.options['compose-file'] = 'docker-compose.yml'
- log('Upserting stack')
- return await client.upsertStack({
- stackFile: model.options['compose-file'],
- ...model,
- ...model.options
- })
- }))
- command('stack ls', 'List stacks')
- .action(action(async (client, model) => await client.getStacks()))
- command('stack rm <name>', 'Removes a stack')
- .action(action(async (client, model) => await client.deleteStack(model)))
- command('endpoint ls', 'List endpoints')
- .action(action(async (client, model) => await client.getEndpoints()))
- const args = process.argv.length === 2 ? [...process.argv, 'help'] : process.argv
- await vorpal.parse(args).catch(err => {
- console.error(err)
- process.exit(1)
- })
- }
- main().catch(err => {
- console.error(err)
- process.exit(1)
- })
|