Statistics
| Branch: | Tag: | Revision:

root / snf-tools / synnefo_tools / burnin / cyclades_common.py @ c2f037ff

History | View | Annotate | Download (27.2 kB)

1 d246be88 Ilias Tsitsimpis
# Copyright 2013 GRNET S.A. All rights reserved.
2 d246be88 Ilias Tsitsimpis
#
3 d246be88 Ilias Tsitsimpis
# Redistribution and use in source and binary forms, with or
4 d246be88 Ilias Tsitsimpis
# without modification, are permitted provided that the following
5 d246be88 Ilias Tsitsimpis
# conditions are met:
6 d246be88 Ilias Tsitsimpis
#
7 d246be88 Ilias Tsitsimpis
#   1. Redistributions of source code must retain the above
8 d246be88 Ilias Tsitsimpis
#      copyright notice, this list of conditions and the following
9 d246be88 Ilias Tsitsimpis
#      disclaimer.
10 d246be88 Ilias Tsitsimpis
#
11 d246be88 Ilias Tsitsimpis
#   2. Redistributions in binary form must reproduce the above
12 d246be88 Ilias Tsitsimpis
#      copyright notice, this list of conditions and the following
13 d246be88 Ilias Tsitsimpis
#      disclaimer in the documentation and/or other materials
14 d246be88 Ilias Tsitsimpis
#      provided with the distribution.
15 d246be88 Ilias Tsitsimpis
#
16 d246be88 Ilias Tsitsimpis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 d246be88 Ilias Tsitsimpis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 d246be88 Ilias Tsitsimpis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 d246be88 Ilias Tsitsimpis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 d246be88 Ilias Tsitsimpis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 d246be88 Ilias Tsitsimpis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 d246be88 Ilias Tsitsimpis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 d246be88 Ilias Tsitsimpis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 d246be88 Ilias Tsitsimpis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 d246be88 Ilias Tsitsimpis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 d246be88 Ilias Tsitsimpis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 d246be88 Ilias Tsitsimpis
# POSSIBILITY OF SUCH DAMAGE.
28 d246be88 Ilias Tsitsimpis
#
29 d246be88 Ilias Tsitsimpis
# The views and conclusions contained in the software and
30 d246be88 Ilias Tsitsimpis
# documentation are those of the authors and should not be
31 d246be88 Ilias Tsitsimpis
# interpreted as representing official policies, either expressed
32 d246be88 Ilias Tsitsimpis
# or implied, of GRNET S.A.
33 d246be88 Ilias Tsitsimpis
34 d246be88 Ilias Tsitsimpis
"""
35 d246be88 Ilias Tsitsimpis
Utility functions for Cyclades Tests
36 d246be88 Ilias Tsitsimpis
Cyclades require a lot helper functions and `common'
37 d246be88 Ilias Tsitsimpis
had grown too much.
38 d246be88 Ilias Tsitsimpis

39 d246be88 Ilias Tsitsimpis
"""
40 d246be88 Ilias Tsitsimpis
41 d246be88 Ilias Tsitsimpis
import time
42 60a80953 Ilias Tsitsimpis
import IPy
43 cee3ee9b Ilias Tsitsimpis
import base64
44 d246be88 Ilias Tsitsimpis
import socket
45 d246be88 Ilias Tsitsimpis
import random
46 cee3ee9b Ilias Tsitsimpis
import paramiko
47 cee3ee9b Ilias Tsitsimpis
import tempfile
48 d246be88 Ilias Tsitsimpis
import subprocess
49 d246be88 Ilias Tsitsimpis
50 60a80953 Ilias Tsitsimpis
from kamaki.clients import ClientError
51 60a80953 Ilias Tsitsimpis
52 c2f037ff Ilias Tsitsimpis
from synnefo_tools.burnin.common import BurninTests, MB, GB, QADD, QREMOVE, \
53 c2f037ff Ilias Tsitsimpis
    QDISK, QVM, QRAM, QIP, QCPU, QNET
54 d246be88 Ilias Tsitsimpis
55 d246be88 Ilias Tsitsimpis
56 9355a604 Ilias Tsitsimpis
# pylint: disable=too-many-public-methods
57 d246be88 Ilias Tsitsimpis
class CycladesTests(BurninTests):
58 d246be88 Ilias Tsitsimpis
    """Extends the BurninTests class for Cyclades"""
59 c2f037ff Ilias Tsitsimpis
    def _parse_images(self):
60 c2f037ff Ilias Tsitsimpis
        """Find images given to command line"""
61 c2f037ff Ilias Tsitsimpis
        if self.images is None:
62 c2f037ff Ilias Tsitsimpis
            self.info("No --images given. Will use the default %s",
63 c2f037ff Ilias Tsitsimpis
                      "^Debian Base$")
64 c2f037ff Ilias Tsitsimpis
            filters = ["name:^Debian Base$"]
65 c2f037ff Ilias Tsitsimpis
        else:
66 c2f037ff Ilias Tsitsimpis
            filters = self.images
67 c2f037ff Ilias Tsitsimpis
        avail_images = self._find_images(filters)
68 c2f037ff Ilias Tsitsimpis
        self.info("Found %s images to choose from", len(avail_images))
69 c2f037ff Ilias Tsitsimpis
        return avail_images
70 c2f037ff Ilias Tsitsimpis
71 c2f037ff Ilias Tsitsimpis
    def _parse_flavors(self):
72 c2f037ff Ilias Tsitsimpis
        """Find flavors given to command line"""
73 c2f037ff Ilias Tsitsimpis
        flavors = self._get_list_of_flavors(detail=True)
74 c2f037ff Ilias Tsitsimpis
75 c2f037ff Ilias Tsitsimpis
        if self.flavors is None:
76 c2f037ff Ilias Tsitsimpis
            self.info("No --flavors given. Will use all of them")
77 c2f037ff Ilias Tsitsimpis
            avail_flavors = flavors
78 c2f037ff Ilias Tsitsimpis
        else:
79 c2f037ff Ilias Tsitsimpis
            avail_flavors = self._find_flavors(self.flavors, flavors=flavors)
80 c2f037ff Ilias Tsitsimpis
81 c2f037ff Ilias Tsitsimpis
        self.info("Found %s flavors to choose from", len(avail_flavors))
82 c2f037ff Ilias Tsitsimpis
        return avail_flavors
83 c2f037ff Ilias Tsitsimpis
84 3eaf0ec5 Ilias Tsitsimpis
    def _try_until_timeout_expires(self, opmsg, check_fun):
85 d246be88 Ilias Tsitsimpis
        """Try to perform an action until timeout expires"""
86 d246be88 Ilias Tsitsimpis
        assert callable(check_fun), "Not a function"
87 d246be88 Ilias Tsitsimpis
88 d246be88 Ilias Tsitsimpis
        action_timeout = self.action_timeout
89 d246be88 Ilias Tsitsimpis
        action_warning = self.action_warning
90 d246be88 Ilias Tsitsimpis
        if action_warning > action_timeout:
91 d246be88 Ilias Tsitsimpis
            action_warning = action_timeout
92 d246be88 Ilias Tsitsimpis
93 8c67f82e Ilias Tsitsimpis
        start_time = int(time.time())
94 8c67f82e Ilias Tsitsimpis
        end_time = start_time + action_warning
95 8c67f82e Ilias Tsitsimpis
        while end_time > time.time():
96 d246be88 Ilias Tsitsimpis
            try:
97 8c67f82e Ilias Tsitsimpis
                ret_value = check_fun()
98 8c67f82e Ilias Tsitsimpis
                self.info("Operation `%s' finished in %s seconds",
99 8c67f82e Ilias Tsitsimpis
                          opmsg, int(time.time()) - start_time)
100 8c67f82e Ilias Tsitsimpis
                return ret_value
101 d246be88 Ilias Tsitsimpis
            except Retry:
102 d246be88 Ilias Tsitsimpis
                time.sleep(self.query_interval)
103 8c67f82e Ilias Tsitsimpis
        self.warning("Operation `%s' is taking too long after %s seconds",
104 8c67f82e Ilias Tsitsimpis
                     opmsg, int(time.time()) - start_time)
105 8c67f82e Ilias Tsitsimpis
106 8c67f82e Ilias Tsitsimpis
        end_time = start_time + action_timeout
107 8c67f82e Ilias Tsitsimpis
        while end_time > time.time():
108 d246be88 Ilias Tsitsimpis
            try:
109 8c67f82e Ilias Tsitsimpis
                ret_value = check_fun()
110 8c67f82e Ilias Tsitsimpis
                self.info("Operation `%s' finished in %s seconds",
111 8c67f82e Ilias Tsitsimpis
                          opmsg, int(time.time()) - start_time)
112 8c67f82e Ilias Tsitsimpis
                return ret_value
113 d246be88 Ilias Tsitsimpis
            except Retry:
114 d246be88 Ilias Tsitsimpis
                time.sleep(self.query_interval)
115 8c67f82e Ilias Tsitsimpis
        self.error("Operation `%s' timed out after %s seconds",
116 8c67f82e Ilias Tsitsimpis
                   opmsg, int(time.time()) - start_time)
117 d246be88 Ilias Tsitsimpis
        self.fail("time out")
118 d246be88 Ilias Tsitsimpis
119 d246be88 Ilias Tsitsimpis
    def _get_list_of_servers(self, detail=False):
120 d246be88 Ilias Tsitsimpis
        """Get (detailed) list of servers"""
121 d246be88 Ilias Tsitsimpis
        if detail:
122 d246be88 Ilias Tsitsimpis
            self.info("Getting detailed list of servers")
123 d246be88 Ilias Tsitsimpis
        else:
124 d246be88 Ilias Tsitsimpis
            self.info("Getting simple list of servers")
125 d246be88 Ilias Tsitsimpis
        return self.clients.cyclades.list_servers(detail=detail)
126 d246be88 Ilias Tsitsimpis
127 3eaf0ec5 Ilias Tsitsimpis
    def _get_list_of_networks(self, detail=False):
128 3eaf0ec5 Ilias Tsitsimpis
        """Get (detailed) list of networks"""
129 3eaf0ec5 Ilias Tsitsimpis
        if detail:
130 3eaf0ec5 Ilias Tsitsimpis
            self.info("Getting detailed list of networks")
131 3eaf0ec5 Ilias Tsitsimpis
        else:
132 3eaf0ec5 Ilias Tsitsimpis
            self.info("Getting simple list of networks")
133 60a80953 Ilias Tsitsimpis
        return self.clients.network.list_networks(detail=detail)
134 3eaf0ec5 Ilias Tsitsimpis
135 3eaf0ec5 Ilias Tsitsimpis
    def _get_server_details(self, server, quiet=False):
136 d246be88 Ilias Tsitsimpis
        """Get details for a server"""
137 3eaf0ec5 Ilias Tsitsimpis
        if not quiet:
138 3eaf0ec5 Ilias Tsitsimpis
            self.info("Getting details for server %s with id %s",
139 3eaf0ec5 Ilias Tsitsimpis
                      server['name'], server['id'])
140 d246be88 Ilias Tsitsimpis
        return self.clients.cyclades.get_server_details(server['id'])
141 d246be88 Ilias Tsitsimpis
142 c2f037ff Ilias Tsitsimpis
    # pylint: disable=too-many-arguments
143 c2f037ff Ilias Tsitsimpis
    def _create_server(self, image, flavor, personality=None,
144 c2f037ff Ilias Tsitsimpis
                       network=False, project_id=None):
145 d246be88 Ilias Tsitsimpis
        """Create a new server"""
146 60a80953 Ilias Tsitsimpis
        if network:
147 c2f037ff Ilias Tsitsimpis
            fip = self._create_floating_ip(project_id=project_id)
148 60a80953 Ilias Tsitsimpis
            port = self._create_port(fip['floating_network_id'],
149 60a80953 Ilias Tsitsimpis
                                     floating_ip=fip)
150 60a80953 Ilias Tsitsimpis
            networks = [{'port': port['id']}]
151 60a80953 Ilias Tsitsimpis
        else:
152 60a80953 Ilias Tsitsimpis
            networks = None
153 60a80953 Ilias Tsitsimpis
154 3eaf0ec5 Ilias Tsitsimpis
        servername = "%s for %s" % (self.run_id, image['name'])
155 3eaf0ec5 Ilias Tsitsimpis
        self.info("Creating a server with name %s", servername)
156 d246be88 Ilias Tsitsimpis
        self.info("Using image %s with id %s", image['name'], image['id'])
157 d246be88 Ilias Tsitsimpis
        self.info("Using flavor %s with id %s", flavor['name'], flavor['id'])
158 d246be88 Ilias Tsitsimpis
        server = self.clients.cyclades.create_server(
159 60a80953 Ilias Tsitsimpis
            servername, flavor['id'], image['id'],
160 c2f037ff Ilias Tsitsimpis
            personality=personality, networks=networks,
161 c2f037ff Ilias Tsitsimpis
            project=project_id)
162 d246be88 Ilias Tsitsimpis
163 d246be88 Ilias Tsitsimpis
        self.info("Server id: %s", server['id'])
164 d246be88 Ilias Tsitsimpis
        self.info("Server password: %s", server['adminPass'])
165 d246be88 Ilias Tsitsimpis
166 3eaf0ec5 Ilias Tsitsimpis
        self.assertEqual(server['name'], servername)
167 d246be88 Ilias Tsitsimpis
        self.assertEqual(server['flavor']['id'], flavor['id'])
168 d246be88 Ilias Tsitsimpis
        self.assertEqual(server['image']['id'], image['id'])
169 d246be88 Ilias Tsitsimpis
        self.assertEqual(server['status'], "BUILD")
170 c2f037ff Ilias Tsitsimpis
        if project_id is None:
171 c2f037ff Ilias Tsitsimpis
            project_id = self._get_uuid()
172 c2f037ff Ilias Tsitsimpis
        self.assertEqual(server['tenant_id'], project_id)
173 d246be88 Ilias Tsitsimpis
174 3e5bbd85 Ilias Tsitsimpis
        # Verify quotas
175 c2f037ff Ilias Tsitsimpis
        changes = \
176 c2f037ff Ilias Tsitsimpis
            {project_id:
177 c2f037ff Ilias Tsitsimpis
                [(QDISK, QADD, flavor['disk'], GB),
178 c2f037ff Ilias Tsitsimpis
                 (QVM, QADD, 1, None),
179 c2f037ff Ilias Tsitsimpis
                 (QRAM, QADD, flavor['ram'], MB),
180 c2f037ff Ilias Tsitsimpis
                 (QCPU, QADD, flavor['vcpus'], None)]}
181 c2f037ff Ilias Tsitsimpis
        self._check_quotas(changes)
182 3e5bbd85 Ilias Tsitsimpis
183 d246be88 Ilias Tsitsimpis
        return server
184 d246be88 Ilias Tsitsimpis
185 60a80953 Ilias Tsitsimpis
    def _delete_servers(self, servers, error=False):
186 60a80953 Ilias Tsitsimpis
        """Deleting a number of servers in parallel"""
187 60a80953 Ilias Tsitsimpis
        # Disconnect floating IPs
188 7c37ab19 Ilias Tsitsimpis
        if not error:
189 7c37ab19 Ilias Tsitsimpis
            # If there is the possibility for the machine to be in
190 7c37ab19 Ilias Tsitsimpis
            # ERROR state we cannot delete its ports.
191 7c37ab19 Ilias Tsitsimpis
            for srv in servers:
192 7c37ab19 Ilias Tsitsimpis
                self.info(
193 7c37ab19 Ilias Tsitsimpis
                    "Disconnecting all floating IPs from server with id %s",
194 7c37ab19 Ilias Tsitsimpis
                    srv['id'])
195 7c37ab19 Ilias Tsitsimpis
                self._disconnect_from_network(srv)
196 60a80953 Ilias Tsitsimpis
197 60a80953 Ilias Tsitsimpis
        # Delete servers
198 60a80953 Ilias Tsitsimpis
        for srv in servers:
199 60a80953 Ilias Tsitsimpis
            self.info("Sending the delete request for server with id %s",
200 60a80953 Ilias Tsitsimpis
                      srv['id'])
201 60a80953 Ilias Tsitsimpis
            self.clients.cyclades.delete_server(srv['id'])
202 60a80953 Ilias Tsitsimpis
203 60a80953 Ilias Tsitsimpis
        if error:
204 60a80953 Ilias Tsitsimpis
            curr_states = ["ACTIVE", "ERROR", "STOPPED", "BUILD"]
205 60a80953 Ilias Tsitsimpis
        else:
206 60a80953 Ilias Tsitsimpis
            curr_states = ["ACTIVE"]
207 60a80953 Ilias Tsitsimpis
        for srv in servers:
208 60a80953 Ilias Tsitsimpis
            self._insist_on_server_transition(srv, curr_states, "DELETED")
209 60a80953 Ilias Tsitsimpis
210 60a80953 Ilias Tsitsimpis
        # Servers no longer in server list
211 60a80953 Ilias Tsitsimpis
        new_servers = [s['id'] for s in self._get_list_of_servers()]
212 60a80953 Ilias Tsitsimpis
        for srv in servers:
213 60a80953 Ilias Tsitsimpis
            self.info("Verifying that server with id %s is no longer in "
214 60a80953 Ilias Tsitsimpis
                      "server list", srv['id'])
215 60a80953 Ilias Tsitsimpis
            self.assertNotIn(srv['id'], new_servers)
216 60a80953 Ilias Tsitsimpis
217 60a80953 Ilias Tsitsimpis
        # Verify quotas
218 c2f037ff Ilias Tsitsimpis
        self._verify_quotas_deleted(servers)
219 60a80953 Ilias Tsitsimpis
220 c2f037ff Ilias Tsitsimpis
    def _verify_quotas_deleted(self, servers):
221 3e5bbd85 Ilias Tsitsimpis
        """Verify quotas for a number of deleted servers"""
222 c2f037ff Ilias Tsitsimpis
        changes = dict()
223 c2f037ff Ilias Tsitsimpis
        for server in servers:
224 c2f037ff Ilias Tsitsimpis
            project = server['tenant_id']
225 c2f037ff Ilias Tsitsimpis
            if project not in changes:
226 c2f037ff Ilias Tsitsimpis
                changes[project] = []
227 c2f037ff Ilias Tsitsimpis
            flavor = \
228 c2f037ff Ilias Tsitsimpis
                self.clients.compute.get_flavor_details(server['flavor']['id'])
229 c2f037ff Ilias Tsitsimpis
            new_changes = [
230 c2f037ff Ilias Tsitsimpis
                (QDISK, QREMOVE, flavor['disk'], GB),
231 c2f037ff Ilias Tsitsimpis
                (QVM, QREMOVE, 1, None),
232 c2f037ff Ilias Tsitsimpis
                (QRAM, QREMOVE, flavor['ram'], MB),
233 c2f037ff Ilias Tsitsimpis
                (QCPU, QREMOVE, flavor['vcpus'], None)]
234 c2f037ff Ilias Tsitsimpis
            changes[project].extend(new_changes)
235 c2f037ff Ilias Tsitsimpis
236 c2f037ff Ilias Tsitsimpis
        self._check_quotas(changes)
237 3e5bbd85 Ilias Tsitsimpis
238 d246be88 Ilias Tsitsimpis
    def _get_connection_username(self, server):
239 d246be88 Ilias Tsitsimpis
        """Determine the username to use to connect to the server"""
240 d246be88 Ilias Tsitsimpis
        users = server['metadata'].get("users", None)
241 d246be88 Ilias Tsitsimpis
        ret_user = None
242 d246be88 Ilias Tsitsimpis
        if users is not None:
243 d246be88 Ilias Tsitsimpis
            user_list = users.split()
244 d246be88 Ilias Tsitsimpis
            if "root" in user_list:
245 d246be88 Ilias Tsitsimpis
                ret_user = "root"
246 d246be88 Ilias Tsitsimpis
            else:
247 d246be88 Ilias Tsitsimpis
                ret_user = random.choice(user_list)
248 d246be88 Ilias Tsitsimpis
        else:
249 d246be88 Ilias Tsitsimpis
            # Return the login name for connections based on the server OS
250 d246be88 Ilias Tsitsimpis
            self.info("Could not find `users' metadata in server. Let's guess")
251 d246be88 Ilias Tsitsimpis
            os_value = server['metadata'].get("os")
252 d246be88 Ilias Tsitsimpis
            if os_value in ("Ubuntu", "Kubuntu", "Fedora"):
253 d246be88 Ilias Tsitsimpis
                ret_user = "user"
254 d246be88 Ilias Tsitsimpis
            elif os_value in ("windows", "windows_alpha1"):
255 d246be88 Ilias Tsitsimpis
                ret_user = "Administrator"
256 d246be88 Ilias Tsitsimpis
            else:
257 d246be88 Ilias Tsitsimpis
                ret_user = "root"
258 d246be88 Ilias Tsitsimpis
259 d246be88 Ilias Tsitsimpis
        self.assertIsNotNone(ret_user)
260 d246be88 Ilias Tsitsimpis
        self.info("User's login name: %s", ret_user)
261 d246be88 Ilias Tsitsimpis
        return ret_user
262 d246be88 Ilias Tsitsimpis
263 3eaf0ec5 Ilias Tsitsimpis
    def _insist_on_server_transition(self, server, curr_statuses, new_status):
264 3eaf0ec5 Ilias Tsitsimpis
        """Insist on server transiting from curr_statuses to new_status"""
265 d246be88 Ilias Tsitsimpis
        def check_fun():
266 d246be88 Ilias Tsitsimpis
            """Check server status"""
267 3eaf0ec5 Ilias Tsitsimpis
            srv = self._get_server_details(server, quiet=True)
268 3eaf0ec5 Ilias Tsitsimpis
            if srv['status'] in curr_statuses:
269 d246be88 Ilias Tsitsimpis
                raise Retry()
270 d246be88 Ilias Tsitsimpis
            elif srv['status'] == new_status:
271 d246be88 Ilias Tsitsimpis
                return
272 d246be88 Ilias Tsitsimpis
            else:
273 3eaf0ec5 Ilias Tsitsimpis
                msg = "Server \"%s\" with id %s went to unexpected status %s"
274 3eaf0ec5 Ilias Tsitsimpis
                self.error(msg, server['name'], server['id'], srv['status'])
275 3eaf0ec5 Ilias Tsitsimpis
                self.fail(msg % (server['name'], server['id'], srv['status']))
276 5bef1f49 Ilias Tsitsimpis
        opmsg = "Waiting for server \"%s\" with id %s to become %s"
277 5bef1f49 Ilias Tsitsimpis
        self.info(opmsg, server['name'], server['id'], new_status)
278 5bef1f49 Ilias Tsitsimpis
        opmsg = opmsg % (server['name'], server['id'], new_status)
279 3eaf0ec5 Ilias Tsitsimpis
        self._try_until_timeout_expires(opmsg, check_fun)
280 3eaf0ec5 Ilias Tsitsimpis
281 3eaf0ec5 Ilias Tsitsimpis
    def _insist_on_network_transition(self, network,
282 3eaf0ec5 Ilias Tsitsimpis
                                      curr_statuses, new_status):
283 3eaf0ec5 Ilias Tsitsimpis
        """Insist on network transiting from curr_statuses to new_status"""
284 3eaf0ec5 Ilias Tsitsimpis
        def check_fun():
285 3eaf0ec5 Ilias Tsitsimpis
            """Check network status"""
286 60a80953 Ilias Tsitsimpis
            ntw = self.clients.network.get_network_details(network['id'])
287 3eaf0ec5 Ilias Tsitsimpis
            if ntw['status'] in curr_statuses:
288 3eaf0ec5 Ilias Tsitsimpis
                raise Retry()
289 3eaf0ec5 Ilias Tsitsimpis
            elif ntw['status'] == new_status:
290 3eaf0ec5 Ilias Tsitsimpis
                return
291 3eaf0ec5 Ilias Tsitsimpis
            else:
292 3eaf0ec5 Ilias Tsitsimpis
                msg = "Network %s with id %s went to unexpected status %s"
293 3eaf0ec5 Ilias Tsitsimpis
                self.error(msg, network['name'], network['id'], ntw['status'])
294 3eaf0ec5 Ilias Tsitsimpis
                self.fail(msg %
295 3eaf0ec5 Ilias Tsitsimpis
                          (network['name'], network['id'], ntw['status']))
296 5bef1f49 Ilias Tsitsimpis
        opmsg = "Waiting for network \"%s\" with id %s to become %s"
297 5bef1f49 Ilias Tsitsimpis
        self.info(opmsg, network['name'], network['id'], new_status)
298 5bef1f49 Ilias Tsitsimpis
        opmsg = opmsg % (network['name'], network['id'], new_status)
299 3eaf0ec5 Ilias Tsitsimpis
        self._try_until_timeout_expires(opmsg, check_fun)
300 3eaf0ec5 Ilias Tsitsimpis
301 d246be88 Ilias Tsitsimpis
    def _insist_on_tcp_connection(self, family, host, port):
302 d246be88 Ilias Tsitsimpis
        """Insist on tcp connection"""
303 d246be88 Ilias Tsitsimpis
        def check_fun():
304 d246be88 Ilias Tsitsimpis
            """Get a connected socket from the specified family to host:port"""
305 d246be88 Ilias Tsitsimpis
            sock = None
306 d246be88 Ilias Tsitsimpis
            for res in socket.getaddrinfo(host, port, family,
307 d246be88 Ilias Tsitsimpis
                                          socket.SOCK_STREAM, 0,
308 d246be88 Ilias Tsitsimpis
                                          socket.AI_PASSIVE):
309 d246be88 Ilias Tsitsimpis
                fam, socktype, proto, _, saddr = res
310 d246be88 Ilias Tsitsimpis
                try:
311 d246be88 Ilias Tsitsimpis
                    sock = socket.socket(fam, socktype, proto)
312 d246be88 Ilias Tsitsimpis
                except socket.error:
313 d246be88 Ilias Tsitsimpis
                    sock = None
314 d246be88 Ilias Tsitsimpis
                    continue
315 d246be88 Ilias Tsitsimpis
                try:
316 d246be88 Ilias Tsitsimpis
                    sock.connect(saddr)
317 d246be88 Ilias Tsitsimpis
                except socket.error:
318 d246be88 Ilias Tsitsimpis
                    sock.close()
319 d246be88 Ilias Tsitsimpis
                    sock = None
320 d246be88 Ilias Tsitsimpis
                    continue
321 d246be88 Ilias Tsitsimpis
            if sock is None:
322 d246be88 Ilias Tsitsimpis
                raise Retry
323 d246be88 Ilias Tsitsimpis
            return sock
324 d246be88 Ilias Tsitsimpis
        familystr = {socket.AF_INET: "IPv4", socket.AF_INET6: "IPv6",
325 d246be88 Ilias Tsitsimpis
                     socket.AF_UNSPEC: "Unspecified-IPv4/6"}
326 d246be88 Ilias Tsitsimpis
        opmsg = "Connecting over %s to %s:%s"
327 d246be88 Ilias Tsitsimpis
        self.info(opmsg, familystr.get(family, "Unknown"), host, port)
328 d246be88 Ilias Tsitsimpis
        opmsg = opmsg % (familystr.get(family, "Unknown"), host, port)
329 d246be88 Ilias Tsitsimpis
        return self._try_until_timeout_expires(opmsg, check_fun)
330 d246be88 Ilias Tsitsimpis
331 60a80953 Ilias Tsitsimpis
    def _get_ips(self, server, version=4, network=None):
332 60a80953 Ilias Tsitsimpis
        """Get the IPs of a server from the detailed server info
333 3eaf0ec5 Ilias Tsitsimpis

334 60a80953 Ilias Tsitsimpis
        If network not given then get the public IPs. Else the IPs
335 3eaf0ec5 Ilias Tsitsimpis
        attached to that network
336 3eaf0ec5 Ilias Tsitsimpis

337 3eaf0ec5 Ilias Tsitsimpis
        """
338 d246be88 Ilias Tsitsimpis
        assert version in (4, 6)
339 d246be88 Ilias Tsitsimpis
340 d246be88 Ilias Tsitsimpis
        nics = server['attachments']
341 60a80953 Ilias Tsitsimpis
        addrs = []
342 d246be88 Ilias Tsitsimpis
        for nic in nics:
343 d246be88 Ilias Tsitsimpis
            net_id = nic['network_id']
344 3eaf0ec5 Ilias Tsitsimpis
            if network is None:
345 60a80953 Ilias Tsitsimpis
                if self.clients.network.get_network_details(net_id)['public']:
346 ee89df69 Ilias Tsitsimpis
                    if nic['ipv' + str(version)]:
347 60a80953 Ilias Tsitsimpis
                        addrs.append(nic['ipv' + str(version)])
348 3eaf0ec5 Ilias Tsitsimpis
            else:
349 3eaf0ec5 Ilias Tsitsimpis
                if net_id == network['id']:
350 ee89df69 Ilias Tsitsimpis
                    if nic['ipv' + str(version)]:
351 60a80953 Ilias Tsitsimpis
                        addrs.append(nic['ipv' + str(version)])
352 60a80953 Ilias Tsitsimpis
353 60a80953 Ilias Tsitsimpis
        self.assertGreater(len(addrs), 0,
354 60a80953 Ilias Tsitsimpis
                           "Can not get IPs from server attachments")
355 60a80953 Ilias Tsitsimpis
356 60a80953 Ilias Tsitsimpis
        for addr in addrs:
357 c2f037ff Ilias Tsitsimpis
            self.assertEqual(IPy.IP(addr).version(), version)
358 d246be88 Ilias Tsitsimpis
359 3eaf0ec5 Ilias Tsitsimpis
        if network is None:
360 3eaf0ec5 Ilias Tsitsimpis
            msg = "Server's public IPv%s is %s"
361 60a80953 Ilias Tsitsimpis
            for addr in addrs:
362 60a80953 Ilias Tsitsimpis
                self.info(msg, version, addr)
363 3eaf0ec5 Ilias Tsitsimpis
        else:
364 3eaf0ec5 Ilias Tsitsimpis
            msg = "Server's IPv%s attached to network \"%s\" is %s"
365 60a80953 Ilias Tsitsimpis
            for addr in addrs:
366 60a80953 Ilias Tsitsimpis
                self.info(msg, version, network['id'], addr)
367 3eaf0ec5 Ilias Tsitsimpis
        return addrs
368 d246be88 Ilias Tsitsimpis
369 cee3ee9b Ilias Tsitsimpis
    def _insist_on_ping(self, ip_addr, version=4):
370 d246be88 Ilias Tsitsimpis
        """Test server responds to a single IPv4 of IPv6 ping"""
371 d246be88 Ilias Tsitsimpis
        def check_fun():
372 d246be88 Ilias Tsitsimpis
            """Ping to server"""
373 d246be88 Ilias Tsitsimpis
            cmd = ("ping%s -c 3 -w 20 %s" %
374 d246be88 Ilias Tsitsimpis
                   ("6" if version == 6 else "", ip_addr))
375 d246be88 Ilias Tsitsimpis
            ping = subprocess.Popen(
376 d246be88 Ilias Tsitsimpis
                cmd, shell=True, stdout=subprocess.PIPE,
377 d246be88 Ilias Tsitsimpis
                stderr=subprocess.PIPE)
378 d246be88 Ilias Tsitsimpis
            ping.communicate()
379 d246be88 Ilias Tsitsimpis
            ret = ping.wait()
380 d246be88 Ilias Tsitsimpis
            if ret != 0:
381 d246be88 Ilias Tsitsimpis
                raise Retry
382 cee3ee9b Ilias Tsitsimpis
        assert version in (4, 6)
383 d246be88 Ilias Tsitsimpis
        opmsg = "Sent IPv%s ping requests to %s"
384 d246be88 Ilias Tsitsimpis
        self.info(opmsg, version, ip_addr)
385 d246be88 Ilias Tsitsimpis
        opmsg = opmsg % (version, ip_addr)
386 d246be88 Ilias Tsitsimpis
        self._try_until_timeout_expires(opmsg, check_fun)
387 d246be88 Ilias Tsitsimpis
388 cee3ee9b Ilias Tsitsimpis
    def _image_is(self, image, osfamily):
389 cee3ee9b Ilias Tsitsimpis
        """Return true if the image is of `osfamily'"""
390 cee3ee9b Ilias Tsitsimpis
        d_image = self.clients.cyclades.get_image_details(image['id'])
391 cee3ee9b Ilias Tsitsimpis
        return d_image['metadata']['osfamily'].lower().find(osfamily) >= 0
392 cee3ee9b Ilias Tsitsimpis
393 9355a604 Ilias Tsitsimpis
    # pylint: disable=no-self-use
394 cee3ee9b Ilias Tsitsimpis
    def _ssh_execute(self, hostip, username, password, command):
395 cee3ee9b Ilias Tsitsimpis
        """Execute a command via ssh"""
396 cee3ee9b Ilias Tsitsimpis
        ssh = paramiko.SSHClient()
397 cee3ee9b Ilias Tsitsimpis
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
398 cee3ee9b Ilias Tsitsimpis
        try:
399 cee3ee9b Ilias Tsitsimpis
            ssh.connect(hostip, username=username, password=password)
400 16c7f032 Ilias Tsitsimpis
        except paramiko.SSHException as err:
401 16c7f032 Ilias Tsitsimpis
            if err.args[0] == "Error reading SSH protocol banner":
402 449a1c40 Ilias Tsitsimpis
                raise Retry()
403 449a1c40 Ilias Tsitsimpis
            else:
404 449a1c40 Ilias Tsitsimpis
                raise
405 449a1c40 Ilias Tsitsimpis
        _, stdout, _ = ssh.exec_command(command)
406 cee3ee9b Ilias Tsitsimpis
        status = stdout.channel.recv_exit_status()
407 cee3ee9b Ilias Tsitsimpis
        output = stdout.readlines()
408 cee3ee9b Ilias Tsitsimpis
        ssh.close()
409 cee3ee9b Ilias Tsitsimpis
        return output, status
410 cee3ee9b Ilias Tsitsimpis
411 cee3ee9b Ilias Tsitsimpis
    def _insist_get_hostname_over_ssh(self, hostip, username, password):
412 cee3ee9b Ilias Tsitsimpis
        """Connect to server using ssh and get it's hostname"""
413 cee3ee9b Ilias Tsitsimpis
        def check_fun():
414 cee3ee9b Ilias Tsitsimpis
            """Get hostname"""
415 cee3ee9b Ilias Tsitsimpis
            try:
416 cee3ee9b Ilias Tsitsimpis
                lines, status = self._ssh_execute(
417 cee3ee9b Ilias Tsitsimpis
                    hostip, username, password, "hostname")
418 cee3ee9b Ilias Tsitsimpis
                self.assertEqual(status, 0)
419 cee3ee9b Ilias Tsitsimpis
                self.assertEqual(len(lines), 1)
420 cee3ee9b Ilias Tsitsimpis
                # Remove new line
421 cee3ee9b Ilias Tsitsimpis
                return lines[0].strip('\n')
422 cee3ee9b Ilias Tsitsimpis
            except AssertionError:
423 cee3ee9b Ilias Tsitsimpis
                raise Retry()
424 cee3ee9b Ilias Tsitsimpis
        opmsg = "Connecting to server using ssh and get it's hostname"
425 cee3ee9b Ilias Tsitsimpis
        self.info(opmsg)
426 cee3ee9b Ilias Tsitsimpis
        hostname = self._try_until_timeout_expires(opmsg, check_fun)
427 cee3ee9b Ilias Tsitsimpis
        self.info("Server's hostname is %s", hostname)
428 cee3ee9b Ilias Tsitsimpis
        return hostname
429 cee3ee9b Ilias Tsitsimpis
430 9355a604 Ilias Tsitsimpis
    # pylint: disable=too-many-arguments
431 cee3ee9b Ilias Tsitsimpis
    def _check_file_through_ssh(self, hostip, username, password,
432 cee3ee9b Ilias Tsitsimpis
                                remotepath, content):
433 cee3ee9b Ilias Tsitsimpis
        """Fetch file from server and compare contents"""
434 cee3ee9b Ilias Tsitsimpis
        self.info("Fetching file %s from remote server", remotepath)
435 cee3ee9b Ilias Tsitsimpis
        transport = paramiko.Transport((hostip, 22))
436 cee3ee9b Ilias Tsitsimpis
        transport.connect(username=username, password=password)
437 cee3ee9b Ilias Tsitsimpis
        with tempfile.NamedTemporaryFile() as ftmp:
438 cee3ee9b Ilias Tsitsimpis
            sftp = paramiko.SFTPClient.from_transport(transport)
439 cee3ee9b Ilias Tsitsimpis
            sftp.get(remotepath, ftmp.name)
440 cee3ee9b Ilias Tsitsimpis
            sftp.close()
441 cee3ee9b Ilias Tsitsimpis
            transport.close()
442 cee3ee9b Ilias Tsitsimpis
            self.info("Comparing file contents")
443 cee3ee9b Ilias Tsitsimpis
            remote_content = base64.b64encode(ftmp.read())
444 cee3ee9b Ilias Tsitsimpis
            self.assertEqual(content, remote_content)
445 cee3ee9b Ilias Tsitsimpis
446 60a80953 Ilias Tsitsimpis
    # ----------------------------------
447 60a80953 Ilias Tsitsimpis
    # Networks
448 c2f037ff Ilias Tsitsimpis
    def _create_network(self, cidr="10.0.1.0/28", dhcp=True,
449 c2f037ff Ilias Tsitsimpis
                        project_id=None):
450 3e5bbd85 Ilias Tsitsimpis
        """Create a new private network"""
451 60a80953 Ilias Tsitsimpis
        name = self.run_id
452 60a80953 Ilias Tsitsimpis
        network = self.clients.network.create_network(
453 c2f037ff Ilias Tsitsimpis
            "MAC_FILTERED", name=name, shared=False,
454 c2f037ff Ilias Tsitsimpis
            project=project_id)
455 3e5bbd85 Ilias Tsitsimpis
        self.info("Network with id %s created", network['id'])
456 60a80953 Ilias Tsitsimpis
        subnet = self.clients.network.create_subnet(
457 60a80953 Ilias Tsitsimpis
            network['id'], cidr=cidr, enable_dhcp=dhcp)
458 60a80953 Ilias Tsitsimpis
        self.info("Subnet with id %s created", subnet['id'])
459 3e5bbd85 Ilias Tsitsimpis
460 3e5bbd85 Ilias Tsitsimpis
        # Verify quotas
461 c2f037ff Ilias Tsitsimpis
        if project_id is None:
462 c2f037ff Ilias Tsitsimpis
            project_id = self._get_uuid()
463 c2f037ff Ilias Tsitsimpis
        changes = \
464 c2f037ff Ilias Tsitsimpis
            {project_id: [(QNET, QADD, 1, None)]}
465 c2f037ff Ilias Tsitsimpis
        self._check_quotas(changes)
466 3e5bbd85 Ilias Tsitsimpis
467 3e5bbd85 Ilias Tsitsimpis
        #Test if the right name is assigned
468 3e5bbd85 Ilias Tsitsimpis
        self.assertEqual(network['name'], name)
469 c2f037ff Ilias Tsitsimpis
        self.assertEqual(network['tenant_id'], project_id)
470 3e5bbd85 Ilias Tsitsimpis
471 3e5bbd85 Ilias Tsitsimpis
        return network
472 3e5bbd85 Ilias Tsitsimpis
473 60a80953 Ilias Tsitsimpis
    def _delete_networks(self, networks, error=False):
474 60a80953 Ilias Tsitsimpis
        """Delete a network"""
475 60a80953 Ilias Tsitsimpis
        for net in networks:
476 60a80953 Ilias Tsitsimpis
            self.info("Deleting network with id %s", net['id'])
477 60a80953 Ilias Tsitsimpis
            self.clients.network.delete_network(net['id'])
478 60a80953 Ilias Tsitsimpis
479 60a80953 Ilias Tsitsimpis
        if error:
480 60a80953 Ilias Tsitsimpis
            curr_states = ["ACTIVE", "SNF:DRAINED", "ERROR"]
481 60a80953 Ilias Tsitsimpis
        else:
482 60a80953 Ilias Tsitsimpis
            curr_states = ["ACTIVE", "SNF:DRAINED"]
483 60a80953 Ilias Tsitsimpis
        for net in networks:
484 60a80953 Ilias Tsitsimpis
            self._insist_on_network_transition(net, curr_states, "DELETED")
485 60a80953 Ilias Tsitsimpis
486 60a80953 Ilias Tsitsimpis
        # Networks no longer in network list
487 60a80953 Ilias Tsitsimpis
        new_networks = [n['id'] for n in self._get_list_of_networks()]
488 60a80953 Ilias Tsitsimpis
        for net in networks:
489 60a80953 Ilias Tsitsimpis
            self.info("Verifying that network with id %s is no longer in "
490 60a80953 Ilias Tsitsimpis
                      "network list", net['id'])
491 60a80953 Ilias Tsitsimpis
            self.assertNotIn(net['id'], new_networks)
492 60a80953 Ilias Tsitsimpis
493 60a80953 Ilias Tsitsimpis
        # Verify quotas
494 c2f037ff Ilias Tsitsimpis
        changes = \
495 c2f037ff Ilias Tsitsimpis
            {self._get_uuid(): [(QNET, QREMOVE, len(networks), None)]}
496 c2f037ff Ilias Tsitsimpis
        self._check_quotas(changes)
497 60a80953 Ilias Tsitsimpis
498 60a80953 Ilias Tsitsimpis
    def _get_public_network(self, networks=None):
499 60a80953 Ilias Tsitsimpis
        """Get the public network"""
500 60a80953 Ilias Tsitsimpis
        if networks is None:
501 60a80953 Ilias Tsitsimpis
            networks = self._get_list_of_networks(detail=True)
502 60a80953 Ilias Tsitsimpis
        self.info("Getting the public network")
503 60a80953 Ilias Tsitsimpis
        for net in networks:
504 60a80953 Ilias Tsitsimpis
            if net['SNF:floating_ip_pool'] and net['public']:
505 60a80953 Ilias Tsitsimpis
                return net
506 60a80953 Ilias Tsitsimpis
        self.fail("Could not find a public network to use")
507 60a80953 Ilias Tsitsimpis
508 c2f037ff Ilias Tsitsimpis
    def _create_floating_ip(self, project_id=None):
509 60a80953 Ilias Tsitsimpis
        """Create a new floating ip"""
510 60a80953 Ilias Tsitsimpis
        pub_net = self._get_public_network()
511 60a80953 Ilias Tsitsimpis
        self.info("Creating a new floating ip for network with id %s",
512 60a80953 Ilias Tsitsimpis
                  pub_net['id'])
513 c2f037ff Ilias Tsitsimpis
        fip = self.clients.network.create_floatingip(
514 c2f037ff Ilias Tsitsimpis
            pub_net['id'], project=project_id)
515 60a80953 Ilias Tsitsimpis
        # Verify that floating ip has been created
516 60a80953 Ilias Tsitsimpis
        fips = self.clients.network.list_floatingips()
517 60a80953 Ilias Tsitsimpis
        fips = [f['id'] for f in fips]
518 60a80953 Ilias Tsitsimpis
        self.assertIn(fip['id'], fips)
519 60a80953 Ilias Tsitsimpis
        # Verify quotas
520 c2f037ff Ilias Tsitsimpis
        if project_id is None:
521 c2f037ff Ilias Tsitsimpis
            project_id = self._get_uuid()
522 c2f037ff Ilias Tsitsimpis
        changes = \
523 c2f037ff Ilias Tsitsimpis
            {project_id: [(QIP, QADD, 1, None)]}
524 c2f037ff Ilias Tsitsimpis
        self._check_quotas(changes)
525 c2f037ff Ilias Tsitsimpis
526 60a80953 Ilias Tsitsimpis
        # Check that IP is IPv4
527 c2f037ff Ilias Tsitsimpis
        self.assertEqual(IPy.IP(fip['floating_ip_address']).version(), 4)
528 c2f037ff Ilias Tsitsimpis
        self.assertEqual(fip['tenant_id'], project_id)
529 60a80953 Ilias Tsitsimpis
530 60a80953 Ilias Tsitsimpis
        self.info("Floating IP %s with id %s created",
531 60a80953 Ilias Tsitsimpis
                  fip['floating_ip_address'], fip['id'])
532 60a80953 Ilias Tsitsimpis
        return fip
533 60a80953 Ilias Tsitsimpis
534 60a80953 Ilias Tsitsimpis
    def _create_port(self, network_id, device_id=None, floating_ip=None):
535 60a80953 Ilias Tsitsimpis
        """Create a new port attached to the a specific network"""
536 60a80953 Ilias Tsitsimpis
        self.info("Creating a new port to network with id %s", network_id)
537 60a80953 Ilias Tsitsimpis
        if floating_ip is not None:
538 60a80953 Ilias Tsitsimpis
            fixed_ips = [{'ip_address': floating_ip['floating_ip_address']}]
539 60a80953 Ilias Tsitsimpis
        else:
540 60a80953 Ilias Tsitsimpis
            fixed_ips = None
541 60a80953 Ilias Tsitsimpis
        port = self.clients.network.create_port(network_id,
542 60a80953 Ilias Tsitsimpis
                                                device_id=device_id,
543 60a80953 Ilias Tsitsimpis
                                                fixed_ips=fixed_ips)
544 60a80953 Ilias Tsitsimpis
        # Verify that port created
545 60a80953 Ilias Tsitsimpis
        ports = self.clients.network.list_ports()
546 60a80953 Ilias Tsitsimpis
        ports = [p['id'] for p in ports]
547 60a80953 Ilias Tsitsimpis
        self.assertIn(port['id'], ports)
548 60a80953 Ilias Tsitsimpis
        # Insist on creation
549 60a80953 Ilias Tsitsimpis
        if device_id is None:
550 60a80953 Ilias Tsitsimpis
            self._insist_on_port_transition(port, ["BUILD"], "DOWN")
551 60a80953 Ilias Tsitsimpis
        else:
552 60a80953 Ilias Tsitsimpis
            self._insist_on_port_transition(port, ["BUILD", "DOWN"], "ACTIVE")
553 60a80953 Ilias Tsitsimpis
554 60a80953 Ilias Tsitsimpis
        self.info("Port with id %s created", port['id'])
555 60a80953 Ilias Tsitsimpis
        return port
556 60a80953 Ilias Tsitsimpis
557 60a80953 Ilias Tsitsimpis
    def _insist_on_port_transition(self, port, curr_statuses, new_status):
558 60a80953 Ilias Tsitsimpis
        """Insist on port transiting from curr_statuses to new_status"""
559 60a80953 Ilias Tsitsimpis
        def check_fun():
560 60a80953 Ilias Tsitsimpis
            """Check port status"""
561 60a80953 Ilias Tsitsimpis
            portd = self.clients.network.get_port_details(port['id'])
562 60a80953 Ilias Tsitsimpis
            if portd['status'] in curr_statuses:
563 60a80953 Ilias Tsitsimpis
                raise Retry()
564 60a80953 Ilias Tsitsimpis
            elif portd['status'] == new_status:
565 60a80953 Ilias Tsitsimpis
                return
566 60a80953 Ilias Tsitsimpis
            else:
567 60a80953 Ilias Tsitsimpis
                msg = "Port %s went to unexpected status %s"
568 60a80953 Ilias Tsitsimpis
                self.fail(msg % (portd['id'], portd['status']))
569 60a80953 Ilias Tsitsimpis
        opmsg = "Waiting for port %s to become %s"
570 60a80953 Ilias Tsitsimpis
        self.info(opmsg, port['id'], new_status)
571 60a80953 Ilias Tsitsimpis
        opmsg = opmsg % (port['id'], new_status)
572 60a80953 Ilias Tsitsimpis
        self._try_until_timeout_expires(opmsg, check_fun)
573 60a80953 Ilias Tsitsimpis
574 60a80953 Ilias Tsitsimpis
    def _insist_on_port_deletion(self, portid):
575 60a80953 Ilias Tsitsimpis
        """Insist on port deletion"""
576 60a80953 Ilias Tsitsimpis
        def check_fun():
577 60a80953 Ilias Tsitsimpis
            """Check port details"""
578 60a80953 Ilias Tsitsimpis
            try:
579 60a80953 Ilias Tsitsimpis
                self.clients.network.get_port_details(portid)
580 60a80953 Ilias Tsitsimpis
            except ClientError as err:
581 60a80953 Ilias Tsitsimpis
                if err.status != 404:
582 60a80953 Ilias Tsitsimpis
                    raise
583 60a80953 Ilias Tsitsimpis
            else:
584 60a80953 Ilias Tsitsimpis
                raise Retry()
585 60a80953 Ilias Tsitsimpis
        opmsg = "Waiting for port %s to be deleted"
586 60a80953 Ilias Tsitsimpis
        self.info(opmsg, portid)
587 60a80953 Ilias Tsitsimpis
        opmsg = opmsg % portid
588 60a80953 Ilias Tsitsimpis
        self._try_until_timeout_expires(opmsg, check_fun)
589 60a80953 Ilias Tsitsimpis
590 60a80953 Ilias Tsitsimpis
    def _disconnect_from_network(self, server, network=None):
591 60a80953 Ilias Tsitsimpis
        """Disconnnect server from network"""
592 60a80953 Ilias Tsitsimpis
        if network is None:
593 60a80953 Ilias Tsitsimpis
            # Disconnect from public network
594 60a80953 Ilias Tsitsimpis
            network = self._get_public_network()
595 60a80953 Ilias Tsitsimpis
596 60a80953 Ilias Tsitsimpis
        lports = self.clients.network.list_ports()
597 60a80953 Ilias Tsitsimpis
        ports = []
598 60a80953 Ilias Tsitsimpis
        for port in lports:
599 60a80953 Ilias Tsitsimpis
            dport = self.clients.network.get_port_details(port['id'])
600 60a80953 Ilias Tsitsimpis
            if str(dport['network_id']) == str(network['id']) \
601 60a80953 Ilias Tsitsimpis
                    and str(dport['device_id']) == str(server['id']):
602 60a80953 Ilias Tsitsimpis
                ports.append(dport)
603 60a80953 Ilias Tsitsimpis
604 60a80953 Ilias Tsitsimpis
        # Find floating IPs attached to these ports
605 60a80953 Ilias Tsitsimpis
        ports_id = [p['id'] for p in ports]
606 60a80953 Ilias Tsitsimpis
        fips = [f for f in self.clients.network.list_floatingips()
607 60a80953 Ilias Tsitsimpis
                if str(f['port_id']) in ports_id]
608 60a80953 Ilias Tsitsimpis
609 60a80953 Ilias Tsitsimpis
        # First destroy the ports
610 60a80953 Ilias Tsitsimpis
        for port in ports:
611 60a80953 Ilias Tsitsimpis
            self.info("Destroying port with id %s", port['id'])
612 60a80953 Ilias Tsitsimpis
            self.clients.network.delete_port(port['id'])
613 60a80953 Ilias Tsitsimpis
            self._insist_on_port_deletion(port['id'])
614 60a80953 Ilias Tsitsimpis
615 60a80953 Ilias Tsitsimpis
        # Then delete the floating IPs
616 17bb60a5 Ilias Tsitsimpis
        self._delete_floating_ips(fips)
617 17bb60a5 Ilias Tsitsimpis
618 17bb60a5 Ilias Tsitsimpis
    def _delete_floating_ips(self, fips):
619 17bb60a5 Ilias Tsitsimpis
        """Delete floating ips"""
620 4cf2178f Ilias Tsitsimpis
        # Renew the list of floating IP objects
621 4cf2178f Ilias Tsitsimpis
        # (It may have been changed, i.e. a port may have been deleted).
622 4cf2178f Ilias Tsitsimpis
        fip_ids = [f['id'] for f in fips]
623 4cf2178f Ilias Tsitsimpis
        new_fips = [f for f in self.clients.network.list_floatingips()
624 4cf2178f Ilias Tsitsimpis
                    if f['id'] in fip_ids]
625 4cf2178f Ilias Tsitsimpis
626 4cf2178f Ilias Tsitsimpis
        for fip in new_fips:
627 fd95755f Ilias Tsitsimpis
            port_id = fip['port_id']
628 fd95755f Ilias Tsitsimpis
            if port_id:
629 fd95755f Ilias Tsitsimpis
                self.info("Destroying port with id %s", port_id)
630 fd95755f Ilias Tsitsimpis
                self.clients.network.delete_port(port_id)
631 fd95755f Ilias Tsitsimpis
                self._insist_on_port_deletion(port_id)
632 fd95755f Ilias Tsitsimpis
633 60a80953 Ilias Tsitsimpis
            self.info("Destroying floating IP %s with id %s",
634 60a80953 Ilias Tsitsimpis
                      fip['floating_ip_address'], fip['id'])
635 60a80953 Ilias Tsitsimpis
            self.clients.network.delete_floatingip(fip['id'])
636 60a80953 Ilias Tsitsimpis
637 60a80953 Ilias Tsitsimpis
        # Check that floating IPs have been deleted
638 60a80953 Ilias Tsitsimpis
        list_ips = [f['id'] for f in self.clients.network.list_floatingips()]
639 60a80953 Ilias Tsitsimpis
        for fip in fips:
640 60a80953 Ilias Tsitsimpis
            self.assertNotIn(fip['id'], list_ips)
641 c2f037ff Ilias Tsitsimpis
642 60a80953 Ilias Tsitsimpis
        # Verify quotas
643 c2f037ff Ilias Tsitsimpis
        changes = dict()
644 c2f037ff Ilias Tsitsimpis
        for fip in fips:
645 c2f037ff Ilias Tsitsimpis
            project = fip['tenant_id']
646 c2f037ff Ilias Tsitsimpis
            if project not in changes:
647 c2f037ff Ilias Tsitsimpis
                changes[project] = []
648 c2f037ff Ilias Tsitsimpis
            changes[project].append((QIP, QREMOVE, 1, None))
649 c2f037ff Ilias Tsitsimpis
        self._check_quotas(changes)
650 c2f037ff Ilias Tsitsimpis
651 c2f037ff Ilias Tsitsimpis
    def _find_project(self, flavors, projects=None):
652 c2f037ff Ilias Tsitsimpis
        """Return a pair of flavor, project that we can use"""
653 c2f037ff Ilias Tsitsimpis
        if projects is None:
654 c2f037ff Ilias Tsitsimpis
            projects = self.quotas.keys()
655 c2f037ff Ilias Tsitsimpis
656 c2f037ff Ilias Tsitsimpis
        # XXX: Well there seems to be no easy way to find how many resources
657 c2f037ff Ilias Tsitsimpis
        # we have left in a project (we have to substract usage from limit,
658 c2f037ff Ilias Tsitsimpis
        # check both per_user and project quotas, blah, blah). For now
659 c2f037ff Ilias Tsitsimpis
        # just return the first flavor with the first project and lets hope
660 c2f037ff Ilias Tsitsimpis
        # that it fits.
661 c2f037ff Ilias Tsitsimpis
        return (flavors[0], projects[0])
662 c2f037ff Ilias Tsitsimpis
663 c2f037ff Ilias Tsitsimpis
        # # Get only the quotas for the given 'projects'
664 c2f037ff Ilias Tsitsimpis
        # quotas = dict()
665 c2f037ff Ilias Tsitsimpis
        # for prj, qts in self.quotas.items():
666 c2f037ff Ilias Tsitsimpis
        #     if prj in projects:
667 c2f037ff Ilias Tsitsimpis
        #         quotas[prj] = qts
668 c2f037ff Ilias Tsitsimpis
        #
669 c2f037ff Ilias Tsitsimpis
        # results = []
670 c2f037ff Ilias Tsitsimpis
        # for flv in flavors:
671 c2f037ff Ilias Tsitsimpis
        #     for prj, qts in quotas.items():
672 c2f037ff Ilias Tsitsimpis
        #         self.debug("Testing flavor %s, project %s", flv['name'], prj)
673 c2f037ff Ilias Tsitsimpis
        #         condition = \
674 c2f037ff Ilias Tsitsimpis
        #             (flv['ram'] <= qts['cyclades.ram']['usage'] and
675 c2f037ff Ilias Tsitsimpis
        #              flv['vcpus'] <= qts['cyclades.cpu']['usage'] and
676 c2f037ff Ilias Tsitsimpis
        #              flv['disk'] <= qts['cyclades.disk']['usage'] and
677 c2f037ff Ilias Tsitsimpis
        #              qts['cyclades.vm']['usage'] >= 1)
678 c2f037ff Ilias Tsitsimpis
        #         if condition:
679 c2f037ff Ilias Tsitsimpis
        #             results.append((flv, prj))
680 c2f037ff Ilias Tsitsimpis
        #
681 c2f037ff Ilias Tsitsimpis
        # if not results:
682 c2f037ff Ilias Tsitsimpis
        #     msg = "Couldn't find a suitable flavor to use for current qutoas"
683 c2f037ff Ilias Tsitsimpis
        #     self.error(msg)
684 c2f037ff Ilias Tsitsimpis
        #
685 c2f037ff Ilias Tsitsimpis
        # return random.choice(results)
686 60a80953 Ilias Tsitsimpis
687 d246be88 Ilias Tsitsimpis
688 d246be88 Ilias Tsitsimpis
class Retry(Exception):
689 d246be88 Ilias Tsitsimpis
    """Retry the action
690 d246be88 Ilias Tsitsimpis

691 d246be88 Ilias Tsitsimpis
    This is used by _try_unit_timeout_expires method.
692 d246be88 Ilias Tsitsimpis

693 d246be88 Ilias Tsitsimpis
    """