blob: 6b261a616f51b91a1c47617a190ab0a9f5d30cae [file] [log] [blame]
alshabib7941d402016-11-08 00:11:20 +01001#
2# Copyright 2016 the original author or authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16from common.utils.dockerhelpers import create_host_config, create_container, start_container, create_networking_config, \
17 get_all_running_containers, inspect_container, remove_container
18
19from structlog import get_logger
20
21log = get_logger()
22
23INSTANCE_ID_KEY = 'com.docker.compose.container-number'
24INSTANCE_NAME_KEY = 'name'
25
26
27def check(event):
28 return ('from' in event) and\
29 ('Actor' in event and 'Attributes' in event['Actor'] and\
30 INSTANCE_ID_KEY in event['Actor']['Attributes']) and\
31 ('Actor' in event and 'Attributes' in event['Actor'] and\
32 INSTANCE_NAME_KEY in event['Actor']['Attributes'])
33
34def get_entry(key, dico, mandatory = False, noneval=None):
35 if key in dico:
36 return dico[key]
37 if mandatory:
38 raise Exception('Key {} must be in container config'.format(key))
39 return noneval
40
41def obtain_network_name(data):
42 return data['NetworkSettings']['Networks'].keys()
43
44
45def create_network_config(network, links):
46 if links is None:
47 return None
48 # Assuming only one network exists....
49 return create_networking_config(network[0], { l : l for l in links})
50
51
52def process_value(value):
53 if value is None:
54 return None
55 if isinstance(value, dict):
56 return value
57 if isinstance(value, list):
58 retval = {}
59 for item in value:
60 if not isinstance(item, int) and ':' in item:
61 item_split = item.split(':')
62 retval[item_split[0]] = item_split[1]
63 else:
64 retval[item] = None
65 return retval
66 raise Exception('Cannot handle {}'.format(value))
67
68def construct_container_spec(config):
69 container_spec = {}
70 container_spec['image'] = get_entry('image', config, mandatory=True)
71 #TODO need to rewrite command to connect to right service instance
72 container_spec['command'] = get_entry('command', config, mandatory=True)
73 container_spec['environment'] = get_entry('environment', config, noneval={})
74 container_spec['ports'] = get_entry('ports', config)
75 container_spec['volumes'] = get_entry('volumes', config)
76 return container_spec
77
78def service_shutdown(service, instance_name, config):
79 containers = get_all_running_containers()
80 for container in containers:
81 info = inspect_container(container['Id'])
82 envs = info['Config']['Env']
83 for env in envs:
84 for name in env.split('='):
85 if name == instance_name:
86 log.info('Removing container {}'.format(container['Names']))
87 remove_container(container['Id'])
88
89def start_slaves(service, instance_name, instance_id, data, config):
90 if service not in config['services']:
91 log.debug('Unknown service {}'.format(service))
92 return
93 for slave in config['services'][service]['slaves']:
94 if slave not in config['slaves']:
95 log.debug('Unknown slave service {}'.format(slave))
96 continue
97 network = obtain_network_name(data)
98 netcfg = create_network_config(network, get_entry('links', config['slaves'][slave]))
99 container_spec = construct_container_spec(config['slaves'][slave])
100 container_spec['networking_config'] = netcfg
101 if 'volumes' in container_spec:
102 container_spec['host_config'] = create_host_config(
103 process_value(container_spec['volumes']),
104 process_value(container_spec['ports']))
105 container_spec['name'] = 'podder_%s_%s' % (slave, instance_id)
106
107 container_spec['environment']['PODDER_MASTER'] = instance_name
108
109 container = create_container(container_spec)
110 start_container(container)
111
112
113def stop_slaves(service, instance_name, instance_id, data, config):
114 log.info('Stopping slaves for {}'.format(instance_name))
115 if service in config['services']:
116 service_shutdown(service, instance_name, config)
117 else:
118 # handle slave shutdown; restart him
119 pass
120
121
122def handler_start(event, data, config):
123 if not check(event):
124 log.debug('event {} is invalid'.format(event) )
125 return
126 service = event['from']
127 instance_name = event['Actor']['Attributes'][INSTANCE_NAME_KEY]
128 instance_id = event['Actor']['Attributes'][INSTANCE_ID_KEY]
129 start_slaves(service, instance_name, instance_id, data, config)
130
131def handler_stop(event, data, config):
132 if not check(event):
133 log.debug('event {} is invalid'.format(event) )
134 return
135 service = event['from']
136 instance_name = event['Actor']['Attributes'][INSTANCE_NAME_KEY]
137 instance_id = event['Actor']['Attributes'][INSTANCE_ID_KEY]
138 stop_slaves(service, instance_name, instance_id, data, config)
139