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