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