Revision 60a80953

b/snf-tools/synnefo_tools/burnin/__init__.py
48 48
from synnefo_tools.burnin.server_tests import ServerTestSuite
49 49
from synnefo_tools.burnin.network_tests import NetworkTestSuite
50 50
from synnefo_tools.burnin.stale_tests import \
51
    StaleServersTestSuite, StaleNetworksTestSuite
51
    StaleServersTestSuite, StaleFloatingIPsTestSuite, StaleNetworksTestSuite
52 52

  
53 53

  
54 54
# --------------------------------------------------------------------
......
66 66
STALE_TESTSUITES = [
67 67
    # Must be runned in this order
68 68
    StaleServersTestSuite,
69
    StaleFloatingIPsTestSuite,
69 70
    StaleNetworksTestSuite,
70 71
]
71 72
STALE_TSUITES_NAMES = [tsuite.__name__ for tsuite in STALE_TESTSUITES]
......
113 114
        help="Disable IPv6 related tests")
114 115
    parser.add_option(
115 116
        "--action-timeout", action="store",
116
        type="int", default=300, dest="action_timeout", metavar="TIMEOUT",
117
        type="int", default=420, dest="action_timeout", metavar="TIMEOUT",
117 118
        help="Wait TIMEOUT seconds for a server action to complete, "
118 119
             "then the test is considered failed")
119 120
    parser.add_option(
120 121
        "--action-warning", action="store",
121
        type="int", default=120, dest="action_warning", metavar="TIMEOUT",
122
        type="int", default=180, dest="action_warning", metavar="TIMEOUT",
122 123
        help="Warn if TIMEOUT seconds have passed and a server action "
123 124
             "has not been completed yet")
124 125
    parser.add_option(
b/snf-tools/synnefo_tools/burnin/common.py
44 44
import tempfile
45 45
import traceback
46 46

  
47
from kamaki.clients.cyclades import CycladesClient
47
from kamaki.clients.cyclades import CycladesClient, CycladesNetworkClient
48 48
from kamaki.clients.astakos import AstakosClient
49 49
from kamaki.clients.compute import ComputeClient
50 50
from kamaki.clients.pithos import PithosClient
......
122 122
    compute_url = None
123 123
    # Cyclades
124 124
    cyclades = None
125
    # Network
126
    network = None
127
    network_url = None
125 128
    # Pithos
126 129
    pithos = None
127 130
    pithos_url = None
......
142 145
        self.cyclades = CycladesClient(self.compute_url, self.token)
143 146
        self.cyclades.CONNECTION_RETRY_LIMIT = self.retry
144 147

  
148
        self.network_url = \
149
            self.astakos.get_service_endpoints('network')['publicURL']
150
        self.network = CycladesNetworkClient(self.network_url, self.token)
151
        self.network.CONNECTION_RETRY_LIMIT = self.retry
152

  
145 153
        self.pithos_url = self.astakos.\
146 154
            get_service_endpoints('object-store')['publicURL']
147 155
        self.pithos = PithosClient(self.pithos_url, self.token)
......
204 212
        self.clients.initialize_clients()
205 213
        self.info("Astakos auth url is %s", self.clients.auth_url)
206 214
        self.info("Cyclades url is %s", self.clients.compute_url)
215
        self.info("Network url is %s", self.clients.network_url)
207 216
        self.info("Pithos url is %s", self.clients.pithos_url)
208 217
        self.info("Image url is %s", self.clients.image_url)
209 218

  
......
216 225
                  self.quotas['system']['pithos.diskspace']['usage'])
217 226
        self.info("  Ram usage is %s bytes",
218 227
                  self.quotas['system']['cyclades.ram']['usage'])
228
        self.info("  Floating IPs usage is %s",
229
                  self.quotas['system']['cyclades.floating_ip']['usage'])
219 230
        self.info("  CPU usage is %s",
220 231
                  self.quotas['system']['cyclades.cpu']['usage'])
221 232
        self.info("  Network usage is %s",
......
490 501
    # Invalid argument name. pylint: disable-msg=C0103
491 502
    # Too many arguments. pylint: disable-msg=R0913
492 503
    def _check_quotas(self, disk=None, vm=None, diskspace=None,
493
                      ram=None, cpu=None, network=None):
504
                      ram=None, ip=None, cpu=None, network=None):
494 505
        """Check that quotas' changes are consistent"""
495 506
        assert any(v is None for v in
496
                   [disk, vm, diskspace, ram, cpu, network]), \
507
                   [disk, vm, diskspace, ram, ip, cpu, network]), \
497 508
            "_check_quotas require arguments"
498 509

  
499 510
        self.info("Check that quotas' changes are consistent")
......
513 524
        # Check Ram usage
514 525
        self._check_quotas_aux(
515 526
            old_quotas, new_quotas, 'cyclades.ram', ram)
527
        # Check Floating IPs usage
528
        self._check_quotas_aux(
529
            old_quotas, new_quotas, 'cyclades.floating_ip', ip)
516 530
        # Check CPU usage
517 531
        self._check_quotas_aux(
518 532
            old_quotas, new_quotas, 'cyclades.cpu', cpu)
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
b/snf-tools/synnefo_tools/burnin/network_tests.py
79 79
        """Submit create server request for server A"""
80 80
        use_image = random.choice(self.avail_images)
81 81
        use_flavor = random.choice(self.avail_flavors)
82
        server = self._create_server(use_image, use_flavor)
82
        server = self._create_server(use_image, use_flavor, network=True)
83 83

  
84 84
        self.server_a = {}
85 85
        self.server_a['server'] = server
......
92 92
        """Submit create server request for server B"""
93 93
        use_image = random.choice(self.avail_images)
94 94
        use_flavor = random.choice(self.avail_flavors)
95
        server = self._create_server(use_image, use_flavor)
95
        server = self._create_server(use_image, use_flavor, network=True)
96 96

  
97 97
        self.server_b = {}
98 98
        self.server_b['server'] = server
......
113 113

  
114 114
    def test_006_create_network(self):
115 115
        """Submit a create network request"""
116
        name = self.run_id
117
        self.network = self._create_network(name)
116
        self.network = self._create_network()
118 117

  
119 118
        self._insist_on_network_transition(
120 119
            self.network, ["BUILD"], "ACTIVE")
121 120

  
122 121
    def test_007_connect_to_network(self):
123 122
        """Connect the two VMs to the newly created network"""
124
        self.clients.cyclades.connect_server(
125
            self.server_a['server']['id'], self.network['id'])
126
        self.clients.cyclades.connect_server(
127
            self.server_b['server']['id'], self.network['id'])
128

  
129
        self._insist_on_network_connection(
130
            self.server_a['server'], self.network)
131
        self._insist_on_network_connection(
132
            self.server_b['server'], self.network)
123
        self._create_port(self.network['id'], self.server_a['server']['id'])
124
        self._create_port(self.network['id'], self.server_b['server']['id'])
133 125

  
134 126
        # Update servers
135 127
        self.server_a['server'] = self._get_server_details(
......
138 130
            self.server_b['server'])
139 131

  
140 132
        # Check that servers got private IPs
141
        self.server_a['pr_ipv4'] = self._get_ip(
142
            self.server_a['server'], network=self.network)
143
        self.server_b['pr_ipv4'] = self._get_ip(
144
            self.server_b['server'], network=self.network)
133
        ipv4 = self._get_ips(self.server_a['server'], network=self.network)
134
        self.assertEqual(len(ipv4), 1)
135
        self.server_a['pr_ipv4'] = ipv4[0]
136
        ipv4 = self._get_ips(self.server_b['server'], network=self.network)
137
        self.assertEqual(len(ipv4), 1)
138
        self.server_b['pr_ipv4'] = ipv4
145 139

  
146 140
    def test_008_reboot_server_a(self):
147 141
        """Rebooting server A"""
......
155 149

  
156 150
    def test_009_ping_server_a(self):
157 151
        """Test if server A responds to IPv4 pings"""
158
        self._insist_on_ping(self._get_ip(self.server_a['server']))
152
        self._insist_on_ping(self._get_ips(self.server_a['server'])[0])
159 153

  
160 154
    def test_010_reboot_server_b(self):
161 155
        """Rebooting server B"""
......
169 163

  
170 164
    def test_011_ping_server_b(self):
171 165
        """Test that server B responds to IPv4 pings"""
172
        self._insist_on_ping(self._get_ip(self.server_b['server']))
166
        self._insist_on_ping(self._get_ips(self.server_b['server'])[0])
173 167

  
174 168
    def test_012_test_connection_exists(self):
175 169
        """Ping server B from server A to test if connection exists"""
......
178 172
        self._skip_if(not self._image_is(self.server_b['image'], "linux"),
179 173
                      "only valid for Linux servers")
180 174

  
181
        server_a_public_ip = self._get_ip(self.server_a['server'])
182
        server_b_private_ip = self._get_ip(
183
            self.server_b['server'], network=self.network)
175
        server_a_public_ip = self._get_ips(self.server_a['server'])[0]
176
        server_b_private_ip = self._get_ips(
177
            self.server_b['server'], network=self.network)[0]
184 178
        msg = "Will try to connect to server A (%s) and ping to server B (%s)"
185 179
        self.info(msg, server_a_public_ip, server_b_private_ip)
186 180

  
......
198 192
        self._disconnect_from_network(self.server_a['server'], self.network)
199 193
        self._disconnect_from_network(self.server_b['server'], self.network)
200 194

  
201
        self._insist_on_network_connection(
202
            self.server_a['server'], self.network, disconnect=True)
203
        self._insist_on_network_connection(
204
            self.server_b['server'], self.network, disconnect=True)
205

  
206 195
    def test_014_destroy_network(self):
207 196
        """Submit delete network request"""
208
        self.clients.cyclades.delete_network(self.network['id'])
209
        self._insist_on_network_transition(
210
            self.network, ["ACTIVE"], "DELETED")
211

  
212
        networks = [net['id'] for net in self._get_list_of_networks()]
213
        self.assertNotIn(self.network['id'], networks)
214

  
215
        # Verify quotas
216
        self._check_quotas(network=-1)
197
        self._delete_networks([self.network])
217 198

  
218 199
    def test_015_cleanup_servers(self):
219 200
        """Cleanup servers created for this test"""
220
        self.clients.cyclades.delete_server(self.server_a['server']['id'])
221
        self.clients.cyclades.delete_server(self.server_b['server']['id'])
222

  
223
        self._insist_on_server_transition(
224
            self.server_a['server'], ["ACTIVE"], "DELETED")
225
        self._insist_on_server_transition(
226
            self.server_b['server'], ["ACTIVE"], "DELETED")
227

  
228
        # Verify quotas
229
        self._verify_quotas_deleted([self.server_a['flavor'],
230
                                     self.server_b['flavor']])
201
        self._delete_servers([self.server_a['server'],
202
                              self.server_b['server']])
b/snf-tools/synnefo_tools/burnin/server_tests.py
37 37
"""
38 38

  
39 39
import sys
40
import IPy
41 40
import stat
42 41
import base64
43 42
import random
......
50 49

  
51 50

  
52 51
# Too many public methods. pylint: disable-msg=R0904
52
# Too many instance attributes. pylint: disable-msg=R0902
53 53
# This class gets replicated into actual TestCases dynamically
54 54
class GeneratedServerTestSuite(CycladesTests):
55 55
    """Test Spawning Serverfunctionality"""
......
78 78
        self.use_flavor = random.choice(self.avail_flavors)
79 79

  
80 80
        self.server = self._create_server(
81
            self.use_image, self.use_flavor, self.personality)
81
            self.use_image, self.use_flavor,
82
            personality=self.personality, network=True)
82 83
        self.username = self._get_connection_username(self.server)
83 84
        self.password = self.server['adminPass']
84 85

  
......
119 120
        """Test server becomes ACTIVE"""
120 121
        self._insist_on_server_transition(self.server, ["BUILD"], "ACTIVE")
121 122

  
122
    def test_006_get_server_oob_console(self):
123
    def test_006_attach_second_network(self):
124
        """Attach a second public IP to our server"""
125
        floating_ip = self._create_floating_ip()
126
        self._create_port(floating_ip['floating_network_id'],
127
                          device_id=self.server['id'],
128
                          floating_ip=floating_ip)
129

  
130
    def test_007_get_server_oob_console(self):
123 131
        """Test getting OOB server console over VNC
124 132

  
125 133
        Implementation of RFB protocol follows
......
157 165
        self.assertEquals(list(result), ['\x00', '\x00', '\x00', '\x00'])
158 166
        sock.close()
159 167

  
160
    def test_007_server_has_ipv4(self):
168
    def test_008_server_has_ipv4(self):
161 169
        """Test active server has a valid IPv4 address"""
162 170
        server = self.clients.cyclades.get_server_details(self.server['id'])
163 171
        # Update the server attribute
164 172
        self.server = server
165 173

  
166
        self.ipv4 = self._get_ip(server, version=4)
167
        self.assertEquals(IPy.IP(self.ipv4).version(), 4)
174
        self.ipv4 = self._get_ips(server, version=4)
168 175

  
169
    def test_008_server_has_ipv6(self):
176
    def test_009_server_has_ipv6(self):
170 177
        """Test active server has a valid IPv6 address"""
171 178
        self._skip_if(not self.use_ipv6, "--no-ipv6 flag enabled")
172 179

  
173
        self.ipv6 = self._get_ip(self.server, version=6)
174
        self.assertEquals(IPy.IP(self.ipv6).version(), 6)
180
        self.ipv6 = self._get_ips(self.server, version=6)
175 181

  
176
    def test_009_server_ping_ipv4(self):
182
    def test_010_server_ping_ipv4(self):
177 183
        """Test server responds to ping on IPv4 address"""
178
        self._insist_on_ping(self.ipv4, version=4)
184
        self._insist_on_ping(self.ipv4[0], version=4)
185
        self._insist_on_ping(self.ipv4[1], version=4)
179 186

  
180
    def test_010_server_ping_ipv6(self):
187
    def test_011_server_ping_ipv6(self):
181 188
        """Test server responds to ping on IPv6 address"""
182 189
        self._skip_if(not self.use_ipv6, "--no-ipv6 flag enabled")
183
        self._insist_on_ping(self.ipv6, version=6)
190
        self._insist_on_ping(self.ipv6[0], version=6)
184 191

  
185
    def test_011_submit_shutdown(self):
192
    def test_012_submit_shutdown(self):
186 193
        """Test submit request to shutdown server"""
187 194
        self.clients.cyclades.shutdown_server(self.server['id'])
188 195

  
189
    def test_012_server_becomes_stopped(self):
196
    def test_013_server_becomes_stopped(self):
190 197
        """Test server becomes STOPPED"""
191 198
        self._insist_on_server_transition(self.server, ["ACTIVE"], "STOPPED")
192 199

  
193
    def test_013_submit_start(self):
200
    def test_014_submit_start(self):
194 201
        """Test submit start server request"""
195 202
        self.clients.cyclades.start_server(self.server['id'])
196 203

  
197
    def test_014_server_becomes_active(self):
204
    def test_015_server_becomes_active(self):
198 205
        """Test server becomes ACTIVE again"""
199 206
        self._insist_on_server_transition(self.server, ["STOPPED"], "ACTIVE")
200 207

  
201
    def test_015_server_ping_ipv4(self):
208
    def test_016_server_ping_ipv4(self):
202 209
        """Test server OS is actually up and running again"""
203
        self.test_009_server_ping_ipv4()
210
        self.test_010_server_ping_ipv4()
204 211

  
205
    def test_016_ssh_to_server_ipv4(self):
212
    def test_017_ssh_to_server_ipv4(self):
206 213
        """Test SSH to server public IPv4 works, verify hostname"""
207 214
        self._skip_if(not self._image_is(self.use_image, "linux"),
208 215
                      "only valid for Linux servers")
209
        hostname = self._insist_get_hostname_over_ssh(
210
            self.ipv4, self.username, self.password)
216
        hostname1 = self._insist_get_hostname_over_ssh(
217
            self.ipv4[0], self.username, self.password)
218
        hostname2 = self._insist_get_hostname_over_ssh(
219
            self.ipv4[1], self.username, self.password)
211 220
        # The hostname must be of the form 'prefix-id'
212
        self.assertTrue(hostname.endswith("-%d" % self.server['id']))
221
        self.assertTrue(hostname1.endswith("-%d" % self.server['id']))
222
        self.assertEqual(hostname1, hostname2)
213 223

  
214
    def test_017_ssh_to_server_ipv6(self):
224
    def test_018_ssh_to_server_ipv6(self):
215 225
        """Test SSH to server public IPv6 works, verify hostname"""
216 226
        self._skip_if(not self._image_is(self.use_image, "linux"),
217 227
                      "only valid for Linux servers")
218 228
        self._skip_if(not self.use_ipv6, "--no-ipv6 flag enabled")
219 229
        hostname = self._insist_get_hostname_over_ssh(
220
            self.ipv6, self.username, self.password)
230
            self.ipv6[0], self.username, self.password)
221 231
        # The hostname must be of the form 'prefix-id'
222 232
        self.assertTrue(hostname.endswith("-%d" % self.server['id']))
223 233

  
224
    def test_018_rdp_to_server_ipv4(self):
234
    def test_019_rdp_to_server_ipv4(self):
225 235
        """Test RDP connection to server public IPv4 works"""
226 236
        self._skip_if(not self._image_is(self.use_image, "windows"),
227 237
                      "only valid for Windows servers")
228
        sock = self._insist_on_tcp_connection(socket.AF_INET, self.ipv4, 3389)
238
        sock = self._insist_on_tcp_connection(
239
            socket.AF_INET, self.ipv4[0], 3389)
229 240
        # No actual RDP processing done. We assume the RDP server is there
230 241
        # if the connection to the RDP port is successful.
231 242
        # pylint: disable-msg=W0511
232 243
        # FIXME: Use rdesktop, analyze exit code? see manpage
233 244
        sock.close()
234 245

  
235
    def test_019_rdp_to_server_ipv6(self):
246
    def test_020_rdp_to_server_ipv6(self):
236 247
        """Test RDP connection to server public IPv6 works"""
237 248
        self._skip_if(not self._image_is(self.use_image, "windows"),
238 249
                      "only valid for Windows servers")
239 250
        self._skip_if(not self.use_ipv6, "--no-ipv6 flag enabled")
240
        sock = self._insist_on_tcp_connection(socket.AF_INET, self.ipv6, 3389)
251
        sock = self._insist_on_tcp_connection(
252
            socket.AF_INET, self.ipv6[0], 3389)
241 253
        # No actual RDP processing done. We assume the RDP server is there
242 254
        # if the connection to the RDP port is successful.
243 255
        # pylint: disable-msg=W0511
244 256
        # FIXME: Use rdesktop, analyze exit code? see manpage
245 257
        sock.close()
246 258

  
247
    def test_020_personality(self):
259
    def test_021_personality(self):
248 260
        """Test file injection for personality enforcement"""
249 261
        self._skip_if(not self._image_is(self.use_image, "linux"),
250 262
                      "only implemented for linux servers")
......
252 264

  
253 265
        for inj_file in self.personality:
254 266
            self._check_file_through_ssh(
255
                self.ipv4, inj_file['owner'], self.password,
267
                self.ipv4[0], inj_file['owner'], self.password,
256 268
                inj_file['path'], inj_file['contents'])
257 269

  
258
    def test_021_submit_delete_request(self):
270
    def test_022_destroy_floating_ips(self):
271
        """Destroy the floating IPs"""
272
        self._disconnect_from_network(self.server)
273

  
274
    def test_023_submit_delete_request(self):
259 275
        """Test submit request to delete server"""
260
        self.clients.cyclades.delete_server(self.server['id'])
261

  
262
    def test_022_server_becomes_deleted(self):
263
        """Test server becomes DELETED"""
264
        self._insist_on_server_transition(self.server, ["ACTIVE"], "DELETED")
265
        # Verify quotas
266
        self._verify_quotas_deleted([self.use_flavor])
267

  
268
    def test_023_server_no_longer(self):
269
        """Test server is no longer in server list"""
270
        servers = self._get_list_of_servers()
271
        self.assertNotIn(self.server['id'], [s['id'] for s in servers])
276
        self._delete_servers([self.server])
272 277

  
273 278

  
274 279
# --------------------------------------------------------------------
b/snf-tools/synnefo_tools/burnin/stale_tests.py
47 47

  
48 48
    def test_001_show_stale_servers(self):
49 49
        """Show staled servers (servers left from previous runs)"""
50
        servers = self._get_list_of_servers()
50
        servers = self._get_list_of_servers(detail=True)
51 51
        self.stale_servers = [s for s in servers
52 52
                              if s['name'].startswith(SNF_TEST_PREFIX)]
53 53

  
......
64 64
        """Delete staled servers (servers left from previous runs)"""
65 65
        len_stale = len(self.stale_servers)
66 66
        if not self.delete_stale and len_stale != 0:
67
            msg = "Use --delete-stale flag to delete stale servers"
68
            self.error(msg)
69
            self.fail(msg)
67
            self.fail("Use --delete-stale flag to delete stale servers")
70 68
        elif len_stale == 0:
71 69
            self.info("No stale servers found")
72 70
        else:
73
            self.info("Deleting %s stale servers:", len_stale)
74
            for stl in self.stale_servers:
75
                self.info("  Deleting server \"%s\" with id %s",
76
                          stl['name'], stl['id'])
77
                self.clients.cyclades.delete_server(stl['id'])
71
            self.info("Deleting %s stale servers", len_stale)
72
            self._delete_servers(self.stale_servers, error=True)
78 73

  
79
            for stl in self.stale_servers:
80
                self._insist_on_server_transition(
81
                    stl, ["ACTIVE", "ERROR", "STOPPED"], "DELETED")
74

  
75
# Too many public methods. pylint: disable-msg=R0904
76
class StaleFloatingIPsTestSuite(CycladesTests):
77
    """Handle stale Floating IPs"""
78
    stale_ips = Proper(value=None)
79

  
80
    def test_001_show_stale_ips(self):
81
        """Show staled floating IPs"""
82
        floating_ips = self.clients.network.list_floatingips()
83
        # We consider all the floating ips that are not attached
84
        # anywhere as stale ips.
85
        self.stale_ips = [ip for ip in floating_ips
86
                          if ip['instance_id'] is None]
87

  
88
        len_stale = len(self.stale_ips)
89
        if len_stale == 0:
90
            self.info("No stale floating IPs found")
91
            return
92

  
93
        self.info("Found %s stale floating IPs:", len_stale)
94
        for stl in self.stale_ips:
95
            self.info("  Floating IP %s with id %s",
96
                      stl['floating_ip_address'], stl['id'])
97

  
98
    def test_002_delete_stale_ips(self):
99
        """Delete staled floating IPs"""
100
        len_stale = len(self.stale_ips)
101
        if not self.delete_stale and len_stale != 0:
102
            self.fail("Use --delete-stale flag to delete stale floating IPs")
103
        elif len_stale == 0:
104
            self.info("No stale floating IPs found")
105
        else:
106
            self.info("Deleteing %s stale floating IPs", len_stale)
107
            self._disconnect_from_floating_ips(self.stale_ips)
82 108

  
83 109

  
84 110
# Too many public methods. pylint: disable-msg=R0904
......
105 131
        """Delete staled networks (networks left from previous runs)"""
106 132
        len_stale = len(self.stale_networks)
107 133
        if not self.delete_stale and len_stale != 0:
108
            msg = "Use --delete-stale flag to delete stale networks"
109
            self.error(msg)
110
            self.fail(msg)
134
            self.fail("Use --delete-stale flag to delete stale networks")
111 135
        elif len_stale == 0:
112 136
            self.info("No stale networks found")
113 137
        else:
114
            self.info("Deleting %s stale networks:", len_stale)
115
            for stl in self.stale_networks:
116
                self.info("  Deleting network \"%s\" with id %s",
117
                          stl['name'], stl['id'])
118
                self.clients.cyclades.delete_network(stl['id'])
119

  
120
            for stl in self.stale_networks:
121
                self._insist_on_network_transition(
122
                    stl, ["ACTIVE", "ERROR"], "DELETED")
138
            self.info("Deleting %s stale networks", len_stale)
139
            self._delete_networks(self.stale_networks)

Also available in: Unified diff