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