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

     1  import re
     2  import time
     3  
     4  from django.conf import settings
     5  from docker import Client
     6  from marathon import MarathonClient
     7  from marathon.models import MarathonApp
     8  
     9  from . import AbstractSchedulerClient
    10  from .fleet import FleetHTTPClient
    11  from .states import JobState
    12  
    13  # turn down standard marathon logging
    14  
    15  MATCH = re.compile(
    16      '(?P<app>[a-z0-9-]+)_?(?P<version>v[0-9]+)?\.?(?P<c_type>[a-z-_]+)?.(?P<c_num>[0-9]+)')
    17  RETRIES = 3
    18  POLL_ATTEMPTS = 30
    19  POLL_WAIT = 100
    20  
    21  
    22  class MarathonHTTPClient(AbstractSchedulerClient):
    23  
    24      def __init__(self, target, auth, options, pkey):
    25          super(MarathonHTTPClient, self).__init__(target, auth, options, pkey)
    26          self.target = settings.MARATHON_HOST
    27          self.registry = settings.REGISTRY_HOST + ':' + settings.REGISTRY_PORT
    28          self.client = MarathonClient('http://'+self.target+':8180')
    29          self.fleet = FleetHTTPClient('/var/run/fleet.sock', auth, options, pkey)
    30  
    31      # helpers
    32      def _app_id(self, name):
    33          return name.replace('_', '.')
    34  
    35      # container api
    36      def create(self, name, image, command='', **kwargs):
    37          """Create a new container"""
    38          app_id = self._app_id(name)
    39          l = locals().copy()
    40          l.update(re.match(MATCH, name).groupdict())
    41          image = self.registry + '/' + image
    42          mems = kwargs.get('memory', {}).get(l['c_type'])
    43          m = 0
    44          if mems:
    45              mems = mems.lower()
    46              if mems[-2:-1].isalpha() and mems[-1].isalpha():
    47                  mems = mems[:-1]
    48              m = int(mems[:-1])
    49          c = 0.5
    50          cpu = kwargs.get('cpu', {}).get(l['c_type'])
    51          if cpu:
    52              c = cpu
    53          cmd = "docker run --name {name} -P {image} {command}".format(**locals())
    54          self.client.create_app(app_id, MarathonApp(cmd=cmd, mem=m, cpus=c, instances=0))
    55          for _ in xrange(POLL_ATTEMPTS):
    56              if self.client.get_app(self._app_id(name)).tasks_running == 0:
    57                  return
    58              time.sleep(1)
    59  
    60      def start(self, name):
    61          """Start a container."""
    62          self.client.scale_app(self._app_id(name), 1, force=True)
    63          for _ in xrange(POLL_ATTEMPTS):
    64              if self.client.get_app(self._app_id(name)).tasks_running == 1:
    65                  break
    66              time.sleep(1)
    67          host = self.client.get_app(self._app_id(name)).tasks[0].host
    68          self._waitforcontainer(host, name)
    69  
    70      def destroy(self, name):
    71          """Destroy a container."""
    72          try:
    73              host = self.client.get_app(self._app_id(name)).tasks[0].host
    74              self.client.delete_app(self._app_id(name), force=True)
    75              self._delete_container(host, name)
    76          except:
    77              self.client.delete_app(self._app_id(name), force=True)
    78  
    79      def _get_container_state(self, host, name):
    80          docker_cli = Client("tcp://{}:2375".format(host), timeout=1200, version='1.17')
    81          try:
    82              if docker_cli.inspect_container(name)['State']['Running']:
    83                  return JobState.up
    84          except:
    85              return JobState.destroyed
    86  
    87      def _waitforcontainer(self, host, name):
    88          for _ in xrange(POLL_WAIT):
    89              if self._get_container_state(host, name) == JobState.up:
    90                  return
    91              time.sleep(1)
    92          raise RuntimeError("App container Not Started")
    93  
    94      def _delete_container(self, host, name):
    95          docker_cli = Client("tcp://{}:2375".format(host), timeout=1200, version='1.17')
    96          if docker_cli.inspect_container(name)['State']:
    97              docker_cli.remove_container(name, force=True)
    98  
    99      def run(self, name, image, entrypoint, command):  # noqa
   100          """Run a one-off command."""
   101          return self.fleet.run(name, image, entrypoint, command)
   102  
   103      def state(self, name):
   104          """Display the given job's running state."""
   105          try:
   106              for _ in xrange(POLL_ATTEMPTS):
   107                  if self.client.get_app(self._app_id(name)).tasks_running == 1:
   108                      return JobState.up
   109                  elif self.client.get_app(self._app_id(name)).tasks_running == 0:
   110                      return JobState.created
   111                  time.sleep(1)
   112          except:
   113              return JobState.destroyed
   114  
   115  SchedulerClient = MarathonHTTPClient