123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- import logging
- import sys
- import re
- from inspect import getdoc
- from .. import __version__
- from ..project import NoSuchService
- from .command import Command
- from .formatter import Formatter
- from .log_printer import LogPrinter
- from docker.client import APIError
- from .errors import UserError
- from .docopt_command import NoSuchCommand
- from .socketclient import SocketClient
- log = logging.getLogger(__name__)
- def main():
- console_handler = logging.StreamHandler()
- console_handler.setFormatter(logging.Formatter())
- console_handler.setLevel(logging.INFO)
- root_logger = logging.getLogger()
- root_logger.addHandler(console_handler)
- root_logger.setLevel(logging.DEBUG)
- # Disable requests logging
- logging.getLogger("requests").propagate = False
- try:
- command = TopLevelCommand()
- command.sys_dispatch()
- except KeyboardInterrupt:
- log.error("\nAborting.")
- exit(1)
- except UserError, e:
- log.error(e.msg)
- exit(1)
- except NoSuchService, e:
- log.error(e.msg)
- exit(1)
- except NoSuchCommand, e:
- log.error("No such command: %s", e.command)
- log.error("")
- log.error("\n".join(parse_doc_section("commands:", getdoc(e.supercommand))))
- exit(1)
- except APIError, e:
- log.error(e.explanation)
- exit(1)
- # stolen from docopt master
- def parse_doc_section(name, source):
- pattern = re.compile('^([^\n]*' + name + '[^\n]*\n?(?:[ \t].*?(?:\n|$))*)',
- re.IGNORECASE | re.MULTILINE)
- return [s.strip() for s in pattern.findall(source)]
- class TopLevelCommand(Command):
- """.
- Usage:
- fig [options] [COMMAND] [ARGS...]
- fig -h|--help
- Options:
- --verbose Show more output
- --version Print version and exit
- Commands:
- up Create and start containers
- logs View output from containers
- ps List containers
- run Run a one-off command
- start Start services
- stop Stop services
- kill Kill containers
- rm Remove stopped containers
- """
- def docopt_options(self):
- options = super(TopLevelCommand, self).docopt_options()
- options['version'] = "fig %s" % __version__
- return options
- def ps(self, options):
- """
- List containers.
- Usage: ps [options] [SERVICE...]
- Options:
- -q Only display IDs
- """
- containers = self.project.containers(service_names=options['SERVICE'], stopped=True) + self.project.containers(service_names=options['SERVICE'], one_off=True)
- if options['-q']:
- for container in containers:
- print container.id
- else:
- headers = [
- 'Name',
- 'Command',
- 'State',
- 'Ports',
- ]
- rows = []
- for container in containers:
- rows.append([
- container.name,
- container.human_readable_command,
- container.human_readable_state,
- container.human_readable_ports,
- ])
- print Formatter().table(headers, rows)
- def run(self, options):
- """
- Run a one-off command.
- Usage: run [options] SERVICE COMMAND [ARGS...]
- Options:
- -d Detached mode: Run container in the background, print new container name
- """
- service = self.project.get_service(options['SERVICE'])
- container_options = {
- 'command': [options['COMMAND']] + options['ARGS'],
- 'tty': not options['-d'],
- 'stdin_open': not options['-d'],
- }
- container = service.create_container(one_off=True, **container_options)
- if options['-d']:
- service.start_container(container, ports=None)
- print container.name
- else:
- with self._attach_to_container(
- container.id,
- interactive=True,
- logs=True,
- raw=True
- ) as c:
- service.start_container(container, ports=None)
- c.run()
- def up(self, options):
- """
- Create and start containers.
- Usage: up [options] [SERVICE...]
- Options:
- -d Detached mode: Run containers in the background, print new container names
- """
- detached = options['-d']
- unstarted = self.project.create_containers(service_names=options['SERVICE'])
- if not detached:
- to_attach = self.project.containers(service_names=options['SERVICE']) + [c for (s, c) in unstarted]
- print "Attaching to", list_containers(to_attach)
- log_printer = LogPrinter(to_attach, attach_params={'logs': True})
- for (s, c) in unstarted:
- s.start_container(c)
- if detached:
- for (s, c) in unstarted:
- print c.name
- else:
- try:
- log_printer.run()
- finally:
- self.project.kill_and_remove(unstarted)
- def start(self, options):
- """
- Start existing containers.
- Usage: start [SERVICE...]
- """
- self.project.start(service_names=options['SERVICE'])
- def stop(self, options):
- """
- Stop running containers.
- Usage: stop [SERVICE...]
- """
- self.project.stop(service_names=options['SERVICE'])
- def kill(self, options):
- """
- Kill containers.
- Usage: kill [SERVICE...]
- """
- self.project.kill(service_names=options['SERVICE'])
- def rm(self, options):
- """
- Remove stopped containers
- Usage: rm [SERVICE...]
- """
- self.project.remove_stopped(service_names=options['SERVICE'])
- def logs(self, options):
- """
- View output from containers.
- Usage: logs [SERVICE...]
- """
- containers = self.project.containers(service_names=options['SERVICE'], stopped=False)
- print "Attaching to", list_containers(containers)
- LogPrinter(containers, attach_params={'logs': True}).run()
- def _attach_to_container(self, container_id, interactive, logs=False, stream=True, raw=False):
- stdio = self.client.attach_socket(
- container_id,
- params={
- 'stdin': 1 if interactive else 0,
- 'stdout': 1,
- 'stderr': 0,
- 'logs': 1 if logs else 0,
- 'stream': 1 if stream else 0
- },
- ws=True,
- )
- stderr = self.client.attach_socket(
- container_id,
- params={
- 'stdin': 0,
- 'stdout': 0,
- 'stderr': 1,
- 'logs': 1 if logs else 0,
- 'stream': 1 if stream else 0
- },
- ws=True,
- )
- return SocketClient(
- socket_in=stdio,
- socket_out=stdio,
- socket_err=stderr,
- raw=raw,
- )
- def list_containers(containers):
- return ", ".join(c.name for c in containers)
|