blob: 93162a32f2adb5fd2cf73f851652c289780952cd [file] [log] [blame]
koder aka kdanilov4643fd62015-02-10 16:20:13 -08001import re
2import os
3import time
koder aka kdanilove21d7472015-02-14 19:02:04 -08004import logging
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +03005import subprocess
koder aka kdanilov4643fd62015-02-10 16:20:13 -08006
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -08007from concurrent.futures import ThreadPoolExecutor
8
koder aka kdanilov652cd802015-04-13 12:21:07 +03009# from novaclient.exceptions import NotFound
koder aka kdanilov4643fd62015-02-10 16:20:13 -080010from novaclient.client import Client as n_client
11from cinderclient.v1.client import Client as c_client
12
koder aka kdanilovda45e882015-04-06 02:24:42 +030013from nodes.node import Node
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030014
koder aka kdanilov4643fd62015-02-10 16:20:13 -080015
koder aka kdanilove21d7472015-02-14 19:02:04 -080016logger = logging.getLogger("io-perf-tool")
17
18
koder aka kdanilov4643fd62015-02-10 16:20:13 -080019def ostack_get_creds():
20 env = os.environ.get
21 name = env('OS_USERNAME')
22 passwd = env('OS_PASSWORD')
23 tenant = env('OS_TENANT_NAME')
24 auth_url = env('OS_AUTH_URL')
gstepanov023c1e42015-04-08 15:50:19 +030025
koder aka kdanilov4643fd62015-02-10 16:20:13 -080026 return name, passwd, tenant, auth_url
27
28
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030029NOVA_CONNECTION = None
30
31
32def nova_connect(name=None, passwd=None, tenant=None, auth_url=None):
33 global NOVA_CONNECTION
34 if NOVA_CONNECTION is None:
35 if name is None:
36 name, passwd, tenant, auth_url = ostack_get_creds()
37 NOVA_CONNECTION = n_client('1.1', name, passwd, tenant, auth_url)
38 return NOVA_CONNECTION
39
40
41def nova_disconnect():
42 global NOVA_CONNECTION
43 if NOVA_CONNECTION is not None:
44 NOVA_CONNECTION.close()
45 NOVA_CONNECTION = None
koder aka kdanilov4643fd62015-02-10 16:20:13 -080046
47
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +030048def prepare_os(name=None, passwd=None, tenant=None, auth_url=None):
49 if name is None:
50 name, passwd, tenant, auth_url = ostack_get_creds()
51
52 params = {
53 'OS_USERNAME': name,
54 'OS_PASSWORD': passwd,
55 'OS_TENANT_NAME': tenant,
56 'OS_AUTH_URL': auth_url
57 }
58
59 params_s = " ".join("{}={}".format(k, v) for k, v in params.items())
60
61 cmd = "env {params} bash scripts/prepare.sh".format(params_s)
62 subprocess.call(cmd, shell=True)
63
64 return NOVA_CONNECTION
65
66
koder aka kdanilov652cd802015-04-13 12:21:07 +030067# def get_or_create_aa_group(nova, name):
68# try:
69# group = conn.server_groups.find(name=name)
70# except NotFound:
71# group = None
72
73# if group is None:
74# conn.server_groups.create
75
76
77def allow_ssh(nova):
78 secgroup = nova.security_groups.find(name="default")
79 nova.security_group_rules.create(secgroup.id,
80 ip_protocol="tcp",
81 from_port="22",
82 to_port="22",
83 cidr="0.0.0.0/0")
84
85 nova.security_group_rules.create(secgroup.id,
86 ip_protocol="icmp",
87 from_port=-1,
88 cidr="0.0.0.0/0",
89 to_port=-1)
90
91
koder aka kdanilov4643fd62015-02-10 16:20:13 -080092def create_keypair(nova, name, key_path):
93 with open(key_path) as key:
94 return nova.keypairs.create(name, key.read())
95
96
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080097def create_volume(size, name):
koder aka kdanilov4643fd62015-02-10 16:20:13 -080098 cinder = c_client(*ostack_get_creds())
koder aka kdanilov4643fd62015-02-10 16:20:13 -080099 vol = cinder.volumes.create(size=size, display_name=name)
100 err_count = 0
101 while vol.status != 'available':
102 if vol.status == 'error':
103 if err_count == 3:
koder aka kdanilove21d7472015-02-14 19:02:04 -0800104 logger.critical("Fail to create volume")
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800105 raise RuntimeError("Fail to create volume")
106 else:
107 err_count += 1
108 cinder.volumes.delete(vol)
109 time.sleep(1)
110 vol = cinder.volumes.create(size=size, display_name=name)
111 continue
112 time.sleep(1)
113 vol = cinder.volumes.get(vol.id)
114 return vol
115
116
117def wait_for_server_active(nova, server, timeout=240):
118 t = time.time()
119 while True:
koder aka kdanilov3f356262015-02-13 08:06:14 -0800120 time.sleep(1)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800121 sstate = getattr(server, 'OS-EXT-STS:vm_state').lower()
122
123 if sstate == 'active':
124 return True
125
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800126 if sstate == 'error':
127 return False
128
129 if time.time() - t > timeout:
130 return False
131
132 server = nova.servers.get(server)
133
134
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800135class Allocate(object):
136 pass
137
138
139def get_floating_ips(nova, pool, amount):
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800140 ip_list = nova.floating_ips.list()
141
142 if pool is not None:
143 ip_list = [ip for ip in ip_list if ip.pool == pool]
144
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800145 return [ip for ip in ip_list if ip.instance_id is None][:amount]
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800146
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800147
koder aka kdanilovcee43342015-04-14 22:52:53 +0300148def launch_vms(params):
koder aka kdanilovda45e882015-04-06 02:24:42 +0300149 logger.debug("Starting new nodes on openstack")
koder aka kdanilovcee43342015-04-14 22:52:53 +0300150 params = params.copy()
koder aka kdanilovda45e882015-04-06 02:24:42 +0300151 count = params.pop('count')
152
153 if isinstance(count, basestring):
154 assert count.startswith("x")
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300155 lst = NOVA_CONNECTION.services.list(binary='nova-compute')
koder aka kdanilovda45e882015-04-06 02:24:42 +0300156 srv_count = len([srv for srv in lst if srv.status == 'enabled'])
157 count = srv_count * int(count[1:])
158
koder aka kdanilovcee43342015-04-14 22:52:53 +0300159 srv_params = "img: {img_name}, flavor: {flavor_name}".format(**params)
koder aka kdanilov66839a92015-04-11 13:22:31 +0300160 msg_templ = "Will start {0} servers with next params: {1}"
koder aka kdanilovcee43342015-04-14 22:52:53 +0300161 logger.info(msg_templ.format(count, srv_params))
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300162 vm_creds = params.pop('creds')
koder aka kdanilovda45e882015-04-06 02:24:42 +0300163
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300164 for ip, os_node in create_vms_mt(NOVA_CONNECTION, count, **params):
165 yield Node(vm_creds.format(ip), []), os_node.id
koder aka kdanilovda45e882015-04-06 02:24:42 +0300166
167
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800168def create_vms_mt(nova, amount, keypair_name, img_name,
169 flavor_name, vol_sz=None, network_zone_name=None,
koder aka kdanilov7dec9df2015-02-15 21:35:19 -0800170 flt_ip_pool=None, name_templ='ceph-test-{0}',
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800171 scheduler_hints=None):
172
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800173 with ThreadPoolExecutor(max_workers=16) as executor:
koder aka kdanilov97644f92015-02-13 11:11:08 -0800174 if network_zone_name is not None:
175 network_future = executor.submit(nova.networks.find,
176 label=network_zone_name)
177 else:
178 network_future = None
179
180 fl_future = executor.submit(nova.flavors.find, name=flavor_name)
181 img_future = executor.submit(nova.images.find, name=img_name)
182
183 if flt_ip_pool is not None:
184 ips_future = executor.submit(get_floating_ips,
185 nova, flt_ip_pool, amount)
koder aka kdanilove21d7472015-02-14 19:02:04 -0800186 logger.debug("Wait for floating ip")
koder aka kdanilov97644f92015-02-13 11:11:08 -0800187 ips = ips_future.result()
188 ips += [Allocate] * (amount - len(ips))
189 else:
190 ips = [None] * amount
191
koder aka kdanilov7dec9df2015-02-15 21:35:19 -0800192 logger.debug("Getting flavor object")
koder aka kdanilov97644f92015-02-13 11:11:08 -0800193 fl = fl_future.result()
koder aka kdanilov7dec9df2015-02-15 21:35:19 -0800194 logger.debug("Getting image object")
koder aka kdanilov97644f92015-02-13 11:11:08 -0800195 img = img_future.result()
196
197 if network_future is not None:
koder aka kdanilove21d7472015-02-14 19:02:04 -0800198 logger.debug("Waiting for network results")
koder aka kdanilov97644f92015-02-13 11:11:08 -0800199 nics = [{'net-id': network_future.result().id}]
200 else:
201 nics = None
202
koder aka kdanilov97644f92015-02-13 11:11:08 -0800203 names = map(name_templ.format, range(amount))
204
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800205 futures = []
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800206 logger.debug("Requesting new vms")
207
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800208 for name, flt_ip in zip(names, ips):
209 params = (nova, name, keypair_name, img, fl,
210 nics, vol_sz, flt_ip, scheduler_hints,
211 flt_ip_pool)
212
213 futures.append(executor.submit(create_vm, *params))
koder aka kdanilove21d7472015-02-14 19:02:04 -0800214 res = [future.result() for future in futures]
215 logger.debug("Done spawning")
216 return res
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800217
218
219def create_vm(nova, name, keypair_name, img,
220 fl, nics, vol_sz=None,
221 flt_ip=False,
222 scheduler_hints=None,
223 pool=None):
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800224 for i in range(3):
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800225 srv = nova.servers.create(name,
226 flavor=fl, image=img, nics=nics,
227 key_name=keypair_name,
228 scheduler_hints=scheduler_hints)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800229
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800230 if not wait_for_server_active(nova, srv):
231 msg = "Server {0} fails to start. Kill it and try again"
koder aka kdanilove21d7472015-02-14 19:02:04 -0800232 logger.debug(msg.format(srv))
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800233 nova.servers.delete(srv)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800234
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800235 while True:
koder aka kdanilov3f356262015-02-13 08:06:14 -0800236 # print "wait till server deleted"
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800237 all_id = set(alive_srv.id for alive_srv in nova.servers.list())
238 if srv.id not in all_id:
239 break
240 time.sleep(1)
241 else:
242 break
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800243
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800244 if vol_sz is not None:
koder aka kdanilov3f356262015-02-13 08:06:14 -0800245 # print "creating volume"
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800246 vol = create_volume(vol_sz, name)
koder aka kdanilov3f356262015-02-13 08:06:14 -0800247 # print "attach volume to server"
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800248 nova.volumes.create_server_volume(srv.id, vol.id, None)
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800249
250 if flt_ip is Allocate:
251 flt_ip = nova.floating_ips.create(pool)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300252
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -0800253 if flt_ip is not None:
koder aka kdanilov3f356262015-02-13 08:06:14 -0800254 # print "attaching ip to server"
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800255 srv.add_floating_ip(flt_ip)
Yulia Portnova0e64ea22015-03-20 17:27:22 +0200256
koder aka kdanilovda45e882015-04-06 02:24:42 +0300257 return flt_ip.ip, nova.servers.get(srv.id)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800258
259
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300260def clear_nodes(nodes_ids):
261 clear_all(NOVA_CONNECTION, nodes_ids, None)
gstepanov023c1e42015-04-08 15:50:19 +0300262
263
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300264def clear_all(nova, ids=None, name_templ="ceph-test-{0}"):
265
266 def need_delete(srv):
267 if name_templ is not None:
268 return re.match(name_templ.format("\\d+"), srv.name) is not None
269 else:
270 return srv.id in ids
271
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800272 deleted_srvs = set()
273 for srv in nova.servers.list():
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300274 if need_delete(srv):
koder aka kdanilove21d7472015-02-14 19:02:04 -0800275 logger.debug("Deleting server {0}".format(srv.name))
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800276 nova.servers.delete(srv)
277 deleted_srvs.add(srv.id)
278
279 while deleted_srvs != set():
koder aka kdanilove21d7472015-02-14 19:02:04 -0800280 logger.debug("Waiting till all servers are actually deleted")
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800281 all_id = set(srv.id for srv in nova.servers.list())
282 if all_id.intersection(deleted_srvs) == set():
koder aka kdanilove21d7472015-02-14 19:02:04 -0800283 logger.debug("Done, deleting volumes")
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800284 break
285 time.sleep(1)
286
287 # wait till vm actually deleted
288
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300289 if name_templ is not None:
290 cinder = c_client(*ostack_get_creds())
291 for vol in cinder.volumes.list():
292 if isinstance(vol.display_name, basestring):
293 if re.match(name_templ.format("\\d+"), vol.display_name):
294 if vol.status in ('available', 'error'):
295 logger.debug("Deleting volume " + vol.display_name)
296 cinder.volumes.delete(vol)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800297
koder aka kdanilove21d7472015-02-14 19:02:04 -0800298 logger.debug("Clearing done (yet some volumes may still deleting)")