blob: 1457da6f5b3afa4f88cae99631b2fa07e5f96a84 [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 kdanilov4e9f3ed2015-04-14 11:26:12 +03007import subprocess
koder aka kdanilov4643fd62015-02-10 16:20:13 -08008
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +03009from concurrent.futures import ThreadPoolExecutor
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080010
koder aka kdanilov4500a5f2015-04-17 16:55:17 +030011from novaclient.exceptions import NotFound
koder aka kdanilov4643fd62015-02-10 16:20:13 -080012from novaclient.client import Client as n_client
13from cinderclient.v1.client import Client as c_client
14
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030015import wally
16from wally.discover import Node
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030017
koder aka kdanilov4643fd62015-02-10 16:20:13 -080018
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030019logger = logging.getLogger("wally.vms")
koder aka kdanilove21d7472015-02-14 19:02:04 -080020
21
koder aka kdanilove87ae652015-04-20 02:14:35 +030022STORED_OPENSTACK_CREDS = None
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030023NOVA_CONNECTION = None
koder aka kdanilove87ae652015-04-20 02:14:35 +030024CINDER_CONNECTION = None
25
26
koder aka kdanilov416b87a2015-05-12 00:26:04 +030027def is_connected():
28 return NOVA_CONNECTION is not None
29
30
koder aka kdanilove87ae652015-04-20 02:14:35 +030031def ostack_get_creds():
32 if STORED_OPENSTACK_CREDS is None:
33 env = os.environ.get
34 name = env('OS_USERNAME')
35 passwd = env('OS_PASSWORD')
36 tenant = env('OS_TENANT_NAME')
37 auth_url = env('OS_AUTH_URL')
38 return name, passwd, tenant, auth_url
39 else:
40 return STORED_OPENSTACK_CREDS
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030041
42
43def nova_connect(name=None, passwd=None, tenant=None, auth_url=None):
44 global NOVA_CONNECTION
koder aka kdanilove87ae652015-04-20 02:14:35 +030045 global STORED_OPENSTACK_CREDS
46
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030047 if NOVA_CONNECTION is None:
48 if name is None:
49 name, passwd, tenant, auth_url = ostack_get_creds()
koder aka kdanilove87ae652015-04-20 02:14:35 +030050 else:
51 STORED_OPENSTACK_CREDS = (name, passwd, tenant, auth_url)
52
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030053 NOVA_CONNECTION = n_client('1.1', name, passwd, tenant, auth_url)
54 return NOVA_CONNECTION
55
56
koder aka kdanilove87ae652015-04-20 02:14:35 +030057def cinder_connect(name=None, passwd=None, tenant=None, auth_url=None):
58 global CINDER_CONNECTION
59 global STORED_OPENSTACK_CREDS
60
61 if CINDER_CONNECTION is None:
62 if name is None:
63 name, passwd, tenant, auth_url = ostack_get_creds()
64 else:
65 STORED_OPENSTACK_CREDS = (name, passwd, tenant, auth_url)
66 CINDER_CONNECTION = c_client(name, passwd, tenant, auth_url)
67 return CINDER_CONNECTION
68
69
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030070def prepare_os_subpr(nova, params, name=None,
71 passwd=None, tenant=None,
koder aka kdanilovc368eb62015-04-28 18:22:01 +030072 auth_url=None):
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +030073 if name is None:
74 name, passwd, tenant, auth_url = ostack_get_creds()
75
koder aka kdanilovc368eb62015-04-28 18:22:01 +030076 MAX_VM_PER_NODE = 8
77 serv_groups = " ".join(map(params['aa_group_name'].format,
78 range(MAX_VM_PER_NODE)))
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +030079
koder aka kdanilov6ab4d432015-06-22 00:26:28 +030080 image_name = params['image']['name']
koder aka kdanilovc368eb62015-04-28 18:22:01 +030081 env = os.environ.copy()
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030082
koder aka kdanilovc368eb62015-04-28 18:22:01 +030083 env.update(dict(
84 OS_USERNAME=name,
85 OS_PASSWORD=passwd,
86 OS_TENANT_NAME=tenant,
87 OS_AUTH_URL=auth_url,
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +030088
koder aka kdanilovc368eb62015-04-28 18:22:01 +030089 FLAVOR_NAME=params['flavor']['name'],
90 FLAVOR_RAM=str(params['flavor']['ram_size']),
91 FLAVOR_HDD=str(params['flavor']['hdd_size']),
92 FLAVOR_CPU_COUNT=str(params['flavor']['cpu_count']),
93
94 SERV_GROUPS=serv_groups,
koder aka kdanilovc368eb62015-04-28 18:22:01 +030095
96 SECGROUP=params['security_group'],
97
koder aka kdanilov6ab4d432015-06-22 00:26:28 +030098 IMAGE_NAME=image_name,
koder aka kdanilovc368eb62015-04-28 18:22:01 +030099 IMAGE_URL=params['image']['url'],
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300100
101 # KEYPAIR_NAME=params['keypair_name'],
102 # KEY_FILE_NAME=params['keypair_file_private'],
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300103 ))
104
105 spath = os.path.dirname(os.path.dirname(wally.__file__))
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300106 spath = os.path.join(spath, 'scripts/prepare.sh')
107
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300108 cmd = "bash {spath} >/dev/null 2>&1 ".format(spath=spath)
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300109 subprocess.check_call(cmd, shell=True, env=env)
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300110
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300111 while True:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300112 status = nova.images.find(name=image_name).status
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300113 if status == 'ACTIVE':
114 break
115 msg = "Image {0} is still in {1} state. Waiting 10 more seconds"
koder aka kdanilov6ab4d432015-06-22 00:26:28 +0300116 logger.info(msg.format(image_name, status))
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300117 time.sleep(10)
118
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300119 create_keypair(nova,
120 params['keypair_name'],
121 params['keypair_file_public'],
122 params['keypair_file_private'])
123
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300124
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300125def find_vms(nova, name_prefix):
126 for srv in nova.servers.list():
127 if srv.name.startswith(name_prefix):
128 for ips in srv.addresses.values():
129 for ip in ips:
130 if ip.get("OS-EXT-IPS:type", None) == 'floating':
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300131 yield ip['addr'], srv.id
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300132 break
133
134
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300135def pause(ids):
136 def pause_vm(conn, vm_id):
137 vm = conn.servers.get(vm_id)
138 if vm.status == 'ACTIVE':
139 vm.pause()
140
141 conn = nova_connect()
142 with ThreadPoolExecutor(max_workers=16) as executor:
143 futures = [executor.submit(pause_vm, conn, vm_id)
144 for vm_id in ids]
145 for future in futures:
146 future.result()
147
148
149def unpause(ids, max_resume_time=10):
150 def unpause(conn, vm_id):
151 vm = conn.servers.get(vm_id)
152 if vm.status == 'PAUSED':
153 vm.unpause()
154
155 for i in range(max_resume_time * 10):
156 vm = conn.servers.get(vm_id)
157 if vm.status != 'PAUSED':
158 return
159 time.sleep(0.1)
160 raise RuntimeError("Can't unpause vm {0}".format(vm_id))
161
162 conn = nova_connect()
163 with ThreadPoolExecutor(max_workers=16) as executor:
164 futures = [executor.submit(unpause, conn, vm_id)
165 for vm_id in ids]
166
167 for future in futures:
168 future.result()
169
170
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300171def prepare_os(nova, params):
172 allow_ssh(nova, params['security_group'])
173
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300174 MAX_VM_PER_NODE = 8
175 serv_groups = " ".join(map(params['aa_group_name'].format,
176 range(MAX_VM_PER_NODE)))
177
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300178 shed_ids = []
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300179 for shed_group in serv_groups:
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300180 shed_ids.append(get_or_create_aa_group(nova, shed_group))
181
182 create_keypair(nova,
183 params['keypair_name'],
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300184 params['keypair_name'] + ".pub",
185 params['keypair_name'] + ".pem")
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300186
187 create_image(nova, params['image']['name'],
188 params['image']['url'])
189
190 create_flavor(nova, **params['flavor'])
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300191
192
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300193def create_keypair(nova, name, pub_key_path, priv_key_path):
194 pub_key_exists = os.path.exists(pub_key_path)
195 priv_key_exists = os.path.exists(priv_key_path)
196
197 try:
198 kpair = nova.keypairs.find(name=name)
199 # if file not found- delete and recreate
200 except NotFound:
201 kpair = None
202
203 if pub_key_exists and not priv_key_exists:
204 raise EnvironmentError("Private key file doesn't exists")
205
206 if not pub_key_exists and priv_key_exists:
207 raise EnvironmentError("Public key file doesn't exists")
208
209 if kpair is None:
210 if pub_key_exists:
211 with open(pub_key_path) as pub_key_fd:
212 return nova.keypairs.create(name, pub_key_fd.read())
213 else:
214 key = nova.keypairs.create(name)
215
216 with open(priv_key_path, "w") as priv_key_fd:
217 priv_key_fd.write(key.private_key)
218 os.chmod(priv_key_path, stat.S_IREAD | stat.S_IWRITE)
219
220 with open(pub_key_path, "w") as pub_key_fd:
221 pub_key_fd.write(key.public_key)
222 elif not priv_key_exists:
223 raise EnvironmentError("Private key file doesn't exists," +
224 " but key uploaded openstack." +
225 " Either set correct path to private key" +
226 " or remove key from openstack")
227
228
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300229def get_or_create_aa_group(nova, name):
230 try:
231 group = nova.server_groups.find(name=name)
232 except NotFound:
233 group = nova.server_groups.create({'name': name,
234 'policies': ['anti-affinity']})
koder aka kdanilov652cd802015-04-13 12:21:07 +0300235
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300236 return group.id
koder aka kdanilov652cd802015-04-13 12:21:07 +0300237
238
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300239def allow_ssh(nova, group_name):
240 try:
241 secgroup = nova.security_groups.find(name=group_name)
242 except NotFound:
243 secgroup = nova.security_groups.create(group_name,
244 "allow ssh/ping to node")
245
koder aka kdanilov652cd802015-04-13 12:21:07 +0300246 nova.security_group_rules.create(secgroup.id,
247 ip_protocol="tcp",
248 from_port="22",
249 to_port="22",
250 cidr="0.0.0.0/0")
251
252 nova.security_group_rules.create(secgroup.id,
253 ip_protocol="icmp",
254 from_port=-1,
255 cidr="0.0.0.0/0",
256 to_port=-1)
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300257 return secgroup.id
koder aka kdanilov652cd802015-04-13 12:21:07 +0300258
259
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300260def create_image(nova, name, url):
261 pass
262
263
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300264def create_flavor(nova, name, ram_size, hdd_size, cpu_count):
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300265 pass
266
267
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800268def create_volume(size, name):
koder aka kdanilove87ae652015-04-20 02:14:35 +0300269 cinder = cinder_connect()
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800270 vol = cinder.volumes.create(size=size, display_name=name)
271 err_count = 0
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300272
koder aka kdanilove87ae652015-04-20 02:14:35 +0300273 while vol.status != 'available':
274 if vol.status == 'error':
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800275 if err_count == 3:
koder aka kdanilove21d7472015-02-14 19:02:04 -0800276 logger.critical("Fail to create volume")
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800277 raise RuntimeError("Fail to create volume")
278 else:
279 err_count += 1
280 cinder.volumes.delete(vol)
281 time.sleep(1)
282 vol = cinder.volumes.create(size=size, display_name=name)
283 continue
284 time.sleep(1)
koder aka kdanilove87ae652015-04-20 02:14:35 +0300285 vol = cinder.volumes.get(vol.id)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800286 return vol
287
288
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300289def wait_for_server_active(nova, server, timeout=300):
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800290 t = time.time()
291 while True:
koder aka kdanilov3f356262015-02-13 08:06:14 -0800292 time.sleep(1)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800293 sstate = getattr(server, 'OS-EXT-STS:vm_state').lower()
294
295 if sstate == 'active':
296 return True
297
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800298 if sstate == 'error':
299 return False
300
301 if time.time() - t > timeout:
302 return False
303
304 server = nova.servers.get(server)
305
306
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800307class Allocate(object):
308 pass
309
310
311def get_floating_ips(nova, pool, amount):
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800312 ip_list = nova.floating_ips.list()
313
314 if pool is not None:
315 ip_list = [ip for ip in ip_list if ip.pool == pool]
316
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800317 return [ip for ip in ip_list if ip.instance_id is None][:amount]
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800318
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800319
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300320def launch_vms(params, already_has_count=0):
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300321 logger.debug("Calculating new vm count")
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300322 count = params['count']
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300323 nova = nova_connect()
324 lst = nova.services.list(binary='nova-compute')
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300325 srv_count = len([srv for srv in lst if srv.status == 'enabled'])
koder aka kdanilovda45e882015-04-06 02:24:42 +0300326
327 if isinstance(count, basestring):
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300328 if count.startswith("x"):
329 count = srv_count * int(count[1:])
330 else:
331 assert count.startswith('=')
332 count = int(count[1:]) - already_has_count
333
334 if count <= 0:
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300335 logger.debug("Not need new vms")
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300336 return
koder aka kdanilovda45e882015-04-06 02:24:42 +0300337
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300338 logger.debug("Starting new nodes on openstack")
339
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300340 assert isinstance(count, (int, long))
341
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300342 srv_params = "img: {image[name]}, flavor: {flavor[name]}".format(**params)
koder aka kdanilov66839a92015-04-11 13:22:31 +0300343 msg_templ = "Will start {0} servers with next params: {1}"
koder aka kdanilovcee43342015-04-14 22:52:53 +0300344 logger.info(msg_templ.format(count, srv_params))
koder aka kdanilovda45e882015-04-06 02:24:42 +0300345
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300346 vm_params = dict(
347 img_name=params['image']['name'],
348 flavor_name=params['flavor']['name'],
349 group_name=params['group_name'],
350 keypair_name=params['keypair_name'],
351 vol_sz=params.get('vol_sz'),
352 network_zone_name=params.get("network_zone_name"),
353 flt_ip_pool=params.get('flt_ip_pool'),
354 name_templ=params.get('name_templ'),
355 scheduler_hints={"group": params['aa_group_name']},
356 security_group=params['security_group'],
357 sec_group_size=srv_count
358 )
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300359
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300360 # precache all errors before start creating vms
361 private_key_path = params['keypair_file_private']
362 creds = params['image']['creds']
363 creds.format(ip="1.1.1.1", private_key_path="/some_path/xx")
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300364
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300365 for ip, os_node in create_vms_mt(NOVA_CONNECTION, count, **vm_params):
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300366
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300367 conn_uri = creds.format(ip=ip, private_key_path=private_key_path)
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300368 yield Node(conn_uri, []), os_node.id
koder aka kdanilovda45e882015-04-06 02:24:42 +0300369
370
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300371def get_free_server_grpoups(nova, template=None):
372 for g in nova.server_groups.list():
373 if g.members == []:
374 if re.match(template, g.name):
375 yield str(g.name)
376
377
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300378def create_vms_mt(nova, amount, group_name, keypair_name, img_name,
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800379 flavor_name, vol_sz=None, network_zone_name=None,
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300380 flt_ip_pool=None, name_templ='wally-{id}',
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300381 scheduler_hints=None, security_group=None,
382 sec_group_size=None):
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800383
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800384 with ThreadPoolExecutor(max_workers=16) as executor:
koder aka kdanilov97644f92015-02-13 11:11:08 -0800385 if network_zone_name is not None:
386 network_future = executor.submit(nova.networks.find,
387 label=network_zone_name)
388 else:
389 network_future = None
390
391 fl_future = executor.submit(nova.flavors.find, name=flavor_name)
392 img_future = executor.submit(nova.images.find, name=img_name)
393
394 if flt_ip_pool is not None:
395 ips_future = executor.submit(get_floating_ips,
396 nova, flt_ip_pool, amount)
koder aka kdanilove21d7472015-02-14 19:02:04 -0800397 logger.debug("Wait for floating ip")
koder aka kdanilov97644f92015-02-13 11:11:08 -0800398 ips = ips_future.result()
399 ips += [Allocate] * (amount - len(ips))
400 else:
401 ips = [None] * amount
402
koder aka kdanilov7dec9df2015-02-15 21:35:19 -0800403 logger.debug("Getting flavor object")
koder aka kdanilov97644f92015-02-13 11:11:08 -0800404 fl = fl_future.result()
koder aka kdanilov7dec9df2015-02-15 21:35:19 -0800405 logger.debug("Getting image object")
koder aka kdanilov97644f92015-02-13 11:11:08 -0800406 img = img_future.result()
407
408 if network_future is not None:
koder aka kdanilove21d7472015-02-14 19:02:04 -0800409 logger.debug("Waiting for network results")
koder aka kdanilov97644f92015-02-13 11:11:08 -0800410 nics = [{'net-id': network_future.result().id}]
411 else:
412 nics = None
413
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300414 names = []
415 for i in range(amount):
416 names.append(name_templ.format(group=group_name, id=i))
koder aka kdanilov97644f92015-02-13 11:11:08 -0800417
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800418 futures = []
koder aka kdanilov168f6092015-04-19 02:33:38 +0300419 logger.debug("Requesting new vm's")
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800420
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300421 orig_scheduler_hints = scheduler_hints.copy()
422
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300423 MAX_SHED_GROUPS = 32
424 for start_idx in range(MAX_SHED_GROUPS):
425 pass
426
427 group_name_template = scheduler_hints['group'].format("\\d+")
428 groups = list(get_free_server_grpoups(nova, group_name_template + "$"))
429 groups.sort()
430
431 for idx, (name, flt_ip) in enumerate(zip(names, ips), 2):
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300432
433 scheduler_hints = None
434 if orig_scheduler_hints is not None and sec_group_size is not None:
435 if "group" in orig_scheduler_hints:
436 scheduler_hints = orig_scheduler_hints.copy()
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300437 scheduler_hints['group'] = groups[idx // sec_group_size]
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300438
439 if scheduler_hints is None:
440 scheduler_hints = orig_scheduler_hints.copy()
441
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800442 params = (nova, name, keypair_name, img, fl,
443 nics, vol_sz, flt_ip, scheduler_hints,
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300444 flt_ip_pool, [security_group])
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800445
446 futures.append(executor.submit(create_vm, *params))
koder aka kdanilove21d7472015-02-14 19:02:04 -0800447 res = [future.result() for future in futures]
448 logger.debug("Done spawning")
449 return res
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800450
451
452def create_vm(nova, name, keypair_name, img,
453 fl, nics, vol_sz=None,
454 flt_ip=False,
455 scheduler_hints=None,
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300456 pool=None,
457 security_groups=None):
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800458 for i in range(3):
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800459 srv = nova.servers.create(name,
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300460 flavor=fl,
461 image=img,
462 nics=nics,
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800463 key_name=keypair_name,
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300464 scheduler_hints=scheduler_hints,
465 security_groups=security_groups)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800466
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800467 if not wait_for_server_active(nova, srv):
468 msg = "Server {0} fails to start. Kill it and try again"
koder aka kdanilove21d7472015-02-14 19:02:04 -0800469 logger.debug(msg.format(srv))
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800470 nova.servers.delete(srv)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800471
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300472 try:
473 for j in range(120):
474 srv = nova.servers.get(srv.id)
475 time.sleep(1)
476 else:
477 msg = "Server {0} delete timeout".format(srv.id)
478 raise RuntimeError(msg)
479 except NotFound:
480 pass
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800481 else:
482 break
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300483 else:
484 raise RuntimeError("Failed to start server".format(srv.id))
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800485
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800486 if vol_sz is not None:
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800487 vol = create_volume(vol_sz, name)
koder aka kdanilove87ae652015-04-20 02:14:35 +0300488 nova.volumes.create_server_volume(srv.id, vol.id, None)
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800489
490 if flt_ip is Allocate:
491 flt_ip = nova.floating_ips.create(pool)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300492
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800493 if flt_ip is not None:
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800494 srv.add_floating_ip(flt_ip)
Yulia Portnova0e64ea22015-03-20 17:27:22 +0200495
koder aka kdanilovda45e882015-04-06 02:24:42 +0300496 return flt_ip.ip, nova.servers.get(srv.id)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800497
498
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300499def clear_nodes(nodes_ids):
500 clear_all(NOVA_CONNECTION, nodes_ids, None)
gstepanov023c1e42015-04-08 15:50:19 +0300501
502
koder aka kdanilove87ae652015-04-20 02:14:35 +0300503def clear_all(nova, ids=None, name_templ=None):
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300504
505 def need_delete(srv):
506 if name_templ is not None:
507 return re.match(name_templ.format("\\d+"), srv.name) is not None
508 else:
509 return srv.id in ids
510
koder aka kdanilove87ae652015-04-20 02:14:35 +0300511 volumes_to_delete = []
512 cinder = cinder_connect()
513 for vol in cinder.volumes.list():
514 for attachment in vol.attachments:
515 if attachment['server_id'] in ids:
516 volumes_to_delete.append(vol)
517 break
518
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800519 deleted_srvs = set()
520 for srv in nova.servers.list():
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300521 if need_delete(srv):
koder aka kdanilove21d7472015-02-14 19:02:04 -0800522 logger.debug("Deleting server {0}".format(srv.name))
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800523 nova.servers.delete(srv)
524 deleted_srvs.add(srv.id)
525
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300526 count = 0
527 while True:
528 if count % 60 == 0:
529 logger.debug("Waiting till all servers are actually deleted")
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800530 all_id = set(srv.id for srv in nova.servers.list())
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300531 if len(all_id.intersection(deleted_srvs)) == 0:
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800532 break
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300533 count += 1
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800534 time.sleep(1)
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300535 logger.debug("Done, deleting volumes")
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800536
537 # wait till vm actually deleted
538
koder aka kdanilov6b1341a2015-04-21 22:44:21 +0300539 # logger.warning("Volume deletion commented out")
540 for vol in volumes_to_delete:
541 logger.debug("Deleting volume " + vol.display_name)
542 cinder.volumes.delete(vol)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800543
koder aka kdanilove21d7472015-02-14 19:02:04 -0800544 logger.debug("Clearing done (yet some volumes may still deleting)")