root / snf-tools / synnefo_tools / burnin / cyclades_common.py @ 5bef1f49
History | View | Annotate | Download (14.9 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 | cee3ee9b | Ilias Tsitsimpis | import base64 |
43 | d246be88 | Ilias Tsitsimpis | import socket |
44 | d246be88 | Ilias Tsitsimpis | import random |
45 | cee3ee9b | Ilias Tsitsimpis | import paramiko |
46 | cee3ee9b | Ilias Tsitsimpis | import tempfile |
47 | d246be88 | Ilias Tsitsimpis | import subprocess |
48 | d246be88 | Ilias Tsitsimpis | |
49 | d246be88 | Ilias Tsitsimpis | from synnefo_tools.burnin.common import BurninTests |
50 | d246be88 | Ilias Tsitsimpis | |
51 | d246be88 | Ilias Tsitsimpis | |
52 | d246be88 | Ilias Tsitsimpis | # Too many public methods. pylint: disable-msg=R0904
|
53 | d246be88 | Ilias Tsitsimpis | class CycladesTests(BurninTests): |
54 | d246be88 | Ilias Tsitsimpis | """Extends the BurninTests class for Cyclades"""
|
55 | 3eaf0ec5 | Ilias Tsitsimpis | def _try_until_timeout_expires(self, opmsg, check_fun): |
56 | d246be88 | Ilias Tsitsimpis | """Try to perform an action until timeout expires"""
|
57 | d246be88 | Ilias Tsitsimpis | assert callable(check_fun), "Not a function" |
58 | d246be88 | Ilias Tsitsimpis | |
59 | d246be88 | Ilias Tsitsimpis | action_timeout = self.action_timeout
|
60 | d246be88 | Ilias Tsitsimpis | action_warning = self.action_warning
|
61 | d246be88 | Ilias Tsitsimpis | if action_warning > action_timeout:
|
62 | d246be88 | Ilias Tsitsimpis | action_warning = action_timeout |
63 | d246be88 | Ilias Tsitsimpis | |
64 | 8c67f82e | Ilias Tsitsimpis | start_time = int(time.time())
|
65 | 8c67f82e | Ilias Tsitsimpis | end_time = start_time + action_warning |
66 | 8c67f82e | Ilias Tsitsimpis | while end_time > time.time():
|
67 | d246be88 | Ilias Tsitsimpis | try:
|
68 | 8c67f82e | Ilias Tsitsimpis | ret_value = check_fun() |
69 | 8c67f82e | Ilias Tsitsimpis | self.info("Operation `%s' finished in %s seconds", |
70 | 8c67f82e | Ilias Tsitsimpis | opmsg, int(time.time()) - start_time)
|
71 | 8c67f82e | Ilias Tsitsimpis | return ret_value
|
72 | d246be88 | Ilias Tsitsimpis | except Retry:
|
73 | d246be88 | Ilias Tsitsimpis | time.sleep(self.query_interval)
|
74 | 8c67f82e | Ilias Tsitsimpis | self.warning("Operation `%s' is taking too long after %s seconds", |
75 | 8c67f82e | Ilias Tsitsimpis | opmsg, int(time.time()) - start_time)
|
76 | 8c67f82e | Ilias Tsitsimpis | |
77 | 8c67f82e | Ilias Tsitsimpis | end_time = start_time + action_timeout |
78 | 8c67f82e | Ilias Tsitsimpis | while end_time > time.time():
|
79 | d246be88 | Ilias Tsitsimpis | try:
|
80 | 8c67f82e | Ilias Tsitsimpis | ret_value = check_fun() |
81 | 8c67f82e | Ilias Tsitsimpis | self.info("Operation `%s' finished in %s seconds", |
82 | 8c67f82e | Ilias Tsitsimpis | opmsg, int(time.time()) - start_time)
|
83 | 8c67f82e | Ilias Tsitsimpis | return ret_value
|
84 | d246be88 | Ilias Tsitsimpis | except Retry:
|
85 | d246be88 | Ilias Tsitsimpis | time.sleep(self.query_interval)
|
86 | 8c67f82e | Ilias Tsitsimpis | self.error("Operation `%s' timed out after %s seconds", |
87 | 8c67f82e | Ilias Tsitsimpis | opmsg, int(time.time()) - start_time)
|
88 | d246be88 | Ilias Tsitsimpis | self.fail("time out") |
89 | d246be88 | Ilias Tsitsimpis | |
90 | d246be88 | Ilias Tsitsimpis | def _get_list_of_servers(self, detail=False): |
91 | d246be88 | Ilias Tsitsimpis | """Get (detailed) list of servers"""
|
92 | d246be88 | Ilias Tsitsimpis | if detail:
|
93 | d246be88 | Ilias Tsitsimpis | self.info("Getting detailed list of servers") |
94 | d246be88 | Ilias Tsitsimpis | else:
|
95 | d246be88 | Ilias Tsitsimpis | self.info("Getting simple list of servers") |
96 | d246be88 | Ilias Tsitsimpis | return self.clients.cyclades.list_servers(detail=detail) |
97 | d246be88 | Ilias Tsitsimpis | |
98 | 3eaf0ec5 | Ilias Tsitsimpis | def _get_list_of_networks(self, detail=False): |
99 | 3eaf0ec5 | Ilias Tsitsimpis | """Get (detailed) list of networks"""
|
100 | 3eaf0ec5 | Ilias Tsitsimpis | if detail:
|
101 | 3eaf0ec5 | Ilias Tsitsimpis | self.info("Getting detailed list of networks") |
102 | 3eaf0ec5 | Ilias Tsitsimpis | else:
|
103 | 3eaf0ec5 | Ilias Tsitsimpis | self.info("Getting simple list of networks") |
104 | 3eaf0ec5 | Ilias Tsitsimpis | return self.clients.cyclades.list_networks(detail=detail) |
105 | 3eaf0ec5 | Ilias Tsitsimpis | |
106 | 3eaf0ec5 | Ilias Tsitsimpis | def _get_server_details(self, server, quiet=False): |
107 | d246be88 | Ilias Tsitsimpis | """Get details for a server"""
|
108 | 3eaf0ec5 | Ilias Tsitsimpis | if not quiet: |
109 | 3eaf0ec5 | Ilias Tsitsimpis | self.info("Getting details for server %s with id %s", |
110 | 3eaf0ec5 | Ilias Tsitsimpis | server['name'], server['id']) |
111 | d246be88 | Ilias Tsitsimpis | return self.clients.cyclades.get_server_details(server['id']) |
112 | d246be88 | Ilias Tsitsimpis | |
113 | 3eaf0ec5 | Ilias Tsitsimpis | def _create_server(self, image, flavor, personality=None): |
114 | d246be88 | Ilias Tsitsimpis | """Create a new server"""
|
115 | 3eaf0ec5 | Ilias Tsitsimpis | servername = "%s for %s" % (self.run_id, image['name']) |
116 | 3eaf0ec5 | Ilias Tsitsimpis | self.info("Creating a server with name %s", servername) |
117 | d246be88 | Ilias Tsitsimpis | self.info("Using image %s with id %s", image['name'], image['id']) |
118 | d246be88 | Ilias Tsitsimpis | self.info("Using flavor %s with id %s", flavor['name'], flavor['id']) |
119 | d246be88 | Ilias Tsitsimpis | server = self.clients.cyclades.create_server(
|
120 | 3eaf0ec5 | Ilias Tsitsimpis | servername, flavor['id'], image['id'], personality=personality) |
121 | d246be88 | Ilias Tsitsimpis | |
122 | d246be88 | Ilias Tsitsimpis | self.info("Server id: %s", server['id']) |
123 | d246be88 | Ilias Tsitsimpis | self.info("Server password: %s", server['adminPass']) |
124 | d246be88 | Ilias Tsitsimpis | |
125 | 3eaf0ec5 | Ilias Tsitsimpis | self.assertEqual(server['name'], servername) |
126 | d246be88 | Ilias Tsitsimpis | self.assertEqual(server['flavor']['id'], flavor['id']) |
127 | d246be88 | Ilias Tsitsimpis | self.assertEqual(server['image']['id'], image['id']) |
128 | d246be88 | Ilias Tsitsimpis | self.assertEqual(server['status'], "BUILD") |
129 | d246be88 | Ilias Tsitsimpis | |
130 | d246be88 | Ilias Tsitsimpis | return server
|
131 | d246be88 | Ilias Tsitsimpis | |
132 | d246be88 | Ilias Tsitsimpis | def _get_connection_username(self, server): |
133 | d246be88 | Ilias Tsitsimpis | """Determine the username to use to connect to the server"""
|
134 | d246be88 | Ilias Tsitsimpis | users = server['metadata'].get("users", None) |
135 | d246be88 | Ilias Tsitsimpis | ret_user = None
|
136 | d246be88 | Ilias Tsitsimpis | if users is not None: |
137 | d246be88 | Ilias Tsitsimpis | user_list = users.split() |
138 | d246be88 | Ilias Tsitsimpis | if "root" in user_list: |
139 | d246be88 | Ilias Tsitsimpis | ret_user = "root"
|
140 | d246be88 | Ilias Tsitsimpis | else:
|
141 | d246be88 | Ilias Tsitsimpis | ret_user = random.choice(user_list) |
142 | d246be88 | Ilias Tsitsimpis | else:
|
143 | d246be88 | Ilias Tsitsimpis | # Return the login name for connections based on the server OS
|
144 | d246be88 | Ilias Tsitsimpis | self.info("Could not find `users' metadata in server. Let's guess") |
145 | d246be88 | Ilias Tsitsimpis | os_value = server['metadata'].get("os") |
146 | d246be88 | Ilias Tsitsimpis | if os_value in ("Ubuntu", "Kubuntu", "Fedora"): |
147 | d246be88 | Ilias Tsitsimpis | ret_user = "user"
|
148 | d246be88 | Ilias Tsitsimpis | elif os_value in ("windows", "windows_alpha1"): |
149 | d246be88 | Ilias Tsitsimpis | ret_user = "Administrator"
|
150 | d246be88 | Ilias Tsitsimpis | else:
|
151 | d246be88 | Ilias Tsitsimpis | ret_user = "root"
|
152 | d246be88 | Ilias Tsitsimpis | |
153 | d246be88 | Ilias Tsitsimpis | self.assertIsNotNone(ret_user)
|
154 | d246be88 | Ilias Tsitsimpis | self.info("User's login name: %s", ret_user) |
155 | d246be88 | Ilias Tsitsimpis | return ret_user
|
156 | d246be88 | Ilias Tsitsimpis | |
157 | 3eaf0ec5 | Ilias Tsitsimpis | def _insist_on_server_transition(self, server, curr_statuses, new_status): |
158 | 3eaf0ec5 | Ilias Tsitsimpis | """Insist on server transiting from curr_statuses to new_status"""
|
159 | d246be88 | Ilias Tsitsimpis | def check_fun(): |
160 | d246be88 | Ilias Tsitsimpis | """Check server status"""
|
161 | 3eaf0ec5 | Ilias Tsitsimpis | srv = self._get_server_details(server, quiet=True) |
162 | 3eaf0ec5 | Ilias Tsitsimpis | if srv['status'] in curr_statuses: |
163 | d246be88 | Ilias Tsitsimpis | raise Retry()
|
164 | d246be88 | Ilias Tsitsimpis | elif srv['status'] == new_status: |
165 | d246be88 | Ilias Tsitsimpis | return
|
166 | d246be88 | Ilias Tsitsimpis | else:
|
167 | 3eaf0ec5 | Ilias Tsitsimpis | msg = "Server \"%s\" with id %s went to unexpected status %s"
|
168 | 3eaf0ec5 | Ilias Tsitsimpis | self.error(msg, server['name'], server['id'], srv['status']) |
169 | 3eaf0ec5 | Ilias Tsitsimpis | self.fail(msg % (server['name'], server['id'], srv['status'])) |
170 | 5bef1f49 | Ilias Tsitsimpis | opmsg = "Waiting for server \"%s\" with id %s to become %s"
|
171 | 5bef1f49 | Ilias Tsitsimpis | self.info(opmsg, server['name'], server['id'], new_status) |
172 | 5bef1f49 | Ilias Tsitsimpis | opmsg = opmsg % (server['name'], server['id'], new_status) |
173 | 3eaf0ec5 | Ilias Tsitsimpis | self._try_until_timeout_expires(opmsg, check_fun)
|
174 | 3eaf0ec5 | Ilias Tsitsimpis | |
175 | 3eaf0ec5 | Ilias Tsitsimpis | def _insist_on_network_transition(self, network, |
176 | 3eaf0ec5 | Ilias Tsitsimpis | curr_statuses, new_status): |
177 | 3eaf0ec5 | Ilias Tsitsimpis | """Insist on network transiting from curr_statuses to new_status"""
|
178 | 3eaf0ec5 | Ilias Tsitsimpis | def check_fun(): |
179 | 3eaf0ec5 | Ilias Tsitsimpis | """Check network status"""
|
180 | 3eaf0ec5 | Ilias Tsitsimpis | ntw = self.clients.cyclades.get_network_details(network['id']) |
181 | 3eaf0ec5 | Ilias Tsitsimpis | if ntw['status'] in curr_statuses: |
182 | 3eaf0ec5 | Ilias Tsitsimpis | raise Retry()
|
183 | 3eaf0ec5 | Ilias Tsitsimpis | elif ntw['status'] == new_status: |
184 | 3eaf0ec5 | Ilias Tsitsimpis | return
|
185 | 3eaf0ec5 | Ilias Tsitsimpis | else:
|
186 | 3eaf0ec5 | Ilias Tsitsimpis | msg = "Network %s with id %s went to unexpected status %s"
|
187 | 3eaf0ec5 | Ilias Tsitsimpis | self.error(msg, network['name'], network['id'], ntw['status']) |
188 | 3eaf0ec5 | Ilias Tsitsimpis | self.fail(msg %
|
189 | 3eaf0ec5 | Ilias Tsitsimpis | (network['name'], network['id'], ntw['status'])) |
190 | 5bef1f49 | Ilias Tsitsimpis | opmsg = "Waiting for network \"%s\" with id %s to become %s"
|
191 | 5bef1f49 | Ilias Tsitsimpis | self.info(opmsg, network['name'], network['id'], new_status) |
192 | 5bef1f49 | Ilias Tsitsimpis | opmsg = opmsg % (network['name'], network['id'], new_status) |
193 | 3eaf0ec5 | Ilias Tsitsimpis | self._try_until_timeout_expires(opmsg, check_fun)
|
194 | 3eaf0ec5 | Ilias Tsitsimpis | |
195 | 3eaf0ec5 | Ilias Tsitsimpis | def _insist_on_network_connection(self, server, network, disconnect=False): |
196 | 3eaf0ec5 | Ilias Tsitsimpis | """Insist that the server has connected to the network"""
|
197 | 3eaf0ec5 | Ilias Tsitsimpis | def check_fun(): |
198 | 3eaf0ec5 | Ilias Tsitsimpis | """Check network connection"""
|
199 | 3eaf0ec5 | Ilias Tsitsimpis | dsrv = self._get_server_details(server, quiet=True) |
200 | 3eaf0ec5 | Ilias Tsitsimpis | nets = [s['network_id'] for s in dsrv['attachments']] |
201 | 3eaf0ec5 | Ilias Tsitsimpis | if not disconnect and network['id'] not in nets: |
202 | 3eaf0ec5 | Ilias Tsitsimpis | raise Retry()
|
203 | 3eaf0ec5 | Ilias Tsitsimpis | if disconnect and network['id'] in nets: |
204 | 3eaf0ec5 | Ilias Tsitsimpis | raise Retry()
|
205 | 3eaf0ec5 | Ilias Tsitsimpis | if disconnect:
|
206 | 3eaf0ec5 | Ilias Tsitsimpis | opmsg = \ |
207 | 3eaf0ec5 | Ilias Tsitsimpis | "Waiting for server \"%s\" to disconnect from network \"%s\""
|
208 | 3eaf0ec5 | Ilias Tsitsimpis | else:
|
209 | 3eaf0ec5 | Ilias Tsitsimpis | opmsg = "Waiting for server \"%s\" to connect to network \"%s\""
|
210 | 3eaf0ec5 | Ilias Tsitsimpis | self.info(opmsg, server['name'], network['name']) |
211 | 3eaf0ec5 | Ilias Tsitsimpis | opmsg = opmsg % (server['name'], network['name']) |
212 | d246be88 | Ilias Tsitsimpis | self._try_until_timeout_expires(opmsg, check_fun)
|
213 | d246be88 | Ilias Tsitsimpis | |
214 | d246be88 | Ilias Tsitsimpis | def _insist_on_tcp_connection(self, family, host, port): |
215 | d246be88 | Ilias Tsitsimpis | """Insist on tcp connection"""
|
216 | d246be88 | Ilias Tsitsimpis | def check_fun(): |
217 | d246be88 | Ilias Tsitsimpis | """Get a connected socket from the specified family to host:port"""
|
218 | d246be88 | Ilias Tsitsimpis | sock = None
|
219 | d246be88 | Ilias Tsitsimpis | for res in socket.getaddrinfo(host, port, family, |
220 | d246be88 | Ilias Tsitsimpis | socket.SOCK_STREAM, 0,
|
221 | d246be88 | Ilias Tsitsimpis | socket.AI_PASSIVE): |
222 | d246be88 | Ilias Tsitsimpis | fam, socktype, proto, _, saddr = res |
223 | d246be88 | Ilias Tsitsimpis | try:
|
224 | d246be88 | Ilias Tsitsimpis | sock = socket.socket(fam, socktype, proto) |
225 | d246be88 | Ilias Tsitsimpis | except socket.error:
|
226 | d246be88 | Ilias Tsitsimpis | sock = None
|
227 | d246be88 | Ilias Tsitsimpis | continue
|
228 | d246be88 | Ilias Tsitsimpis | try:
|
229 | d246be88 | Ilias Tsitsimpis | sock.connect(saddr) |
230 | d246be88 | Ilias Tsitsimpis | except socket.error:
|
231 | d246be88 | Ilias Tsitsimpis | sock.close() |
232 | d246be88 | Ilias Tsitsimpis | sock = None
|
233 | d246be88 | Ilias Tsitsimpis | continue
|
234 | d246be88 | Ilias Tsitsimpis | if sock is None: |
235 | d246be88 | Ilias Tsitsimpis | raise Retry
|
236 | d246be88 | Ilias Tsitsimpis | return sock
|
237 | d246be88 | Ilias Tsitsimpis | familystr = {socket.AF_INET: "IPv4", socket.AF_INET6: "IPv6", |
238 | d246be88 | Ilias Tsitsimpis | socket.AF_UNSPEC: "Unspecified-IPv4/6"}
|
239 | d246be88 | Ilias Tsitsimpis | opmsg = "Connecting over %s to %s:%s"
|
240 | d246be88 | Ilias Tsitsimpis | self.info(opmsg, familystr.get(family, "Unknown"), host, port) |
241 | d246be88 | Ilias Tsitsimpis | opmsg = opmsg % (familystr.get(family, "Unknown"), host, port)
|
242 | d246be88 | Ilias Tsitsimpis | return self._try_until_timeout_expires(opmsg, check_fun) |
243 | d246be88 | Ilias Tsitsimpis | |
244 | 3eaf0ec5 | Ilias Tsitsimpis | def _get_ip(self, server, version=4, network=None): |
245 | 3eaf0ec5 | Ilias Tsitsimpis | """Get the IP of a server from the detailed server info
|
246 | 3eaf0ec5 | Ilias Tsitsimpis |
|
247 | 3eaf0ec5 | Ilias Tsitsimpis | If network not given then get the public IP. Else the ip
|
248 | 3eaf0ec5 | Ilias Tsitsimpis | attached to that network
|
249 | 3eaf0ec5 | Ilias Tsitsimpis |
|
250 | 3eaf0ec5 | Ilias Tsitsimpis | """
|
251 | d246be88 | Ilias Tsitsimpis | assert version in (4, 6) |
252 | d246be88 | Ilias Tsitsimpis | |
253 | d246be88 | Ilias Tsitsimpis | nics = server['attachments']
|
254 | 3eaf0ec5 | Ilias Tsitsimpis | addrs = None
|
255 | d246be88 | Ilias Tsitsimpis | for nic in nics: |
256 | d246be88 | Ilias Tsitsimpis | net_id = nic['network_id']
|
257 | 3eaf0ec5 | Ilias Tsitsimpis | if network is None: |
258 | 3eaf0ec5 | Ilias Tsitsimpis | if self.clients.cyclades.get_network_details(net_id)['public']: |
259 | ee89df69 | Ilias Tsitsimpis | if nic['ipv' + str(version)]: |
260 | ee89df69 | Ilias Tsitsimpis | addrs = nic['ipv' + str(version)] |
261 | ee89df69 | Ilias Tsitsimpis | break
|
262 | 3eaf0ec5 | Ilias Tsitsimpis | else:
|
263 | 3eaf0ec5 | Ilias Tsitsimpis | if net_id == network['id']: |
264 | ee89df69 | Ilias Tsitsimpis | if nic['ipv' + str(version)]: |
265 | ee89df69 | Ilias Tsitsimpis | addrs = nic['ipv' + str(version)] |
266 | ee89df69 | Ilias Tsitsimpis | break
|
267 | d246be88 | Ilias Tsitsimpis | |
268 | 3eaf0ec5 | Ilias Tsitsimpis | self.assertIsNotNone(addrs, "Can not get IP from server attachments") |
269 | 3eaf0ec5 | Ilias Tsitsimpis | if network is None: |
270 | 3eaf0ec5 | Ilias Tsitsimpis | msg = "Server's public IPv%s is %s"
|
271 | 3eaf0ec5 | Ilias Tsitsimpis | self.info(msg, version, addrs)
|
272 | 3eaf0ec5 | Ilias Tsitsimpis | else:
|
273 | 3eaf0ec5 | Ilias Tsitsimpis | msg = "Server's IPv%s attached to network \"%s\" is %s"
|
274 | 3eaf0ec5 | Ilias Tsitsimpis | self.info(msg, version, network['id'], addrs) |
275 | 3eaf0ec5 | Ilias Tsitsimpis | return addrs
|
276 | d246be88 | Ilias Tsitsimpis | |
277 | cee3ee9b | Ilias Tsitsimpis | def _insist_on_ping(self, ip_addr, version=4): |
278 | d246be88 | Ilias Tsitsimpis | """Test server responds to a single IPv4 of IPv6 ping"""
|
279 | d246be88 | Ilias Tsitsimpis | def check_fun(): |
280 | d246be88 | Ilias Tsitsimpis | """Ping to server"""
|
281 | d246be88 | Ilias Tsitsimpis | cmd = ("ping%s -c 3 -w 20 %s" %
|
282 | d246be88 | Ilias Tsitsimpis | ("6" if version == 6 else "", ip_addr)) |
283 | d246be88 | Ilias Tsitsimpis | ping = subprocess.Popen( |
284 | d246be88 | Ilias Tsitsimpis | cmd, shell=True, stdout=subprocess.PIPE,
|
285 | d246be88 | Ilias Tsitsimpis | stderr=subprocess.PIPE) |
286 | d246be88 | Ilias Tsitsimpis | ping.communicate() |
287 | d246be88 | Ilias Tsitsimpis | ret = ping.wait() |
288 | d246be88 | Ilias Tsitsimpis | if ret != 0: |
289 | d246be88 | Ilias Tsitsimpis | raise Retry
|
290 | cee3ee9b | Ilias Tsitsimpis | assert version in (4, 6) |
291 | d246be88 | Ilias Tsitsimpis | opmsg = "Sent IPv%s ping requests to %s"
|
292 | d246be88 | Ilias Tsitsimpis | self.info(opmsg, version, ip_addr)
|
293 | d246be88 | Ilias Tsitsimpis | opmsg = opmsg % (version, ip_addr) |
294 | d246be88 | Ilias Tsitsimpis | self._try_until_timeout_expires(opmsg, check_fun)
|
295 | d246be88 | Ilias Tsitsimpis | |
296 | cee3ee9b | Ilias Tsitsimpis | def _image_is(self, image, osfamily): |
297 | cee3ee9b | Ilias Tsitsimpis | """Return true if the image is of `osfamily'"""
|
298 | cee3ee9b | Ilias Tsitsimpis | d_image = self.clients.cyclades.get_image_details(image['id']) |
299 | cee3ee9b | Ilias Tsitsimpis | return d_image['metadata']['osfamily'].lower().find(osfamily) >= 0 |
300 | cee3ee9b | Ilias Tsitsimpis | |
301 | cee3ee9b | Ilias Tsitsimpis | def _ssh_execute(self, hostip, username, password, command): |
302 | cee3ee9b | Ilias Tsitsimpis | """Execute a command via ssh"""
|
303 | cee3ee9b | Ilias Tsitsimpis | ssh = paramiko.SSHClient() |
304 | cee3ee9b | Ilias Tsitsimpis | ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) |
305 | cee3ee9b | Ilias Tsitsimpis | try:
|
306 | cee3ee9b | Ilias Tsitsimpis | ssh.connect(hostip, username=username, password=password) |
307 | cee3ee9b | Ilias Tsitsimpis | except socket.error as err: |
308 | cee3ee9b | Ilias Tsitsimpis | self.fail(err)
|
309 | cee3ee9b | Ilias Tsitsimpis | try:
|
310 | cee3ee9b | Ilias Tsitsimpis | _, stdout, _ = ssh.exec_command(command) |
311 | cee3ee9b | Ilias Tsitsimpis | except paramiko.SSHException as err: |
312 | cee3ee9b | Ilias Tsitsimpis | self.fail(err)
|
313 | cee3ee9b | Ilias Tsitsimpis | status = stdout.channel.recv_exit_status() |
314 | cee3ee9b | Ilias Tsitsimpis | output = stdout.readlines() |
315 | cee3ee9b | Ilias Tsitsimpis | ssh.close() |
316 | cee3ee9b | Ilias Tsitsimpis | return output, status
|
317 | cee3ee9b | Ilias Tsitsimpis | |
318 | cee3ee9b | Ilias Tsitsimpis | def _insist_get_hostname_over_ssh(self, hostip, username, password): |
319 | cee3ee9b | Ilias Tsitsimpis | """Connect to server using ssh and get it's hostname"""
|
320 | cee3ee9b | Ilias Tsitsimpis | def check_fun(): |
321 | cee3ee9b | Ilias Tsitsimpis | """Get hostname"""
|
322 | cee3ee9b | Ilias Tsitsimpis | try:
|
323 | cee3ee9b | Ilias Tsitsimpis | lines, status = self._ssh_execute(
|
324 | cee3ee9b | Ilias Tsitsimpis | hostip, username, password, "hostname")
|
325 | cee3ee9b | Ilias Tsitsimpis | self.assertEqual(status, 0) |
326 | cee3ee9b | Ilias Tsitsimpis | self.assertEqual(len(lines), 1) |
327 | cee3ee9b | Ilias Tsitsimpis | # Remove new line
|
328 | cee3ee9b | Ilias Tsitsimpis | return lines[0].strip('\n') |
329 | cee3ee9b | Ilias Tsitsimpis | except AssertionError: |
330 | cee3ee9b | Ilias Tsitsimpis | raise Retry()
|
331 | cee3ee9b | Ilias Tsitsimpis | opmsg = "Connecting to server using ssh and get it's hostname"
|
332 | cee3ee9b | Ilias Tsitsimpis | self.info(opmsg)
|
333 | cee3ee9b | Ilias Tsitsimpis | hostname = self._try_until_timeout_expires(opmsg, check_fun)
|
334 | cee3ee9b | Ilias Tsitsimpis | self.info("Server's hostname is %s", hostname) |
335 | cee3ee9b | Ilias Tsitsimpis | return hostname
|
336 | cee3ee9b | Ilias Tsitsimpis | |
337 | cee3ee9b | Ilias Tsitsimpis | # Too many arguments. pylint: disable-msg=R0913
|
338 | cee3ee9b | Ilias Tsitsimpis | def _check_file_through_ssh(self, hostip, username, password, |
339 | cee3ee9b | Ilias Tsitsimpis | remotepath, content): |
340 | cee3ee9b | Ilias Tsitsimpis | """Fetch file from server and compare contents"""
|
341 | cee3ee9b | Ilias Tsitsimpis | self.info("Fetching file %s from remote server", remotepath) |
342 | cee3ee9b | Ilias Tsitsimpis | transport = paramiko.Transport((hostip, 22))
|
343 | cee3ee9b | Ilias Tsitsimpis | transport.connect(username=username, password=password) |
344 | cee3ee9b | Ilias Tsitsimpis | with tempfile.NamedTemporaryFile() as ftmp: |
345 | cee3ee9b | Ilias Tsitsimpis | sftp = paramiko.SFTPClient.from_transport(transport) |
346 | cee3ee9b | Ilias Tsitsimpis | sftp.get(remotepath, ftmp.name) |
347 | cee3ee9b | Ilias Tsitsimpis | sftp.close() |
348 | cee3ee9b | Ilias Tsitsimpis | transport.close() |
349 | cee3ee9b | Ilias Tsitsimpis | self.info("Comparing file contents") |
350 | cee3ee9b | Ilias Tsitsimpis | remote_content = base64.b64encode(ftmp.read()) |
351 | cee3ee9b | Ilias Tsitsimpis | self.assertEqual(content, remote_content)
|
352 | cee3ee9b | Ilias Tsitsimpis | |
353 | 3eaf0ec5 | Ilias Tsitsimpis | def _disconnect_from_network(self, server, network): |
354 | 3eaf0ec5 | Ilias Tsitsimpis | """Disconnect server from network"""
|
355 | 3eaf0ec5 | Ilias Tsitsimpis | nid = None
|
356 | 3eaf0ec5 | Ilias Tsitsimpis | for nic in server['attachments']: |
357 | 3eaf0ec5 | Ilias Tsitsimpis | if nic['network_id'] == network['id']: |
358 | 3eaf0ec5 | Ilias Tsitsimpis | nid = nic['id']
|
359 | 3eaf0ec5 | Ilias Tsitsimpis | break
|
360 | 3eaf0ec5 | Ilias Tsitsimpis | self.assertIsNotNone(nid, "Could not find network card") |
361 | 3eaf0ec5 | Ilias Tsitsimpis | self.clients.cyclades.disconnect_server(server['id'], nid) |
362 | 3eaf0ec5 | Ilias Tsitsimpis | |
363 | d246be88 | Ilias Tsitsimpis | |
364 | d246be88 | Ilias Tsitsimpis | class Retry(Exception): |
365 | d246be88 | Ilias Tsitsimpis | """Retry the action
|
366 | d246be88 | Ilias Tsitsimpis |
|
367 | d246be88 | Ilias Tsitsimpis | This is used by _try_unit_timeout_expires method.
|
368 | d246be88 | Ilias Tsitsimpis |
|
369 | d246be88 | Ilias Tsitsimpis | """ |