Revision 60a80953 snf-tools/synnefo_tools/burnin/cyclades_common.py
b/snf-tools/synnefo_tools/burnin/cyclades_common.py | ||
---|---|---|
39 | 39 |
""" |
40 | 40 |
|
41 | 41 |
import time |
42 |
import IPy |
|
42 | 43 |
import base64 |
43 | 44 |
import socket |
44 | 45 |
import random |
... | ... | |
46 | 47 |
import tempfile |
47 | 48 |
import subprocess |
48 | 49 |
|
50 |
from kamaki.clients import ClientError |
|
51 |
|
|
49 | 52 |
from synnefo_tools.burnin.common import BurninTests, MB, GB |
50 | 53 |
|
51 | 54 |
|
... | ... | |
101 | 104 |
self.info("Getting detailed list of networks") |
102 | 105 |
else: |
103 | 106 |
self.info("Getting simple list of networks") |
104 |
return self.clients.cyclades.list_networks(detail=detail)
|
|
107 |
return self.clients.network.list_networks(detail=detail)
|
|
105 | 108 |
|
106 | 109 |
def _get_server_details(self, server, quiet=False): |
107 | 110 |
"""Get details for a server""" |
... | ... | |
110 | 113 |
server['name'], server['id']) |
111 | 114 |
return self.clients.cyclades.get_server_details(server['id']) |
112 | 115 |
|
113 |
def _create_server(self, image, flavor, personality=None): |
|
116 |
def _create_server(self, image, flavor, personality=None, network=False):
|
|
114 | 117 |
"""Create a new server""" |
118 |
if network: |
|
119 |
fip = self._create_floating_ip() |
|
120 |
port = self._create_port(fip['floating_network_id'], |
|
121 |
floating_ip=fip) |
|
122 |
networks = [{'port': port['id']}] |
|
123 |
else: |
|
124 |
networks = None |
|
125 |
|
|
115 | 126 |
servername = "%s for %s" % (self.run_id, image['name']) |
116 | 127 |
self.info("Creating a server with name %s", servername) |
117 | 128 |
self.info("Using image %s with id %s", image['name'], image['id']) |
118 | 129 |
self.info("Using flavor %s with id %s", flavor['name'], flavor['id']) |
119 | 130 |
server = self.clients.cyclades.create_server( |
120 |
servername, flavor['id'], image['id'], personality=personality) |
|
131 |
servername, flavor['id'], image['id'], |
|
132 |
personality=personality, networks=networks) |
|
121 | 133 |
|
122 | 134 |
self.info("Server id: %s", server['id']) |
123 | 135 |
self.info("Server password: %s", server['adminPass']) |
... | ... | |
135 | 147 |
|
136 | 148 |
return server |
137 | 149 |
|
150 |
def _delete_servers(self, servers, error=False): |
|
151 |
"""Deleting a number of servers in parallel""" |
|
152 |
# Disconnect floating IPs |
|
153 |
for srv in servers: |
|
154 |
self.info("Disconnecting all floating IPs from server with id %s", |
|
155 |
srv['id']) |
|
156 |
self._disconnect_from_network(srv) |
|
157 |
|
|
158 |
# Delete servers |
|
159 |
for srv in servers: |
|
160 |
self.info("Sending the delete request for server with id %s", |
|
161 |
srv['id']) |
|
162 |
self.clients.cyclades.delete_server(srv['id']) |
|
163 |
|
|
164 |
if error: |
|
165 |
curr_states = ["ACTIVE", "ERROR", "STOPPED", "BUILD"] |
|
166 |
else: |
|
167 |
curr_states = ["ACTIVE"] |
|
168 |
for srv in servers: |
|
169 |
self._insist_on_server_transition(srv, curr_states, "DELETED") |
|
170 |
|
|
171 |
# Servers no longer in server list |
|
172 |
new_servers = [s['id'] for s in self._get_list_of_servers()] |
|
173 |
for srv in servers: |
|
174 |
self.info("Verifying that server with id %s is no longer in " |
|
175 |
"server list", srv['id']) |
|
176 |
self.assertNotIn(srv['id'], new_servers) |
|
177 |
|
|
178 |
# Verify quotas |
|
179 |
flavors = \ |
|
180 |
[self.clients.compute.get_flavor_details(srv['flavor']['id']) |
|
181 |
for srv in servers] |
|
182 |
self._verify_quotas_deleted(flavors) |
|
183 |
|
|
138 | 184 |
def _verify_quotas_deleted(self, flavors): |
139 | 185 |
"""Verify quotas for a number of deleted servers""" |
140 | 186 |
used_disk = 0 |
... | ... | |
199 | 245 |
"""Insist on network transiting from curr_statuses to new_status""" |
200 | 246 |
def check_fun(): |
201 | 247 |
"""Check network status""" |
202 |
ntw = self.clients.cyclades.get_network_details(network['id'])
|
|
248 |
ntw = self.clients.network.get_network_details(network['id'])
|
|
203 | 249 |
if ntw['status'] in curr_statuses: |
204 | 250 |
raise Retry() |
205 | 251 |
elif ntw['status'] == new_status: |
... | ... | |
214 | 260 |
opmsg = opmsg % (network['name'], network['id'], new_status) |
215 | 261 |
self._try_until_timeout_expires(opmsg, check_fun) |
216 | 262 |
|
217 |
def _insist_on_network_connection(self, server, network, disconnect=False): |
|
218 |
"""Insist that the server has connected to the network""" |
|
219 |
def check_fun(): |
|
220 |
"""Check network connection""" |
|
221 |
dsrv = self._get_server_details(server, quiet=True) |
|
222 |
nets = [s['network_id'] for s in dsrv['attachments']] |
|
223 |
if not disconnect and network['id'] not in nets: |
|
224 |
raise Retry() |
|
225 |
if disconnect and network['id'] in nets: |
|
226 |
raise Retry() |
|
227 |
if disconnect: |
|
228 |
opmsg = \ |
|
229 |
"Waiting for server \"%s\" to disconnect from network \"%s\"" |
|
230 |
else: |
|
231 |
opmsg = "Waiting for server \"%s\" to connect to network \"%s\"" |
|
232 |
self.info(opmsg, server['name'], network['name']) |
|
233 |
opmsg = opmsg % (server['name'], network['name']) |
|
234 |
self._try_until_timeout_expires(opmsg, check_fun) |
|
235 |
|
|
236 | 263 |
def _insist_on_tcp_connection(self, family, host, port): |
237 | 264 |
"""Insist on tcp connection""" |
238 | 265 |
def check_fun(): |
... | ... | |
263 | 290 |
opmsg = opmsg % (familystr.get(family, "Unknown"), host, port) |
264 | 291 |
return self._try_until_timeout_expires(opmsg, check_fun) |
265 | 292 |
|
266 |
def _get_ip(self, server, version=4, network=None): |
|
267 |
"""Get the IP of a server from the detailed server info |
|
293 |
def _get_ips(self, server, version=4, network=None):
|
|
294 |
"""Get the IPs of a server from the detailed server info
|
|
268 | 295 |
|
269 |
If network not given then get the public IP. Else the ip
|
|
296 |
If network not given then get the public IPs. Else the IPs
|
|
270 | 297 |
attached to that network |
271 | 298 |
|
272 | 299 |
""" |
273 | 300 |
assert version in (4, 6) |
274 | 301 |
|
275 | 302 |
nics = server['attachments'] |
276 |
addrs = None
|
|
303 |
addrs = []
|
|
277 | 304 |
for nic in nics: |
278 | 305 |
net_id = nic['network_id'] |
279 | 306 |
if network is None: |
280 |
if self.clients.cyclades.get_network_details(net_id)['public']:
|
|
307 |
if self.clients.network.get_network_details(net_id)['public']:
|
|
281 | 308 |
if nic['ipv' + str(version)]: |
282 |
addrs = nic['ipv' + str(version)] |
|
283 |
break |
|
309 |
addrs.append(nic['ipv' + str(version)]) |
|
284 | 310 |
else: |
285 | 311 |
if net_id == network['id']: |
286 | 312 |
if nic['ipv' + str(version)]: |
287 |
addrs = nic['ipv' + str(version)] |
|
288 |
break |
|
313 |
addrs.append(nic['ipv' + str(version)]) |
|
314 |
|
|
315 |
self.assertGreater(len(addrs), 0, |
|
316 |
"Can not get IPs from server attachments") |
|
317 |
|
|
318 |
for addr in addrs: |
|
319 |
self.assertEquals(IPy.IP(addr).version(), version) |
|
289 | 320 |
|
290 |
self.assertIsNotNone(addrs, "Can not get IP from server attachments") |
|
291 | 321 |
if network is None: |
292 | 322 |
msg = "Server's public IPv%s is %s" |
293 |
self.info(msg, version, addrs) |
|
323 |
for addr in addrs: |
|
324 |
self.info(msg, version, addr) |
|
294 | 325 |
else: |
295 | 326 |
msg = "Server's IPv%s attached to network \"%s\" is %s" |
296 |
self.info(msg, version, network['id'], addrs) |
|
327 |
for addr in addrs: |
|
328 |
self.info(msg, version, network['id'], addr) |
|
297 | 329 |
return addrs |
298 | 330 |
|
299 | 331 |
def _insist_on_ping(self, ip_addr, version=4): |
... | ... | |
372 | 404 |
remote_content = base64.b64encode(ftmp.read()) |
373 | 405 |
self.assertEqual(content, remote_content) |
374 | 406 |
|
375 |
def _disconnect_from_network(self, server, network): |
|
376 |
"""Disconnect server from network""" |
|
377 |
nid = None |
|
378 |
for nic in server['attachments']: |
|
379 |
if nic['network_id'] == network['id']: |
|
380 |
nid = nic['id'] |
|
381 |
break |
|
382 |
self.assertIsNotNone(nid, "Could not find network card") |
|
383 |
self.clients.cyclades.disconnect_server(server['id'], nid) |
|
384 |
|
|
385 |
def _create_network(self, name, cidr="10.0.1.0/28", dhcp=True): |
|
407 |
# ---------------------------------- |
|
408 |
# Networks |
|
409 |
def _create_network(self, cidr="10.0.1.0/28", dhcp=True): |
|
386 | 410 |
"""Create a new private network""" |
387 |
network = self.clients.cyclades.create_network( |
|
388 |
name, cidr=cidr, dhcp=dhcp) |
|
411 |
name = self.run_id |
|
412 |
network = self.clients.network.create_network( |
|
413 |
"MAC_FILTERED", name=name, shared=False) |
|
389 | 414 |
self.info("Network with id %s created", network['id']) |
415 |
subnet = self.clients.network.create_subnet( |
|
416 |
network['id'], cidr=cidr, enable_dhcp=dhcp) |
|
417 |
self.info("Subnet with id %s created", subnet['id']) |
|
390 | 418 |
|
391 | 419 |
# Verify quotas |
392 | 420 |
self._check_quotas(network=+1) |
... | ... | |
396 | 424 |
|
397 | 425 |
return network |
398 | 426 |
|
427 |
def _delete_networks(self, networks, error=False): |
|
428 |
"""Delete a network""" |
|
429 |
for net in networks: |
|
430 |
self.info("Deleting network with id %s", net['id']) |
|
431 |
self.clients.network.delete_network(net['id']) |
|
432 |
|
|
433 |
if error: |
|
434 |
curr_states = ["ACTIVE", "SNF:DRAINED", "ERROR"] |
|
435 |
else: |
|
436 |
curr_states = ["ACTIVE", "SNF:DRAINED"] |
|
437 |
for net in networks: |
|
438 |
self._insist_on_network_transition(net, curr_states, "DELETED") |
|
439 |
|
|
440 |
# Networks no longer in network list |
|
441 |
new_networks = [n['id'] for n in self._get_list_of_networks()] |
|
442 |
for net in networks: |
|
443 |
self.info("Verifying that network with id %s is no longer in " |
|
444 |
"network list", net['id']) |
|
445 |
self.assertNotIn(net['id'], new_networks) |
|
446 |
|
|
447 |
# Verify quotas |
|
448 |
self._check_quotas(network=-len(networks)) |
|
449 |
|
|
450 |
def _get_public_network(self, networks=None): |
|
451 |
"""Get the public network""" |
|
452 |
if networks is None: |
|
453 |
networks = self._get_list_of_networks(detail=True) |
|
454 |
self.info("Getting the public network") |
|
455 |
for net in networks: |
|
456 |
if net['SNF:floating_ip_pool'] and net['public']: |
|
457 |
return net |
|
458 |
self.fail("Could not find a public network to use") |
|
459 |
|
|
460 |
def _create_floating_ip(self): |
|
461 |
"""Create a new floating ip""" |
|
462 |
pub_net = self._get_public_network() |
|
463 |
self.info("Creating a new floating ip for network with id %s", |
|
464 |
pub_net['id']) |
|
465 |
fip = self.clients.network.create_floatingip(pub_net['id']) |
|
466 |
# Verify that floating ip has been created |
|
467 |
fips = self.clients.network.list_floatingips() |
|
468 |
fips = [f['id'] for f in fips] |
|
469 |
self.assertIn(fip['id'], fips) |
|
470 |
# Verify quotas |
|
471 |
self._check_quotas(ip=+1) |
|
472 |
# Check that IP is IPv4 |
|
473 |
self.assertEquals(IPy.IP(fip['floating_ip_address']).version(), 4) |
|
474 |
|
|
475 |
self.info("Floating IP %s with id %s created", |
|
476 |
fip['floating_ip_address'], fip['id']) |
|
477 |
return fip |
|
478 |
|
|
479 |
def _create_port(self, network_id, device_id=None, floating_ip=None): |
|
480 |
"""Create a new port attached to the a specific network""" |
|
481 |
self.info("Creating a new port to network with id %s", network_id) |
|
482 |
if floating_ip is not None: |
|
483 |
fixed_ips = [{'ip_address': floating_ip['floating_ip_address']}] |
|
484 |
else: |
|
485 |
fixed_ips = None |
|
486 |
port = self.clients.network.create_port(network_id, |
|
487 |
device_id=device_id, |
|
488 |
fixed_ips=fixed_ips) |
|
489 |
# Verify that port created |
|
490 |
ports = self.clients.network.list_ports() |
|
491 |
ports = [p['id'] for p in ports] |
|
492 |
self.assertIn(port['id'], ports) |
|
493 |
# Insist on creation |
|
494 |
if device_id is None: |
|
495 |
self._insist_on_port_transition(port, ["BUILD"], "DOWN") |
|
496 |
else: |
|
497 |
self._insist_on_port_transition(port, ["BUILD", "DOWN"], "ACTIVE") |
|
498 |
|
|
499 |
self.info("Port with id %s created", port['id']) |
|
500 |
return port |
|
501 |
|
|
502 |
def _insist_on_port_transition(self, port, curr_statuses, new_status): |
|
503 |
"""Insist on port transiting from curr_statuses to new_status""" |
|
504 |
def check_fun(): |
|
505 |
"""Check port status""" |
|
506 |
portd = self.clients.network.get_port_details(port['id']) |
|
507 |
if portd['status'] in curr_statuses: |
|
508 |
raise Retry() |
|
509 |
elif portd['status'] == new_status: |
|
510 |
return |
|
511 |
else: |
|
512 |
msg = "Port %s went to unexpected status %s" |
|
513 |
self.fail(msg % (portd['id'], portd['status'])) |
|
514 |
opmsg = "Waiting for port %s to become %s" |
|
515 |
self.info(opmsg, port['id'], new_status) |
|
516 |
opmsg = opmsg % (port['id'], new_status) |
|
517 |
self._try_until_timeout_expires(opmsg, check_fun) |
|
518 |
|
|
519 |
def _insist_on_port_deletion(self, portid): |
|
520 |
"""Insist on port deletion""" |
|
521 |
def check_fun(): |
|
522 |
"""Check port details""" |
|
523 |
try: |
|
524 |
self.clients.network.get_port_details(portid) |
|
525 |
except ClientError as err: |
|
526 |
if err.status != 404: |
|
527 |
raise |
|
528 |
else: |
|
529 |
raise Retry() |
|
530 |
opmsg = "Waiting for port %s to be deleted" |
|
531 |
self.info(opmsg, portid) |
|
532 |
opmsg = opmsg % portid |
|
533 |
self._try_until_timeout_expires(opmsg, check_fun) |
|
534 |
|
|
535 |
def _disconnect_from_network(self, server, network=None): |
|
536 |
"""Disconnnect server from network""" |
|
537 |
if network is None: |
|
538 |
# Disconnect from public network |
|
539 |
network = self._get_public_network() |
|
540 |
|
|
541 |
lports = self.clients.network.list_ports() |
|
542 |
ports = [] |
|
543 |
for port in lports: |
|
544 |
dport = self.clients.network.get_port_details(port['id']) |
|
545 |
if str(dport['network_id']) == str(network['id']) \ |
|
546 |
and str(dport['device_id']) == str(server['id']): |
|
547 |
ports.append(dport) |
|
548 |
|
|
549 |
# Find floating IPs attached to these ports |
|
550 |
ports_id = [p['id'] for p in ports] |
|
551 |
fips = [f for f in self.clients.network.list_floatingips() |
|
552 |
if str(f['port_id']) in ports_id] |
|
553 |
|
|
554 |
# First destroy the ports |
|
555 |
for port in ports: |
|
556 |
self.info("Destroying port with id %s", port['id']) |
|
557 |
self.clients.network.delete_port(port['id']) |
|
558 |
self._insist_on_port_deletion(port['id']) |
|
559 |
|
|
560 |
# Then delete the floating IPs |
|
561 |
for fip in fips: |
|
562 |
self.info("Destroying floating IP %s with id %s", |
|
563 |
fip['floating_ip_address'], fip['id']) |
|
564 |
self.clients.network.delete_floatingip(fip['id']) |
|
565 |
|
|
566 |
# Check that floating IPs have been deleted |
|
567 |
list_ips = [f['id'] for f in self.clients.network.list_floatingips()] |
|
568 |
for fip in fips: |
|
569 |
self.assertNotIn(fip['id'], list_ips) |
|
570 |
# Verify quotas |
|
571 |
self._check_quotas(ip=-len(fips)) |
|
572 |
|
|
399 | 573 |
|
400 | 574 |
class Retry(Exception): |
401 | 575 |
"""Retry the action |
Also available in: Unified diff