main.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import logging
  2. import re
  3. from inspect import getdoc
  4. from .. import __version__
  5. from .command import Command
  6. from .formatter import Formatter
  7. from .log_printer import LogPrinter
  8. from docker.client import APIError
  9. from .errors import UserError
  10. from .docopt_command import NoSuchCommand
  11. log = logging.getLogger(__name__)
  12. def main():
  13. console_handler = logging.StreamHandler()
  14. console_handler.setFormatter(logging.Formatter())
  15. console_handler.setLevel(logging.INFO)
  16. root_logger = logging.getLogger()
  17. root_logger.addHandler(console_handler)
  18. root_logger.setLevel(logging.DEBUG)
  19. # Disable requests logging
  20. logging.getLogger("requests").propagate = False
  21. try:
  22. command = TopLevelCommand()
  23. command.sys_dispatch()
  24. except KeyboardInterrupt:
  25. log.error("\nAborting.")
  26. exit(1)
  27. except UserError, e:
  28. log.error(e.msg)
  29. exit(1)
  30. except NoSuchCommand, e:
  31. log.error("No such command: %s", e.command)
  32. log.error("")
  33. log.error("\n".join(parse_doc_section("commands:", getdoc(e.supercommand))))
  34. exit(1)
  35. except APIError, e:
  36. log.error(e.explanation)
  37. exit(1)
  38. # stolen from docopt master
  39. def parse_doc_section(name, source):
  40. pattern = re.compile('^([^\n]*' + name + '[^\n]*\n?(?:[ \t].*?(?:\n|$))*)',
  41. re.IGNORECASE | re.MULTILINE)
  42. return [s.strip() for s in pattern.findall(source)]
  43. class TopLevelCommand(Command):
  44. """.
  45. Usage:
  46. plum [options] [COMMAND] [ARGS...]
  47. plum -h|--help
  48. Options:
  49. --verbose Show more output
  50. --version Print version and exit
  51. Commands:
  52. ps List services and containers
  53. run Run a one-off command
  54. start Start services
  55. stop Stop services
  56. """
  57. def ps(self, options):
  58. """
  59. List services and containers.
  60. Usage: ps [options]
  61. Options:
  62. -q Only display IDs
  63. """
  64. if options['-q']:
  65. for container in self.service_collection.containers(all=True):
  66. print container.id
  67. else:
  68. headers = [
  69. 'Name',
  70. 'Command',
  71. 'State',
  72. 'Ports',
  73. ]
  74. rows = []
  75. for container in self.service_collection.containers(all=True):
  76. rows.append([
  77. container.name,
  78. container.human_readable_command,
  79. container.human_readable_state,
  80. container.human_readable_ports,
  81. ])
  82. print Formatter().table(headers, rows)
  83. def run(self, options):
  84. """
  85. Run a one-off command.
  86. Usage: run SERVICE COMMAND [ARGS...]
  87. """
  88. service = self.service_collection.get(options['SERVICE'])
  89. if service is None:
  90. raise UserError("No such service: %s" % options['SERVICE'])
  91. container_options = {
  92. 'command': [options['COMMAND']] + options['ARGS'],
  93. }
  94. container = service.create_container(**container_options)
  95. stream = container.logs(stream=True)
  96. service.start_container(container, ports=None)
  97. for data in stream:
  98. if data is None:
  99. break
  100. print data
  101. def start(self, options):
  102. """
  103. Start all services
  104. Usage: start [-d]
  105. """
  106. if options['-d']:
  107. self.service_collection.start()
  108. return
  109. running = []
  110. unstarted = []
  111. for s in self.service_collection:
  112. if len(s.containers()) == 0:
  113. unstarted.append((s, s.create_container()))
  114. else:
  115. running += s.containers(all=False)
  116. log_printer = LogPrinter(running + [c for (s, c) in unstarted])
  117. for (s, c) in unstarted:
  118. s.start_container(c)
  119. try:
  120. log_printer.run()
  121. finally:
  122. self.service_collection.stop()
  123. def stop(self, options):
  124. """
  125. Stop all services
  126. Usage: stop
  127. """
  128. self.service_collection.stop()
  129. def logs(self, options):
  130. """
  131. View containers' output
  132. Usage: logs
  133. """
  134. containers = self.service_collection.containers(all=False)
  135. print "Attaching to", list_containers(containers)
  136. LogPrinter(containers, attach_params={'logs': True}).run()
  137. def list_containers(containers):
  138. return ", ".join(c.name for c in containers)