Statistics
| Branch: | Tag: | Revision:

root / snf-tools / synnefo_tools / burnin.py @ c0448f4f

History | View | Annotate | Download (61.8 kB)

1 65462ca9 John Giannelos
#!/usr/bin/env python
2 5a140b23 Vangelis Koukis
3 5a140b23 Vangelis Koukis
# Copyright 2011 GRNET S.A. All rights reserved.
4 5a140b23 Vangelis Koukis
#
5 5a140b23 Vangelis Koukis
# Redistribution and use in source and binary forms, with or
6 5a140b23 Vangelis Koukis
# without modification, are permitted provided that the following
7 5a140b23 Vangelis Koukis
# conditions are met:
8 5a140b23 Vangelis Koukis
#
9 5a140b23 Vangelis Koukis
#   1. Redistributions of source code must retain the above
10 5a140b23 Vangelis Koukis
#      copyright notice, this list of conditions and the following
11 5a140b23 Vangelis Koukis
#      disclaimer.
12 5a140b23 Vangelis Koukis
#
13 5a140b23 Vangelis Koukis
#   2. Redistributions in binary form must reproduce the above
14 5a140b23 Vangelis Koukis
#      copyright notice, this list of conditions and the following
15 5a140b23 Vangelis Koukis
#      disclaimer in the documentation and/or other materials
16 5a140b23 Vangelis Koukis
#      provided with the distribution.
17 5a140b23 Vangelis Koukis
#
18 5a140b23 Vangelis Koukis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 5a140b23 Vangelis Koukis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 5a140b23 Vangelis Koukis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 5a140b23 Vangelis Koukis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 5a140b23 Vangelis Koukis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 5a140b23 Vangelis Koukis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 5a140b23 Vangelis Koukis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 5a140b23 Vangelis Koukis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 5a140b23 Vangelis Koukis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 5a140b23 Vangelis Koukis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 5a140b23 Vangelis Koukis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 5a140b23 Vangelis Koukis
# POSSIBILITY OF SUCH DAMAGE.
30 5a140b23 Vangelis Koukis
#
31 5a140b23 Vangelis Koukis
# The views and conclusions contained in the software and
32 5a140b23 Vangelis Koukis
# documentation are those of the authors and should not be
33 5a140b23 Vangelis Koukis
# interpreted as representing official policies, either expressed
34 5a140b23 Vangelis Koukis
# or implied, of GRNET S.A.
35 5a140b23 Vangelis Koukis
36 5a140b23 Vangelis Koukis
"""Perform integration testing on a running Synnefo deployment"""
37 5a140b23 Vangelis Koukis
38 21bbbc9b Vangelis Koukis
import __main__
39 5a140b23 Vangelis Koukis
import datetime
40 5a140b23 Vangelis Koukis
import inspect
41 5a140b23 Vangelis Koukis
import logging
42 5a140b23 Vangelis Koukis
import os
43 5a140b23 Vangelis Koukis
import paramiko
44 21bbbc9b Vangelis Koukis
import prctl
45 5a140b23 Vangelis Koukis
import subprocess
46 21bbbc9b Vangelis Koukis
import signal
47 5a140b23 Vangelis Koukis
import socket
48 5a140b23 Vangelis Koukis
import sys
49 5a140b23 Vangelis Koukis
import time
50 9659e075 John Giannelos
from base64 import b64encode
51 5a140b23 Vangelis Koukis
from IPy import IP
52 21bbbc9b Vangelis Koukis
from multiprocessing import Process, Queue
53 bc14ba88 Vangelis Koukis
from random import choice
54 22efe1fe John Giannelos
from optparse import OptionParser, OptionValueError
55 21bbbc9b Vangelis Koukis
56 96da37c8 John Giannelos
from kamaki.clients.compute import ComputeClient
57 96da37c8 John Giannelos
from kamaki.clients.cyclades import CycladesClient
58 946da8b6 John Giannelos
from kamaki.clients.image import ImageClient
59 21dcb666 John Giannelos
from kamaki.clients import ClientError
60 96da37c8 John Giannelos
61 88736f65 John Giannelos
from fabric.api import *
62 1c636ad6 John Giannelos
63 bc14ba88 Vangelis Koukis
from vncauthproxy.d3des import generate_response as d3des_generate_response
64 5a140b23 Vangelis Koukis
65 5a140b23 Vangelis Koukis
# Use backported unittest functionality if Python < 2.7
66 5a140b23 Vangelis Koukis
try:
67 5a140b23 Vangelis Koukis
    import unittest2 as unittest
68 5a140b23 Vangelis Koukis
except ImportError:
69 bc14ba88 Vangelis Koukis
    if sys.version_info < (2, 7):
70 bc14ba88 Vangelis Koukis
        raise Exception("The unittest2 package is required for Python < 2.7")
71 5a140b23 Vangelis Koukis
    import unittest
72 5a140b23 Vangelis Koukis
73 5a140b23 Vangelis Koukis
74 21bbbc9b Vangelis Koukis
API = None
75 21bbbc9b Vangelis Koukis
TOKEN = None
76 567ffb85 John Giannelos
DEFAULT_API = "https://cyclades.okeanos.grnet.gr/api/v1.1"
77 946da8b6 John Giannelos
DEFAULT_PLANKTON = "https://cyclades.okeanos.grnet.gr/plankton"
78 946da8b6 John Giannelos
DEFAULT_PLANKTON_USER = "images@okeanos.grnet.gr"
79 38d247df Kostas Papadimitriou
80 5a140b23 Vangelis Koukis
# A unique id identifying this test run
81 21bbbc9b Vangelis Koukis
TEST_RUN_ID = datetime.datetime.strftime(datetime.datetime.now(),
82 21bbbc9b Vangelis Koukis
                                         "%Y%m%d%H%M%S")
83 21bbbc9b Vangelis Koukis
SNF_TEST_PREFIX = "snf-test-"
84 5a140b23 Vangelis Koukis
85 746540cd John Giannelos
red = '\x1b[31m'
86 746540cd John Giannelos
yellow = '\x1b[33m'
87 746540cd John Giannelos
green = '\x1b[32m'
88 746540cd John Giannelos
normal = '\x1b[0m'
89 746540cd John Giannelos
90 746540cd John Giannelos
91 746540cd John Giannelos
class burninFormatter(logging.Formatter):
92 746540cd John Giannelos
93 746540cd John Giannelos
    err_fmt = red + "ERROR: %(msg)s" + normal
94 9b013c3a John Giannelos
    dbg_fmt = green + "* %(msg)s" + normal
95 746540cd John Giannelos
    info_fmt = "%(msg)s"
96 746540cd John Giannelos
97 746540cd John Giannelos
    def __init__(self, fmt="%(levelno)s: %(msg)s"):
98 746540cd John Giannelos
        logging.Formatter.__init__(self, fmt)
99 746540cd John Giannelos
100 746540cd John Giannelos
    def format(self, record):
101 746540cd John Giannelos
102 746540cd John Giannelos
        format_orig = self._fmt
103 746540cd John Giannelos
104 746540cd John Giannelos
        # Replace the original format with one customized by logging level
105 746540cd John Giannelos
        if record.levelno == 10:    # DEBUG
106 746540cd John Giannelos
            self._fmt = burninFormatter.dbg_fmt
107 746540cd John Giannelos
108 746540cd John Giannelos
        elif record.levelno == 20:  # INFO
109 746540cd John Giannelos
            self._fmt = burninFormatter.info_fmt
110 746540cd John Giannelos
111 746540cd John Giannelos
        elif record.levelno == 40:  # ERROR
112 746540cd John Giannelos
            self._fmt = burninFormatter.err_fmt
113 746540cd John Giannelos
114 746540cd John Giannelos
        result = logging.Formatter.format(self, record)
115 746540cd John Giannelos
        self._fmt = format_orig
116 746540cd John Giannelos
117 746540cd John Giannelos
        return result
118 746540cd John Giannelos
119 746540cd John Giannelos
120 00f87624 Vangelis Koukis
log = logging.getLogger("burnin")
121 746540cd John Giannelos
log.setLevel(logging.DEBUG)
122 746540cd John Giannelos
handler = logging.StreamHandler()
123 746540cd John Giannelos
handler.setFormatter(burninFormatter())
124 746540cd John Giannelos
log.addHandler(handler)
125 5a140b23 Vangelis Koukis
126 2bcfb712 John Giannelos
127 5a140b23 Vangelis Koukis
class UnauthorizedTestCase(unittest.TestCase):
128 5a140b23 Vangelis Koukis
    def test_unauthorized_access(self):
129 5a140b23 Vangelis Koukis
        """Test access without a valid token fails"""
130 81e8cbf6 John Giannelos
        log.info("Authentication test")
131 81e8cbf6 John Giannelos
132 1c636ad6 John Giannelos
        falseToken = '12345'
133 2bcfb712 John Giannelos
        c = ComputeClient(API, falseToken)
134 1c636ad6 John Giannelos
135 5a140b23 Vangelis Koukis
        with self.assertRaises(ClientError) as cm:
136 5a140b23 Vangelis Koukis
            c.list_servers()
137 21dcb666 John Giannelos
            self.assertEqual(cm.exception.status, 401)
138 5a140b23 Vangelis Koukis
139 5a140b23 Vangelis Koukis
140 5a140b23 Vangelis Koukis
class ImagesTestCase(unittest.TestCase):
141 5a140b23 Vangelis Koukis
    """Test image lists for consistency"""
142 5a140b23 Vangelis Koukis
    @classmethod
143 5a140b23 Vangelis Koukis
    def setUpClass(cls):
144 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of images"""
145 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of images")
146 1c636ad6 John Giannelos
147 846980fe John Giannelos
        cls.client = ComputeClient(API, TOKEN)
148 946da8b6 John Giannelos
        cls.plankton = ImageClient(PLANKTON, TOKEN)
149 946da8b6 John Giannelos
        cls.images = cls.plankton.list_public()
150 946da8b6 John Giannelos
        cls.dimages = cls.plankton.list_public(detail=True)
151 5a140b23 Vangelis Koukis
152 5a140b23 Vangelis Koukis
    def test_001_list_images(self):
153 5a140b23 Vangelis Koukis
        """Test image list actually returns images"""
154 6207533f John Giannelos
        self.assertGreater(len(self.images), 0)
155 74ec726f John Giannelos
156 5a140b23 Vangelis Koukis
    def test_002_list_images_detailed(self):
157 5a140b23 Vangelis Koukis
        """Test detailed image list is the same length as list"""
158 6207533f John Giannelos
        self.assertEqual(len(self.dimages), len(self.images))
159 74ec726f John Giannelos
160 5a140b23 Vangelis Koukis
    def test_003_same_image_names(self):
161 5a140b23 Vangelis Koukis
        """Test detailed and simple image list contain same names"""
162 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.images))
163 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dimages))
164 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
165 5a140b23 Vangelis Koukis
166 5a140b23 Vangelis Koukis
    def test_004_unique_image_names(self):
167 946da8b6 John Giannelos
        """Test system images have unique names"""
168 946da8b6 John Giannelos
        sys_images = filter(lambda x: x['owner'] == PLANKTON_USER,
169 946da8b6 John Giannelos
                            self.dimages)
170 946da8b6 John Giannelos
        names = sorted(map(lambda x: x["name"], sys_images))
171 5a140b23 Vangelis Koukis
        self.assertEqual(sorted(list(set(names))), names)
172 5a140b23 Vangelis Koukis
173 5a140b23 Vangelis Koukis
    def test_005_image_metadata(self):
174 5a140b23 Vangelis Koukis
        """Test every image has specific metadata defined"""
175 2e3b7dc8 John Giannelos
        keys = frozenset(["osfamily", "root_partition"])
176 846980fe John Giannelos
        details = self.client.list_images(detail=True)
177 846980fe John Giannelos
        for i in details:
178 5a140b23 Vangelis Koukis
            self.assertTrue(keys.issubset(i["metadata"]["values"].keys()))
179 5a140b23 Vangelis Koukis
180 5a140b23 Vangelis Koukis
181 5a140b23 Vangelis Koukis
class FlavorsTestCase(unittest.TestCase):
182 5a140b23 Vangelis Koukis
    """Test flavor lists for consistency"""
183 5a140b23 Vangelis Koukis
    @classmethod
184 5a140b23 Vangelis Koukis
    def setUpClass(cls):
185 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of flavors"""
186 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of flavors")
187 1c636ad6 John Giannelos
188 567ffb85 John Giannelos
        cls.client = ComputeClient(API, TOKEN)
189 5a140b23 Vangelis Koukis
        cls.flavors = cls.client.list_flavors()
190 5a140b23 Vangelis Koukis
        cls.dflavors = cls.client.list_flavors(detail=True)
191 5a140b23 Vangelis Koukis
192 5a140b23 Vangelis Koukis
    def test_001_list_flavors(self):
193 5a140b23 Vangelis Koukis
        """Test flavor list actually returns flavors"""
194 5a140b23 Vangelis Koukis
        self.assertGreater(len(self.flavors), 0)
195 5a140b23 Vangelis Koukis
196 5a140b23 Vangelis Koukis
    def test_002_list_flavors_detailed(self):
197 5a140b23 Vangelis Koukis
        """Test detailed flavor list is the same length as list"""
198 5a140b23 Vangelis Koukis
        self.assertEquals(len(self.dflavors), len(self.flavors))
199 5a140b23 Vangelis Koukis
200 5a140b23 Vangelis Koukis
    def test_003_same_flavor_names(self):
201 5a140b23 Vangelis Koukis
        """Test detailed and simple flavor list contain same names"""
202 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.flavors))
203 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dflavors))
204 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
205 5a140b23 Vangelis Koukis
206 5a140b23 Vangelis Koukis
    def test_004_unique_flavor_names(self):
207 5a140b23 Vangelis Koukis
        """Test flavors have unique names"""
208 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.flavors))
209 5a140b23 Vangelis Koukis
        self.assertEqual(sorted(list(set(names))), names)
210 5a140b23 Vangelis Koukis
211 5a140b23 Vangelis Koukis
    def test_005_well_formed_flavor_names(self):
212 5a140b23 Vangelis Koukis
        """Test flavors have names of the form CxxRyyDzz
213 5a140b23 Vangelis Koukis

214 5a140b23 Vangelis Koukis
        Where xx is vCPU count, yy is RAM in MiB, zz is Disk in GiB
215 5a140b23 Vangelis Koukis

216 5a140b23 Vangelis Koukis
        """
217 5a140b23 Vangelis Koukis
        for f in self.dflavors:
218 5a140b23 Vangelis Koukis
            self.assertEqual("C%dR%dD%d" % (f["cpu"], f["ram"], f["disk"]),
219 5a140b23 Vangelis Koukis
                             f["name"],
220 5a140b23 Vangelis Koukis
                             "Flavor %s does not match its specs." % f["name"])
221 5a140b23 Vangelis Koukis
222 5a140b23 Vangelis Koukis
223 5a140b23 Vangelis Koukis
class ServersTestCase(unittest.TestCase):
224 5a140b23 Vangelis Koukis
    """Test server lists for consistency"""
225 5a140b23 Vangelis Koukis
    @classmethod
226 5a140b23 Vangelis Koukis
    def setUpClass(cls):
227 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of servers"""
228 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of servers")
229 1c636ad6 John Giannelos
230 567ffb85 John Giannelos
        cls.client = ComputeClient(API, TOKEN)
231 5a140b23 Vangelis Koukis
        cls.servers = cls.client.list_servers()
232 5a140b23 Vangelis Koukis
        cls.dservers = cls.client.list_servers(detail=True)
233 5a140b23 Vangelis Koukis
234 74ec726f John Giannelos
    # def test_001_list_servers(self):
235 74ec726f John Giannelos
    #     """Test server list actually returns servers"""
236 74ec726f John Giannelos
    #     self.assertGreater(len(self.servers), 0)
237 5a140b23 Vangelis Koukis
238 5a140b23 Vangelis Koukis
    def test_002_list_servers_detailed(self):
239 5a140b23 Vangelis Koukis
        """Test detailed server list is the same length as list"""
240 5a140b23 Vangelis Koukis
        self.assertEqual(len(self.dservers), len(self.servers))
241 5a140b23 Vangelis Koukis
242 5a140b23 Vangelis Koukis
    def test_003_same_server_names(self):
243 5a140b23 Vangelis Koukis
        """Test detailed and simple flavor list contain same names"""
244 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.servers))
245 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dservers))
246 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
247 5a140b23 Vangelis Koukis
248 5a140b23 Vangelis Koukis
249 5a140b23 Vangelis Koukis
# This class gets replicated into actual TestCases dynamically
250 5a140b23 Vangelis Koukis
class SpawnServerTestCase(unittest.TestCase):
251 5a140b23 Vangelis Koukis
    """Test scenario for server of the specified image"""
252 5a140b23 Vangelis Koukis
253 5a140b23 Vangelis Koukis
    @classmethod
254 5a140b23 Vangelis Koukis
    def setUpClass(cls):
255 5a140b23 Vangelis Koukis
        """Initialize a kamaki instance"""
256 2e3b7dc8 John Giannelos
        log.info("Spawning server for image `%s'" %cls.imagename)
257 567ffb85 John Giannelos
        cls.client = ComputeClient(API, TOKEN)
258 567ffb85 John Giannelos
        cls.cyclades = CycladesClient(API, TOKEN)
259 5a140b23 Vangelis Koukis
260 5a140b23 Vangelis Koukis
    def _get_ipv4(self, server):
261 bc14ba88 Vangelis Koukis
        """Get the public IPv4 of a server from the detailed server info"""
262 1c636ad6 John Giannelos
263 5a140b23 Vangelis Koukis
        public_addrs = filter(lambda x: x["id"] == "public",
264 5a140b23 Vangelis Koukis
                              server["addresses"]["values"])
265 5a140b23 Vangelis Koukis
        self.assertEqual(len(public_addrs), 1)
266 5a140b23 Vangelis Koukis
        ipv4_addrs = filter(lambda x: x["version"] == 4,
267 5a140b23 Vangelis Koukis
                            public_addrs[0]["values"])
268 5a140b23 Vangelis Koukis
        self.assertEqual(len(ipv4_addrs), 1)
269 5a140b23 Vangelis Koukis
        return ipv4_addrs[0]["addr"]
270 5a140b23 Vangelis Koukis
271 5a140b23 Vangelis Koukis
    def _get_ipv6(self, server):
272 bc14ba88 Vangelis Koukis
        """Get the public IPv6 of a server from the detailed server info"""
273 5a140b23 Vangelis Koukis
        public_addrs = filter(lambda x: x["id"] == "public",
274 5a140b23 Vangelis Koukis
                              server["addresses"]["values"])
275 5a140b23 Vangelis Koukis
        self.assertEqual(len(public_addrs), 1)
276 5a140b23 Vangelis Koukis
        ipv6_addrs = filter(lambda x: x["version"] == 6,
277 5a140b23 Vangelis Koukis
                            public_addrs[0]["values"])
278 5a140b23 Vangelis Koukis
        self.assertEqual(len(ipv6_addrs), 1)
279 5a140b23 Vangelis Koukis
        return ipv6_addrs[0]["addr"]
280 5a140b23 Vangelis Koukis
281 bc14ba88 Vangelis Koukis
    def _connect_loginname(self, os):
282 bc14ba88 Vangelis Koukis
        """Return the login name for connections based on the server OS"""
283 1c636ad6 John Giannelos
        if os in ("Ubuntu", "Kubuntu", "Fedora"):
284 21bbbc9b Vangelis Koukis
            return "user"
285 1c636ad6 John Giannelos
        elif os in ("windows", "windows_alpha1"):
286 21bbbc9b Vangelis Koukis
            return "Administrator"
287 bc14ba88 Vangelis Koukis
        else:
288 21bbbc9b Vangelis Koukis
            return "root"
289 bc14ba88 Vangelis Koukis
290 bc14ba88 Vangelis Koukis
    def _verify_server_status(self, current_status, new_status):
291 bc14ba88 Vangelis Koukis
        """Verify a server has switched to a specified status"""
292 bc14ba88 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
293 21bbbc9b Vangelis Koukis
        if server["status"] not in (current_status, new_status):
294 21bbbc9b Vangelis Koukis
            return None  # Do not raise exception, return so the test fails
295 bc14ba88 Vangelis Koukis
        self.assertEquals(server["status"], new_status)
296 bc14ba88 Vangelis Koukis
297 bc14ba88 Vangelis Koukis
    def _get_connected_tcp_socket(self, family, host, port):
298 bc14ba88 Vangelis Koukis
        """Get a connected socket from the specified family to host:port"""
299 bc14ba88 Vangelis Koukis
        sock = None
300 bc14ba88 Vangelis Koukis
        for res in \
301 bc14ba88 Vangelis Koukis
            socket.getaddrinfo(host, port, family, socket.SOCK_STREAM, 0,
302 bc14ba88 Vangelis Koukis
                               socket.AI_PASSIVE):
303 bc14ba88 Vangelis Koukis
            af, socktype, proto, canonname, sa = res
304 bc14ba88 Vangelis Koukis
            try:
305 bc14ba88 Vangelis Koukis
                sock = socket.socket(af, socktype, proto)
306 bc14ba88 Vangelis Koukis
            except socket.error as msg:
307 bc14ba88 Vangelis Koukis
                sock = None
308 bc14ba88 Vangelis Koukis
                continue
309 bc14ba88 Vangelis Koukis
            try:
310 bc14ba88 Vangelis Koukis
                sock.connect(sa)
311 bc14ba88 Vangelis Koukis
            except socket.error as msg:
312 bc14ba88 Vangelis Koukis
                sock.close()
313 bc14ba88 Vangelis Koukis
                sock = None
314 bc14ba88 Vangelis Koukis
                continue
315 bc14ba88 Vangelis Koukis
        self.assertIsNotNone(sock)
316 bc14ba88 Vangelis Koukis
        return sock
317 bc14ba88 Vangelis Koukis
318 bc14ba88 Vangelis Koukis
    def _ping_once(self, ipv6, ip):
319 bc14ba88 Vangelis Koukis
        """Test server responds to a single IPv4 or IPv6 ping"""
320 bc14ba88 Vangelis Koukis
        cmd = "ping%s -c 2 -w 3 %s" % ("6" if ipv6 else "", ip)
321 bc14ba88 Vangelis Koukis
        ping = subprocess.Popen(cmd, shell=True,
322 bc14ba88 Vangelis Koukis
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
323 bc14ba88 Vangelis Koukis
        (stdout, stderr) = ping.communicate()
324 bc14ba88 Vangelis Koukis
        ret = ping.wait()
325 bc14ba88 Vangelis Koukis
        self.assertEquals(ret, 0)
326 5a140b23 Vangelis Koukis
327 bc14ba88 Vangelis Koukis
    def _get_hostname_over_ssh(self, hostip, username, password):
328 bc14ba88 Vangelis Koukis
        ssh = paramiko.SSHClient()
329 bc14ba88 Vangelis Koukis
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
330 bc14ba88 Vangelis Koukis
        try:
331 bc14ba88 Vangelis Koukis
            ssh.connect(hostip, username=username, password=password)
332 bc14ba88 Vangelis Koukis
        except socket.error:
333 bc14ba88 Vangelis Koukis
            raise AssertionError
334 bc14ba88 Vangelis Koukis
        stdin, stdout, stderr = ssh.exec_command("hostname")
335 bc14ba88 Vangelis Koukis
        lines = stdout.readlines()
336 bc14ba88 Vangelis Koukis
        self.assertEqual(len(lines), 1)
337 4fdd25ab Vangelis Koukis
        return lines[0]
338 bc14ba88 Vangelis Koukis
339 bc14ba88 Vangelis Koukis
    def _try_until_timeout_expires(self, warn_timeout, fail_timeout,
340 bc14ba88 Vangelis Koukis
                                   opmsg, callable, *args, **kwargs):
341 bc14ba88 Vangelis Koukis
        if warn_timeout == fail_timeout:
342 5a140b23 Vangelis Koukis
            warn_timeout = fail_timeout + 1
343 5a140b23 Vangelis Koukis
        warn_tmout = time.time() + warn_timeout
344 5a140b23 Vangelis Koukis
        fail_tmout = time.time() + fail_timeout
345 5a140b23 Vangelis Koukis
        while True:
346 4fdd25ab Vangelis Koukis
            self.assertLess(time.time(), fail_tmout,
347 21bbbc9b Vangelis Koukis
                            "operation `%s' timed out" % opmsg)
348 5a140b23 Vangelis Koukis
            if time.time() > warn_tmout:
349 4fdd25ab Vangelis Koukis
                log.warning("Server %d: `%s' operation `%s' not done yet",
350 4fdd25ab Vangelis Koukis
                            self.serverid, self.servername, opmsg)
351 bc14ba88 Vangelis Koukis
            try:
352 4fdd25ab Vangelis Koukis
                log.info("%s... " % opmsg)
353 bc14ba88 Vangelis Koukis
                return callable(*args, **kwargs)
354 bc14ba88 Vangelis Koukis
            except AssertionError:
355 bc14ba88 Vangelis Koukis
                pass
356 5a140b23 Vangelis Koukis
            time.sleep(self.query_interval)
357 5a140b23 Vangelis Koukis
358 bc14ba88 Vangelis Koukis
    def _insist_on_tcp_connection(self, family, host, port):
359 21bbbc9b Vangelis Koukis
        familystr = {socket.AF_INET: "IPv4", socket.AF_INET6: "IPv6",
360 21bbbc9b Vangelis Koukis
                     socket.AF_UNSPEC: "Unspecified-IPv4/6"}
361 bc14ba88 Vangelis Koukis
        msg = "connect over %s to %s:%s" % \
362 bc14ba88 Vangelis Koukis
              (familystr.get(family, "Unknown"), host, port)
363 bc14ba88 Vangelis Koukis
        sock = self._try_until_timeout_expires(
364 bc14ba88 Vangelis Koukis
                self.action_timeout, self.action_timeout,
365 bc14ba88 Vangelis Koukis
                msg, self._get_connected_tcp_socket,
366 bc14ba88 Vangelis Koukis
                family, host, port)
367 bc14ba88 Vangelis Koukis
        return sock
368 bc14ba88 Vangelis Koukis
369 bc14ba88 Vangelis Koukis
    def _insist_on_status_transition(self, current_status, new_status,
370 bc14ba88 Vangelis Koukis
                                    fail_timeout, warn_timeout=None):
371 4fdd25ab Vangelis Koukis
        msg = "Server %d: `%s', waiting for %s -> %s" % \
372 4fdd25ab Vangelis Koukis
              (self.serverid, self.servername, current_status, new_status)
373 bc14ba88 Vangelis Koukis
        if warn_timeout is None:
374 bc14ba88 Vangelis Koukis
            warn_timeout = fail_timeout
375 bc14ba88 Vangelis Koukis
        self._try_until_timeout_expires(warn_timeout, fail_timeout,
376 bc14ba88 Vangelis Koukis
                                        msg, self._verify_server_status,
377 bc14ba88 Vangelis Koukis
                                        current_status, new_status)
378 21bbbc9b Vangelis Koukis
        # Ensure the status is actually the expected one
379 21bbbc9b Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
380 21bbbc9b Vangelis Koukis
        self.assertEquals(server["status"], new_status)
381 bc14ba88 Vangelis Koukis
382 bc14ba88 Vangelis Koukis
    def _insist_on_ssh_hostname(self, hostip, username, password):
383 4fdd25ab Vangelis Koukis
        msg = "SSH to %s, as %s/%s" % (hostip, username, password)
384 bc14ba88 Vangelis Koukis
        hostname = self._try_until_timeout_expires(
385 bc14ba88 Vangelis Koukis
                self.action_timeout, self.action_timeout,
386 bc14ba88 Vangelis Koukis
                msg, self._get_hostname_over_ssh,
387 bc14ba88 Vangelis Koukis
                hostip, username, password)
388 bc14ba88 Vangelis Koukis
389 bc14ba88 Vangelis Koukis
        # The hostname must be of the form 'prefix-id'
390 bc14ba88 Vangelis Koukis
        self.assertTrue(hostname.endswith("-%d\n" % self.serverid))
391 5a140b23 Vangelis Koukis
392 8252d64f John Giannelos
    def _check_file_through_ssh(self, hostip, username, password,
393 8252d64f John Giannelos
                                remotepath, content):
394 8252d64f John Giannelos
        msg = "Trying file injection through SSH to %s, as %s/%s" % \
395 8252d64f John Giannelos
            (hostip, username, password)
396 f97dce4d John Giannelos
        log.info(msg)
397 77054bf5 John Giannelos
        try:
398 77054bf5 John Giannelos
            ssh = paramiko.SSHClient()
399 77054bf5 John Giannelos
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
400 77054bf5 John Giannelos
            ssh.connect(hostip, username=username, password=password)
401 77054bf5 John Giannelos
        except socket.error:
402 77054bf5 John Giannelos
            raise AssertionError
403 9659e075 John Giannelos
404 2bcfb712 John Giannelos
        transport = paramiko.Transport((hostip, 22))
405 2bcfb712 John Giannelos
        transport.connect(username=username, password=password)
406 2bcfb712 John Giannelos
407 2bcfb712 John Giannelos
        localpath = '/tmp/' + SNF_TEST_PREFIX + 'injection'
408 77054bf5 John Giannelos
        sftp = paramiko.SFTPClient.from_transport(transport)
409 8252d64f John Giannelos
        sftp.get(remotepath, localpath)
410 77054bf5 John Giannelos
        sftp.close()
411 77054bf5 John Giannelos
        transport.close()
412 77054bf5 John Giannelos
413 9659e075 John Giannelos
        f = open(localpath)
414 9659e075 John Giannelos
        remote_content = b64encode(f.read())
415 9659e075 John Giannelos
416 77054bf5 John Giannelos
        # Check if files are the same
417 65462ca9 John Giannelos
        return (remote_content == content)
418 77054bf5 John Giannelos
419 5a140b23 Vangelis Koukis
    def _skipIf(self, condition, msg):
420 5a140b23 Vangelis Koukis
        if condition:
421 5a140b23 Vangelis Koukis
            self.skipTest(msg)
422 5a140b23 Vangelis Koukis
423 5a140b23 Vangelis Koukis
    def test_001_submit_create_server(self):
424 5a140b23 Vangelis Koukis
        """Test submit create server request"""
425 f89d0238 John Giannelos
426 f89d0238 John Giannelos
        log.info("Submit new server request")
427 5a140b23 Vangelis Koukis
        server = self.client.create_server(self.servername, self.flavorid,
428 5a140b23 Vangelis Koukis
                                           self.imageid, self.personality)
429 9659e075 John Giannelos
430 81e8cbf6 John Giannelos
        log.info("Server id: " + str(server["id"]))
431 81e8cbf6 John Giannelos
        log.info("Server password: " + server["adminPass"])
432 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
433 5a140b23 Vangelis Koukis
        self.assertEqual(server["flavorRef"], self.flavorid)
434 5a140b23 Vangelis Koukis
        self.assertEqual(server["imageRef"], self.imageid)
435 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
436 5a140b23 Vangelis Koukis
437 5a140b23 Vangelis Koukis
        # Update class attributes to reflect data on building server
438 5a140b23 Vangelis Koukis
        cls = type(self)
439 5a140b23 Vangelis Koukis
        cls.serverid = server["id"]
440 bc14ba88 Vangelis Koukis
        cls.username = None
441 5a140b23 Vangelis Koukis
        cls.passwd = server["adminPass"]
442 5a140b23 Vangelis Koukis
443 5a140b23 Vangelis Koukis
    def test_002a_server_is_building_in_list(self):
444 5a140b23 Vangelis Koukis
        """Test server is in BUILD state, in server list"""
445 f89d0238 John Giannelos
        log.info("Server in BUILD state in server list")
446 f89d0238 John Giannelos
447 5a140b23 Vangelis Koukis
        servers = self.client.list_servers(detail=True)
448 5a140b23 Vangelis Koukis
        servers = filter(lambda x: x["name"] == self.servername, servers)
449 5a140b23 Vangelis Koukis
        self.assertEqual(len(servers), 1)
450 5a140b23 Vangelis Koukis
        server = servers[0]
451 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
452 5a140b23 Vangelis Koukis
        self.assertEqual(server["flavorRef"], self.flavorid)
453 5a140b23 Vangelis Koukis
        self.assertEqual(server["imageRef"], self.imageid)
454 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
455 5a140b23 Vangelis Koukis
456 5a140b23 Vangelis Koukis
    def test_002b_server_is_building_in_details(self):
457 5a140b23 Vangelis Koukis
        """Test server is in BUILD state, in details"""
458 f89d0238 John Giannelos
459 f89d0238 John Giannelos
        log.info("Server in BUILD state in details")
460 f89d0238 John Giannelos
461 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
462 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
463 5a140b23 Vangelis Koukis
        self.assertEqual(server["flavorRef"], self.flavorid)
464 5a140b23 Vangelis Koukis
        self.assertEqual(server["imageRef"], self.imageid)
465 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
466 5a140b23 Vangelis Koukis
467 5a140b23 Vangelis Koukis
    def test_002c_set_server_metadata(self):
468 f89d0238 John Giannelos
469 f89d0238 John Giannelos
        log.info("Creating server metadata")
470 f89d0238 John Giannelos
471 5a140b23 Vangelis Koukis
        image = self.client.get_image_details(self.imageid)
472 74193008 John Giannelos
        os = image["metadata"]["values"]["os"]
473 e49bdb7c John Giannelos
        users = image["metadata"]["values"].get("users", None)
474 c1d11f96 John Giannelos
        self.client.update_server_metadata(self.serverid, OS=os)
475 746540cd John Giannelos
476 e49bdb7c John Giannelos
        userlist = users.split()
477 81e8cbf6 John Giannelos
478 bc14ba88 Vangelis Koukis
        # Determine the username to use for future connections
479 bc14ba88 Vangelis Koukis
        # to this host
480 bc14ba88 Vangelis Koukis
        cls = type(self)
481 81e8cbf6 John Giannelos
482 81e8cbf6 John Giannelos
        if "root" in userlist:
483 81e8cbf6 John Giannelos
            cls.username = "root"
484 81e8cbf6 John Giannelos
        elif users == None:
485 bc14ba88 Vangelis Koukis
            cls.username = self._connect_loginname(os)
486 81e8cbf6 John Giannelos
        else:
487 81e8cbf6 John Giannelos
            cls.username = choice(userlist)
488 81e8cbf6 John Giannelos
489 bc14ba88 Vangelis Koukis
        self.assertIsNotNone(cls.username)
490 5a140b23 Vangelis Koukis
491 5a140b23 Vangelis Koukis
    def test_002d_verify_server_metadata(self):
492 5a140b23 Vangelis Koukis
        """Test server metadata keys are set based on image metadata"""
493 f89d0238 John Giannelos
494 f89d0238 John Giannelos
        log.info("Verifying image metadata")
495 f89d0238 John Giannelos
496 5a140b23 Vangelis Koukis
        servermeta = self.client.get_server_metadata(self.serverid)
497 5a140b23 Vangelis Koukis
        imagemeta = self.client.get_image_metadata(self.imageid)
498 81e8cbf6 John Giannelos
499 99d41650 John Giannelos
        self.assertEqual(servermeta["OS"], imagemeta["os"])
500 5a140b23 Vangelis Koukis
501 5a140b23 Vangelis Koukis
    def test_003_server_becomes_active(self):
502 5a140b23 Vangelis Koukis
        """Test server becomes ACTIVE"""
503 f89d0238 John Giannelos
504 f89d0238 John Giannelos
        log.info("Waiting for server to become ACTIVE")
505 f89d0238 John Giannelos
506 bc14ba88 Vangelis Koukis
        self._insist_on_status_transition("BUILD", "ACTIVE",
507 5a140b23 Vangelis Koukis
                                         self.build_fail, self.build_warning)
508 5a140b23 Vangelis Koukis
509 65462ca9 John Giannelos
    def test_003a_get_server_oob_console(self):
510 65462ca9 John Giannelos
        """Test getting OOB server console over VNC
511 bc14ba88 Vangelis Koukis

512 65462ca9 John Giannelos
        Implementation of RFB protocol follows
513 65462ca9 John Giannelos
        http://www.realvnc.com/docs/rfbproto.pdf.
514 bc14ba88 Vangelis Koukis

515 65462ca9 John Giannelos
        """
516 65462ca9 John Giannelos
        console = self.cyclades.get_server_console(self.serverid)
517 65462ca9 John Giannelos
        self.assertEquals(console['type'], "vnc")
518 aa388d48 John Giannelos
        sock = self._insist_on_tcp_connection(socket.AF_INET,
519 65462ca9 John Giannelos
                                        console["host"], console["port"])
520 65462ca9 John Giannelos
521 65462ca9 John Giannelos
        # Step 1. ProtocolVersion message (par. 6.1.1)
522 65462ca9 John Giannelos
        version = sock.recv(1024)
523 65462ca9 John Giannelos
        self.assertEquals(version, 'RFB 003.008\n')
524 65462ca9 John Giannelos
        sock.send(version)
525 65462ca9 John Giannelos
526 65462ca9 John Giannelos
        # Step 2. Security (par 6.1.2): Only VNC Authentication supported
527 65462ca9 John Giannelos
        sec = sock.recv(1024)
528 65462ca9 John Giannelos
        self.assertEquals(list(sec), ['\x01', '\x02'])
529 65462ca9 John Giannelos
530 65462ca9 John Giannelos
        # Step 3. Request VNC Authentication (par 6.1.2)
531 65462ca9 John Giannelos
        sock.send('\x02')
532 65462ca9 John Giannelos
533 65462ca9 John Giannelos
        # Step 4. Receive Challenge (par 6.2.2)
534 65462ca9 John Giannelos
        challenge = sock.recv(1024)
535 65462ca9 John Giannelos
        self.assertEquals(len(challenge), 16)
536 65462ca9 John Giannelos
537 65462ca9 John Giannelos
        # Step 5. DES-Encrypt challenge, use password as key (par 6.2.2)
538 65462ca9 John Giannelos
        response = d3des_generate_response(
539 65462ca9 John Giannelos
            (console["password"] + '\0' * 8)[:8], challenge)
540 65462ca9 John Giannelos
        sock.send(response)
541 65462ca9 John Giannelos
542 65462ca9 John Giannelos
        # Step 6. SecurityResult (par 6.1.3)
543 65462ca9 John Giannelos
        result = sock.recv(4)
544 65462ca9 John Giannelos
        self.assertEquals(list(result), ['\x00', '\x00', '\x00', '\x00'])
545 65462ca9 John Giannelos
        sock.close()
546 8252d64f John Giannelos
547 5a140b23 Vangelis Koukis
    def test_004_server_has_ipv4(self):
548 5a140b23 Vangelis Koukis
        """Test active server has a valid IPv4 address"""
549 f89d0238 John Giannelos
550 81e8cbf6 John Giannelos
        log.info("Validate server's IPv4")
551 f89d0238 John Giannelos
552 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
553 5a140b23 Vangelis Koukis
        ipv4 = self._get_ipv4(server)
554 5a140b23 Vangelis Koukis
        self.assertEquals(IP(ipv4).version(), 4)
555 5a140b23 Vangelis Koukis
556 65462ca9 John Giannelos
    def test_005_server_has_ipv6(self):
557 65462ca9 John Giannelos
        """Test active server has a valid IPv6 address"""
558 946da8b6 John Giannelos
        self._skipIf(NO_IPV6, "--no-ipv6 flag enabled")
559 f89d0238 John Giannelos
560 81e8cbf6 John Giannelos
        log.info("Validate server's IPv6")
561 f89d0238 John Giannelos
562 65462ca9 John Giannelos
        server = self.client.get_server_details(self.serverid)
563 65462ca9 John Giannelos
        ipv6 = self._get_ipv6(server)
564 65462ca9 John Giannelos
        self.assertEquals(IP(ipv6).version(), 6)
565 5a140b23 Vangelis Koukis
566 5a140b23 Vangelis Koukis
    def test_006_server_responds_to_ping_IPv4(self):
567 5a140b23 Vangelis Koukis
        """Test server responds to ping on IPv4 address"""
568 f89d0238 John Giannelos
569 f89d0238 John Giannelos
        log.info("Testing if server responds to pings in IPv4")
570 f89d0238 John Giannelos
571 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
572 bc14ba88 Vangelis Koukis
        ip = self._get_ipv4(server)
573 bc14ba88 Vangelis Koukis
        self._try_until_timeout_expires(self.action_timeout,
574 bc14ba88 Vangelis Koukis
                                        self.action_timeout,
575 4fdd25ab Vangelis Koukis
                                        "PING IPv4 to %s" % ip,
576 4fdd25ab Vangelis Koukis
                                        self._ping_once,
577 bc14ba88 Vangelis Koukis
                                        False, ip)
578 5a140b23 Vangelis Koukis
579 65462ca9 John Giannelos
    def test_007_server_responds_to_ping_IPv6(self):
580 65462ca9 John Giannelos
        """Test server responds to ping on IPv6 address"""
581 946da8b6 John Giannelos
        self._skipIf(NO_IPV6, "--no-ipv6 flag enabled")
582 f89d0238 John Giannelos
        log.info("Testing if server responds to pings in IPv6")
583 f89d0238 John Giannelos
584 65462ca9 John Giannelos
        server = self.client.get_server_details(self.serverid)
585 65462ca9 John Giannelos
        ip = self._get_ipv6(server)
586 65462ca9 John Giannelos
        self._try_until_timeout_expires(self.action_timeout,
587 65462ca9 John Giannelos
                                        self.action_timeout,
588 65462ca9 John Giannelos
                                        "PING IPv6 to %s" % ip,
589 65462ca9 John Giannelos
                                        self._ping_once,
590 65462ca9 John Giannelos
                                        True, ip)
591 5a140b23 Vangelis Koukis
592 5a140b23 Vangelis Koukis
    def test_008_submit_shutdown_request(self):
593 5a140b23 Vangelis Koukis
        """Test submit request to shutdown server"""
594 f89d0238 John Giannelos
595 f89d0238 John Giannelos
        log.info("Shutting down server")
596 f89d0238 John Giannelos
597 74193008 John Giannelos
        self.cyclades.shutdown_server(self.serverid)
598 5a140b23 Vangelis Koukis
599 5a140b23 Vangelis Koukis
    def test_009_server_becomes_stopped(self):
600 5a140b23 Vangelis Koukis
        """Test server becomes STOPPED"""
601 f89d0238 John Giannelos
602 f89d0238 John Giannelos
        log.info("Waiting until server becomes STOPPED")
603 bc14ba88 Vangelis Koukis
        self._insist_on_status_transition("ACTIVE", "STOPPED",
604 bc14ba88 Vangelis Koukis
                                         self.action_timeout,
605 5a140b23 Vangelis Koukis
                                         self.action_timeout)
606 5a140b23 Vangelis Koukis
607 5a140b23 Vangelis Koukis
    def test_010_submit_start_request(self):
608 5a140b23 Vangelis Koukis
        """Test submit start server request"""
609 f89d0238 John Giannelos
610 f89d0238 John Giannelos
        log.info("Starting server")
611 f89d0238 John Giannelos
612 74193008 John Giannelos
        self.cyclades.start_server(self.serverid)
613 5a140b23 Vangelis Koukis
614 5a140b23 Vangelis Koukis
    def test_011_server_becomes_active(self):
615 5a140b23 Vangelis Koukis
        """Test server becomes ACTIVE again"""
616 f89d0238 John Giannelos
617 f89d0238 John Giannelos
        log.info("Waiting until server becomes ACTIVE")
618 bc14ba88 Vangelis Koukis
        self._insist_on_status_transition("STOPPED", "ACTIVE",
619 bc14ba88 Vangelis Koukis
                                         self.action_timeout,
620 5a140b23 Vangelis Koukis
                                         self.action_timeout)
621 5a140b23 Vangelis Koukis
622 5a140b23 Vangelis Koukis
    def test_011a_server_responds_to_ping_IPv4(self):
623 5a140b23 Vangelis Koukis
        """Test server OS is actually up and running again"""
624 f89d0238 John Giannelos
625 f89d0238 John Giannelos
        log.info("Testing if server is actually up and running")
626 f89d0238 John Giannelos
627 5a140b23 Vangelis Koukis
        self.test_006_server_responds_to_ping_IPv4()
628 5a140b23 Vangelis Koukis
629 5a140b23 Vangelis Koukis
    def test_012_ssh_to_server_IPv4(self):
630 5a140b23 Vangelis Koukis
        """Test SSH to server public IPv4 works, verify hostname"""
631 f89d0238 John Giannelos
632 bc14ba88 Vangelis Koukis
        self._skipIf(self.is_windows, "only valid for Linux servers")
633 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
634 bc14ba88 Vangelis Koukis
        self._insist_on_ssh_hostname(self._get_ipv4(server),
635 bc14ba88 Vangelis Koukis
                                     self.username, self.passwd)
636 5a140b23 Vangelis Koukis
637 65462ca9 John Giannelos
    def test_013_ssh_to_server_IPv6(self):
638 65462ca9 John Giannelos
        """Test SSH to server public IPv6 works, verify hostname"""
639 65462ca9 John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
640 946da8b6 John Giannelos
        self._skipIf(NO_IPV6, "--no-ipv6 flag enabled")
641 946da8b6 John Giannelos
642 65462ca9 John Giannelos
        server = self.client.get_server_details(self.serverid)
643 65462ca9 John Giannelos
        self._insist_on_ssh_hostname(self._get_ipv6(server),
644 65462ca9 John Giannelos
                                     self.username, self.passwd)
645 5a140b23 Vangelis Koukis
646 5a140b23 Vangelis Koukis
    def test_014_rdp_to_server_IPv4(self):
647 5a140b23 Vangelis Koukis
        "Test RDP connection to server public IPv4 works"""
648 bc14ba88 Vangelis Koukis
        self._skipIf(not self.is_windows, "only valid for Windows servers")
649 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
650 5a140b23 Vangelis Koukis
        ipv4 = self._get_ipv4(server)
651 bc14ba88 Vangelis Koukis
        sock = _insist_on_tcp_connection(socket.AF_INET, ipv4, 3389)
652 5a140b23 Vangelis Koukis
653 5a140b23 Vangelis Koukis
        # No actual RDP processing done. We assume the RDP server is there
654 5a140b23 Vangelis Koukis
        # if the connection to the RDP port is successful.
655 cb1fa17c Vangelis Koukis
        # FIXME: Use rdesktop, analyze exit code? see manpage [costasd]
656 5a140b23 Vangelis Koukis
        sock.close()
657 5a140b23 Vangelis Koukis
658 65462ca9 John Giannelos
    def test_015_rdp_to_server_IPv6(self):
659 65462ca9 John Giannelos
        "Test RDP connection to server public IPv6 works"""
660 65462ca9 John Giannelos
        self._skipIf(not self.is_windows, "only valid for Windows servers")
661 946da8b6 John Giannelos
        self._skipIf(NO_IPV6, "--no-ipv6 flag enabled")
662 946da8b6 John Giannelos
663 65462ca9 John Giannelos
        server = self.client.get_server_details(self.serverid)
664 65462ca9 John Giannelos
        ipv6 = self._get_ipv6(server)
665 65462ca9 John Giannelos
        sock = _get_tcp_connection(socket.AF_INET6, ipv6, 3389)
666 5a140b23 Vangelis Koukis
667 65462ca9 John Giannelos
        # No actual RDP processing done. We assume the RDP server is there
668 65462ca9 John Giannelos
        # if the connection to the RDP port is successful.
669 65462ca9 John Giannelos
        sock.close()
670 5a140b23 Vangelis Koukis
671 5a140b23 Vangelis Koukis
    def test_016_personality_is_enforced(self):
672 5a140b23 Vangelis Koukis
        """Test file injection for personality enforcement"""
673 21dcb666 John Giannelos
        self._skipIf(self.is_windows, "only implemented for Linux servers")
674 21dcb666 John Giannelos
        self._skipIf(self.personality == None, "No personality file selected")
675 f89d0238 John Giannelos
676 f89d0238 John Giannelos
        log.info("Trying to inject file for personality enforcement")
677 f89d0238 John Giannelos
678 77054bf5 John Giannelos
        server = self.client.get_server_details(self.serverid)
679 77054bf5 John Giannelos
680 9659e075 John Giannelos
        for inj_file in self.personality:
681 8252d64f John Giannelos
            equal_files = self._check_file_through_ssh(self._get_ipv4(server),
682 8252d64f John Giannelos
                                                       inj_file['owner'],
683 8252d64f John Giannelos
                                                       self.passwd,
684 8252d64f John Giannelos
                                                       inj_file['path'],
685 8252d64f John Giannelos
                                                       inj_file['contents'])
686 9659e075 John Giannelos
            self.assertTrue(equal_files)
687 8252d64f John Giannelos
688 4fdd25ab Vangelis Koukis
    def test_017_submit_delete_request(self):
689 4fdd25ab Vangelis Koukis
        """Test submit request to delete server"""
690 f89d0238 John Giannelos
691 f89d0238 John Giannelos
        log.info("Deleting server")
692 f89d0238 John Giannelos
693 4fdd25ab Vangelis Koukis
        self.client.delete_server(self.serverid)
694 4fdd25ab Vangelis Koukis
695 4fdd25ab Vangelis Koukis
    def test_018_server_becomes_deleted(self):
696 4fdd25ab Vangelis Koukis
        """Test server becomes DELETED"""
697 f89d0238 John Giannelos
698 f89d0238 John Giannelos
        log.info("Testing if server becomes DELETED")
699 f89d0238 John Giannelos
700 4fdd25ab Vangelis Koukis
        self._insist_on_status_transition("ACTIVE", "DELETED",
701 4fdd25ab Vangelis Koukis
                                         self.action_timeout,
702 4fdd25ab Vangelis Koukis
                                         self.action_timeout)
703 4fdd25ab Vangelis Koukis
704 4fdd25ab Vangelis Koukis
    def test_019_server_no_longer_in_server_list(self):
705 4fdd25ab Vangelis Koukis
        """Test server is no longer in server list"""
706 f89d0238 John Giannelos
707 f89d0238 John Giannelos
        log.info("Test if server is no longer listed")
708 f89d0238 John Giannelos
709 4fdd25ab Vangelis Koukis
        servers = self.client.list_servers()
710 21bbbc9b Vangelis Koukis
        self.assertNotIn(self.serverid, [s["id"] for s in servers])
711 21bbbc9b Vangelis Koukis
712 21bbbc9b Vangelis Koukis
713 9e4682b5 John Giannelos
class NetworkTestCase(unittest.TestCase):
714 e94a9d8c John Giannelos
    """ Testing networking in cyclades """
715 8252d64f John Giannelos
716 9e4682b5 John Giannelos
    @classmethod
717 e94a9d8c John Giannelos
    def setUpClass(cls):
718 e94a9d8c John Giannelos
        "Initialize kamaki, get list of current networks"
719 567ffb85 John Giannelos
720 567ffb85 John Giannelos
        cls.client = CycladesClient(API, TOKEN)
721 567ffb85 John Giannelos
        cls.compute = ComputeClient(API, TOKEN)
722 9e4682b5 John Giannelos
723 8252d64f John Giannelos
        cls.servername = "%s%s for %s" % (SNF_TEST_PREFIX,
724 8252d64f John Giannelos
                                          TEST_RUN_ID,
725 8252d64f John Giannelos
                                          cls.imagename)
726 91de9b55 John Giannelos
727 91de9b55 John Giannelos
        #Dictionary initialization for the vms credentials
728 91de9b55 John Giannelos
        cls.serverid = dict()
729 91de9b55 John Giannelos
        cls.username = dict()
730 91de9b55 John Giannelos
        cls.password = dict()
731 846980fe John Giannelos
        cls.is_windows = cls.imagename.lower().find("windows") >= 0
732 e49bdb7c John Giannelos
733 e49bdb7c John Giannelos
    def _skipIf(self, condition, msg):
734 e49bdb7c John Giannelos
        if condition:
735 e49bdb7c John Giannelos
            self.skipTest(msg)
736 91de9b55 John Giannelos
737 1b40b5e3 John Giannelos
    def _get_ipv4(self, server):
738 1b40b5e3 John Giannelos
        """Get the public IPv4 of a server from the detailed server info"""
739 1b40b5e3 John Giannelos
740 1b40b5e3 John Giannelos
        public_addrs = filter(lambda x: x["id"] == "public",
741 1b40b5e3 John Giannelos
                              server["addresses"]["values"])
742 1b40b5e3 John Giannelos
        self.assertEqual(len(public_addrs), 1)
743 1b40b5e3 John Giannelos
        ipv4_addrs = filter(lambda x: x["version"] == 4,
744 1b40b5e3 John Giannelos
                            public_addrs[0]["values"])
745 1b40b5e3 John Giannelos
        self.assertEqual(len(ipv4_addrs), 1)
746 1b40b5e3 John Giannelos
        return ipv4_addrs[0]["addr"]
747 8252d64f John Giannelos
748 1b40b5e3 John Giannelos
    def _connect_loginname(self, os):
749 1b40b5e3 John Giannelos
        """Return the login name for connections based on the server OS"""
750 1b40b5e3 John Giannelos
        if os in ("Ubuntu", "Kubuntu", "Fedora"):
751 1b40b5e3 John Giannelos
            return "user"
752 1b40b5e3 John Giannelos
        elif os in ("windows", "windows_alpha1"):
753 1b40b5e3 John Giannelos
            return "Administrator"
754 1b40b5e3 John Giannelos
        else:
755 1b40b5e3 John Giannelos
            return "root"
756 1b40b5e3 John Giannelos
757 88736f65 John Giannelos
    def _ping_once(self, ip):
758 8252d64f John Giannelos
759 88736f65 John Giannelos
        """Test server responds to a single IPv4 or IPv6 ping"""
760 88736f65 John Giannelos
        cmd = "ping -c 2 -w 3 %s" % (ip)
761 88736f65 John Giannelos
        ping = subprocess.Popen(cmd, shell=True,
762 88736f65 John Giannelos
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
763 88736f65 John Giannelos
        (stdout, stderr) = ping.communicate()
764 88736f65 John Giannelos
        ret = ping.wait()
765 8252d64f John Giannelos
766 88736f65 John Giannelos
        return (ret == 0)
767 88736f65 John Giannelos
768 740a5649 John Giannelos
    def test_00001a_submit_create_server_A(self):
769 91de9b55 John Giannelos
        """Test submit create server request"""
770 f89d0238 John Giannelos
771 f89d0238 John Giannelos
        log.info("Creating test server A")
772 f89d0238 John Giannelos
773 91de9b55 John Giannelos
        serverA = self.client.create_server(self.servername, self.flavorid,
774 ae139e8a John Giannelos
                                            self.imageid, personality=None)
775 91de9b55 John Giannelos
776 c54e3d4c John Giannelos
        self.assertEqual(serverA["name"], self.servername)
777 c54e3d4c John Giannelos
        self.assertEqual(serverA["flavorRef"], self.flavorid)
778 c54e3d4c John Giannelos
        self.assertEqual(serverA["imageRef"], self.imageid)
779 c54e3d4c John Giannelos
        self.assertEqual(serverA["status"], "BUILD")
780 91de9b55 John Giannelos
781 91de9b55 John Giannelos
        # Update class attributes to reflect data on building server
782 08748d73 John Giannelos
        self.serverid['A'] = serverA["id"]
783 08748d73 John Giannelos
        self.username['A'] = None
784 08748d73 John Giannelos
        self.password['A'] = serverA["adminPass"]
785 91de9b55 John Giannelos
786 81e8cbf6 John Giannelos
        log.info("Server A id:" + str(serverA["id"]))
787 81e8cbf6 John Giannelos
        log.info("Server password " + (self.password['A']))
788 8252d64f John Giannelos
789 740a5649 John Giannelos
    def test_00001b_serverA_becomes_active(self):
790 91de9b55 John Giannelos
        """Test server becomes ACTIVE"""
791 8252d64f John Giannelos
792 f89d0238 John Giannelos
        log.info("Waiting until test server A becomes ACTIVE")
793 91de9b55 John Giannelos
794 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
795 91de9b55 John Giannelos
        while True:
796 91de9b55 John Giannelos
            d = self.client.get_server_details(self.serverid['A'])
797 91de9b55 John Giannelos
            status = d['status']
798 91de9b55 John Giannelos
            if status == 'ACTIVE':
799 91de9b55 John Giannelos
                active = True
800 91de9b55 John Giannelos
                break
801 91de9b55 John Giannelos
            elif time.time() > fail_tmout:
802 91de9b55 John Giannelos
                self.assertLess(time.time(), fail_tmout)
803 91de9b55 John Giannelos
            else:
804 91de9b55 John Giannelos
                time.sleep(self.query_interval)
805 91de9b55 John Giannelos
806 91de9b55 John Giannelos
        self.assertTrue(active)
807 91de9b55 John Giannelos
808 740a5649 John Giannelos
    def test_00002a_submit_create_server_B(self):
809 fade8dab John Giannelos
        """Test submit create server request"""
810 8252d64f John Giannelos
811 f89d0238 John Giannelos
        log.info("Creating test server B")
812 f89d0238 John Giannelos
813 fade8dab John Giannelos
        serverB = self.client.create_server(self.servername, self.flavorid,
814 ae139e8a John Giannelos
                                            self.imageid, personality=None)
815 ae139e8a John Giannelos
816 fade8dab John Giannelos
        self.assertEqual(serverB["name"], self.servername)
817 fade8dab John Giannelos
        self.assertEqual(serverB["flavorRef"], self.flavorid)
818 fade8dab John Giannelos
        self.assertEqual(serverB["imageRef"], self.imageid)
819 fade8dab John Giannelos
        self.assertEqual(serverB["status"], "BUILD")
820 fade8dab John Giannelos
821 fade8dab John Giannelos
        # Update class attributes to reflect data on building server
822 fade8dab John Giannelos
        self.serverid['B'] = serverB["id"]
823 fade8dab John Giannelos
        self.username['B'] = None
824 fade8dab John Giannelos
        self.password['B'] = serverB["adminPass"]
825 fade8dab John Giannelos
826 81e8cbf6 John Giannelos
        log.info("Server B id: " + str(serverB["id"]))
827 81e8cbf6 John Giannelos
        log.info("Password " + (self.password['B']))
828 ae139e8a John Giannelos
829 740a5649 John Giannelos
    def test_00002b_serverB_becomes_active(self):
830 91de9b55 John Giannelos
        """Test server becomes ACTIVE"""
831 91de9b55 John Giannelos
832 f89d0238 John Giannelos
        log.info("Waiting until test server B becomes ACTIVE")
833 f89d0238 John Giannelos
834 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
835 91de9b55 John Giannelos
        while True:
836 91de9b55 John Giannelos
            d = self.client.get_server_details(self.serverid['B'])
837 91de9b55 John Giannelos
            status = d['status']
838 91de9b55 John Giannelos
            if status == 'ACTIVE':
839 91de9b55 John Giannelos
                active = True
840 91de9b55 John Giannelos
                break
841 91de9b55 John Giannelos
            elif time.time() > fail_tmout:
842 91de9b55 John Giannelos
                self.assertLess(time.time(), fail_tmout)
843 91de9b55 John Giannelos
            else:
844 91de9b55 John Giannelos
                time.sleep(self.query_interval)
845 91de9b55 John Giannelos
846 91de9b55 John Giannelos
        self.assertTrue(active)
847 567ffb85 John Giannelos
848 9e4682b5 John Giannelos
    def test_001_create_network(self):
849 e94a9d8c John Giannelos
        """Test submit create network request"""
850 f89d0238 John Giannelos
851 f89d0238 John Giannelos
        log.info("Submit new network request")
852 f89d0238 John Giannelos
853 2bcfb712 John Giannelos
        name = SNF_TEST_PREFIX + TEST_RUN_ID
854 9e4682b5 John Giannelos
        previous_num = len(self.client.list_networks())
855 2bcfb712 John Giannelos
        network = self.client.create_network(name)
856 8252d64f John Giannelos
857 9e4682b5 John Giannelos
        #Test if right name is assigned
858 e94a9d8c John Giannelos
        self.assertEqual(network['name'], name)
859 8252d64f John Giannelos
860 9e4682b5 John Giannelos
        # Update class attributes
861 e94a9d8c John Giannelos
        cls = type(self)
862 e94a9d8c John Giannelos
        cls.networkid = network['id']
863 9e4682b5 John Giannelos
        networks = self.client.list_networks()
864 9e4682b5 John Giannelos
865 9e4682b5 John Giannelos
        #Test if new network is created
866 9e4682b5 John Giannelos
        self.assertTrue(len(networks) > previous_num)
867 8252d64f John Giannelos
868 9e4682b5 John Giannelos
    def test_002_connect_to_network(self):
869 4573ea07 John Giannelos
        """Test connect VMs to network"""
870 9e4682b5 John Giannelos
871 f89d0238 John Giannelos
        log.info("Connect VMs to private network")
872 f89d0238 John Giannelos
873 91de9b55 John Giannelos
        self.client.connect_server(self.serverid['A'], self.networkid)
874 91de9b55 John Giannelos
        self.client.connect_server(self.serverid['B'], self.networkid)
875 8252d64f John Giannelos
876 65462ca9 John Giannelos
        #Insist on connecting until action timeout
877 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
878 9e4682b5 John Giannelos
879 65462ca9 John Giannelos
        while True:
880 de2461ec John Giannelos
            connected = (self.client.get_network_details(self.networkid))
881 65462ca9 John Giannelos
            connections = connected['servers']['values']
882 8252d64f John Giannelos
            if (self.serverid['A'] in connections) \
883 8252d64f John Giannelos
                    and (self.serverid['B'] in connections):
884 65462ca9 John Giannelos
                conn_exists = True
885 de2461ec John Giannelos
                break
886 de2461ec John Giannelos
            elif time.time() > fail_tmout:
887 65462ca9 John Giannelos
                self.assertLess(time.time(), fail_tmout)
888 65462ca9 John Giannelos
            else:
889 65462ca9 John Giannelos
                time.sleep(self.query_interval)
890 65462ca9 John Giannelos
891 65462ca9 John Giannelos
        self.assertTrue(conn_exists)
892 9e4682b5 John Giannelos
893 88736f65 John Giannelos
    def test_002a_reboot(self):
894 f89d0238 John Giannelos
        """Rebooting server A"""
895 f89d0238 John Giannelos
896 f89d0238 John Giannelos
        log.info("Rebooting server A")
897 f89d0238 John Giannelos
898 8252d64f John Giannelos
        self.client.shutdown_server(self.serverid['A'])
899 8252d64f John Giannelos
900 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
901 4573ea07 John Giannelos
        while True:
902 4573ea07 John Giannelos
            d = self.client.get_server_details(self.serverid['A'])
903 4573ea07 John Giannelos
            status = d['status']
904 81e8cbf6 John Giannelos
            if status == 'STOPPED':
905 81e8cbf6 John Giannelos
                break
906 81e8cbf6 John Giannelos
            elif time.time() > fail_tmout:
907 81e8cbf6 John Giannelos
                self.assertLess(time.time(), fail_tmout)
908 81e8cbf6 John Giannelos
            else:
909 81e8cbf6 John Giannelos
                time.sleep(self.query_interval)
910 81e8cbf6 John Giannelos
911 81e8cbf6 John Giannelos
        self.client.start_server(self.serverid['A'])
912 81e8cbf6 John Giannelos
913 81e8cbf6 John Giannelos
        while True:
914 81e8cbf6 John Giannelos
            d = self.client.get_server_details(self.serverid['A'])
915 81e8cbf6 John Giannelos
            status = d['status']
916 4573ea07 John Giannelos
            if status == 'ACTIVE':
917 4573ea07 John Giannelos
                active = True
918 4573ea07 John Giannelos
                break
919 4573ea07 John Giannelos
            elif time.time() > fail_tmout:
920 4573ea07 John Giannelos
                self.assertLess(time.time(), fail_tmout)
921 4573ea07 John Giannelos
            else:
922 4573ea07 John Giannelos
                time.sleep(self.query_interval)
923 8252d64f John Giannelos
924 4573ea07 John Giannelos
        self.assertTrue(active)
925 88736f65 John Giannelos
926 4573ea07 John Giannelos
    def test_002b_ping_server_A(self):
927 9b013c3a John Giannelos
        "Test if server A responds to IPv4 pings"
928 4573ea07 John Giannelos
929 9b013c3a John Giannelos
        log.info("Testing if server A responds to IPv4 pings ")
930 f89d0238 John Giannelos
931 88736f65 John Giannelos
        server = self.client.get_server_details(self.serverid['A'])
932 88736f65 John Giannelos
        ip = self._get_ipv4(server)
933 8252d64f John Giannelos
934 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
935 8252d64f John Giannelos
936 88736f65 John Giannelos
        s = False
937 88736f65 John Giannelos
938 88736f65 John Giannelos
        while True:
939 88736f65 John Giannelos
940 88736f65 John Giannelos
            if self._ping_once(ip):
941 88736f65 John Giannelos
                s = True
942 88736f65 John Giannelos
                break
943 88736f65 John Giannelos
944 88736f65 John Giannelos
            elif time.time() > fail_tmout:
945 88736f65 John Giannelos
                self.assertLess(time.time(), fail_tmout)
946 88736f65 John Giannelos
947 88736f65 John Giannelos
            else:
948 88736f65 John Giannelos
                time.sleep(self.query_interval)
949 88736f65 John Giannelos
950 88736f65 John Giannelos
        self.assertTrue(s)
951 4573ea07 John Giannelos
952 4573ea07 John Giannelos
    def test_002c_reboot(self):
953 f89d0238 John Giannelos
        """Reboot server B"""
954 f89d0238 John Giannelos
955 f89d0238 John Giannelos
        log.info("Rebooting server B")
956 f89d0238 John Giannelos
957 8252d64f John Giannelos
        self.client.shutdown_server(self.serverid['B'])
958 8252d64f John Giannelos
959 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
960 4573ea07 John Giannelos
        while True:
961 4573ea07 John Giannelos
            d = self.client.get_server_details(self.serverid['B'])
962 4573ea07 John Giannelos
            status = d['status']
963 81e8cbf6 John Giannelos
            if status == 'STOPPED':
964 81e8cbf6 John Giannelos
                break
965 81e8cbf6 John Giannelos
            elif time.time() > fail_tmout:
966 81e8cbf6 John Giannelos
                self.assertLess(time.time(), fail_tmout)
967 81e8cbf6 John Giannelos
            else:
968 81e8cbf6 John Giannelos
                time.sleep(self.query_interval)
969 81e8cbf6 John Giannelos
970 81e8cbf6 John Giannelos
        self.client.start_server(self.serverid['B'])
971 81e8cbf6 John Giannelos
972 81e8cbf6 John Giannelos
        while True:
973 81e8cbf6 John Giannelos
            d = self.client.get_server_details(self.serverid['B'])
974 81e8cbf6 John Giannelos
            status = d['status']
975 4573ea07 John Giannelos
            if status == 'ACTIVE':
976 4573ea07 John Giannelos
                active = True
977 4573ea07 John Giannelos
                break
978 4573ea07 John Giannelos
            elif time.time() > fail_tmout:
979 4573ea07 John Giannelos
                self.assertLess(time.time(), fail_tmout)
980 4573ea07 John Giannelos
            else:
981 4573ea07 John Giannelos
                time.sleep(self.query_interval)
982 8252d64f John Giannelos
983 4573ea07 John Giannelos
        self.assertTrue(active)
984 8252d64f John Giannelos
985 88736f65 John Giannelos
    def test_002d_ping_server_B(self):
986 9b013c3a John Giannelos
        """Test if server B responds to IPv4 pings"""
987 4573ea07 John Giannelos
988 9b013c3a John Giannelos
        log.info("Testing if server B responds to IPv4 pings")
989 88736f65 John Giannelos
        server = self.client.get_server_details(self.serverid['B'])
990 88736f65 John Giannelos
        ip = self._get_ipv4(server)
991 8252d64f John Giannelos
992 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
993 8252d64f John Giannelos
994 88736f65 John Giannelos
        s = False
995 88736f65 John Giannelos
996 88736f65 John Giannelos
        while True:
997 88736f65 John Giannelos
            if self._ping_once(ip):
998 88736f65 John Giannelos
                s = True
999 88736f65 John Giannelos
                break
1000 88736f65 John Giannelos
1001 88736f65 John Giannelos
            elif time.time() > fail_tmout:
1002 88736f65 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1003 88736f65 John Giannelos
1004 88736f65 John Giannelos
            else:
1005 88736f65 John Giannelos
                time.sleep(self.query_interval)
1006 88736f65 John Giannelos
1007 88736f65 John Giannelos
        self.assertTrue(s)
1008 88736f65 John Giannelos
1009 88736f65 John Giannelos
    def test_003a_setup_interface_A(self):
1010 f89d0238 John Giannelos
        """Set up eth1 for server A"""
1011 f89d0238 John Giannelos
1012 e49bdb7c John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
1013 e49bdb7c John Giannelos
1014 f89d0238 John Giannelos
        log.info("Setting up interface eth1 for server A")
1015 ae139e8a John Giannelos
1016 1b40b5e3 John Giannelos
        server = self.client.get_server_details(self.serverid['A'])
1017 08748d73 John Giannelos
        image = self.client.get_image_details(self.imageid)
1018 1b40b5e3 John Giannelos
        os = image['metadata']['values']['os']
1019 8252d64f John Giannelos
1020 d5cc50b3 John Giannelos
        users = image["metadata"]["values"].get("users", None)
1021 d5cc50b3 John Giannelos
        userlist = users.split()
1022 d5cc50b3 John Giannelos
1023 d5cc50b3 John Giannelos
        if "root" in userlist:
1024 d5cc50b3 John Giannelos
            loginname = "root"
1025 d5cc50b3 John Giannelos
        elif users == None:
1026 1b40b5e3 John Giannelos
            loginname = self._connect_loginname(os)
1027 d5cc50b3 John Giannelos
        else:
1028 d5cc50b3 John Giannelos
            loginname = choice(userlist)
1029 1b40b5e3 John Giannelos
1030 ae139e8a John Giannelos
        hostip = self._get_ipv4(server)
1031 740a5649 John Giannelos
        myPass = self.password['A']
1032 8252d64f John Giannelos
1033 2bcfb712 John Giannelos
        log.info("SSH in server A as %s/%s" % (loginname, myPass))
1034 8252d64f John Giannelos
1035 88736f65 John Giannelos
        res = False
1036 1b40b5e3 John Giannelos
1037 d5cc50b3 John Giannelos
        if loginname != "root":
1038 88736f65 John Giannelos
            with settings(
1039 33ae1493 John Giannelos
                hide('warnings', 'running'),
1040 8252d64f John Giannelos
                warn_only=True,
1041 8252d64f John Giannelos
                host_string=hostip,
1042 8252d64f John Giannelos
                user=loginname, password=myPass
1043 88736f65 John Giannelos
                ):
1044 88736f65 John Giannelos
1045 8252d64f John Giannelos
                if len(sudo('ifconfig eth1 192.168.0.12')) == 0:
1046 88736f65 John Giannelos
                    res = True
1047 8252d64f John Giannelos
1048 ae139e8a John Giannelos
        else:
1049 ae139e8a John Giannelos
            with settings(
1050 33ae1493 John Giannelos
                hide('warnings', 'running'),
1051 8252d64f John Giannelos
                warn_only=True,
1052 8252d64f John Giannelos
                host_string=hostip,
1053 8252d64f John Giannelos
                user=loginname, password=myPass
1054 ae139e8a John Giannelos
                ):
1055 4573ea07 John Giannelos
1056 33ae1493 John Giannelos
                if len(run('ifconfig eth1 192.168.0.12')) == 0:
1057 ae139e8a John Giannelos
                    res = True
1058 88736f65 John Giannelos
1059 88736f65 John Giannelos
        self.assertTrue(res)
1060 1b40b5e3 John Giannelos
1061 88736f65 John Giannelos
    def test_003b_setup_interface_B(self):
1062 f89d0238 John Giannelos
        """Setup eth1 for server B"""
1063 1b40b5e3 John Giannelos
1064 e49bdb7c John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
1065 e49bdb7c John Giannelos
1066 f89d0238 John Giannelos
        log.info("Setting up interface eth1 for server B")
1067 ae139e8a John Giannelos
1068 1b40b5e3 John Giannelos
        server = self.client.get_server_details(self.serverid['B'])
1069 08748d73 John Giannelos
        image = self.client.get_image_details(self.imageid)
1070 1b40b5e3 John Giannelos
        os = image['metadata']['values']['os']
1071 8252d64f John Giannelos
1072 d5cc50b3 John Giannelos
        users = image["metadata"]["values"].get("users", None)
1073 d5cc50b3 John Giannelos
        userlist = users.split()
1074 d5cc50b3 John Giannelos
1075 d5cc50b3 John Giannelos
        if "root" in userlist:
1076 d5cc50b3 John Giannelos
            loginname = "root"
1077 d5cc50b3 John Giannelos
        elif users == None:
1078 1b40b5e3 John Giannelos
            loginname = self._connect_loginname(os)
1079 d5cc50b3 John Giannelos
        else:
1080 d5cc50b3 John Giannelos
            loginname = choice(userlist)
1081 d5cc50b3 John Giannelos
1082 d5cc50b3 John Giannelos
        hostip = self._get_ipv4(server)
1083 740a5649 John Giannelos
        myPass = self.password['B']
1084 740a5649 John Giannelos
1085 2bcfb712 John Giannelos
        log.info("SSH in server B as %s/%s" % (loginname, myPass))
1086 1b40b5e3 John Giannelos
1087 88736f65 John Giannelos
        res = False
1088 88736f65 John Giannelos
1089 d5cc50b3 John Giannelos
        if loginname != "root":
1090 88736f65 John Giannelos
            with settings(
1091 33ae1493 John Giannelos
                hide('warnings', 'running'),
1092 8252d64f John Giannelos
                warn_only=True,
1093 8252d64f John Giannelos
                host_string=hostip,
1094 8252d64f John Giannelos
                user=loginname, password=myPass
1095 88736f65 John Giannelos
                ):
1096 8252d64f John Giannelos
1097 2bcfb712 John Giannelos
                if len(sudo('ifconfig eth1 192.168.0.13')) == 0:
1098 88736f65 John Giannelos
                    res = True
1099 8252d64f John Giannelos
1100 2bcfb712 John Giannelos
        else:
1101 ae139e8a John Giannelos
            with settings(
1102 33ae1493 John Giannelos
                hide('warnings', 'running'),
1103 8252d64f John Giannelos
                warn_only=True,
1104 8252d64f John Giannelos
                host_string=hostip,
1105 8252d64f John Giannelos
                user=loginname, password=myPass
1106 ae139e8a John Giannelos
                ):
1107 ae139e8a John Giannelos
1108 33ae1493 John Giannelos
                if len(run('ifconfig eth1 192.168.0.13')) == 0:
1109 ae139e8a John Giannelos
                    res = True
1110 ae139e8a John Giannelos
1111 88736f65 John Giannelos
        self.assertTrue(res)
1112 ae139e8a John Giannelos
1113 88736f65 John Giannelos
    def test_003c_test_connection_exists(self):
1114 4573ea07 John Giannelos
        """Ping server B from server A to test if connection exists"""
1115 1b40b5e3 John Giannelos
1116 e49bdb7c John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
1117 e49bdb7c John Giannelos
1118 f89d0238 John Giannelos
        log.info("Testing if server A is actually connected to server B")
1119 f89d0238 John Giannelos
1120 1b40b5e3 John Giannelos
        server = self.client.get_server_details(self.serverid['A'])
1121 08748d73 John Giannelos
        image = self.client.get_image_details(self.imageid)
1122 1b40b5e3 John Giannelos
        os = image['metadata']['values']['os']
1123 1b40b5e3 John Giannelos
        hostip = self._get_ipv4(server)
1124 d5cc50b3 John Giannelos
1125 d5cc50b3 John Giannelos
        users = image["metadata"]["values"].get("users", None)
1126 d5cc50b3 John Giannelos
        userlist = users.split()
1127 d5cc50b3 John Giannelos
1128 d5cc50b3 John Giannelos
        if "root" in userlist:
1129 d5cc50b3 John Giannelos
            loginname = "root"
1130 d5cc50b3 John Giannelos
        elif users == None:
1131 1b40b5e3 John Giannelos
            loginname = self._connect_loginname(os)
1132 d5cc50b3 John Giannelos
        else:
1133 d5cc50b3 John Giannelos
            loginname = choice(userlist)
1134 1b40b5e3 John Giannelos
1135 88736f65 John Giannelos
        myPass = self.password['A']
1136 88736f65 John Giannelos
1137 1b40b5e3 John Giannelos
        try:
1138 1b40b5e3 John Giannelos
            ssh = paramiko.SSHClient()
1139 1b40b5e3 John Giannelos
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
1140 8252d64f John Giannelos
            ssh.connect(hostip, username=loginname, password=myPass)
1141 1b40b5e3 John Giannelos
        except socket.error:
1142 1b40b5e3 John Giannelos
            raise AssertionError
1143 1b40b5e3 John Giannelos
1144 8252d64f John Giannelos
        cmd = "if ping -c 2 -w 3 192.168.0.13 >/dev/null; \
1145 8252d64f John Giannelos
               then echo \'True\'; fi;"
1146 1b40b5e3 John Giannelos
        stdin, stdout, stderr = ssh.exec_command(cmd)
1147 1b40b5e3 John Giannelos
        lines = stdout.readlines()
1148 1b40b5e3 John Giannelos
1149 740a5649 John Giannelos
        exists = False
1150 4573ea07 John Giannelos
1151 88736f65 John Giannelos
        if 'True\n' in lines:
1152 88736f65 John Giannelos
            exists = True
1153 1b40b5e3 John Giannelos
1154 1b40b5e3 John Giannelos
        self.assertTrue(exists)
1155 1b40b5e3 John Giannelos
1156 88736f65 John Giannelos
    def test_004_disconnect_from_network(self):
1157 4573ea07 John Giannelos
        "Disconnecting server A and B from network"
1158 4573ea07 John Giannelos
1159 f89d0238 John Giannelos
        log.info("Disconnecting servers from private network")
1160 f89d0238 John Giannelos
1161 f97dce4d John Giannelos
        prev_state = self.client.get_network_details(self.networkid)
1162 9e4682b5 John Giannelos
        prev_conn = len(prev_state['servers']['values'])
1163 e94a9d8c John Giannelos
1164 91de9b55 John Giannelos
        self.client.disconnect_server(self.serverid['A'], self.networkid)
1165 91de9b55 John Giannelos
        self.client.disconnect_server(self.serverid['B'], self.networkid)
1166 f97dce4d John Giannelos
1167 65462ca9 John Giannelos
        #Insist on deleting until action timeout
1168 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1169 9e4682b5 John Giannelos
1170 65462ca9 John Giannelos
        while True:
1171 de2461ec John Giannelos
            connected = (self.client.get_network_details(self.networkid))
1172 65462ca9 John Giannelos
            connections = connected['servers']['values']
1173 8252d64f John Giannelos
            if ((self.serverid['A'] not in connections) and
1174 8252d64f John Giannelos
                (self.serverid['B'] not in connections)):
1175 65462ca9 John Giannelos
                conn_exists = False
1176 de2461ec John Giannelos
                break
1177 de2461ec John Giannelos
            elif time.time() > fail_tmout:
1178 65462ca9 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1179 65462ca9 John Giannelos
            else:
1180 65462ca9 John Giannelos
                time.sleep(self.query_interval)
1181 65462ca9 John Giannelos
1182 65462ca9 John Giannelos
        self.assertFalse(conn_exists)
1183 9e4682b5 John Giannelos
1184 88736f65 John Giannelos
    def test_005_destroy_network(self):
1185 e94a9d8c John Giannelos
        """Test submit delete network request"""
1186 f89d0238 John Giannelos
1187 f89d0238 John Giannelos
        log.info("Submitting delete network request")
1188 f89d0238 John Giannelos
1189 8252d64f John Giannelos
        self.client.delete_network(self.networkid)
1190 9e4682b5 John Giannelos
        networks = self.client.list_networks()
1191 e94a9d8c John Giannelos
1192 65462ca9 John Giannelos
        curr_net = []
1193 65462ca9 John Giannelos
        for net in networks:
1194 de2461ec John Giannelos
            curr_net.append(net['id'])
1195 65462ca9 John Giannelos
1196 65462ca9 John Giannelos
        self.assertTrue(self.networkid not in curr_net)
1197 8252d64f John Giannelos
1198 88736f65 John Giannelos
    def test_006_cleanup_servers(self):
1199 65462ca9 John Giannelos
        """Cleanup servers created for this test"""
1200 f89d0238 John Giannelos
1201 f89d0238 John Giannelos
        log.info("Delete servers created for this test")
1202 f89d0238 John Giannelos
1203 91de9b55 John Giannelos
        self.compute.delete_server(self.serverid['A'])
1204 91de9b55 John Giannelos
        self.compute.delete_server(self.serverid['B'])
1205 91de9b55 John Giannelos
1206 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1207 65462ca9 John Giannelos
1208 65462ca9 John Giannelos
        #Ensure server gets deleted
1209 8252d64f John Giannelos
        status = dict()
1210 91de9b55 John Giannelos
1211 65462ca9 John Giannelos
        while True:
1212 91de9b55 John Giannelos
            details = self.compute.get_server_details(self.serverid['A'])
1213 91de9b55 John Giannelos
            status['A'] = details['status']
1214 91de9b55 John Giannelos
            details = self.compute.get_server_details(self.serverid['B'])
1215 91de9b55 John Giannelos
            status['B'] = details['status']
1216 91de9b55 John Giannelos
            if (status['A'] == 'DELETED') and (status['B'] == 'DELETED'):
1217 65462ca9 John Giannelos
                deleted = True
1218 de2461ec John Giannelos
                break
1219 8252d64f John Giannelos
            elif time.time() > fail_tmout:
1220 65462ca9 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1221 65462ca9 John Giannelos
            else:
1222 65462ca9 John Giannelos
                time.sleep(self.query_interval)
1223 8252d64f John Giannelos
1224 65462ca9 John Giannelos
        self.assertTrue(deleted)
1225 e94a9d8c John Giannelos
1226 4573ea07 John Giannelos
1227 21bbbc9b Vangelis Koukis
class TestRunnerProcess(Process):
1228 21bbbc9b Vangelis Koukis
    """A distinct process used to execute part of the tests in parallel"""
1229 21bbbc9b Vangelis Koukis
    def __init__(self, **kw):
1230 21bbbc9b Vangelis Koukis
        Process.__init__(self, **kw)
1231 96da37c8 John Giannelos
        kwargs = kw["kwargs"]
1232 21bbbc9b Vangelis Koukis
        self.testq = kwargs["testq"]
1233 21bbbc9b Vangelis Koukis
        self.runner = kwargs["runner"]
1234 21bbbc9b Vangelis Koukis
1235 21bbbc9b Vangelis Koukis
    def run(self):
1236 21bbbc9b Vangelis Koukis
        # Make sure this test runner process dies with the parent
1237 21bbbc9b Vangelis Koukis
        # and is not left behind.
1238 21bbbc9b Vangelis Koukis
        #
1239 21bbbc9b Vangelis Koukis
        # WARNING: This uses the prctl(2) call and is
1240 21bbbc9b Vangelis Koukis
        # Linux-specific.
1241 21bbbc9b Vangelis Koukis
        prctl.set_pdeathsig(signal.SIGHUP)
1242 21bbbc9b Vangelis Koukis
1243 21bbbc9b Vangelis Koukis
        while True:
1244 21bbbc9b Vangelis Koukis
            log.debug("I am process %d, GETting from queue is %s",
1245 21bbbc9b Vangelis Koukis
                     os.getpid(), self.testq)
1246 21bbbc9b Vangelis Koukis
            msg = self.testq.get()
1247 21bbbc9b Vangelis Koukis
            log.debug("Dequeued msg: %s", msg)
1248 21bbbc9b Vangelis Koukis
1249 21bbbc9b Vangelis Koukis
            if msg == "TEST_RUNNER_TERMINATE":
1250 21bbbc9b Vangelis Koukis
                raise SystemExit
1251 21bbbc9b Vangelis Koukis
            elif issubclass(msg, unittest.TestCase):
1252 21bbbc9b Vangelis Koukis
                # Assemble a TestSuite, and run it
1253 21bbbc9b Vangelis Koukis
                suite = unittest.TestLoader().loadTestsFromTestCase(msg)
1254 21bbbc9b Vangelis Koukis
                self.runner.run(suite)
1255 21bbbc9b Vangelis Koukis
            else:
1256 21bbbc9b Vangelis Koukis
                raise Exception("Cannot handle msg: %s" % msg)
1257 21bbbc9b Vangelis Koukis
1258 21bbbc9b Vangelis Koukis
1259 21bbbc9b Vangelis Koukis
def _run_cases_in_parallel(cases, fanout=1, runner=None):
1260 21bbbc9b Vangelis Koukis
    """Run instances of TestCase in parallel, in a number of distinct processes
1261 21bbbc9b Vangelis Koukis

1262 21bbbc9b Vangelis Koukis
    The cases iterable specifies the TestCases to be executed in parallel,
1263 21bbbc9b Vangelis Koukis
    by test runners running in distinct processes.
1264 21bbbc9b Vangelis Koukis
    The fanout parameter specifies the number of processes to spawn,
1265 21bbbc9b Vangelis Koukis
    and defaults to 1.
1266 21bbbc9b Vangelis Koukis
    The runner argument specifies the test runner class to use inside each
1267 21bbbc9b Vangelis Koukis
    runner process.
1268 21bbbc9b Vangelis Koukis

1269 21bbbc9b Vangelis Koukis
    """
1270 21bbbc9b Vangelis Koukis
    if runner is None:
1271 00f87624 Vangelis Koukis
        runner = unittest.TextTestRunner(verbosity=2, failfast=True)
1272 21bbbc9b Vangelis Koukis
1273 21bbbc9b Vangelis Koukis
    # testq: The master process enqueues TestCase objects into this queue,
1274 21bbbc9b Vangelis Koukis
    #        test runner processes pick them up for execution, in parallel.
1275 21bbbc9b Vangelis Koukis
    testq = Queue()
1276 21bbbc9b Vangelis Koukis
    runners = []
1277 21bbbc9b Vangelis Koukis
    for i in xrange(0, fanout):
1278 21bbbc9b Vangelis Koukis
        kwargs = dict(testq=testq, runner=runner)
1279 21bbbc9b Vangelis Koukis
        runners.append(TestRunnerProcess(kwargs=kwargs))
1280 21bbbc9b Vangelis Koukis
1281 21bbbc9b Vangelis Koukis
    log.info("Spawning %d test runner processes", len(runners))
1282 21bbbc9b Vangelis Koukis
    for p in runners:
1283 21bbbc9b Vangelis Koukis
        p.start()
1284 21bbbc9b Vangelis Koukis
    log.debug("Spawned %d test runners, PIDs are %s",
1285 21bbbc9b Vangelis Koukis
              len(runners), [p.pid for p in runners])
1286 21bbbc9b Vangelis Koukis
1287 21bbbc9b Vangelis Koukis
    # Enqueue test cases
1288 21bbbc9b Vangelis Koukis
    map(testq.put, cases)
1289 21bbbc9b Vangelis Koukis
    map(testq.put, ["TEST_RUNNER_TERMINATE"] * len(runners))
1290 21bbbc9b Vangelis Koukis
1291 21bbbc9b Vangelis Koukis
    log.debug("Joining %d processes", len(runners))
1292 21bbbc9b Vangelis Koukis
    for p in runners:
1293 21bbbc9b Vangelis Koukis
        p.join()
1294 21bbbc9b Vangelis Koukis
    log.debug("Done joining %d processes", len(runners))
1295 4fdd25ab Vangelis Koukis
1296 5a140b23 Vangelis Koukis
1297 5a140b23 Vangelis Koukis
def _spawn_server_test_case(**kwargs):
1298 5a140b23 Vangelis Koukis
    """Construct a new unit test case class from SpawnServerTestCase"""
1299 5a140b23 Vangelis Koukis
1300 c1d11f96 John Giannelos
    name = "SpawnServerTestCase_%s" % kwargs["imageid"]
1301 5a140b23 Vangelis Koukis
    cls = type(name, (SpawnServerTestCase,), kwargs)
1302 5a140b23 Vangelis Koukis
1303 5a140b23 Vangelis Koukis
    # Patch extra parameters into test names by manipulating method docstrings
1304 5a140b23 Vangelis Koukis
    for (mname, m) in \
1305 5a140b23 Vangelis Koukis
        inspect.getmembers(cls, lambda x: inspect.ismethod(x)):
1306 74ec726f John Giannelos
        if hasattr(m, __doc__):
1307 74ec726f John Giannelos
            m.__func__.__doc__ = "[%s] %s" % (imagename, m.__doc__)
1308 e72bcf60 Vangelis Koukis
1309 e72bcf60 Vangelis Koukis
    # Make sure the class can be pickled, by listing it among
1310 e72bcf60 Vangelis Koukis
    # the attributes of __main__. A PicklingError is raised otherwise.
1311 e72bcf60 Vangelis Koukis
    setattr(__main__, name, cls)
1312 8252d64f John Giannelos
    return cls
1313 65462ca9 John Giannelos
1314 2bcfb712 John Giannelos
1315 65462ca9 John Giannelos
def _spawn_network_test_case(**kwargs):
1316 65462ca9 John Giannelos
    """Construct a new unit test case class from NetworkTestCase"""
1317 65462ca9 John Giannelos
1318 2bcfb712 John Giannelos
    name = "NetworkTestCase" + TEST_RUN_ID
1319 65462ca9 John Giannelos
    cls = type(name, (NetworkTestCase,), kwargs)
1320 65462ca9 John Giannelos
1321 65462ca9 John Giannelos
    # Make sure the class can be pickled, by listing it among
1322 65462ca9 John Giannelos
    # the attributes of __main__. A PicklingError is raised otherwise.
1323 65462ca9 John Giannelos
    setattr(__main__, name, cls)
1324 8252d64f John Giannelos
    return cls
1325 5a140b23 Vangelis Koukis
1326 5a140b23 Vangelis Koukis
1327 c0448f4f John Giannelos
def cleanup_servers(timeout, query_interval, delete_stale=False):
1328 74193008 John Giannelos
1329 567ffb85 John Giannelos
    c = ComputeClient(API, TOKEN)
1330 74193008 John Giannelos
1331 5a140b23 Vangelis Koukis
    servers = c.list_servers()
1332 5a140b23 Vangelis Koukis
    stale = [s for s in servers if s["name"].startswith(SNF_TEST_PREFIX)]
1333 5a140b23 Vangelis Koukis
1334 4fdd25ab Vangelis Koukis
    if len(stale) == 0:
1335 4fdd25ab Vangelis Koukis
        return
1336 4fdd25ab Vangelis Koukis
1337 746540cd John Giannelos
    print >> sys.stderr, yellow + "Found these stale servers from previous runs:" + normal
1338 5a140b23 Vangelis Koukis
    print "    " + \
1339 21bbbc9b Vangelis Koukis
          "\n    ".join(["%d: %s" % (s["id"], s["name"]) for s in stale])
1340 5a140b23 Vangelis Koukis
1341 5a140b23 Vangelis Koukis
    if delete_stale:
1342 5a140b23 Vangelis Koukis
        print >> sys.stderr, "Deleting %d stale servers:" % len(stale)
1343 c0448f4f John Giannelos
1344 c0448f4f John Giannelos
        fail_tmout = time.time() + timeout
1345 c0448f4f John Giannelos
1346 c0448f4f John Giannelos
1347 c0448f4f John Giannelos
        for s in stale:
1348 c0448f4f John Giannelos
            c.delete_server(s["id"])
1349 c0448f4f John Giannelos
1350 c0448f4f John Giannelos
        
1351 c0448f4f John Giannelos
        while True:
1352 c0448f4f John Giannelos
            servers = c.list_servers()
1353 c0448f4f John Giannelos
            stale = [s for s in servers if s["name"].startswith(SNF_TEST_PREFIX)]
1354 c0448f4f John Giannelos
            for s in stale:
1355 c0448f4f John Giannelos
                c.delete_server(s["id"])
1356 c0448f4f John Giannelos
1357 c0448f4f John Giannelos
            if len(stale)==0:
1358 c0448f4f John Giannelos
                print >> sys.stderr, green + "    ...done" + normal
1359 c0448f4f John Giannelos
                break
1360 c0448f4f John Giannelos
1361 c0448f4f John Giannelos
            elif time.time() > fail_tmout:
1362 c0448f4f John Giannelos
                print >> sys.stderr, red + "Not all stale servers deleted. Action timed out." + normal
1363 c0448f4f John Giannelos
                return 
1364 c0448f4f John Giannelos
            else:
1365 c0448f4f John Giannelos
                time.sleep(query_interval)
1366 c0448f4f John Giannelos
                
1367 5a140b23 Vangelis Koukis
    else:
1368 5a140b23 Vangelis Koukis
        print >> sys.stderr, "Use --delete-stale to delete them."
1369 5a140b23 Vangelis Koukis
1370 2bcfb712 John Giannelos
1371 c0448f4f John Giannelos
def cleanup_networks(timeout, query_interval, delete_stale=False):
1372 74ec726f John Giannelos
1373 74ec726f John Giannelos
    c = CycladesClient(API, TOKEN)
1374 74ec726f John Giannelos
1375 74ec726f John Giannelos
    networks = c.list_networks()
1376 74ec726f John Giannelos
    stale = [n for n in networks if n["name"].startswith(SNF_TEST_PREFIX)]
1377 74ec726f John Giannelos
1378 74ec726f John Giannelos
    if len(stale) == 0:
1379 74ec726f John Giannelos
        return
1380 74ec726f John Giannelos
1381 746540cd John Giannelos
    print >> sys.stderr, yellow + "Found these stale networks from previous runs:" + normal
1382 74ec726f John Giannelos
    print "    " + \
1383 74ec726f John Giannelos
          "\n    ".join(["%s: %s" % (str(n["id"]), n["name"]) for n in stale])
1384 74ec726f John Giannelos
1385 74ec726f John Giannelos
    if delete_stale:
1386 74ec726f John Giannelos
        print >> sys.stderr, "Deleting %d stale networks:" % len(stale)
1387 c0448f4f John Giannelos
1388 c0448f4f John Giannelos
        fail_tmout = time.time() + timeout
1389 c0448f4f John Giannelos
        
1390 c0448f4f John Giannelos
        for n in stale:
1391 c0448f4f John Giannelos
            c.delete_network(n["id"])
1392 c0448f4f John Giannelos
1393 c0448f4f John Giannelos
1394 c0448f4f John Giannelos
        while True:
1395 c0448f4f John Giannelos
            networks = c.list_networks()
1396 c0448f4f John Giannelos
            stale = [n for n in networks if n["name"].startswith(SNF_TEST_PREFIX)]
1397 c0448f4f John Giannelos
1398 c0448f4f John Giannelos
            if len(stale)==0:
1399 c0448f4f John Giannelos
                print >> sys.stderr, green + "    ...done" + normal
1400 c0448f4f John Giannelos
                break
1401 c0448f4f John Giannelos
1402 c0448f4f John Giannelos
            elif time.time() > fail_tmout:
1403 c0448f4f John Giannelos
                print >> sys.stderr, red + "Not all stale networks deleted. Action timed out." + normal
1404 c0448f4f John Giannelos
                return 
1405 c0448f4f John Giannelos
            else:
1406 c0448f4f John Giannelos
                time.sleep(query_interval)
1407 c0448f4f John Giannelos
1408 74ec726f John Giannelos
    else:
1409 74ec726f John Giannelos
        print >> sys.stderr, "Use --delete-stale to delete them."
1410 74ec726f John Giannelos
1411 746540cd John Giannelos
1412 22efe1fe John Giannelos
def parse_comma(option, opt, value, parser):
1413 746540cd John Giannelos
    tests = set(['all', 'auth', 'images', 'flavors',
1414 22efe1fe John Giannelos
               'servers', 'server_spawn', 'network_spawn'])
1415 22efe1fe John Giannelos
    parse_input = value.split(',')
1416 22efe1fe John Giannelos
1417 22efe1fe John Giannelos
    if not (set(parse_input)).issubset(tests):
1418 22efe1fe John Giannelos
        raise OptionValueError("The selected set of tests is invalid")
1419 22efe1fe John Giannelos
1420 22efe1fe John Giannelos
    setattr(parser.values, option.dest, value.split(','))
1421 22efe1fe John Giannelos
1422 74ec726f John Giannelos
1423 5a140b23 Vangelis Koukis
def parse_arguments(args):
1424 5a140b23 Vangelis Koukis
1425 5a140b23 Vangelis Koukis
    kw = {}
1426 5a140b23 Vangelis Koukis
    kw["usage"] = "%prog [options]"
1427 5a140b23 Vangelis Koukis
    kw["description"] = \
1428 5a140b23 Vangelis Koukis
        "%prog runs a number of test scenarios on a " \
1429 5a140b23 Vangelis Koukis
        "Synnefo deployment."
1430 5a140b23 Vangelis Koukis
1431 5a140b23 Vangelis Koukis
    parser = OptionParser(**kw)
1432 5a140b23 Vangelis Koukis
    parser.disable_interspersed_args()
1433 22efe1fe John Giannelos
1434 21bbbc9b Vangelis Koukis
    parser.add_option("--api",
1435 21bbbc9b Vangelis Koukis
                      action="store", type="string", dest="api",
1436 21bbbc9b Vangelis Koukis
                      help="The API URI to use to reach the Synnefo API",
1437 21bbbc9b Vangelis Koukis
                      default=DEFAULT_API)
1438 946da8b6 John Giannelos
    parser.add_option("--plankton",
1439 946da8b6 John Giannelos
                      action="store", type="string", dest="plankton",
1440 946da8b6 John Giannelos
                      help="The API URI to use to reach the Plankton API",
1441 946da8b6 John Giannelos
                      default=DEFAULT_PLANKTON)
1442 946da8b6 John Giannelos
    parser.add_option("--plankton-user",
1443 946da8b6 John Giannelos
                      action="store", type="string", dest="plankton_user",
1444 946da8b6 John Giannelos
                      help="Owner of system images",
1445 946da8b6 John Giannelos
                      default=DEFAULT_PLANKTON_USER)
1446 21bbbc9b Vangelis Koukis
    parser.add_option("--token",
1447 21bbbc9b Vangelis Koukis
                      action="store", type="string", dest="token",
1448 38d247df Kostas Papadimitriou
                      help="The token to use for authentication to the API")
1449 00f87624 Vangelis Koukis
    parser.add_option("--nofailfast",
1450 00f87624 Vangelis Koukis
                      action="store_true", dest="nofailfast",
1451 00f87624 Vangelis Koukis
                      help="Do not fail immediately if one of the tests " \
1452 00f87624 Vangelis Koukis
                           "fails (EXPERIMENTAL)",
1453 bc14ba88 Vangelis Koukis
                      default=False)
1454 946da8b6 John Giannelos
    parser.add_option("--no-ipv6",
1455 946da8b6 John Giannelos
                      action="store_true", dest="no_ipv6",
1456 946da8b6 John Giannelos
                      help="Disables ipv6 related tests",
1457 946da8b6 John Giannelos
                      default=False)
1458 5a140b23 Vangelis Koukis
    parser.add_option("--action-timeout",
1459 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="action_timeout",
1460 5a140b23 Vangelis Koukis
                      metavar="TIMEOUT",
1461 5a140b23 Vangelis Koukis
                      help="Wait SECONDS seconds for a server action to " \
1462 5a140b23 Vangelis Koukis
                           "complete, then the test is considered failed",
1463 9e4682b5 John Giannelos
                      default=100)
1464 5a140b23 Vangelis Koukis
    parser.add_option("--build-warning",
1465 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="build_warning",
1466 5a140b23 Vangelis Koukis
                      metavar="TIMEOUT",
1467 5a140b23 Vangelis Koukis
                      help="Warn if TIMEOUT seconds have passed and a " \
1468 5a140b23 Vangelis Koukis
                           "build operation is still pending",
1469 5a140b23 Vangelis Koukis
                      default=600)
1470 5a140b23 Vangelis Koukis
    parser.add_option("--build-fail",
1471 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="build_fail",
1472 5a140b23 Vangelis Koukis
                      metavar="BUILD_TIMEOUT",
1473 5a140b23 Vangelis Koukis
                      help="Fail the test if TIMEOUT seconds have passed " \
1474 5a140b23 Vangelis Koukis
                           "and a build operation is still incomplete",
1475 5a140b23 Vangelis Koukis
                      default=900)
1476 5a140b23 Vangelis Koukis
    parser.add_option("--query-interval",
1477 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="query_interval",
1478 5a140b23 Vangelis Koukis
                      metavar="INTERVAL",
1479 5a140b23 Vangelis Koukis
                      help="Query server status when requests are pending " \
1480 5a140b23 Vangelis Koukis
                           "every INTERVAL seconds",
1481 5a140b23 Vangelis Koukis
                      default=3)
1482 21bbbc9b Vangelis Koukis
    parser.add_option("--fanout",
1483 21bbbc9b Vangelis Koukis
                      action="store", type="int", dest="fanout",
1484 5a140b23 Vangelis Koukis
                      metavar="COUNT",
1485 21bbbc9b Vangelis Koukis
                      help="Spawn up to COUNT child processes to execute " \
1486 21bbbc9b Vangelis Koukis
                           "in parallel, essentially have up to COUNT " \
1487 00f87624 Vangelis Koukis
                           "server build requests outstanding (EXPERIMENTAL)",
1488 5a140b23 Vangelis Koukis
                      default=1)
1489 5a140b23 Vangelis Koukis
    parser.add_option("--force-flavor",
1490 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="force_flavorid",
1491 5a140b23 Vangelis Koukis
                      metavar="FLAVOR ID",
1492 5a140b23 Vangelis Koukis
                      help="Force all server creations to use the specified "\
1493 5a140b23 Vangelis Koukis
                           "FLAVOR ID instead of a randomly chosen one, " \
1494 5a140b23 Vangelis Koukis
                           "useful if disk space is scarce",
1495 00f87624 Vangelis Koukis
                      default=None)
1496 7f62a0b5 Vangelis Koukis
    parser.add_option("--image-id",
1497 7f62a0b5 Vangelis Koukis
                      action="store", type="string", dest="force_imageid",
1498 00f87624 Vangelis Koukis
                      metavar="IMAGE ID",
1499 7f62a0b5 Vangelis Koukis
                      help="Test the specified image id, use 'all' to test " \
1500 7f62a0b5 Vangelis Koukis
                           "all available images (mandatory argument)",
1501 00f87624 Vangelis Koukis
                      default=None)
1502 5a140b23 Vangelis Koukis
    parser.add_option("--show-stale",
1503 5a140b23 Vangelis Koukis
                      action="store_true", dest="show_stale",
1504 5a140b23 Vangelis Koukis
                      help="Show stale servers from previous runs, whose "\
1505 21bbbc9b Vangelis Koukis
                           "name starts with `%s'" % SNF_TEST_PREFIX,
1506 5a140b23 Vangelis Koukis
                      default=False)
1507 5a140b23 Vangelis Koukis
    parser.add_option("--delete-stale",
1508 5a140b23 Vangelis Koukis
                      action="store_true", dest="delete_stale",
1509 5a140b23 Vangelis Koukis
                      help="Delete stale servers from previous runs, whose "\
1510 21bbbc9b Vangelis Koukis
                           "name starts with `%s'" % SNF_TEST_PREFIX,
1511 5a140b23 Vangelis Koukis
                      default=False)
1512 9659e075 John Giannelos
    parser.add_option("--force-personality",
1513 65462ca9 John Giannelos
                      action="store", type="string", dest="personality_path",
1514 8252d64f John Giannelos
                      help="Force a personality file injection.\
1515 8252d64f John Giannelos
                            File path required. ",
1516 9659e075 John Giannelos
                      default=None)
1517 74ec726f John Giannelos
    parser.add_option("--log-folder",
1518 74ec726f John Giannelos
                      action="store", type="string", dest="log_folder",
1519 8252d64f John Giannelos
                      help="Define the absolute path where the output \
1520 8252d64f John Giannelos
                            log is stored. ",
1521 2bcfb712 John Giannelos
                      default="/var/log/burnin/")
1522 22efe1fe John Giannelos
    parser.add_option("--set-tests",
1523 22efe1fe John Giannelos
                      action="callback",
1524 746540cd John Giannelos
                      dest="tests",
1525 22efe1fe John Giannelos
                      type="string",
1526 22efe1fe John Giannelos
                      help='Set comma seperated tests for this run. \
1527 22efe1fe John Giannelos
                            Available tests: auth, images, flavors, \
1528 746540cd John Giannelos
                                             servers, server_spawn, \
1529 746540cd John Giannelos
                                             network_spawn. \
1530 22efe1fe John Giannelos
                            Default = all',
1531 22efe1fe John Giannelos
                      default='all',
1532 22efe1fe John Giannelos
                      callback=parse_comma)
1533 22efe1fe John Giannelos
1534 5a140b23 Vangelis Koukis
    # FIXME: Change the default for build-fanout to 10
1535 5a140b23 Vangelis Koukis
    # FIXME: Allow the user to specify a specific set of Images to test
1536 5a140b23 Vangelis Koukis
1537 5a140b23 Vangelis Koukis
    (opts, args) = parser.parse_args(args)
1538 5a140b23 Vangelis Koukis
1539 5a140b23 Vangelis Koukis
    # Verify arguments
1540 5a140b23 Vangelis Koukis
    if opts.delete_stale:
1541 5a140b23 Vangelis Koukis
        opts.show_stale = True
1542 5a140b23 Vangelis Koukis
1543 7f62a0b5 Vangelis Koukis
    if not opts.show_stale:
1544 7f62a0b5 Vangelis Koukis
        if not opts.force_imageid:
1545 746540cd John Giannelos
            print >>sys.stderr, red + "The --image-id argument " \
1546 746540cd John Giannelos
                                       "is mandatory.\n" + normal
1547 22efe1fe John Giannelos
            parser.print_help()
1548 22efe1fe John Giannelos
            sys.exit(1)
1549 22efe1fe John Giannelos
1550 22efe1fe John Giannelos
        if not opts.token:
1551 746540cd John Giannelos
            print >>sys.stderr, red + "The --token argument is " \
1552 746540cd John Giannelos
                                      "mandatory.\n" + normal
1553 7f62a0b5 Vangelis Koukis
            parser.print_help()
1554 7f62a0b5 Vangelis Koukis
            sys.exit(1)
1555 7f62a0b5 Vangelis Koukis
1556 7f62a0b5 Vangelis Koukis
        if opts.force_imageid != 'all':
1557 7f62a0b5 Vangelis Koukis
            try:
1558 99d41650 John Giannelos
                opts.force_imageid = str(opts.force_imageid)
1559 7f62a0b5 Vangelis Koukis
            except ValueError:
1560 746540cd John Giannelos
                print >>sys.stderr, red + "Invalid value specified for" \
1561 746540cd John Giannelos
                    "--image-id. Use a valid id, or `all'." + normal
1562 7f62a0b5 Vangelis Koukis
                sys.exit(1)
1563 7f62a0b5 Vangelis Koukis
1564 5a140b23 Vangelis Koukis
    return (opts, args)
1565 5a140b23 Vangelis Koukis
1566 5a140b23 Vangelis Koukis
1567 5a140b23 Vangelis Koukis
def main():
1568 5a140b23 Vangelis Koukis
    """Assemble test cases into a test suite, and run it
1569 5a140b23 Vangelis Koukis

1570 5a140b23 Vangelis Koukis
    IMPORTANT: Tests have dependencies and have to be run in the specified
1571 5a140b23 Vangelis Koukis
    order inside a single test case. They communicate through attributes of the
1572 21bbbc9b Vangelis Koukis
    corresponding TestCase class (shared fixtures). Distinct subclasses of
1573 21bbbc9b Vangelis Koukis
    TestCase MAY SHARE NO DATA, since they are run in parallel, in distinct
1574 21bbbc9b Vangelis Koukis
    test runner processes.
1575 5a140b23 Vangelis Koukis

1576 5a140b23 Vangelis Koukis
    """
1577 ae139e8a John Giannelos
1578 5a140b23 Vangelis Koukis
    (opts, args) = parse_arguments(sys.argv[1:])
1579 5a140b23 Vangelis Koukis
1580 946da8b6 John Giannelos
    global API, TOKEN, PLANKTON, PLANKTON_USER, NO_IPV6
1581 21bbbc9b Vangelis Koukis
    API = opts.api
1582 21bbbc9b Vangelis Koukis
    TOKEN = opts.token
1583 946da8b6 John Giannelos
    PLANKTON = opts.plankton
1584 946da8b6 John Giannelos
    PLANKTON_USER = opts.plankton_user
1585 946da8b6 John Giannelos
    NO_IPV6 = opts.no_ipv6
1586 21bbbc9b Vangelis Koukis
1587 5a140b23 Vangelis Koukis
    # Cleanup stale servers from previous runs
1588 5a140b23 Vangelis Koukis
    if opts.show_stale:
1589 c0448f4f John Giannelos
        cleanup_servers(delete_stale=opts.delete_stale, timeout=opts.action_timeout, query_interval=opts.query_interval)
1590 c0448f4f John Giannelos
        cleanup_networks(delete_stale=opts.delete_stale, timeout=opts.action_timeout, query_interval=opts.query_interval)
1591 74ec726f John Giannelos
        return 0
1592 5a140b23 Vangelis Koukis
1593 5a140b23 Vangelis Koukis
    # Initialize a kamaki instance, get flavors, images
1594 96da37c8 John Giannelos
    c = ComputeClient(API, TOKEN)
1595 74193008 John Giannelos
1596 5a140b23 Vangelis Koukis
    DIMAGES = c.list_images(detail=True)
1597 5a140b23 Vangelis Koukis
    DFLAVORS = c.list_flavors(detail=True)
1598 5a140b23 Vangelis Koukis
1599 21bbbc9b Vangelis Koukis
    # FIXME: logging, log, LOG PID, TEST_RUN_ID, arguments
1600 5a140b23 Vangelis Koukis
    # Run them: FIXME: In parallel, FAILEARLY, catchbreak?
1601 5a140b23 Vangelis Koukis
    #unittest.main(verbosity=2, catchbreak=True)
1602 5a140b23 Vangelis Koukis
1603 e94a9d8c John Giannelos
    if opts.force_imageid == 'all':
1604 e94a9d8c John Giannelos
        test_images = DIMAGES
1605 e94a9d8c John Giannelos
    else:
1606 e94a9d8c John Giannelos
        test_images = filter(lambda x: x["id"] == opts.force_imageid, DIMAGES)
1607 e94a9d8c John Giannelos
1608 81e8cbf6 John Giannelos
    #New folder for log per image
1609 74ec726f John Giannelos
    if not os.path.exists(opts.log_folder):
1610 74ec726f John Giannelos
        os.mkdir(opts.log_folder)
1611 74ec726f John Giannelos
1612 2bcfb712 John Giannelos
    test_folder = os.path.join(opts.log_folder, TEST_RUN_ID)
1613 74ec726f John Giannelos
    os.mkdir(test_folder)
1614 81e8cbf6 John Giannelos
1615 00f87624 Vangelis Koukis
    for image in test_images:
1616 8252d64f John Giannelos
1617 99d41650 John Giannelos
        imageid = str(image["id"])
1618 8252d64f John Giannelos
1619 81e8cbf6 John Giannelos
        if opts.force_flavorid:
1620 81e8cbf6 John Giannelos
            flavorid = opts.force_flavorid
1621 81e8cbf6 John Giannelos
        else:
1622 81e8cbf6 John Giannelos
            flavorid = choice([f["id"] for f in DFLAVORS if f["disk"] >= 20])
1623 81e8cbf6 John Giannelos
1624 21bbbc9b Vangelis Koukis
        imagename = image["name"]
1625 8252d64f John Giannelos
1626 567ffb85 John Giannelos
        #Personality dictionary for file injection test
1627 9659e075 John Giannelos
        if opts.personality_path != None:
1628 9659e075 John Giannelos
            f = open(opts.personality_path)
1629 9659e075 John Giannelos
            content = b64encode(f.read())
1630 9659e075 John Giannelos
            personality = []
1631 9659e075 John Giannelos
            st = os.stat(opts.personality_path)
1632 9659e075 John Giannelos
            personality.append({
1633 9659e075 John Giannelos
                    'path': '/root/test_inj_file',
1634 9659e075 John Giannelos
                    'owner': 'root',
1635 9659e075 John Giannelos
                    'group': 'root',
1636 9659e075 John Giannelos
                    'mode': 0x7777 & st.st_mode,
1637 9659e075 John Giannelos
                    'contents': content
1638 9659e075 John Giannelos
                    })
1639 9659e075 John Giannelos
        else:
1640 9659e075 John Giannelos
            personality = None
1641 9659e075 John Giannelos
1642 21bbbc9b Vangelis Koukis
        servername = "%s%s for %s" % (SNF_TEST_PREFIX, TEST_RUN_ID, imagename)
1643 21bbbc9b Vangelis Koukis
        is_windows = imagename.lower().find("windows") >= 0
1644 8252d64f John Giannelos
1645 8252d64f John Giannelos
        ServerTestCase = _spawn_server_test_case(
1646 8252d64f John Giannelos
            imageid=imageid,
1647 8252d64f John Giannelos
            flavorid=flavorid,
1648 8252d64f John Giannelos
            imagename=imagename,
1649 8252d64f John Giannelos
            personality=personality,
1650 8252d64f John Giannelos
            servername=servername,
1651 8252d64f John Giannelos
            is_windows=is_windows,
1652 8252d64f John Giannelos
            action_timeout=opts.action_timeout,
1653 8252d64f John Giannelos
            build_warning=opts.build_warning,
1654 8252d64f John Giannelos
            build_fail=opts.build_fail,
1655 8252d64f John Giannelos
            query_interval=opts.query_interval,
1656 8252d64f John Giannelos
            )
1657 8252d64f John Giannelos
1658 8252d64f John Giannelos
        NetworkTestCase = _spawn_network_test_case(
1659 8252d64f John Giannelos
            action_timeout=opts.action_timeout,
1660 8252d64f John Giannelos
            imageid=imageid,
1661 8252d64f John Giannelos
            flavorid=flavorid,
1662 8252d64f John Giannelos
            imagename=imagename,
1663 8252d64f John Giannelos
            query_interval=opts.query_interval,
1664 8252d64f John Giannelos
            )
1665 8252d64f John Giannelos
1666 746540cd John Giannelos
        test_dict = {'auth': UnauthorizedTestCase,
1667 746540cd John Giannelos
                     'images': ImagesTestCase,
1668 746540cd John Giannelos
                     'flavors': FlavorsTestCase,
1669 746540cd John Giannelos
                     'servers': ServersTestCase,
1670 746540cd John Giannelos
                     'server_spawn': ServerTestCase,
1671 746540cd John Giannelos
                     'network_spawn': NetworkTestCase}
1672 22efe1fe John Giannelos
1673 22efe1fe John Giannelos
        seq_cases = []
1674 22efe1fe John Giannelos
        if 'all' in opts.tests:
1675 22efe1fe John Giannelos
            seq_cases = [UnauthorizedTestCase, ImagesTestCase, FlavorsTestCase,
1676 22efe1fe John Giannelos
                         ServersTestCase, ServerTestCase, NetworkTestCase]
1677 22efe1fe John Giannelos
        else:
1678 22efe1fe John Giannelos
            for test in opts.tests:
1679 22efe1fe John Giannelos
                seq_cases.append(test_dict[test])
1680 22efe1fe John Giannelos
1681 8252d64f John Giannelos
        #folder for each image
1682 2bcfb712 John Giannelos
        image_folder = os.path.join(test_folder, imageid)
1683 81e8cbf6 John Giannelos
        os.mkdir(image_folder)
1684 81e8cbf6 John Giannelos
1685 81e8cbf6 John Giannelos
        for case in seq_cases:
1686 746540cd John Giannelos
1687 746540cd John Giannelos
            test = (key for key, value in test_dict.items()
1688 746540cd John Giannelos
                    if value == case).next()
1689 746540cd John Giannelos
1690 746540cd John Giannelos
            log.info(yellow + '* Starting testcase: %s' %test + normal)
1691 8252d64f John Giannelos
            log_file = os.path.join(image_folder, 'details_' +
1692 8252d64f John Giannelos
                                    (case.__name__) + "_" +
1693 8252d64f John Giannelos
                                    TEST_RUN_ID + '.log')
1694 8252d64f John Giannelos
            fail_file = os.path.join(image_folder, 'failed_' +
1695 8252d64f John Giannelos
                                     (case.__name__) + "_" +
1696 8252d64f John Giannelos
                                     TEST_RUN_ID + '.log')
1697 8252d64f John Giannelos
            error_file = os.path.join(image_folder, 'error_' +
1698 8252d64f John Giannelos
                                      (case.__name__) + "_" +
1699 8252d64f John Giannelos
                                      TEST_RUN_ID + '.log')
1700 81e8cbf6 John Giannelos
1701 81e8cbf6 John Giannelos
            f = open(log_file, "w")
1702 81e8cbf6 John Giannelos
            fail = open(fail_file, "w")
1703 81e8cbf6 John Giannelos
            error = open(error_file, "w")
1704 81e8cbf6 John Giannelos
1705 81e8cbf6 John Giannelos
            suite = unittest.TestLoader().loadTestsFromTestCase(case)
1706 8252d64f John Giannelos
            runner = unittest.TextTestRunner(f, verbosity=2, failfast=True)
1707 81e8cbf6 John Giannelos
            result = runner.run(suite)
1708 8252d64f John Giannelos
1709 81e8cbf6 John Giannelos
            for res in result.errors:
1710 746540cd John Giannelos
                log.error("snf-burnin encountered an error in " \
1711 746540cd John Giannelos
                              "testcase: %s" %test)
1712 746540cd John Giannelos
                log.error("See log for details")
1713 2bcfb712 John Giannelos
                error.write(str(res[0]) + '\n')
1714 74ec726f John Giannelos
                error.write(str(res[0].shortDescription()) + '\n')
1715 81e8cbf6 John Giannelos
                error.write('\n')
1716 4d6e355c John Giannelos
1717 aa388d48 John Giannelos
            for res in result.failures:
1718 746540cd John Giannelos
                log.error("snf-burnin failed in testcase: %s" %test)
1719 746540cd John Giannelos
                log.error("See log for details")
1720 2bcfb712 John Giannelos
                fail.write(str(res[0]) + '\n')
1721 74ec726f John Giannelos
                fail.write(str(res[0].shortDescription()) + '\n')
1722 aa388d48 John Giannelos
                fail.write('\n')
1723 e8a6a168 John Giannelos
                if opts.nofailfast == False:
1724 e8a6a168 John Giannelos
                    sys.exit()
1725 8252d64f John Giannelos
1726 746540cd John Giannelos
            if (len(result.failures) == 0) and (len(result.errors) == 0):
1727 746540cd John Giannelos
                log.debug("Passed testcase: %s" %test)
1728 746540cd John Giannelos
1729 5a140b23 Vangelis Koukis
if __name__ == "__main__":
1730 5a140b23 Vangelis Koukis
    sys.exit(main())