Revision c2f037ff snf-tools/synnefo_tools/burnin/cyclades_common.py
b/snf-tools/synnefo_tools/burnin/cyclades_common.py | ||
---|---|---|
49 | 49 |
|
50 | 50 |
from kamaki.clients import ClientError |
51 | 51 |
|
52 |
from synnefo_tools.burnin.common import BurninTests, MB, GB |
|
52 |
from synnefo_tools.burnin.common import BurninTests, MB, GB, QADD, QREMOVE, \ |
|
53 |
QDISK, QVM, QRAM, QIP, QCPU, QNET |
|
53 | 54 |
|
54 | 55 |
|
55 | 56 |
# pylint: disable=too-many-public-methods |
56 | 57 |
class CycladesTests(BurninTests): |
57 | 58 |
"""Extends the BurninTests class for Cyclades""" |
59 |
def _parse_images(self): |
|
60 |
"""Find images given to command line""" |
|
61 |
if self.images is None: |
|
62 |
self.info("No --images given. Will use the default %s", |
|
63 |
"^Debian Base$") |
|
64 |
filters = ["name:^Debian Base$"] |
|
65 |
else: |
|
66 |
filters = self.images |
|
67 |
avail_images = self._find_images(filters) |
|
68 |
self.info("Found %s images to choose from", len(avail_images)) |
|
69 |
return avail_images |
|
70 |
|
|
71 |
def _parse_flavors(self): |
|
72 |
"""Find flavors given to command line""" |
|
73 |
flavors = self._get_list_of_flavors(detail=True) |
|
74 |
|
|
75 |
if self.flavors is None: |
|
76 |
self.info("No --flavors given. Will use all of them") |
|
77 |
avail_flavors = flavors |
|
78 |
else: |
|
79 |
avail_flavors = self._find_flavors(self.flavors, flavors=flavors) |
|
80 |
|
|
81 |
self.info("Found %s flavors to choose from", len(avail_flavors)) |
|
82 |
return avail_flavors |
|
83 |
|
|
58 | 84 |
def _try_until_timeout_expires(self, opmsg, check_fun): |
59 | 85 |
"""Try to perform an action until timeout expires""" |
60 | 86 |
assert callable(check_fun), "Not a function" |
... | ... | |
113 | 139 |
server['name'], server['id']) |
114 | 140 |
return self.clients.cyclades.get_server_details(server['id']) |
115 | 141 |
|
116 |
def _create_server(self, image, flavor, personality=None, network=False): |
|
142 |
# pylint: disable=too-many-arguments |
|
143 |
def _create_server(self, image, flavor, personality=None, |
|
144 |
network=False, project_id=None): |
|
117 | 145 |
"""Create a new server""" |
118 | 146 |
if network: |
119 |
fip = self._create_floating_ip() |
|
147 |
fip = self._create_floating_ip(project_id=project_id)
|
|
120 | 148 |
port = self._create_port(fip['floating_network_id'], |
121 | 149 |
floating_ip=fip) |
122 | 150 |
networks = [{'port': port['id']}] |
... | ... | |
129 | 157 |
self.info("Using flavor %s with id %s", flavor['name'], flavor['id']) |
130 | 158 |
server = self.clients.cyclades.create_server( |
131 | 159 |
servername, flavor['id'], image['id'], |
132 |
personality=personality, networks=networks) |
|
160 |
personality=personality, networks=networks, |
|
161 |
project=project_id) |
|
133 | 162 |
|
134 | 163 |
self.info("Server id: %s", server['id']) |
135 | 164 |
self.info("Server password: %s", server['adminPass']) |
... | ... | |
138 | 167 |
self.assertEqual(server['flavor']['id'], flavor['id']) |
139 | 168 |
self.assertEqual(server['image']['id'], image['id']) |
140 | 169 |
self.assertEqual(server['status'], "BUILD") |
170 |
if project_id is None: |
|
171 |
project_id = self._get_uuid() |
|
172 |
self.assertEqual(server['tenant_id'], project_id) |
|
141 | 173 |
|
142 | 174 |
# Verify quotas |
143 |
self._check_quotas(disk=+int(flavor['disk'])*GB, |
|
144 |
vm=+1, |
|
145 |
ram=+int(flavor['ram'])*MB, |
|
146 |
cpu=+int(flavor['vcpus'])) |
|
175 |
changes = \ |
|
176 |
{project_id: |
|
177 |
[(QDISK, QADD, flavor['disk'], GB), |
|
178 |
(QVM, QADD, 1, None), |
|
179 |
(QRAM, QADD, flavor['ram'], MB), |
|
180 |
(QCPU, QADD, flavor['vcpus'], None)]} |
|
181 |
self._check_quotas(changes) |
|
147 | 182 |
|
148 | 183 |
return server |
149 | 184 |
|
... | ... | |
180 | 215 |
self.assertNotIn(srv['id'], new_servers) |
181 | 216 |
|
182 | 217 |
# Verify quotas |
183 |
flavors = \ |
|
184 |
[self.clients.compute.get_flavor_details(srv['flavor']['id']) |
|
185 |
for srv in servers] |
|
186 |
self._verify_quotas_deleted(flavors) |
|
218 |
self._verify_quotas_deleted(servers) |
|
187 | 219 |
|
188 |
def _verify_quotas_deleted(self, flavors):
|
|
220 |
def _verify_quotas_deleted(self, servers):
|
|
189 | 221 |
"""Verify quotas for a number of deleted servers""" |
190 |
used_disk = 0 |
|
191 |
used_vm = 0 |
|
192 |
used_ram = 0 |
|
193 |
used_cpu = 0 |
|
194 |
for flavor in flavors: |
|
195 |
used_disk += int(flavor['disk']) * GB |
|
196 |
used_vm += 1 |
|
197 |
used_ram += int(flavor['ram']) * MB |
|
198 |
used_cpu += int(flavor['vcpus']) |
|
199 |
self._check_quotas(disk=-used_disk, |
|
200 |
vm=-used_vm, |
|
201 |
ram=-used_ram, |
|
202 |
cpu=-used_cpu) |
|
222 |
changes = dict() |
|
223 |
for server in servers: |
|
224 |
project = server['tenant_id'] |
|
225 |
if project not in changes: |
|
226 |
changes[project] = [] |
|
227 |
flavor = \ |
|
228 |
self.clients.compute.get_flavor_details(server['flavor']['id']) |
|
229 |
new_changes = [ |
|
230 |
(QDISK, QREMOVE, flavor['disk'], GB), |
|
231 |
(QVM, QREMOVE, 1, None), |
|
232 |
(QRAM, QREMOVE, flavor['ram'], MB), |
|
233 |
(QCPU, QREMOVE, flavor['vcpus'], None)] |
|
234 |
changes[project].extend(new_changes) |
|
235 |
|
|
236 |
self._check_quotas(changes) |
|
203 | 237 |
|
204 | 238 |
def _get_connection_username(self, server): |
205 | 239 |
"""Determine the username to use to connect to the server""" |
... | ... | |
320 | 354 |
"Can not get IPs from server attachments") |
321 | 355 |
|
322 | 356 |
for addr in addrs: |
323 |
self.assertEquals(IPy.IP(addr).version(), version)
|
|
357 |
self.assertEqual(IPy.IP(addr).version(), version) |
|
324 | 358 |
|
325 | 359 |
if network is None: |
326 | 360 |
msg = "Server's public IPv%s is %s" |
... | ... | |
411 | 445 |
|
412 | 446 |
# ---------------------------------- |
413 | 447 |
# Networks |
414 |
def _create_network(self, cidr="10.0.1.0/28", dhcp=True): |
|
448 |
def _create_network(self, cidr="10.0.1.0/28", dhcp=True, |
|
449 |
project_id=None): |
|
415 | 450 |
"""Create a new private network""" |
416 | 451 |
name = self.run_id |
417 | 452 |
network = self.clients.network.create_network( |
418 |
"MAC_FILTERED", name=name, shared=False) |
|
453 |
"MAC_FILTERED", name=name, shared=False, |
|
454 |
project=project_id) |
|
419 | 455 |
self.info("Network with id %s created", network['id']) |
420 | 456 |
subnet = self.clients.network.create_subnet( |
421 | 457 |
network['id'], cidr=cidr, enable_dhcp=dhcp) |
422 | 458 |
self.info("Subnet with id %s created", subnet['id']) |
423 | 459 |
|
424 | 460 |
# Verify quotas |
425 |
self._check_quotas(network=+1) |
|
461 |
if project_id is None: |
|
462 |
project_id = self._get_uuid() |
|
463 |
changes = \ |
|
464 |
{project_id: [(QNET, QADD, 1, None)]} |
|
465 |
self._check_quotas(changes) |
|
426 | 466 |
|
427 | 467 |
#Test if the right name is assigned |
428 | 468 |
self.assertEqual(network['name'], name) |
469 |
self.assertEqual(network['tenant_id'], project_id) |
|
429 | 470 |
|
430 | 471 |
return network |
431 | 472 |
|
... | ... | |
450 | 491 |
self.assertNotIn(net['id'], new_networks) |
451 | 492 |
|
452 | 493 |
# Verify quotas |
453 |
self._check_quotas(network=-len(networks)) |
|
494 |
changes = \ |
|
495 |
{self._get_uuid(): [(QNET, QREMOVE, len(networks), None)]} |
|
496 |
self._check_quotas(changes) |
|
454 | 497 |
|
455 | 498 |
def _get_public_network(self, networks=None): |
456 | 499 |
"""Get the public network""" |
... | ... | |
462 | 505 |
return net |
463 | 506 |
self.fail("Could not find a public network to use") |
464 | 507 |
|
465 |
def _create_floating_ip(self): |
|
508 |
def _create_floating_ip(self, project_id=None):
|
|
466 | 509 |
"""Create a new floating ip""" |
467 | 510 |
pub_net = self._get_public_network() |
468 | 511 |
self.info("Creating a new floating ip for network with id %s", |
469 | 512 |
pub_net['id']) |
470 |
fip = self.clients.network.create_floatingip(pub_net['id']) |
|
513 |
fip = self.clients.network.create_floatingip( |
|
514 |
pub_net['id'], project=project_id) |
|
471 | 515 |
# Verify that floating ip has been created |
472 | 516 |
fips = self.clients.network.list_floatingips() |
473 | 517 |
fips = [f['id'] for f in fips] |
474 | 518 |
self.assertIn(fip['id'], fips) |
475 | 519 |
# Verify quotas |
476 |
self._check_quotas(ip=+1) |
|
520 |
if project_id is None: |
|
521 |
project_id = self._get_uuid() |
|
522 |
changes = \ |
|
523 |
{project_id: [(QIP, QADD, 1, None)]} |
|
524 |
self._check_quotas(changes) |
|
525 |
|
|
477 | 526 |
# Check that IP is IPv4 |
478 |
self.assertEquals(IPy.IP(fip['floating_ip_address']).version(), 4) |
|
527 |
self.assertEqual(IPy.IP(fip['floating_ip_address']).version(), 4) |
|
528 |
self.assertEqual(fip['tenant_id'], project_id) |
|
479 | 529 |
|
480 | 530 |
self.info("Floating IP %s with id %s created", |
481 | 531 |
fip['floating_ip_address'], fip['id']) |
... | ... | |
588 | 638 |
list_ips = [f['id'] for f in self.clients.network.list_floatingips()] |
589 | 639 |
for fip in fips: |
590 | 640 |
self.assertNotIn(fip['id'], list_ips) |
641 |
|
|
591 | 642 |
# Verify quotas |
592 |
self._check_quotas(ip=-len(fips)) |
|
643 |
changes = dict() |
|
644 |
for fip in fips: |
|
645 |
project = fip['tenant_id'] |
|
646 |
if project not in changes: |
|
647 |
changes[project] = [] |
|
648 |
changes[project].append((QIP, QREMOVE, 1, None)) |
|
649 |
self._check_quotas(changes) |
|
650 |
|
|
651 |
def _find_project(self, flavors, projects=None): |
|
652 |
"""Return a pair of flavor, project that we can use""" |
|
653 |
if projects is None: |
|
654 |
projects = self.quotas.keys() |
|
655 |
|
|
656 |
# XXX: Well there seems to be no easy way to find how many resources |
|
657 |
# we have left in a project (we have to substract usage from limit, |
|
658 |
# check both per_user and project quotas, blah, blah). For now |
|
659 |
# just return the first flavor with the first project and lets hope |
|
660 |
# that it fits. |
|
661 |
return (flavors[0], projects[0]) |
|
662 |
|
|
663 |
# # Get only the quotas for the given 'projects' |
|
664 |
# quotas = dict() |
|
665 |
# for prj, qts in self.quotas.items(): |
|
666 |
# if prj in projects: |
|
667 |
# quotas[prj] = qts |
|
668 |
# |
|
669 |
# results = [] |
|
670 |
# for flv in flavors: |
|
671 |
# for prj, qts in quotas.items(): |
|
672 |
# self.debug("Testing flavor %s, project %s", flv['name'], prj) |
|
673 |
# condition = \ |
|
674 |
# (flv['ram'] <= qts['cyclades.ram']['usage'] and |
|
675 |
# flv['vcpus'] <= qts['cyclades.cpu']['usage'] and |
|
676 |
# flv['disk'] <= qts['cyclades.disk']['usage'] and |
|
677 |
# qts['cyclades.vm']['usage'] >= 1) |
|
678 |
# if condition: |
|
679 |
# results.append((flv, prj)) |
|
680 |
# |
|
681 |
# if not results: |
|
682 |
# msg = "Couldn't find a suitable flavor to use for current qutoas" |
|
683 |
# self.error(msg) |
|
684 |
# |
|
685 |
# return random.choice(results) |
|
593 | 686 |
|
594 | 687 |
|
595 | 688 |
class Retry(Exception): |
Also available in: Unified diff