github.com/dustinrc/deis@v1.10.1-0.20150917223407-0894a5fb979e/controller/scheduler/swarm.py (about)

     1  import re
     2  import time
     3  
     4  from django.conf import settings
     5  from docker import Client
     6  
     7  from . import AbstractSchedulerClient
     8  from .states import JobState
     9  
    10  
    11  MATCH = re.compile(
    12      r'(?P<app>[a-z0-9-]+)_?(?P<version>v[0-9]+)?\.?(?P<c_type>[a-z-_]+)?.(?P<c_num>[0-9]+)')
    13  
    14  
    15  class SwarmClient(AbstractSchedulerClient):
    16  
    17      def __init__(self, target, auth, options, pkey):
    18          super(SchedulerClient, self).__init__(target, auth, options, pkey)
    19          self.target = settings.SWARM_HOST
    20          # single global connection
    21          self.registry = settings.REGISTRY_HOST + ':' + settings.REGISTRY_PORT
    22          self.docker_cli = Client("tcp://{}:2395".format(self.target),
    23                                   timeout=1200, version='1.17')
    24  
    25      def create(self, name, image, command='', template=None, **kwargs):
    26          """Create a new container."""
    27          cimage = self.registry + '/' + image
    28          affinity = "affinity:container!=~/{}*/".format(re.split(r'_v\d.', name)[0])
    29          l = locals().copy()
    30          l.update(re.match(MATCH, name).groupdict())
    31          mem = kwargs.get('memory', {}).get(l['c_type'])
    32          if mem:
    33              mem = mem.lower()
    34              if mem[-2:-1].isalpha() and mem[-1].isalpha():
    35                  mem = mem[:-1]
    36          cpu = kwargs.get('cpu', {}).get(l['c_type'])
    37          self.docker_cli.create_container(image=cimage, name=name,
    38                                           command=command.encode('utf-8'),
    39                                           mem_limit=mem,
    40                                           cpu_shares=cpu,
    41                                           environment=[affinity],
    42                                           host_config={'PublishAllPorts': True})
    43  
    44      def start(self, name):
    45          """Start a container."""
    46          self.docker_cli.start(name)
    47  
    48      def stop(self, name):
    49          """Stop a container."""
    50          self.docker_cli.stop(name)
    51  
    52      def destroy(self, name):
    53          """Destroy a container."""
    54          self.stop(name)
    55          self.docker_cli.remove_container(name)
    56  
    57      def run(self, name, image, entrypoint, command):
    58          """Run a one-off command."""
    59          cimage = self.registry + '/' + image
    60          # use affinity for nodes that already have the image
    61          affinity = "affinity:image==~{}".format(cimage)
    62          self.docker_cli.create_container(image=cimage, name=name,
    63                                           command=command.encode('utf-8'),
    64                                           environment=[affinity],
    65                                           entrypoint=[entrypoint])
    66          time.sleep(2)
    67          self.start(name)
    68          rc = 0
    69          while (True):
    70              if self._get_container_state(name) == JobState.created:
    71                  break
    72              time.sleep(1)
    73          try:
    74              output = self.docker_cli.logs(name)
    75              return rc, output
    76          except:
    77              rc = 1
    78              return rc, output
    79  
    80      def _get_container_state(self, name):
    81          try:
    82              if self.docker_cli.inspect_container(name)['State']['Running']:
    83                  return JobState.up
    84              else:
    85                  return JobState.created
    86          except:
    87              return JobState.destroyed
    88  
    89      def state(self, name):
    90          """Display the given job's running state."""
    91          try:
    92              for _ in xrange(30):
    93                  return self._get_container_state(name)
    94                  time.sleep(1)
    95              # FIXME (smothiki): should be able to send JobState.crashed
    96          except KeyError:
    97              return JobState.error
    98          except RuntimeError:
    99              return JobState.destroyed
   100  
   101      def _get_hostname(self, application_name):
   102          hostname = settings.UNIT_HOSTNAME
   103          if hostname == 'default':
   104              return ''
   105          elif hostname == 'application':
   106              # replace underscore with dots, since underscore is not valid in DNS hostnames
   107              dns_name = application_name.replace('_', '.')
   108              return dns_name
   109          elif hostname == 'server':
   110              raise NotImplementedError
   111          else:
   112              raise RuntimeError('Unsupported hostname: ' + hostname)
   113  
   114      def _get_portbindings(self, image):
   115          dictports = self.docker_cli.inspect_image(image)['ContainerConfig']['ExposedPorts']
   116          for port in dictports:
   117              dictports[port] = None
   118          return dictports
   119  
   120      def _get_ports(self, image):
   121          dictports = self.docker_cli.inspect_image(image)['ContainerConfig']['ExposedPorts']
   122          return [int(port.split('/')[0]) for port in dictports]
   123  
   124  SchedulerClient = SwarmClient