portainer.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #!/usr/bin/env node
  2. const { createClient } = require('../lib/client')
  3. const getConfig = require('microservice-config')
  4. const passwordPrompt = require('password-prompt')
  5. const asTable = require('as-table')
  6. const Vorpal = require('vorpal')
  7. const main = async() => {
  8. const vorpal = new Vorpal()
  9. function log(...args) { vorpal.activeCommand.log(...args) }
  10. const fillModel = async model => {
  11. if (!model.options) model.options = {}
  12. model.options.username = model.options.username || process.env.PORTAINER_USERNAME
  13. if (!model.options.username) throw new Error('Username is required.')
  14. model.options.password = model.options.password || process.env.PORTAINER_PASSWORD || await passwordPrompt('Password: ', {method: 'hide'})
  15. if (!model.options.password) throw new Error('Password is required.')
  16. model.options.url = model.options.url || process.env.PORTAINER_URL
  17. if (!model.options.url) throw new Error('URL is required.')
  18. if (model.options.verbose) {
  19. log('options', JSON.stringify({
  20. ...model,
  21. options: {
  22. ...model.options,
  23. password: '******'
  24. }
  25. }, null, 4))
  26. }
  27. }
  28. const command = commandSpec => vorpal.command(commandSpec)
  29. .option('-v, --verbose', 'Enable verbose logging')
  30. .option('-u, --username <username>', 'Portainer username. Defaults to environment variable PORTAINER_USERNAME.')
  31. .option('-p, --password <password>', 'Portainer password. Defaults to environment variable PORTAINER_PASSWORD.')
  32. .option('-r, --url <url>', 'Portainer URL, such as http://server:9000. Defaults to environment variable PORTAINER_URL.')
  33. .option('-k, --insecure', 'Ignore certificate errors.')
  34. .option('-j, --json', 'Format JSON.')
  35. const action = handler => async function(model, cb) {
  36. try {
  37. await fillModel(model)
  38. if (model.options.insecure) {
  39. process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0
  40. }
  41. const client = createClient({
  42. log,
  43. ...model.options
  44. })
  45. const result = await handler(client, model)
  46. if (result) {
  47. if (!model.options.json) {
  48. if (Array.isArray(result)) {
  49. log(asTable(result))
  50. } else {
  51. log(asTable([result]))
  52. }
  53. } else {
  54. log(JSON.stringify(result))
  55. }
  56. }
  57. cb()
  58. } catch (err) {
  59. console.warn(err.message || err)
  60. process.exit(1)
  61. }
  62. }
  63. command('stack deploy <name>', 'Creates or updates a stack.')
  64. .option('-c, --compose-file <compose_file>', 'Path to docker-compose.yml file. Defaults to ./docker-compose.yml.')
  65. .option('-P, --prune', 'Prune obsolete or orphaned containers. Defaults to true.')
  66. .option('-W, --warning', 'Add warning message to head of yaml. Defaults to true.')
  67. .action(action(async (client, model) => {
  68. if (model.options.prune === undefined) model.options.prune = true
  69. if (model.options.warning === undefined) model.options.warning = true
  70. if (model.options['compose-file'] === undefined) model.options['compose-file'] = 'docker-compose.yml'
  71. log('Upserting stack')
  72. return await client.upsertStack({
  73. stackFile: model.options['compose-file'],
  74. ...model,
  75. ...model.options
  76. })
  77. }))
  78. command('stack ls', 'List stacks')
  79. .action(action(async (client, model) => await client.getStacks()))
  80. command('stack rm <name>', 'Removes a stack')
  81. .action(action(async (client, model) => await client.deleteStack(model)))
  82. command('endpoint ls', 'List endpoints')
  83. .action(action(async (client, model) => await client.getEndpoints()))
  84. const args = process.argv.length === 2 ? [...process.argv, 'help'] : process.argv
  85. await vorpal.parse(args).catch(err => {
  86. console.error(err)
  87. process.exit(1)
  88. })
  89. }
  90. main().catch(err => {
  91. console.error(err)
  92. process.exit(1)
  93. })