blob: b5eb17efdfa492b1d8c2e0b3f7537f1555eb7be2 [file] [log] [blame]
koder aka kdanilov4643fd62015-02-10 16:20:13 -08001import re
2import os
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +03003import stat
koder aka kdanilov4643fd62015-02-10 16:20:13 -08004import time
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +03005import os.path
koder aka kdanilove21d7472015-02-14 19:02:04 -08006import logging
koder aka kdanilov76471642015-08-14 11:44:43 +03007import warnings
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +03008import subprocess
koder aka kdanilovb7197432015-07-15 00:40:43 +03009import collections
koder aka kdanilov4643fd62015-02-10 16:20:13 -080010
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +030011from concurrent.futures import ThreadPoolExecutor
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080012
koder aka kdanilov4500a5f2015-04-17 16:55:17 +030013from novaclient.exceptions import NotFound
koder aka kdanilov4643fd62015-02-10 16:20:13 -080014from novaclient.client import Client as n_client
15from cinderclient.v1.client import Client as c_client
16
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030017import wally
18from wally.discover import Node
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030019
koder aka kdanilov4643fd62015-02-10 16:20:13 -080020
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030021logger = logging.getLogger("wally.vms")
koder aka kdanilove21d7472015-02-14 19:02:04 -080022
23
koder aka kdanilove87ae652015-04-20 02:14:35 +030024STORED_OPENSTACK_CREDS = None
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030025NOVA_CONNECTION = None
koder aka kdanilove87ae652015-04-20 02:14:35 +030026CINDER_CONNECTION = None
27
28
koder aka kdanilov416b87a2015-05-12 00:26:04 +030029def is_connected():
30 return NOVA_CONNECTION is not None
31
32
koder aka kdanilovb7197432015-07-15 00:40:43 +030033OSCreds = collections.namedtuple("OSCreds",
34 ["name", "passwd",
35 "tenant", "auth_url", "insecure"])
36
37
koder aka kdanilove87ae652015-04-20 02:14:35 +030038def ostack_get_creds():
39 if STORED_OPENSTACK_CREDS is None:
koder aka kdanilovb7197432015-07-15 00:40:43 +030040 return OSCreds(os.environ.get('OS_USERNAME'),
41 os.environ.get('OS_PASSWORD'),
42 os.environ.get('OS_TENANT_NAME'),
43 os.environ.get('OS_AUTH_URL'),
44 os.environ.get('OS_INSECURE', False))
koder aka kdanilove87ae652015-04-20 02:14:35 +030045 else:
46 return STORED_OPENSTACK_CREDS
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030047
48
koder aka kdanilovb7197432015-07-15 00:40:43 +030049def nova_connect(os_creds=None):
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030050 global NOVA_CONNECTION
koder aka kdanilove87ae652015-04-20 02:14:35 +030051 global STORED_OPENSTACK_CREDS
52
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030053 if NOVA_CONNECTION is None:
koder aka kdanilovb7197432015-07-15 00:40:43 +030054 if os_creds is None:
55 os_creds = ostack_get_creds()
koder aka kdanilove87ae652015-04-20 02:14:35 +030056 else:
koder aka kdanilovb7197432015-07-15 00:40:43 +030057 STORED_OPENSTACK_CREDS = os_creds
koder aka kdanilove87ae652015-04-20 02:14:35 +030058
koder aka kdanilovb7197432015-07-15 00:40:43 +030059 NOVA_CONNECTION = n_client('1.1',
60 os_creds.name,
61 os_creds.passwd,
62 os_creds.tenant,
63 os_creds.auth_url,
64 insecure=os_creds.insecure)
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030065 return NOVA_CONNECTION
66
67
koder aka kdanilovb7197432015-07-15 00:40:43 +030068def cinder_connect(os_creds=None):
koder aka kdanilove87ae652015-04-20 02:14:35 +030069 global CINDER_CONNECTION
70 global STORED_OPENSTACK_CREDS
71
72 if CINDER_CONNECTION is None:
koder aka kdanilovb7197432015-07-15 00:40:43 +030073 if os_creds is None:
74 os_creds = ostack_get_creds()
koder aka kdanilove87ae652015-04-20 02:14:35 +030075 else:
koder aka kdanilovb7197432015-07-15 00:40:43 +030076 STORED_OPENSTACK_CREDS = os_creds
77 CINDER_CONNECTION = c_client(os_creds.name,
78 os_creds.passwd,
79 os_creds.tenant,
80 os_creds.auth_url,
81 insecure=os_creds.insecure)
koder aka kdanilove87ae652015-04-20 02:14:35 +030082 return CINDER_CONNECTION
83
84
koder aka kdanilovb7197432015-07-15 00:40:43 +030085def prepare_os_subpr(nova, params, os_creds):
86 if os_creds is None:
87 os_creds = ostack_get_creds()
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +030088
koder aka kdanilovc368eb62015-04-28 18:22:01 +030089 MAX_VM_PER_NODE = 8
90 serv_groups = " ".join(map(params['aa_group_name'].format,
91 range(MAX_VM_PER_NODE)))
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +030092
koder aka kdanilov6ab4d432015-06-22 00:26:28 +030093 image_name = params['image']['name']
koder aka kdanilovc368eb62015-04-28 18:22:01 +030094 env = os.environ.copy()
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030095
koder aka kdanilovc368eb62015-04-28 18:22:01 +030096 env.update(dict(
koder aka kdanilovb7197432015-07-15 00:40:43 +030097 OS_USERNAME=os_creds.name,
98 OS_PASSWORD=os_creds.passwd,
99 OS_TENANT_NAME=os_creds.tenant,
100 OS_AUTH_URL=os_creds.auth_url,
101 OS_INSECURE="1" if os_creds.insecure else "0",
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300102
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300103 FLAVOR_NAME=params['flavor']['name'],
104 FLAVOR_RAM=str(params['flavor']['ram_size']),
105 FLAVOR_HDD=str(params['flavor']['hdd_size']),
106 FLAVOR_CPU_COUNT=str(params['flavor']['cpu_count']),
107
108 SERV_GROUPS=serv_groups,
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300109
110 SECGROUP=params['security_group'],
111
koder aka kdanilov6ab4d432015-06-22 00:26:28 +0300112 IMAGE_NAME=image_name,
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300113 IMAGE_URL=params['image']['url'],
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300114
115 # KEYPAIR_NAME=params['keypair_name'],
116 # KEY_FILE_NAME=params['keypair_file_private'],
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300117 ))
118
119 spath = os.path.dirname(os.path.dirname(wally.__file__))
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300120 spath = os.path.join(spath, 'scripts/prepare.sh')
121
koder aka kdanilov76471642015-08-14 11:44:43 +0300122 with warnings.catch_warnings():
123 warnings.simplefilter("ignore")
124 fname = os.tempnam()
125
126 cmd = "bash {spath} >{fname} 2>&1".format(spath=spath, fname=fname)
127 try:
128 subprocess.check_call(cmd, shell=True, env=env)
129 except:
130 logger.error("Prepare failed. Logs in " + fname)
131 with open(fname) as fd:
132 logger.error("Message:\n " + fd.read().replace("\n", "\n "))
133 raise
134 os.unlink(fname)
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300135
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300136 while True:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300137 status = nova.images.find(name=image_name).status
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300138 if status == 'ACTIVE':
139 break
140 msg = "Image {0} is still in {1} state. Waiting 10 more seconds"
koder aka kdanilov6ab4d432015-06-22 00:26:28 +0300141 logger.info(msg.format(image_name, status))
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300142 time.sleep(10)
143
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300144 create_keypair(nova,
145 params['keypair_name'],
146 params['keypair_file_public'],
147 params['keypair_file_private'])
148
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300149
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300150def find_vms(nova, name_prefix):
151 for srv in nova.servers.list():
152 if srv.name.startswith(name_prefix):
153 for ips in srv.addresses.values():
154 for ip in ips:
155 if ip.get("OS-EXT-IPS:type", None) == 'floating':
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300156 yield ip['addr'], srv.id
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300157 break
158
159
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300160def pause(ids):
161 def pause_vm(conn, vm_id):
162 vm = conn.servers.get(vm_id)
163 if vm.status == 'ACTIVE':
164 vm.pause()
165
166 conn = nova_connect()
167 with ThreadPoolExecutor(max_workers=16) as executor:
168 futures = [executor.submit(pause_vm, conn, vm_id)
169 for vm_id in ids]
170 for future in futures:
171 future.result()
172
173
174def unpause(ids, max_resume_time=10):
175 def unpause(conn, vm_id):
176 vm = conn.servers.get(vm_id)
177 if vm.status == 'PAUSED':
178 vm.unpause()
179
180 for i in range(max_resume_time * 10):
181 vm = conn.servers.get(vm_id)
182 if vm.status != 'PAUSED':
183 return
184 time.sleep(0.1)
185 raise RuntimeError("Can't unpause vm {0}".format(vm_id))
186
187 conn = nova_connect()
188 with ThreadPoolExecutor(max_workers=16) as executor:
189 futures = [executor.submit(unpause, conn, vm_id)
190 for vm_id in ids]
191
192 for future in futures:
193 future.result()
194
195
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300196def prepare_os(nova, params):
197 allow_ssh(nova, params['security_group'])
198
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300199 MAX_VM_PER_NODE = 8
200 serv_groups = " ".join(map(params['aa_group_name'].format,
201 range(MAX_VM_PER_NODE)))
202
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300203 shed_ids = []
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300204 for shed_group in serv_groups:
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300205 shed_ids.append(get_or_create_aa_group(nova, shed_group))
206
207 create_keypair(nova,
208 params['keypair_name'],
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300209 params['keypair_name'] + ".pub",
210 params['keypair_name'] + ".pem")
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300211
212 create_image(nova, params['image']['name'],
213 params['image']['url'])
214
215 create_flavor(nova, **params['flavor'])
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300216
217
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300218def create_keypair(nova, name, pub_key_path, priv_key_path):
219 pub_key_exists = os.path.exists(pub_key_path)
220 priv_key_exists = os.path.exists(priv_key_path)
221
222 try:
223 kpair = nova.keypairs.find(name=name)
224 # if file not found- delete and recreate
225 except NotFound:
226 kpair = None
227
228 if pub_key_exists and not priv_key_exists:
229 raise EnvironmentError("Private key file doesn't exists")
230
231 if not pub_key_exists and priv_key_exists:
232 raise EnvironmentError("Public key file doesn't exists")
233
234 if kpair is None:
235 if pub_key_exists:
236 with open(pub_key_path) as pub_key_fd:
237 return nova.keypairs.create(name, pub_key_fd.read())
238 else:
239 key = nova.keypairs.create(name)
240
241 with open(priv_key_path, "w") as priv_key_fd:
242 priv_key_fd.write(key.private_key)
243 os.chmod(priv_key_path, stat.S_IREAD | stat.S_IWRITE)
244
245 with open(pub_key_path, "w") as pub_key_fd:
246 pub_key_fd.write(key.public_key)
247 elif not priv_key_exists:
248 raise EnvironmentError("Private key file doesn't exists," +
249 " but key uploaded openstack." +
250 " Either set correct path to private key" +
251 " or remove key from openstack")
252
253
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300254def get_or_create_aa_group(nova, name):
255 try:
256 group = nova.server_groups.find(name=name)
257 except NotFound:
258 group = nova.server_groups.create({'name': name,
259 'policies': ['anti-affinity']})
koder aka kdanilov652cd802015-04-13 12:21:07 +0300260
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300261 return group.id
koder aka kdanilov652cd802015-04-13 12:21:07 +0300262
263
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300264def allow_ssh(nova, group_name):
265 try:
266 secgroup = nova.security_groups.find(name=group_name)
267 except NotFound:
268 secgroup = nova.security_groups.create(group_name,
269 "allow ssh/ping to node")
270
koder aka kdanilov652cd802015-04-13 12:21:07 +0300271 nova.security_group_rules.create(secgroup.id,
272 ip_protocol="tcp",
273 from_port="22",
274 to_port="22",
275 cidr="0.0.0.0/0")
276
277 nova.security_group_rules.create(secgroup.id,
278 ip_protocol="icmp",
279 from_port=-1,
280 cidr="0.0.0.0/0",
281 to_port=-1)
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300282 return secgroup.id
koder aka kdanilov652cd802015-04-13 12:21:07 +0300283
284
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300285def create_image(nova, name, url):
286 pass
287
288
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300289def create_flavor(nova, name, ram_size, hdd_size, cpu_count):
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300290 pass
291
292
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800293def create_volume(size, name):
koder aka kdanilove87ae652015-04-20 02:14:35 +0300294 cinder = cinder_connect()
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800295 vol = cinder.volumes.create(size=size, display_name=name)
296 err_count = 0
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300297
koder aka kdanilove87ae652015-04-20 02:14:35 +0300298 while vol.status != 'available':
299 if vol.status == 'error':
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800300 if err_count == 3:
koder aka kdanilove21d7472015-02-14 19:02:04 -0800301 logger.critical("Fail to create volume")
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800302 raise RuntimeError("Fail to create volume")
303 else:
304 err_count += 1
305 cinder.volumes.delete(vol)
306 time.sleep(1)
307 vol = cinder.volumes.create(size=size, display_name=name)
308 continue
309 time.sleep(1)
koder aka kdanilove87ae652015-04-20 02:14:35 +0300310 vol = cinder.volumes.get(vol.id)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800311 return vol
312
313
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300314def wait_for_server_active(nova, server, timeout=300):
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800315 t = time.time()
316 while True:
koder aka kdanilov3f356262015-02-13 08:06:14 -0800317 time.sleep(1)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800318 sstate = getattr(server, 'OS-EXT-STS:vm_state').lower()
319
320 if sstate == 'active':
321 return True
322
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800323 if sstate == 'error':
324 return False
325
326 if time.time() - t > timeout:
327 return False
328
329 server = nova.servers.get(server)
330
331
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800332class Allocate(object):
333 pass
334
335
336def get_floating_ips(nova, pool, amount):
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800337 ip_list = nova.floating_ips.list()
338
339 if pool is not None:
340 ip_list = [ip for ip in ip_list if ip.pool == pool]
341
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800342 return [ip for ip in ip_list if ip.instance_id is None][:amount]
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800343
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800344
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300345def launch_vms(params, already_has_count=0):
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300346 logger.debug("Calculating new vm count")
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300347 count = params['count']
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300348 nova = nova_connect()
349 lst = nova.services.list(binary='nova-compute')
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300350 srv_count = len([srv for srv in lst if srv.status == 'enabled'])
koder aka kdanilovda45e882015-04-06 02:24:42 +0300351
352 if isinstance(count, basestring):
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300353 if count.startswith("x"):
354 count = srv_count * int(count[1:])
355 else:
356 assert count.startswith('=')
357 count = int(count[1:]) - already_has_count
358
359 if count <= 0:
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300360 logger.debug("Not need new vms")
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300361 return
koder aka kdanilovda45e882015-04-06 02:24:42 +0300362
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300363 logger.debug("Starting new nodes on openstack")
364
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300365 assert isinstance(count, (int, long))
366
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300367 srv_params = "img: {image[name]}, flavor: {flavor[name]}".format(**params)
koder aka kdanilov66839a92015-04-11 13:22:31 +0300368 msg_templ = "Will start {0} servers with next params: {1}"
koder aka kdanilovcee43342015-04-14 22:52:53 +0300369 logger.info(msg_templ.format(count, srv_params))
koder aka kdanilovda45e882015-04-06 02:24:42 +0300370
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300371 vm_params = dict(
372 img_name=params['image']['name'],
373 flavor_name=params['flavor']['name'],
374 group_name=params['group_name'],
375 keypair_name=params['keypair_name'],
376 vol_sz=params.get('vol_sz'),
377 network_zone_name=params.get("network_zone_name"),
378 flt_ip_pool=params.get('flt_ip_pool'),
379 name_templ=params.get('name_templ'),
380 scheduler_hints={"group": params['aa_group_name']},
381 security_group=params['security_group'],
382 sec_group_size=srv_count
383 )
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300384
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300385 # precache all errors before start creating vms
386 private_key_path = params['keypair_file_private']
387 creds = params['image']['creds']
388 creds.format(ip="1.1.1.1", private_key_path="/some_path/xx")
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300389
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300390 for ip, os_node in create_vms_mt(NOVA_CONNECTION, count, **vm_params):
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300391
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300392 conn_uri = creds.format(ip=ip, private_key_path=private_key_path)
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300393 yield Node(conn_uri, []), os_node.id
koder aka kdanilovda45e882015-04-06 02:24:42 +0300394
395
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300396def get_free_server_grpoups(nova, template=None):
397 for g in nova.server_groups.list():
398 if g.members == []:
399 if re.match(template, g.name):
400 yield str(g.name)
401
402
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300403def create_vms_mt(nova, amount, group_name, keypair_name, img_name,
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800404 flavor_name, vol_sz=None, network_zone_name=None,
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300405 flt_ip_pool=None, name_templ='wally-{id}',
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300406 scheduler_hints=None, security_group=None,
407 sec_group_size=None):
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800408
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800409 with ThreadPoolExecutor(max_workers=16) as executor:
koder aka kdanilov97644f92015-02-13 11:11:08 -0800410 if network_zone_name is not None:
411 network_future = executor.submit(nova.networks.find,
412 label=network_zone_name)
413 else:
414 network_future = None
415
416 fl_future = executor.submit(nova.flavors.find, name=flavor_name)
417 img_future = executor.submit(nova.images.find, name=img_name)
418
419 if flt_ip_pool is not None:
420 ips_future = executor.submit(get_floating_ips,
421 nova, flt_ip_pool, amount)
koder aka kdanilove21d7472015-02-14 19:02:04 -0800422 logger.debug("Wait for floating ip")
koder aka kdanilov97644f92015-02-13 11:11:08 -0800423 ips = ips_future.result()
424 ips += [Allocate] * (amount - len(ips))
425 else:
426 ips = [None] * amount
427
koder aka kdanilov7dec9df2015-02-15 21:35:19 -0800428 logger.debug("Getting flavor object")
koder aka kdanilov97644f92015-02-13 11:11:08 -0800429 fl = fl_future.result()
koder aka kdanilov7dec9df2015-02-15 21:35:19 -0800430 logger.debug("Getting image object")
koder aka kdanilov97644f92015-02-13 11:11:08 -0800431 img = img_future.result()
432
433 if network_future is not None:
koder aka kdanilove21d7472015-02-14 19:02:04 -0800434 logger.debug("Waiting for network results")
koder aka kdanilov97644f92015-02-13 11:11:08 -0800435 nics = [{'net-id': network_future.result().id}]
436 else:
437 nics = None
438
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300439 names = []
440 for i in range(amount):
441 names.append(name_templ.format(group=group_name, id=i))
koder aka kdanilov97644f92015-02-13 11:11:08 -0800442
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800443 futures = []
koder aka kdanilov168f6092015-04-19 02:33:38 +0300444 logger.debug("Requesting new vm's")
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800445
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300446 orig_scheduler_hints = scheduler_hints.copy()
447
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300448 MAX_SHED_GROUPS = 32
449 for start_idx in range(MAX_SHED_GROUPS):
450 pass
451
452 group_name_template = scheduler_hints['group'].format("\\d+")
453 groups = list(get_free_server_grpoups(nova, group_name_template + "$"))
454 groups.sort()
455
456 for idx, (name, flt_ip) in enumerate(zip(names, ips), 2):
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300457
458 scheduler_hints = None
459 if orig_scheduler_hints is not None and sec_group_size is not None:
460 if "group" in orig_scheduler_hints:
461 scheduler_hints = orig_scheduler_hints.copy()
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300462 scheduler_hints['group'] = groups[idx // sec_group_size]
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300463
464 if scheduler_hints is None:
465 scheduler_hints = orig_scheduler_hints.copy()
466
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800467 params = (nova, name, keypair_name, img, fl,
468 nics, vol_sz, flt_ip, scheduler_hints,
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300469 flt_ip_pool, [security_group])
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800470
471 futures.append(executor.submit(create_vm, *params))
koder aka kdanilove21d7472015-02-14 19:02:04 -0800472 res = [future.result() for future in futures]
473 logger.debug("Done spawning")
474 return res
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800475
476
477def create_vm(nova, name, keypair_name, img,
478 fl, nics, vol_sz=None,
479 flt_ip=False,
480 scheduler_hints=None,
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300481 pool=None,
482 security_groups=None):
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800483 for i in range(3):
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800484 srv = nova.servers.create(name,
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300485 flavor=fl,
486 image=img,
487 nics=nics,
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800488 key_name=keypair_name,
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300489 scheduler_hints=scheduler_hints,
490 security_groups=security_groups)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800491
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800492 if not wait_for_server_active(nova, srv):
493 msg = "Server {0} fails to start. Kill it and try again"
koder aka kdanilove21d7472015-02-14 19:02:04 -0800494 logger.debug(msg.format(srv))
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800495 nova.servers.delete(srv)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800496
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300497 try:
498 for j in range(120):
499 srv = nova.servers.get(srv.id)
500 time.sleep(1)
501 else:
502 msg = "Server {0} delete timeout".format(srv.id)
503 raise RuntimeError(msg)
504 except NotFound:
505 pass
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800506 else:
507 break
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300508 else:
509 raise RuntimeError("Failed to start server".format(srv.id))
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800510
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800511 if vol_sz is not None:
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800512 vol = create_volume(vol_sz, name)
koder aka kdanilove87ae652015-04-20 02:14:35 +0300513 nova.volumes.create_server_volume(srv.id, vol.id, None)
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800514
515 if flt_ip is Allocate:
516 flt_ip = nova.floating_ips.create(pool)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300517
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800518 if flt_ip is not None:
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800519 srv.add_floating_ip(flt_ip)
Yulia Portnova0e64ea22015-03-20 17:27:22 +0200520
koder aka kdanilovda45e882015-04-06 02:24:42 +0300521 return flt_ip.ip, nova.servers.get(srv.id)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800522
523
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300524def clear_nodes(nodes_ids):
525 clear_all(NOVA_CONNECTION, nodes_ids, None)
gstepanov023c1e42015-04-08 15:50:19 +0300526
527
koder aka kdanilove87ae652015-04-20 02:14:35 +0300528def clear_all(nova, ids=None, name_templ=None):
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300529
530 def need_delete(srv):
531 if name_templ is not None:
532 return re.match(name_templ.format("\\d+"), srv.name) is not None
533 else:
534 return srv.id in ids
535
koder aka kdanilove87ae652015-04-20 02:14:35 +0300536 volumes_to_delete = []
537 cinder = cinder_connect()
538 for vol in cinder.volumes.list():
539 for attachment in vol.attachments:
540 if attachment['server_id'] in ids:
541 volumes_to_delete.append(vol)
542 break
543
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800544 deleted_srvs = set()
545 for srv in nova.servers.list():
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300546 if need_delete(srv):
koder aka kdanilove21d7472015-02-14 19:02:04 -0800547 logger.debug("Deleting server {0}".format(srv.name))
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800548 nova.servers.delete(srv)
549 deleted_srvs.add(srv.id)
550
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300551 count = 0
552 while True:
553 if count % 60 == 0:
554 logger.debug("Waiting till all servers are actually deleted")
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800555 all_id = set(srv.id for srv in nova.servers.list())
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300556 if len(all_id.intersection(deleted_srvs)) == 0:
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800557 break
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300558 count += 1
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800559 time.sleep(1)
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300560 logger.debug("Done, deleting volumes")
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800561
562 # wait till vm actually deleted
563
koder aka kdanilov6b1341a2015-04-21 22:44:21 +0300564 # logger.warning("Volume deletion commented out")
565 for vol in volumes_to_delete:
566 logger.debug("Deleting volume " + vol.display_name)
567 cinder.volumes.delete(vol)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800568
koder aka kdanilove21d7472015-02-14 19:02:04 -0800569 logger.debug("Clearing done (yet some volumes may still deleting)")