Statistics
| Branch: | Tag: | Revision:

root / snf-tools / synnefo_tools / burnin.py @ 139d3a0b

History | View | Annotate | Download (70.1 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 6e168615 Ilias Tsitsimpis
#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 bc14ba88 Vangelis Koukis
from vncauthproxy.d3des import generate_response as d3des_generate_response
62 5a140b23 Vangelis Koukis
63 5a140b23 Vangelis Koukis
# Use backported unittest functionality if Python < 2.7
64 5a140b23 Vangelis Koukis
try:
65 5a140b23 Vangelis Koukis
    import unittest2 as unittest
66 5a140b23 Vangelis Koukis
except ImportError:
67 bc14ba88 Vangelis Koukis
    if sys.version_info < (2, 7):
68 bc14ba88 Vangelis Koukis
        raise Exception("The unittest2 package is required for Python < 2.7")
69 5a140b23 Vangelis Koukis
    import unittest
70 5a140b23 Vangelis Koukis
71 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
72 6e168615 Ilias Tsitsimpis
# Global Variables
73 6e168615 Ilias Tsitsimpis
API = None
74 6e168615 Ilias Tsitsimpis
TOKEN = None
75 6e168615 Ilias Tsitsimpis
PLANKTON = None
76 6e168615 Ilias Tsitsimpis
PLANKTON_USER = None
77 6e168615 Ilias Tsitsimpis
NO_IPV6 = None
78 6e168615 Ilias Tsitsimpis
DEFAULT_API = "https://cyclades.okeanos.grnet.gr/api/v1.1"
79 6e168615 Ilias Tsitsimpis
DEFAULT_PLANKTON = "https://cyclades.okeanos.grnet.gr/plankton"
80 6e168615 Ilias Tsitsimpis
DEFAULT_PLANKTON_USER = "images@okeanos.grnet.gr"
81 6e168615 Ilias Tsitsimpis
NOFAILFAST = None
82 6e168615 Ilias Tsitsimpis
VERBOSE = None
83 6e168615 Ilias Tsitsimpis
84 6e168615 Ilias Tsitsimpis
# A unique id identifying this test run
85 6e168615 Ilias Tsitsimpis
TEST_RUN_ID = datetime.datetime.strftime(datetime.datetime.now(),
86 6e168615 Ilias Tsitsimpis
                                         "%Y%m%d%H%M%S")
87 6e168615 Ilias Tsitsimpis
SNF_TEST_PREFIX = "snf-test-"
88 6e168615 Ilias Tsitsimpis
89 6e168615 Ilias Tsitsimpis
red = '\x1b[31m'
90 6e168615 Ilias Tsitsimpis
yellow = '\x1b[33m'
91 6e168615 Ilias Tsitsimpis
green = '\x1b[32m'
92 6e168615 Ilias Tsitsimpis
normal = '\x1b[0m'
93 6e168615 Ilias Tsitsimpis
94 5a140b23 Vangelis Koukis
95 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
96 2a410f76 Ilias Tsitsimpis
# Global functions
97 2a410f76 Ilias Tsitsimpis
def _ssh_execute(hostip, username, password, command):
98 2a410f76 Ilias Tsitsimpis
    """Execute a command via ssh"""
99 2a410f76 Ilias Tsitsimpis
    ssh = paramiko.SSHClient()
100 2a410f76 Ilias Tsitsimpis
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
101 2a410f76 Ilias Tsitsimpis
    try:
102 2a410f76 Ilias Tsitsimpis
        ssh.connect(hostip, username=username, password=password)
103 2a410f76 Ilias Tsitsimpis
    except socket.error:
104 2a410f76 Ilias Tsitsimpis
        raise AssertionError
105 2a410f76 Ilias Tsitsimpis
    try:
106 2a410f76 Ilias Tsitsimpis
        stdin, stdout, stderr = ssh.exec_command(command)
107 2a410f76 Ilias Tsitsimpis
    except paramiko.SSHException:
108 2a410f76 Ilias Tsitsimpis
        raise AssertionError
109 2a410f76 Ilias Tsitsimpis
    status = stdout.channel.recv_exit_status()
110 2a410f76 Ilias Tsitsimpis
    output = stdout.readlines()
111 2a410f76 Ilias Tsitsimpis
    ssh.close()
112 2a410f76 Ilias Tsitsimpis
    return output, status
113 2a410f76 Ilias Tsitsimpis
114 2a410f76 Ilias Tsitsimpis
115 2a410f76 Ilias Tsitsimpis
# --------------------------------------------------------------------
116 6e168615 Ilias Tsitsimpis
# BurninTestReulst class
117 66eba2cf John Giannelos
class BurninTestResult(unittest.TextTestResult):
118 66eba2cf John Giannelos
    def addSuccess(self, test):
119 66eba2cf John Giannelos
        super(BurninTestResult, self).addSuccess(test)
120 66eba2cf John Giannelos
        if self.showAll:
121 3e4c5c32 John Giannelos
            if hasattr(test, 'result_dict'):
122 66eba2cf John Giannelos
                run_details = test.result_dict
123 66eba2cf John Giannelos
124 66eba2cf John Giannelos
                self.stream.write("\n")
125 66eba2cf John Giannelos
                for i in run_details:
126 66eba2cf John Giannelos
                    self.stream.write("%s : %s \n" % (i, run_details[i]))
127 66eba2cf John Giannelos
                self.stream.write("\n")
128 66eba2cf John Giannelos
129 66eba2cf John Giannelos
        elif self.dots:
130 66eba2cf John Giannelos
            self.stream.write('.')
131 6e168615 Ilias Tsitsimpis
            self.stream.flush()
132 6e168615 Ilias Tsitsimpis
133 66eba2cf John Giannelos
    def addError(self, test, err):
134 66eba2cf John Giannelos
        super(BurninTestResult, self).addError(test, err)
135 66eba2cf John Giannelos
        if self.showAll:
136 66eba2cf John Giannelos
            self.stream.writeln("ERROR")
137 3e4c5c32 John Giannelos
            if hasattr(test, 'result_dict'):
138 3e4c5c32 John Giannelos
                run_details = test.result_dict
139 66eba2cf John Giannelos
140 3e4c5c32 John Giannelos
                self.stream.write("\n")
141 3e4c5c32 John Giannelos
                for i in run_details:
142 3e4c5c32 John Giannelos
                    self.stream.write("%s : %s \n" % (i, run_details[i]))
143 3e4c5c32 John Giannelos
                self.stream.write("\n")
144 66eba2cf John Giannelos
145 66eba2cf John Giannelos
        elif self.dots:
146 66eba2cf John Giannelos
            self.stream.write('E')
147 66eba2cf John Giannelos
            self.stream.flush()
148 66eba2cf John Giannelos
149 66eba2cf John Giannelos
    def addFailure(self, test, err):
150 66eba2cf John Giannelos
        super(BurninTestResult, self).addFailure(test, err)
151 66eba2cf John Giannelos
        if self.showAll:
152 66eba2cf John Giannelos
            self.stream.writeln("FAIL")
153 3e4c5c32 John Giannelos
            if hasattr(test, 'result_dict'):
154 3e4c5c32 John Giannelos
                run_details = test.result_dict
155 66eba2cf John Giannelos
156 3e4c5c32 John Giannelos
                self.stream.write("\n")
157 3e4c5c32 John Giannelos
                for i in run_details:
158 3e4c5c32 John Giannelos
                    self.stream.write("%s : %s \n" % (i, run_details[i]))
159 3e4c5c32 John Giannelos
                self.stream.write("\n")
160 66eba2cf John Giannelos
161 66eba2cf John Giannelos
        elif self.dots:
162 66eba2cf John Giannelos
            self.stream.write('F')
163 66eba2cf John Giannelos
            self.stream.flush()
164 66eba2cf John Giannelos
165 66eba2cf John Giannelos
166 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
167 6e168615 Ilias Tsitsimpis
# Format Results
168 746540cd John Giannelos
class burninFormatter(logging.Formatter):
169 746540cd John Giannelos
    err_fmt = red + "ERROR: %(msg)s" + normal
170 9b013c3a John Giannelos
    dbg_fmt = green + "* %(msg)s" + normal
171 746540cd John Giannelos
    info_fmt = "%(msg)s"
172 746540cd John Giannelos
173 746540cd John Giannelos
    def __init__(self, fmt="%(levelno)s: %(msg)s"):
174 746540cd John Giannelos
        logging.Formatter.__init__(self, fmt)
175 746540cd John Giannelos
176 746540cd John Giannelos
    def format(self, record):
177 746540cd John Giannelos
        format_orig = self._fmt
178 746540cd John Giannelos
        # Replace the original format with one customized by logging level
179 746540cd John Giannelos
        if record.levelno == 10:    # DEBUG
180 746540cd John Giannelos
            self._fmt = burninFormatter.dbg_fmt
181 746540cd John Giannelos
        elif record.levelno == 20:  # INFO
182 746540cd John Giannelos
            self._fmt = burninFormatter.info_fmt
183 746540cd John Giannelos
        elif record.levelno == 40:  # ERROR
184 746540cd John Giannelos
            self._fmt = burninFormatter.err_fmt
185 746540cd John Giannelos
        result = logging.Formatter.format(self, record)
186 746540cd John Giannelos
        self._fmt = format_orig
187 746540cd John Giannelos
        return result
188 746540cd John Giannelos
189 00f87624 Vangelis Koukis
log = logging.getLogger("burnin")
190 746540cd John Giannelos
log.setLevel(logging.DEBUG)
191 746540cd John Giannelos
handler = logging.StreamHandler()
192 746540cd John Giannelos
handler.setFormatter(burninFormatter())
193 746540cd John Giannelos
log.addHandler(handler)
194 5a140b23 Vangelis Koukis
195 2bcfb712 John Giannelos
196 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
197 6e168615 Ilias Tsitsimpis
# UnauthorizedTestCase class
198 5a140b23 Vangelis Koukis
class UnauthorizedTestCase(unittest.TestCase):
199 6e168615 Ilias Tsitsimpis
    """Test unauthorized access"""
200 66eba2cf John Giannelos
    @classmethod
201 66eba2cf John Giannelos
    def setUpClass(cls):
202 66eba2cf John Giannelos
        cls.result_dict = dict()
203 66eba2cf John Giannelos
204 5a140b23 Vangelis Koukis
    def test_unauthorized_access(self):
205 5a140b23 Vangelis Koukis
        """Test access without a valid token fails"""
206 81e8cbf6 John Giannelos
        log.info("Authentication test")
207 1c636ad6 John Giannelos
        falseToken = '12345'
208 2bcfb712 John Giannelos
        c = ComputeClient(API, falseToken)
209 1c636ad6 John Giannelos
210 5a140b23 Vangelis Koukis
        with self.assertRaises(ClientError) as cm:
211 5a140b23 Vangelis Koukis
            c.list_servers()
212 21dcb666 John Giannelos
            self.assertEqual(cm.exception.status, 401)
213 5a140b23 Vangelis Koukis
214 5a140b23 Vangelis Koukis
215 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
216 6e168615 Ilias Tsitsimpis
# ImagesTestCase class
217 5a140b23 Vangelis Koukis
class ImagesTestCase(unittest.TestCase):
218 5a140b23 Vangelis Koukis
    """Test image lists for consistency"""
219 5a140b23 Vangelis Koukis
    @classmethod
220 5a140b23 Vangelis Koukis
    def setUpClass(cls):
221 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of images"""
222 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of images")
223 846980fe John Giannelos
        cls.client = ComputeClient(API, TOKEN)
224 946da8b6 John Giannelos
        cls.plankton = ImageClient(PLANKTON, TOKEN)
225 946da8b6 John Giannelos
        cls.images = cls.plankton.list_public()
226 946da8b6 John Giannelos
        cls.dimages = cls.plankton.list_public(detail=True)
227 66eba2cf John Giannelos
        cls.result_dict = dict()
228 5a140b23 Vangelis Koukis
229 5a140b23 Vangelis Koukis
    def test_001_list_images(self):
230 5a140b23 Vangelis Koukis
        """Test image list actually returns images"""
231 6207533f John Giannelos
        self.assertGreater(len(self.images), 0)
232 74ec726f John Giannelos
233 5a140b23 Vangelis Koukis
    def test_002_list_images_detailed(self):
234 5a140b23 Vangelis Koukis
        """Test detailed image list is the same length as list"""
235 6207533f John Giannelos
        self.assertEqual(len(self.dimages), len(self.images))
236 74ec726f John Giannelos
237 5a140b23 Vangelis Koukis
    def test_003_same_image_names(self):
238 5a140b23 Vangelis Koukis
        """Test detailed and simple image list contain same names"""
239 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.images))
240 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dimages))
241 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
242 5a140b23 Vangelis Koukis
243 5a140b23 Vangelis Koukis
    def test_004_unique_image_names(self):
244 946da8b6 John Giannelos
        """Test system images have unique names"""
245 946da8b6 John Giannelos
        sys_images = filter(lambda x: x['owner'] == PLANKTON_USER,
246 946da8b6 John Giannelos
                            self.dimages)
247 946da8b6 John Giannelos
        names = sorted(map(lambda x: x["name"], sys_images))
248 5a140b23 Vangelis Koukis
        self.assertEqual(sorted(list(set(names))), names)
249 5a140b23 Vangelis Koukis
250 5a140b23 Vangelis Koukis
    def test_005_image_metadata(self):
251 5a140b23 Vangelis Koukis
        """Test every image has specific metadata defined"""
252 2e3b7dc8 John Giannelos
        keys = frozenset(["osfamily", "root_partition"])
253 846980fe John Giannelos
        details = self.client.list_images(detail=True)
254 846980fe John Giannelos
        for i in details:
255 5a140b23 Vangelis Koukis
            self.assertTrue(keys.issubset(i["metadata"]["values"].keys()))
256 5a140b23 Vangelis Koukis
257 5a140b23 Vangelis Koukis
258 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
259 6e168615 Ilias Tsitsimpis
# FlavorsTestCase class
260 5a140b23 Vangelis Koukis
class FlavorsTestCase(unittest.TestCase):
261 5a140b23 Vangelis Koukis
    """Test flavor lists for consistency"""
262 5a140b23 Vangelis Koukis
    @classmethod
263 5a140b23 Vangelis Koukis
    def setUpClass(cls):
264 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of flavors"""
265 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of flavors")
266 567ffb85 John Giannelos
        cls.client = ComputeClient(API, TOKEN)
267 5a140b23 Vangelis Koukis
        cls.flavors = cls.client.list_flavors()
268 5a140b23 Vangelis Koukis
        cls.dflavors = cls.client.list_flavors(detail=True)
269 66eba2cf John Giannelos
        cls.result_dict = dict()
270 5a140b23 Vangelis Koukis
271 5a140b23 Vangelis Koukis
    def test_001_list_flavors(self):
272 5a140b23 Vangelis Koukis
        """Test flavor list actually returns flavors"""
273 5a140b23 Vangelis Koukis
        self.assertGreater(len(self.flavors), 0)
274 5a140b23 Vangelis Koukis
275 5a140b23 Vangelis Koukis
    def test_002_list_flavors_detailed(self):
276 5a140b23 Vangelis Koukis
        """Test detailed flavor list is the same length as list"""
277 5a140b23 Vangelis Koukis
        self.assertEquals(len(self.dflavors), len(self.flavors))
278 5a140b23 Vangelis Koukis
279 5a140b23 Vangelis Koukis
    def test_003_same_flavor_names(self):
280 5a140b23 Vangelis Koukis
        """Test detailed and simple flavor list contain same names"""
281 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.flavors))
282 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dflavors))
283 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
284 5a140b23 Vangelis Koukis
285 5a140b23 Vangelis Koukis
    def test_004_unique_flavor_names(self):
286 5a140b23 Vangelis Koukis
        """Test flavors have unique names"""
287 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.flavors))
288 5a140b23 Vangelis Koukis
        self.assertEqual(sorted(list(set(names))), names)
289 5a140b23 Vangelis Koukis
290 5a140b23 Vangelis Koukis
    def test_005_well_formed_flavor_names(self):
291 5a140b23 Vangelis Koukis
        """Test flavors have names of the form CxxRyyDzz
292 5a140b23 Vangelis Koukis
        Where xx is vCPU count, yy is RAM in MiB, zz is Disk in GiB
293 5a140b23 Vangelis Koukis
        """
294 5a140b23 Vangelis Koukis
        for f in self.dflavors:
295 5a140b23 Vangelis Koukis
            self.assertEqual("C%dR%dD%d" % (f["cpu"], f["ram"], f["disk"]),
296 5a140b23 Vangelis Koukis
                             f["name"],
297 5a140b23 Vangelis Koukis
                             "Flavor %s does not match its specs." % f["name"])
298 5a140b23 Vangelis Koukis
299 5a140b23 Vangelis Koukis
300 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
301 6e168615 Ilias Tsitsimpis
# ServersTestCase class
302 5a140b23 Vangelis Koukis
class ServersTestCase(unittest.TestCase):
303 5a140b23 Vangelis Koukis
    """Test server lists for consistency"""
304 5a140b23 Vangelis Koukis
    @classmethod
305 5a140b23 Vangelis Koukis
    def setUpClass(cls):
306 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of servers"""
307 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of servers")
308 1c636ad6 John Giannelos
309 567ffb85 John Giannelos
        cls.client = ComputeClient(API, TOKEN)
310 5a140b23 Vangelis Koukis
        cls.servers = cls.client.list_servers()
311 5a140b23 Vangelis Koukis
        cls.dservers = cls.client.list_servers(detail=True)
312 66eba2cf John Giannelos
        cls.result_dict = dict()
313 5a140b23 Vangelis Koukis
314 139d3a0b Ilias Tsitsimpis
    # def test_001_list_servers(self):
315 139d3a0b Ilias Tsitsimpis
    #     """Test server list actually returns servers"""
316 139d3a0b Ilias Tsitsimpis
    #     self.assertGreater(len(self.servers), 0)
317 5a140b23 Vangelis Koukis
318 5a140b23 Vangelis Koukis
    def test_002_list_servers_detailed(self):
319 5a140b23 Vangelis Koukis
        """Test detailed server list is the same length as list"""
320 5a140b23 Vangelis Koukis
        self.assertEqual(len(self.dservers), len(self.servers))
321 5a140b23 Vangelis Koukis
322 5a140b23 Vangelis Koukis
    def test_003_same_server_names(self):
323 5a140b23 Vangelis Koukis
        """Test detailed and simple flavor list contain same names"""
324 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.servers))
325 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dservers))
326 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
327 5a140b23 Vangelis Koukis
328 5a140b23 Vangelis Koukis
329 5a140b23 Vangelis Koukis
# This class gets replicated into actual TestCases dynamically
330 5a140b23 Vangelis Koukis
class SpawnServerTestCase(unittest.TestCase):
331 5a140b23 Vangelis Koukis
    """Test scenario for server of the specified image"""
332 5a140b23 Vangelis Koukis
333 5a140b23 Vangelis Koukis
    @classmethod
334 5a140b23 Vangelis Koukis
    def setUpClass(cls):
335 5a140b23 Vangelis Koukis
        """Initialize a kamaki instance"""
336 6e168615 Ilias Tsitsimpis
        log.info("Spawning server for image `%s'" % cls.imagename)
337 567ffb85 John Giannelos
        cls.client = ComputeClient(API, TOKEN)
338 567ffb85 John Giannelos
        cls.cyclades = CycladesClient(API, TOKEN)
339 66eba2cf John Giannelos
        cls.result_dict = dict()
340 5a140b23 Vangelis Koukis
341 5a140b23 Vangelis Koukis
    def _get_ipv4(self, server):
342 bc14ba88 Vangelis Koukis
        """Get the public IPv4 of a server from the detailed server info"""
343 1c636ad6 John Giannelos
344 e50133da John Giannelos
        nics = server["attachments"]["values"]
345 2aaa1336 John Giannelos
346 e50133da John Giannelos
        for nic in nics:
347 e50133da John Giannelos
            net_id = nic["network_id"]
348 6e168615 Ilias Tsitsimpis
            if self.cyclades.get_network_details(net_id)["public"]:
349 e50133da John Giannelos
                public_addrs = nic["ipv4"]
350 6e168615 Ilias Tsitsimpis
351 6e168615 Ilias Tsitsimpis
        self.assertTrue(public_addrs is not None)
352 2aaa1336 John Giannelos
353 e50133da John Giannelos
        return public_addrs
354 5a140b23 Vangelis Koukis
355 5a140b23 Vangelis Koukis
    def _get_ipv6(self, server):
356 bc14ba88 Vangelis Koukis
        """Get the public IPv6 of a server from the detailed server info"""
357 2aaa1336 John Giannelos
358 e50133da John Giannelos
        nics = server["attachments"]["values"]
359 2aaa1336 John Giannelos
360 e50133da John Giannelos
        for nic in nics:
361 e50133da John Giannelos
            net_id = nic["network_id"]
362 6e168615 Ilias Tsitsimpis
            if self.cyclades.get_network_details(net_id)["public"]:
363 e50133da John Giannelos
                public_addrs = nic["ipv6"]
364 2aaa1336 John Giannelos
365 6e168615 Ilias Tsitsimpis
        self.assertTrue(public_addrs is not None)
366 2aaa1336 John Giannelos
367 6e168615 Ilias Tsitsimpis
        return public_addrs
368 5a140b23 Vangelis Koukis
369 6e168615 Ilias Tsitsimpis
    def _connect_loginname(self, os_value):
370 bc14ba88 Vangelis Koukis
        """Return the login name for connections based on the server OS"""
371 6e168615 Ilias Tsitsimpis
        if os_value in ("Ubuntu", "Kubuntu", "Fedora"):
372 21bbbc9b Vangelis Koukis
            return "user"
373 6e168615 Ilias Tsitsimpis
        elif os_value in ("windows", "windows_alpha1"):
374 21bbbc9b Vangelis Koukis
            return "Administrator"
375 bc14ba88 Vangelis Koukis
        else:
376 21bbbc9b Vangelis Koukis
            return "root"
377 bc14ba88 Vangelis Koukis
378 bc14ba88 Vangelis Koukis
    def _verify_server_status(self, current_status, new_status):
379 bc14ba88 Vangelis Koukis
        """Verify a server has switched to a specified status"""
380 bc14ba88 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
381 21bbbc9b Vangelis Koukis
        if server["status"] not in (current_status, new_status):
382 21bbbc9b Vangelis Koukis
            return None  # Do not raise exception, return so the test fails
383 bc14ba88 Vangelis Koukis
        self.assertEquals(server["status"], new_status)
384 bc14ba88 Vangelis Koukis
385 bc14ba88 Vangelis Koukis
    def _get_connected_tcp_socket(self, family, host, port):
386 bc14ba88 Vangelis Koukis
        """Get a connected socket from the specified family to host:port"""
387 bc14ba88 Vangelis Koukis
        sock = None
388 bc14ba88 Vangelis Koukis
        for res in \
389 bc14ba88 Vangelis Koukis
            socket.getaddrinfo(host, port, family, socket.SOCK_STREAM, 0,
390 bc14ba88 Vangelis Koukis
                               socket.AI_PASSIVE):
391 bc14ba88 Vangelis Koukis
            af, socktype, proto, canonname, sa = res
392 bc14ba88 Vangelis Koukis
            try:
393 bc14ba88 Vangelis Koukis
                sock = socket.socket(af, socktype, proto)
394 6e168615 Ilias Tsitsimpis
            except socket.error:
395 bc14ba88 Vangelis Koukis
                sock = None
396 bc14ba88 Vangelis Koukis
                continue
397 bc14ba88 Vangelis Koukis
            try:
398 bc14ba88 Vangelis Koukis
                sock.connect(sa)
399 6e168615 Ilias Tsitsimpis
            except socket.error:
400 bc14ba88 Vangelis Koukis
                sock.close()
401 bc14ba88 Vangelis Koukis
                sock = None
402 bc14ba88 Vangelis Koukis
                continue
403 bc14ba88 Vangelis Koukis
        self.assertIsNotNone(sock)
404 bc14ba88 Vangelis Koukis
        return sock
405 bc14ba88 Vangelis Koukis
406 bc14ba88 Vangelis Koukis
    def _ping_once(self, ipv6, ip):
407 bc14ba88 Vangelis Koukis
        """Test server responds to a single IPv4 or IPv6 ping"""
408 bc14ba88 Vangelis Koukis
        cmd = "ping%s -c 2 -w 3 %s" % ("6" if ipv6 else "", ip)
409 bc14ba88 Vangelis Koukis
        ping = subprocess.Popen(cmd, shell=True,
410 bc14ba88 Vangelis Koukis
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
411 bc14ba88 Vangelis Koukis
        (stdout, stderr) = ping.communicate()
412 bc14ba88 Vangelis Koukis
        ret = ping.wait()
413 bc14ba88 Vangelis Koukis
        self.assertEquals(ret, 0)
414 5a140b23 Vangelis Koukis
415 bc14ba88 Vangelis Koukis
    def _get_hostname_over_ssh(self, hostip, username, password):
416 2a410f76 Ilias Tsitsimpis
        lines, status = _ssh_execute(
417 2a410f76 Ilias Tsitsimpis
            hostip, username, password, "hostname")
418 bc14ba88 Vangelis Koukis
        self.assertEqual(len(lines), 1)
419 4fdd25ab Vangelis Koukis
        return lines[0]
420 bc14ba88 Vangelis Koukis
421 bc14ba88 Vangelis Koukis
    def _try_until_timeout_expires(self, warn_timeout, fail_timeout,
422 bc14ba88 Vangelis Koukis
                                   opmsg, callable, *args, **kwargs):
423 bc14ba88 Vangelis Koukis
        if warn_timeout == fail_timeout:
424 5a140b23 Vangelis Koukis
            warn_timeout = fail_timeout + 1
425 5a140b23 Vangelis Koukis
        warn_tmout = time.time() + warn_timeout
426 5a140b23 Vangelis Koukis
        fail_tmout = time.time() + fail_timeout
427 5a140b23 Vangelis Koukis
        while True:
428 4fdd25ab Vangelis Koukis
            self.assertLess(time.time(), fail_tmout,
429 21bbbc9b Vangelis Koukis
                            "operation `%s' timed out" % opmsg)
430 5a140b23 Vangelis Koukis
            if time.time() > warn_tmout:
431 4fdd25ab Vangelis Koukis
                log.warning("Server %d: `%s' operation `%s' not done yet",
432 4fdd25ab Vangelis Koukis
                            self.serverid, self.servername, opmsg)
433 bc14ba88 Vangelis Koukis
            try:
434 4fdd25ab Vangelis Koukis
                log.info("%s... " % opmsg)
435 bc14ba88 Vangelis Koukis
                return callable(*args, **kwargs)
436 bc14ba88 Vangelis Koukis
            except AssertionError:
437 bc14ba88 Vangelis Koukis
                pass
438 5a140b23 Vangelis Koukis
            time.sleep(self.query_interval)
439 5a140b23 Vangelis Koukis
440 bc14ba88 Vangelis Koukis
    def _insist_on_tcp_connection(self, family, host, port):
441 21bbbc9b Vangelis Koukis
        familystr = {socket.AF_INET: "IPv4", socket.AF_INET6: "IPv6",
442 21bbbc9b Vangelis Koukis
                     socket.AF_UNSPEC: "Unspecified-IPv4/6"}
443 bc14ba88 Vangelis Koukis
        msg = "connect over %s to %s:%s" % \
444 bc14ba88 Vangelis Koukis
              (familystr.get(family, "Unknown"), host, port)
445 bc14ba88 Vangelis Koukis
        sock = self._try_until_timeout_expires(
446 6e168615 Ilias Tsitsimpis
            self.action_timeout, self.action_timeout,
447 6e168615 Ilias Tsitsimpis
            msg, self._get_connected_tcp_socket,
448 6e168615 Ilias Tsitsimpis
            family, host, port)
449 bc14ba88 Vangelis Koukis
        return sock
450 bc14ba88 Vangelis Koukis
451 bc14ba88 Vangelis Koukis
    def _insist_on_status_transition(self, current_status, new_status,
452 6e168615 Ilias Tsitsimpis
                                     fail_timeout, warn_timeout=None):
453 4fdd25ab Vangelis Koukis
        msg = "Server %d: `%s', waiting for %s -> %s" % \
454 4fdd25ab Vangelis Koukis
              (self.serverid, self.servername, current_status, new_status)
455 bc14ba88 Vangelis Koukis
        if warn_timeout is None:
456 bc14ba88 Vangelis Koukis
            warn_timeout = fail_timeout
457 bc14ba88 Vangelis Koukis
        self._try_until_timeout_expires(warn_timeout, fail_timeout,
458 bc14ba88 Vangelis Koukis
                                        msg, self._verify_server_status,
459 bc14ba88 Vangelis Koukis
                                        current_status, new_status)
460 21bbbc9b Vangelis Koukis
        # Ensure the status is actually the expected one
461 21bbbc9b Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
462 21bbbc9b Vangelis Koukis
        self.assertEquals(server["status"], new_status)
463 bc14ba88 Vangelis Koukis
464 bc14ba88 Vangelis Koukis
    def _insist_on_ssh_hostname(self, hostip, username, password):
465 4fdd25ab Vangelis Koukis
        msg = "SSH to %s, as %s/%s" % (hostip, username, password)
466 bc14ba88 Vangelis Koukis
        hostname = self._try_until_timeout_expires(
467 6e168615 Ilias Tsitsimpis
            self.action_timeout, self.action_timeout,
468 6e168615 Ilias Tsitsimpis
            msg, self._get_hostname_over_ssh,
469 6e168615 Ilias Tsitsimpis
            hostip, username, password)
470 bc14ba88 Vangelis Koukis
471 bc14ba88 Vangelis Koukis
        # The hostname must be of the form 'prefix-id'
472 bc14ba88 Vangelis Koukis
        self.assertTrue(hostname.endswith("-%d\n" % self.serverid))
473 5a140b23 Vangelis Koukis
474 8252d64f John Giannelos
    def _check_file_through_ssh(self, hostip, username, password,
475 8252d64f John Giannelos
                                remotepath, content):
476 8252d64f John Giannelos
        msg = "Trying file injection through SSH to %s, as %s/%s" % \
477 8252d64f John Giannelos
            (hostip, username, password)
478 f97dce4d John Giannelos
        log.info(msg)
479 77054bf5 John Giannelos
        try:
480 77054bf5 John Giannelos
            ssh = paramiko.SSHClient()
481 77054bf5 John Giannelos
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
482 77054bf5 John Giannelos
            ssh.connect(hostip, username=username, password=password)
483 2a410f76 Ilias Tsitsimpis
            ssh.close()
484 77054bf5 John Giannelos
        except socket.error:
485 77054bf5 John Giannelos
            raise AssertionError
486 9659e075 John Giannelos
487 2bcfb712 John Giannelos
        transport = paramiko.Transport((hostip, 22))
488 2bcfb712 John Giannelos
        transport.connect(username=username, password=password)
489 2bcfb712 John Giannelos
490 2bcfb712 John Giannelos
        localpath = '/tmp/' + SNF_TEST_PREFIX + 'injection'
491 77054bf5 John Giannelos
        sftp = paramiko.SFTPClient.from_transport(transport)
492 8252d64f John Giannelos
        sftp.get(remotepath, localpath)
493 77054bf5 John Giannelos
        sftp.close()
494 77054bf5 John Giannelos
        transport.close()
495 77054bf5 John Giannelos
496 9659e075 John Giannelos
        f = open(localpath)
497 9659e075 John Giannelos
        remote_content = b64encode(f.read())
498 9659e075 John Giannelos
499 77054bf5 John Giannelos
        # Check if files are the same
500 65462ca9 John Giannelos
        return (remote_content == content)
501 77054bf5 John Giannelos
502 5a140b23 Vangelis Koukis
    def _skipIf(self, condition, msg):
503 5a140b23 Vangelis Koukis
        if condition:
504 5a140b23 Vangelis Koukis
            self.skipTest(msg)
505 5a140b23 Vangelis Koukis
506 5a140b23 Vangelis Koukis
    def test_001_submit_create_server(self):
507 5a140b23 Vangelis Koukis
        """Test submit create server request"""
508 f89d0238 John Giannelos
509 f89d0238 John Giannelos
        log.info("Submit new server request")
510 5a140b23 Vangelis Koukis
        server = self.client.create_server(self.servername, self.flavorid,
511 5a140b23 Vangelis Koukis
                                           self.imageid, self.personality)
512 9659e075 John Giannelos
513 81e8cbf6 John Giannelos
        log.info("Server id: " + str(server["id"]))
514 81e8cbf6 John Giannelos
        log.info("Server password: " + server["adminPass"])
515 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
516 5a140b23 Vangelis Koukis
        self.assertEqual(server["flavorRef"], self.flavorid)
517 5a140b23 Vangelis Koukis
        self.assertEqual(server["imageRef"], self.imageid)
518 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
519 5a140b23 Vangelis Koukis
520 5a140b23 Vangelis Koukis
        # Update class attributes to reflect data on building server
521 5a140b23 Vangelis Koukis
        cls = type(self)
522 5a140b23 Vangelis Koukis
        cls.serverid = server["id"]
523 bc14ba88 Vangelis Koukis
        cls.username = None
524 5a140b23 Vangelis Koukis
        cls.passwd = server["adminPass"]
525 5a140b23 Vangelis Koukis
526 66eba2cf John Giannelos
        self.result_dict["Server ID"] = str(server["id"])
527 66eba2cf John Giannelos
        self.result_dict["Password"] = str(server["adminPass"])
528 66eba2cf John Giannelos
529 5a140b23 Vangelis Koukis
    def test_002a_server_is_building_in_list(self):
530 5a140b23 Vangelis Koukis
        """Test server is in BUILD state, in server list"""
531 f89d0238 John Giannelos
        log.info("Server in BUILD state in server list")
532 f89d0238 John Giannelos
533 66eba2cf John Giannelos
        self.result_dict.clear()
534 66eba2cf John Giannelos
535 5a140b23 Vangelis Koukis
        servers = self.client.list_servers(detail=True)
536 5a140b23 Vangelis Koukis
        servers = filter(lambda x: x["name"] == self.servername, servers)
537 2aaa1336 John Giannelos
538 5a140b23 Vangelis Koukis
        server = servers[0]
539 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
540 5a140b23 Vangelis Koukis
        self.assertEqual(server["flavorRef"], self.flavorid)
541 5a140b23 Vangelis Koukis
        self.assertEqual(server["imageRef"], self.imageid)
542 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
543 5a140b23 Vangelis Koukis
544 5a140b23 Vangelis Koukis
    def test_002b_server_is_building_in_details(self):
545 5a140b23 Vangelis Koukis
        """Test server is in BUILD state, in details"""
546 f89d0238 John Giannelos
547 f89d0238 John Giannelos
        log.info("Server in BUILD state in details")
548 f89d0238 John Giannelos
549 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
550 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
551 5a140b23 Vangelis Koukis
        self.assertEqual(server["flavorRef"], self.flavorid)
552 5a140b23 Vangelis Koukis
        self.assertEqual(server["imageRef"], self.imageid)
553 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
554 5a140b23 Vangelis Koukis
555 5a140b23 Vangelis Koukis
    def test_002c_set_server_metadata(self):
556 f89d0238 John Giannelos
557 f89d0238 John Giannelos
        log.info("Creating server metadata")
558 f89d0238 John Giannelos
559 5a140b23 Vangelis Koukis
        image = self.client.get_image_details(self.imageid)
560 6e168615 Ilias Tsitsimpis
        os_value = image["metadata"]["values"]["os"]
561 e49bdb7c John Giannelos
        users = image["metadata"]["values"].get("users", None)
562 6e168615 Ilias Tsitsimpis
        self.client.update_server_metadata(self.serverid, OS=os_value)
563 746540cd John Giannelos
564 e49bdb7c John Giannelos
        userlist = users.split()
565 81e8cbf6 John Giannelos
566 bc14ba88 Vangelis Koukis
        # Determine the username to use for future connections
567 bc14ba88 Vangelis Koukis
        # to this host
568 bc14ba88 Vangelis Koukis
        cls = type(self)
569 81e8cbf6 John Giannelos
570 81e8cbf6 John Giannelos
        if "root" in userlist:
571 81e8cbf6 John Giannelos
            cls.username = "root"
572 6e168615 Ilias Tsitsimpis
        elif users is None:
573 6e168615 Ilias Tsitsimpis
            cls.username = self._connect_loginname(os_value)
574 81e8cbf6 John Giannelos
        else:
575 81e8cbf6 John Giannelos
            cls.username = choice(userlist)
576 81e8cbf6 John Giannelos
577 bc14ba88 Vangelis Koukis
        self.assertIsNotNone(cls.username)
578 5a140b23 Vangelis Koukis
579 5a140b23 Vangelis Koukis
    def test_002d_verify_server_metadata(self):
580 5a140b23 Vangelis Koukis
        """Test server metadata keys are set based on image metadata"""
581 f89d0238 John Giannelos
582 f89d0238 John Giannelos
        log.info("Verifying image metadata")
583 f89d0238 John Giannelos
584 5a140b23 Vangelis Koukis
        servermeta = self.client.get_server_metadata(self.serverid)
585 5a140b23 Vangelis Koukis
        imagemeta = self.client.get_image_metadata(self.imageid)
586 81e8cbf6 John Giannelos
587 99d41650 John Giannelos
        self.assertEqual(servermeta["OS"], imagemeta["os"])
588 5a140b23 Vangelis Koukis
589 5a140b23 Vangelis Koukis
    def test_003_server_becomes_active(self):
590 5a140b23 Vangelis Koukis
        """Test server becomes ACTIVE"""
591 f89d0238 John Giannelos
592 f89d0238 John Giannelos
        log.info("Waiting for server to become ACTIVE")
593 f89d0238 John Giannelos
594 6e168615 Ilias Tsitsimpis
        self._insist_on_status_transition(
595 6e168615 Ilias Tsitsimpis
            "BUILD", "ACTIVE", self.build_fail, self.build_warning)
596 5a140b23 Vangelis Koukis
597 f752215c John Giannelos
    def test_003a_get_server_oob_console(self):
598 f752215c John Giannelos
        """Test getting OOB server console over VNC
599 bc14ba88 Vangelis Koukis

600 f752215c John Giannelos
        Implementation of RFB protocol follows
601 f752215c John Giannelos
        http://www.realvnc.com/docs/rfbproto.pdf.
602 bc14ba88 Vangelis Koukis

603 f752215c John Giannelos
        """
604 f752215c John Giannelos
        console = self.cyclades.get_server_console(self.serverid)
605 f752215c John Giannelos
        self.assertEquals(console['type'], "vnc")
606 6e168615 Ilias Tsitsimpis
        sock = self._insist_on_tcp_connection(
607 6e168615 Ilias Tsitsimpis
            socket.AF_INET, console["host"], console["port"])
608 f752215c John Giannelos
609 f752215c John Giannelos
        # Step 1. ProtocolVersion message (par. 6.1.1)
610 f752215c John Giannelos
        version = sock.recv(1024)
611 f752215c John Giannelos
        self.assertEquals(version, 'RFB 003.008\n')
612 f752215c John Giannelos
        sock.send(version)
613 f752215c John Giannelos
614 f752215c John Giannelos
        # Step 2. Security (par 6.1.2): Only VNC Authentication supported
615 f752215c John Giannelos
        sec = sock.recv(1024)
616 f752215c John Giannelos
        self.assertEquals(list(sec), ['\x01', '\x02'])
617 f752215c John Giannelos
618 f752215c John Giannelos
        # Step 3. Request VNC Authentication (par 6.1.2)
619 f752215c John Giannelos
        sock.send('\x02')
620 f752215c John Giannelos
621 f752215c John Giannelos
        # Step 4. Receive Challenge (par 6.2.2)
622 f752215c John Giannelos
        challenge = sock.recv(1024)
623 f752215c John Giannelos
        self.assertEquals(len(challenge), 16)
624 f752215c John Giannelos
625 f752215c John Giannelos
        # Step 5. DES-Encrypt challenge, use password as key (par 6.2.2)
626 f752215c John Giannelos
        response = d3des_generate_response(
627 f752215c John Giannelos
            (console["password"] + '\0' * 8)[:8], challenge)
628 f752215c John Giannelos
        sock.send(response)
629 f752215c John Giannelos
630 f752215c John Giannelos
        # Step 6. SecurityResult (par 6.1.3)
631 f752215c John Giannelos
        result = sock.recv(4)
632 f752215c John Giannelos
        self.assertEquals(list(result), ['\x00', '\x00', '\x00', '\x00'])
633 f752215c John Giannelos
        sock.close()
634 8252d64f John Giannelos
635 5a140b23 Vangelis Koukis
    def test_004_server_has_ipv4(self):
636 5a140b23 Vangelis Koukis
        """Test active server has a valid IPv4 address"""
637 f89d0238 John Giannelos
638 81e8cbf6 John Giannelos
        log.info("Validate server's IPv4")
639 f89d0238 John Giannelos
640 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
641 5a140b23 Vangelis Koukis
        ipv4 = self._get_ipv4(server)
642 66eba2cf John Giannelos
643 66eba2cf John Giannelos
        self.result_dict.clear()
644 66eba2cf John Giannelos
        self.result_dict["IPv4"] = str(ipv4)
645 66eba2cf John Giannelos
646 5a140b23 Vangelis Koukis
        self.assertEquals(IP(ipv4).version(), 4)
647 5a140b23 Vangelis Koukis
648 65462ca9 John Giannelos
    def test_005_server_has_ipv6(self):
649 65462ca9 John Giannelos
        """Test active server has a valid IPv6 address"""
650 946da8b6 John Giannelos
        self._skipIf(NO_IPV6, "--no-ipv6 flag enabled")
651 f89d0238 John Giannelos
652 81e8cbf6 John Giannelos
        log.info("Validate server's IPv6")
653 f89d0238 John Giannelos
654 65462ca9 John Giannelos
        server = self.client.get_server_details(self.serverid)
655 65462ca9 John Giannelos
        ipv6 = self._get_ipv6(server)
656 66eba2cf John Giannelos
657 66eba2cf John Giannelos
        self.result_dict.clear()
658 66eba2cf John Giannelos
        self.result_dict["IPv6"] = str(ipv6)
659 66eba2cf John Giannelos
660 65462ca9 John Giannelos
        self.assertEquals(IP(ipv6).version(), 6)
661 5a140b23 Vangelis Koukis
662 daac4017 John Giannelos
    def test_006_server_responds_to_ping_IPv4(self):
663 daac4017 John Giannelos
        """Test server responds to ping on IPv4 address"""
664 daac4017 John Giannelos
665 daac4017 John Giannelos
        log.info("Testing if server responds to pings in IPv4")
666 66eba2cf John Giannelos
        self.result_dict.clear()
667 daac4017 John Giannelos
668 daac4017 John Giannelos
        server = self.client.get_server_details(self.serverid)
669 daac4017 John Giannelos
        ip = self._get_ipv4(server)
670 daac4017 John Giannelos
        self._try_until_timeout_expires(self.action_timeout,
671 daac4017 John Giannelos
                                        self.action_timeout,
672 daac4017 John Giannelos
                                        "PING IPv4 to %s" % ip,
673 daac4017 John Giannelos
                                        self._ping_once,
674 daac4017 John Giannelos
                                        False, ip)
675 daac4017 John Giannelos
676 daac4017 John Giannelos
    def test_007_server_responds_to_ping_IPv6(self):
677 daac4017 John Giannelos
        """Test server responds to ping on IPv6 address"""
678 daac4017 John Giannelos
        self._skipIf(NO_IPV6, "--no-ipv6 flag enabled")
679 daac4017 John Giannelos
        log.info("Testing if server responds to pings in IPv6")
680 daac4017 John Giannelos
681 daac4017 John Giannelos
        server = self.client.get_server_details(self.serverid)
682 daac4017 John Giannelos
        ip = self._get_ipv6(server)
683 daac4017 John Giannelos
        self._try_until_timeout_expires(self.action_timeout,
684 daac4017 John Giannelos
                                        self.action_timeout,
685 daac4017 John Giannelos
                                        "PING IPv6 to %s" % ip,
686 daac4017 John Giannelos
                                        self._ping_once,
687 daac4017 John Giannelos
                                        True, ip)
688 5a140b23 Vangelis Koukis
689 5a140b23 Vangelis Koukis
    def test_008_submit_shutdown_request(self):
690 5a140b23 Vangelis Koukis
        """Test submit request to shutdown server"""
691 f89d0238 John Giannelos
692 f89d0238 John Giannelos
        log.info("Shutting down server")
693 f89d0238 John Giannelos
694 74193008 John Giannelos
        self.cyclades.shutdown_server(self.serverid)
695 5a140b23 Vangelis Koukis
696 5a140b23 Vangelis Koukis
    def test_009_server_becomes_stopped(self):
697 5a140b23 Vangelis Koukis
        """Test server becomes STOPPED"""
698 f89d0238 John Giannelos
699 f89d0238 John Giannelos
        log.info("Waiting until server becomes STOPPED")
700 6e168615 Ilias Tsitsimpis
        self._insist_on_status_transition(
701 6e168615 Ilias Tsitsimpis
            "ACTIVE", "STOPPED", self.action_timeout, self.action_timeout)
702 5a140b23 Vangelis Koukis
703 5a140b23 Vangelis Koukis
    def test_010_submit_start_request(self):
704 5a140b23 Vangelis Koukis
        """Test submit start server request"""
705 f89d0238 John Giannelos
706 f89d0238 John Giannelos
        log.info("Starting server")
707 f89d0238 John Giannelos
708 74193008 John Giannelos
        self.cyclades.start_server(self.serverid)
709 5a140b23 Vangelis Koukis
710 5a140b23 Vangelis Koukis
    def test_011_server_becomes_active(self):
711 5a140b23 Vangelis Koukis
        """Test server becomes ACTIVE again"""
712 f89d0238 John Giannelos
713 f89d0238 John Giannelos
        log.info("Waiting until server becomes ACTIVE")
714 6e168615 Ilias Tsitsimpis
        self._insist_on_status_transition(
715 6e168615 Ilias Tsitsimpis
            "STOPPED", "ACTIVE", self.action_timeout, self.action_timeout)
716 5a140b23 Vangelis Koukis
717 daac4017 John Giannelos
    def test_011a_server_responds_to_ping_IPv4(self):
718 daac4017 John Giannelos
        """Test server OS is actually up and running again"""
719 f89d0238 John Giannelos
720 daac4017 John Giannelos
        log.info("Testing if server is actually up and running")
721 f89d0238 John Giannelos
722 daac4017 John Giannelos
        self.test_006_server_responds_to_ping_IPv4()
723 5a140b23 Vangelis Koukis
724 daac4017 John Giannelos
    def test_012_ssh_to_server_IPv4(self):
725 daac4017 John Giannelos
        """Test SSH to server public IPv4 works, verify hostname"""
726 f89d0238 John Giannelos
727 daac4017 John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
728 daac4017 John Giannelos
        server = self.client.get_server_details(self.serverid)
729 daac4017 John Giannelos
        self._insist_on_ssh_hostname(self._get_ipv4(server),
730 daac4017 John Giannelos
                                     self.username, self.passwd)
731 5a140b23 Vangelis Koukis
732 daac4017 John Giannelos
    def test_013_ssh_to_server_IPv6(self):
733 daac4017 John Giannelos
        """Test SSH to server public IPv6 works, verify hostname"""
734 daac4017 John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
735 daac4017 John Giannelos
        self._skipIf(NO_IPV6, "--no-ipv6 flag enabled")
736 946da8b6 John Giannelos
737 daac4017 John Giannelos
        server = self.client.get_server_details(self.serverid)
738 daac4017 John Giannelos
        self._insist_on_ssh_hostname(self._get_ipv6(server),
739 daac4017 John Giannelos
                                     self.username, self.passwd)
740 5a140b23 Vangelis Koukis
741 daac4017 John Giannelos
    def test_014_rdp_to_server_IPv4(self):
742 daac4017 John Giannelos
        "Test RDP connection to server public IPv4 works"""
743 daac4017 John Giannelos
        self._skipIf(not self.is_windows, "only valid for Windows servers")
744 daac4017 John Giannelos
        server = self.client.get_server_details(self.serverid)
745 daac4017 John Giannelos
        ipv4 = self._get_ipv4(server)
746 6e168615 Ilias Tsitsimpis
        sock = self._insist_on_tcp_connection(socket.AF_INET, ipv4, 3389)
747 5a140b23 Vangelis Koukis
748 daac4017 John Giannelos
        # No actual RDP processing done. We assume the RDP server is there
749 daac4017 John Giannelos
        # if the connection to the RDP port is successful.
750 daac4017 John Giannelos
        # FIXME: Use rdesktop, analyze exit code? see manpage [costasd]
751 daac4017 John Giannelos
        sock.close()
752 5a140b23 Vangelis Koukis
753 daac4017 John Giannelos
    def test_015_rdp_to_server_IPv6(self):
754 daac4017 John Giannelos
        "Test RDP connection to server public IPv6 works"""
755 daac4017 John Giannelos
        self._skipIf(not self.is_windows, "only valid for Windows servers")
756 daac4017 John Giannelos
        self._skipIf(NO_IPV6, "--no-ipv6 flag enabled")
757 946da8b6 John Giannelos
758 daac4017 John Giannelos
        server = self.client.get_server_details(self.serverid)
759 daac4017 John Giannelos
        ipv6 = self._get_ipv6(server)
760 6e168615 Ilias Tsitsimpis
        sock = self._get_tcp_connection(socket.AF_INET6, ipv6, 3389)
761 5a140b23 Vangelis Koukis
762 daac4017 John Giannelos
        # No actual RDP processing done. We assume the RDP server is there
763 daac4017 John Giannelos
        # if the connection to the RDP port is successful.
764 daac4017 John Giannelos
        sock.close()
765 5a140b23 Vangelis Koukis
766 daac4017 John Giannelos
    def test_016_personality_is_enforced(self):
767 daac4017 John Giannelos
        """Test file injection for personality enforcement"""
768 daac4017 John Giannelos
        self._skipIf(self.is_windows, "only implemented for Linux servers")
769 6e168615 Ilias Tsitsimpis
        self._skipIf(self.personality is None, "No personality file selected")
770 f89d0238 John Giannelos
771 daac4017 John Giannelos
        log.info("Trying to inject file for personality enforcement")
772 f89d0238 John Giannelos
773 daac4017 John Giannelos
        server = self.client.get_server_details(self.serverid)
774 77054bf5 John Giannelos
775 daac4017 John Giannelos
        for inj_file in self.personality:
776 daac4017 John Giannelos
            equal_files = self._check_file_through_ssh(self._get_ipv4(server),
777 daac4017 John Giannelos
                                                       inj_file['owner'],
778 daac4017 John Giannelos
                                                       self.passwd,
779 daac4017 John Giannelos
                                                       inj_file['path'],
780 daac4017 John Giannelos
                                                       inj_file['contents'])
781 daac4017 John Giannelos
            self.assertTrue(equal_files)
782 8252d64f John Giannelos
783 4fdd25ab Vangelis Koukis
    def test_017_submit_delete_request(self):
784 4fdd25ab Vangelis Koukis
        """Test submit request to delete server"""
785 f89d0238 John Giannelos
786 f89d0238 John Giannelos
        log.info("Deleting server")
787 f89d0238 John Giannelos
788 4fdd25ab Vangelis Koukis
        self.client.delete_server(self.serverid)
789 4fdd25ab Vangelis Koukis
790 4fdd25ab Vangelis Koukis
    def test_018_server_becomes_deleted(self):
791 4fdd25ab Vangelis Koukis
        """Test server becomes DELETED"""
792 f89d0238 John Giannelos
793 f89d0238 John Giannelos
        log.info("Testing if server becomes DELETED")
794 f89d0238 John Giannelos
795 6e168615 Ilias Tsitsimpis
        self._insist_on_status_transition(
796 6e168615 Ilias Tsitsimpis
            "ACTIVE", "DELETED", self.action_timeout, self.action_timeout)
797 4fdd25ab Vangelis Koukis
798 4fdd25ab Vangelis Koukis
    def test_019_server_no_longer_in_server_list(self):
799 4fdd25ab Vangelis Koukis
        """Test server is no longer in server list"""
800 f89d0238 John Giannelos
801 f89d0238 John Giannelos
        log.info("Test if server is no longer listed")
802 f89d0238 John Giannelos
803 4fdd25ab Vangelis Koukis
        servers = self.client.list_servers()
804 21bbbc9b Vangelis Koukis
        self.assertNotIn(self.serverid, [s["id"] for s in servers])
805 21bbbc9b Vangelis Koukis
806 21bbbc9b Vangelis Koukis
807 9e4682b5 John Giannelos
class NetworkTestCase(unittest.TestCase):
808 e94a9d8c John Giannelos
    """ Testing networking in cyclades """
809 8252d64f John Giannelos
810 9e4682b5 John Giannelos
    @classmethod
811 e94a9d8c John Giannelos
    def setUpClass(cls):
812 e94a9d8c John Giannelos
        "Initialize kamaki, get list of current networks"
813 567ffb85 John Giannelos
814 567ffb85 John Giannelos
        cls.client = CycladesClient(API, TOKEN)
815 567ffb85 John Giannelos
        cls.compute = ComputeClient(API, TOKEN)
816 9e4682b5 John Giannelos
817 8252d64f John Giannelos
        cls.servername = "%s%s for %s" % (SNF_TEST_PREFIX,
818 8252d64f John Giannelos
                                          TEST_RUN_ID,
819 8252d64f John Giannelos
                                          cls.imagename)
820 91de9b55 John Giannelos
821 91de9b55 John Giannelos
        #Dictionary initialization for the vms credentials
822 91de9b55 John Giannelos
        cls.serverid = dict()
823 91de9b55 John Giannelos
        cls.username = dict()
824 91de9b55 John Giannelos
        cls.password = dict()
825 846980fe John Giannelos
        cls.is_windows = cls.imagename.lower().find("windows") >= 0
826 e49bdb7c John Giannelos
827 66eba2cf John Giannelos
        cls.result_dict = dict()
828 66eba2cf John Giannelos
829 e49bdb7c John Giannelos
    def _skipIf(self, condition, msg):
830 e49bdb7c John Giannelos
        if condition:
831 e49bdb7c John Giannelos
            self.skipTest(msg)
832 91de9b55 John Giannelos
833 1b40b5e3 John Giannelos
    def _get_ipv4(self, server):
834 1b40b5e3 John Giannelos
        """Get the public IPv4 of a server from the detailed server info"""
835 1b40b5e3 John Giannelos
836 e50133da John Giannelos
        nics = server["attachments"]["values"]
837 2aaa1336 John Giannelos
838 e50133da John Giannelos
        for nic in nics:
839 e50133da John Giannelos
            net_id = nic["network_id"]
840 6e168615 Ilias Tsitsimpis
            if self.client.get_network_details(net_id)["public"]:
841 e50133da John Giannelos
                public_addrs = nic["ipv4"]
842 2aaa1336 John Giannelos
843 6e168615 Ilias Tsitsimpis
        self.assertTrue(public_addrs is not None)
844 2aaa1336 John Giannelos
845 6e168615 Ilias Tsitsimpis
        return public_addrs
846 8252d64f John Giannelos
847 6e168615 Ilias Tsitsimpis
    def _connect_loginname(self, os_value):
848 1b40b5e3 John Giannelos
        """Return the login name for connections based on the server OS"""
849 6e168615 Ilias Tsitsimpis
        if os_value in ("Ubuntu", "Kubuntu", "Fedora"):
850 1b40b5e3 John Giannelos
            return "user"
851 6e168615 Ilias Tsitsimpis
        elif os_value in ("windows", "windows_alpha1"):
852 1b40b5e3 John Giannelos
            return "Administrator"
853 1b40b5e3 John Giannelos
        else:
854 1b40b5e3 John Giannelos
            return "root"
855 1b40b5e3 John Giannelos
856 88736f65 John Giannelos
    def _ping_once(self, ip):
857 8252d64f John Giannelos
858 88736f65 John Giannelos
        """Test server responds to a single IPv4 or IPv6 ping"""
859 88736f65 John Giannelos
        cmd = "ping -c 2 -w 3 %s" % (ip)
860 88736f65 John Giannelos
        ping = subprocess.Popen(cmd, shell=True,
861 88736f65 John Giannelos
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
862 88736f65 John Giannelos
        (stdout, stderr) = ping.communicate()
863 88736f65 John Giannelos
        ret = ping.wait()
864 8252d64f John Giannelos
865 88736f65 John Giannelos
        return (ret == 0)
866 88736f65 John Giannelos
867 740a5649 John Giannelos
    def test_00001a_submit_create_server_A(self):
868 91de9b55 John Giannelos
        """Test submit create server request"""
869 f89d0238 John Giannelos
870 f89d0238 John Giannelos
        log.info("Creating test server A")
871 f89d0238 John Giannelos
872 91de9b55 John Giannelos
        serverA = self.client.create_server(self.servername, self.flavorid,
873 ae139e8a John Giannelos
                                            self.imageid, personality=None)
874 91de9b55 John Giannelos
875 c54e3d4c John Giannelos
        self.assertEqual(serverA["name"], self.servername)
876 c54e3d4c John Giannelos
        self.assertEqual(serverA["flavorRef"], self.flavorid)
877 c54e3d4c John Giannelos
        self.assertEqual(serverA["imageRef"], self.imageid)
878 c54e3d4c John Giannelos
        self.assertEqual(serverA["status"], "BUILD")
879 91de9b55 John Giannelos
880 91de9b55 John Giannelos
        # Update class attributes to reflect data on building server
881 08748d73 John Giannelos
        self.serverid['A'] = serverA["id"]
882 08748d73 John Giannelos
        self.username['A'] = None
883 08748d73 John Giannelos
        self.password['A'] = serverA["adminPass"]
884 91de9b55 John Giannelos
885 81e8cbf6 John Giannelos
        log.info("Server A id:" + str(serverA["id"]))
886 81e8cbf6 John Giannelos
        log.info("Server password " + (self.password['A']))
887 8252d64f John Giannelos
888 66eba2cf John Giannelos
        self.result_dict["Server A ID"] = str(serverA["id"])
889 66eba2cf John Giannelos
        self.result_dict["Server A password"] = serverA["adminPass"]
890 6e168615 Ilias Tsitsimpis
891 740a5649 John Giannelos
    def test_00001b_serverA_becomes_active(self):
892 91de9b55 John Giannelos
        """Test server becomes ACTIVE"""
893 8252d64f John Giannelos
894 f89d0238 John Giannelos
        log.info("Waiting until test server A becomes ACTIVE")
895 66eba2cf John Giannelos
        self.result_dict.clear()
896 91de9b55 John Giannelos
897 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
898 91de9b55 John Giannelos
        while True:
899 91de9b55 John Giannelos
            d = self.client.get_server_details(self.serverid['A'])
900 91de9b55 John Giannelos
            status = d['status']
901 91de9b55 John Giannelos
            if status == 'ACTIVE':
902 91de9b55 John Giannelos
                active = True
903 91de9b55 John Giannelos
                break
904 91de9b55 John Giannelos
            elif time.time() > fail_tmout:
905 91de9b55 John Giannelos
                self.assertLess(time.time(), fail_tmout)
906 91de9b55 John Giannelos
            else:
907 91de9b55 John Giannelos
                time.sleep(self.query_interval)
908 91de9b55 John Giannelos
909 91de9b55 John Giannelos
        self.assertTrue(active)
910 91de9b55 John Giannelos
911 740a5649 John Giannelos
    def test_00002a_submit_create_server_B(self):
912 fade8dab John Giannelos
        """Test submit create server request"""
913 8252d64f John Giannelos
914 f89d0238 John Giannelos
        log.info("Creating test server B")
915 6e168615 Ilias Tsitsimpis
916 fade8dab John Giannelos
        serverB = self.client.create_server(self.servername, self.flavorid,
917 ae139e8a John Giannelos
                                            self.imageid, personality=None)
918 ae139e8a John Giannelos
919 fade8dab John Giannelos
        self.assertEqual(serverB["name"], self.servername)
920 fade8dab John Giannelos
        self.assertEqual(serverB["flavorRef"], self.flavorid)
921 fade8dab John Giannelos
        self.assertEqual(serverB["imageRef"], self.imageid)
922 fade8dab John Giannelos
        self.assertEqual(serverB["status"], "BUILD")
923 fade8dab John Giannelos
924 fade8dab John Giannelos
        # Update class attributes to reflect data on building server
925 fade8dab John Giannelos
        self.serverid['B'] = serverB["id"]
926 fade8dab John Giannelos
        self.username['B'] = None
927 fade8dab John Giannelos
        self.password['B'] = serverB["adminPass"]
928 fade8dab John Giannelos
929 81e8cbf6 John Giannelos
        log.info("Server B id: " + str(serverB["id"]))
930 81e8cbf6 John Giannelos
        log.info("Password " + (self.password['B']))
931 ae139e8a John Giannelos
932 66eba2cf John Giannelos
        self.result_dict.clear()
933 66eba2cf John Giannelos
        self.result_dict["Server B ID"] = str(serverB["id"])
934 66eba2cf John Giannelos
        self.result_dict["Server B password"] = serverB["adminPass"]
935 66eba2cf John Giannelos
936 740a5649 John Giannelos
    def test_00002b_serverB_becomes_active(self):
937 91de9b55 John Giannelos
        """Test server becomes ACTIVE"""
938 91de9b55 John Giannelos
939 f89d0238 John Giannelos
        log.info("Waiting until test server B becomes ACTIVE")
940 66eba2cf John Giannelos
        self.result_dict.clear()
941 f89d0238 John Giannelos
942 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
943 91de9b55 John Giannelos
        while True:
944 91de9b55 John Giannelos
            d = self.client.get_server_details(self.serverid['B'])
945 91de9b55 John Giannelos
            status = d['status']
946 91de9b55 John Giannelos
            if status == 'ACTIVE':
947 91de9b55 John Giannelos
                active = True
948 91de9b55 John Giannelos
                break
949 91de9b55 John Giannelos
            elif time.time() > fail_tmout:
950 91de9b55 John Giannelos
                self.assertLess(time.time(), fail_tmout)
951 91de9b55 John Giannelos
            else:
952 91de9b55 John Giannelos
                time.sleep(self.query_interval)
953 91de9b55 John Giannelos
954 91de9b55 John Giannelos
        self.assertTrue(active)
955 567ffb85 John Giannelos
956 9e4682b5 John Giannelos
    def test_001_create_network(self):
957 e94a9d8c John Giannelos
        """Test submit create network request"""
958 f89d0238 John Giannelos
959 f89d0238 John Giannelos
        log.info("Submit new network request")
960 66eba2cf John Giannelos
        self.result_dict.clear()
961 6e168615 Ilias Tsitsimpis
962 2bcfb712 John Giannelos
        name = SNF_TEST_PREFIX + TEST_RUN_ID
963 6e168615 Ilias Tsitsimpis
        #previous_num = len(self.client.list_networks())
964 6e168615 Ilias Tsitsimpis
        network = self.client.create_network(name, cidr='10.0.0.1/28')
965 8252d64f John Giannelos
966 9e4682b5 John Giannelos
        #Test if right name is assigned
967 e94a9d8c John Giannelos
        self.assertEqual(network['name'], name)
968 8252d64f John Giannelos
969 9e4682b5 John Giannelos
        # Update class attributes
970 e94a9d8c John Giannelos
        cls = type(self)
971 e94a9d8c John Giannelos
        cls.networkid = network['id']
972 6e168615 Ilias Tsitsimpis
        #networks = self.client.list_networks()
973 9e4682b5 John Giannelos
974 2aaa1336 John Giannelos
        fail_tmout = time.time() + self.action_timeout
975 2aaa1336 John Giannelos
976 9e4682b5 John Giannelos
        #Test if new network is created
977 2aaa1336 John Giannelos
        while True:
978 2aaa1336 John Giannelos
            d = self.client.get_network_details(network['id'])
979 2aaa1336 John Giannelos
            if d['status'] == 'ACTIVE':
980 2aaa1336 John Giannelos
                connected = True
981 2aaa1336 John Giannelos
                break
982 2aaa1336 John Giannelos
            elif time.time() > fail_tmout:
983 2aaa1336 John Giannelos
                self.assertLess(time.time(), fail_tmout)
984 2aaa1336 John Giannelos
            else:
985 2aaa1336 John Giannelos
                log.info("Waiting for network to become ACTIVE")
986 2aaa1336 John Giannelos
                time.sleep(self.query_interval)
987 2aaa1336 John Giannelos
988 2aaa1336 John Giannelos
        self.assertTrue(connected)
989 8252d64f John Giannelos
990 66eba2cf John Giannelos
        self.result_dict["Private network ID"] = str(network['id'])
991 66eba2cf John Giannelos
992 9e4682b5 John Giannelos
    def test_002_connect_to_network(self):
993 4573ea07 John Giannelos
        """Test connect VMs to network"""
994 9e4682b5 John Giannelos
995 f89d0238 John Giannelos
        log.info("Connect VMs to private network")
996 66eba2cf John Giannelos
        self.result_dict.clear()
997 f89d0238 John Giannelos
998 91de9b55 John Giannelos
        self.client.connect_server(self.serverid['A'], self.networkid)
999 91de9b55 John Giannelos
        self.client.connect_server(self.serverid['B'], self.networkid)
1000 8252d64f John Giannelos
1001 65462ca9 John Giannelos
        #Insist on connecting until action timeout
1002 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1003 9e4682b5 John Giannelos
1004 65462ca9 John Giannelos
        while True:
1005 2aaa1336 John Giannelos
1006 6e168615 Ilias Tsitsimpis
            netsA = [x['network_id']
1007 6e168615 Ilias Tsitsimpis
                     for x in self.client.get_server_details(
1008 6e168615 Ilias Tsitsimpis
                         self.serverid['A'])['attachments']['values']]
1009 6e168615 Ilias Tsitsimpis
            netsB = [x['network_id']
1010 6e168615 Ilias Tsitsimpis
                     for x in self.client.get_server_details(
1011 6e168615 Ilias Tsitsimpis
                         self.serverid['B'])['attachments']['values']]
1012 2aaa1336 John Giannelos
1013 2aaa1336 John Giannelos
            if (self.networkid in netsA) and (self.networkid in netsB):
1014 65462ca9 John Giannelos
                conn_exists = True
1015 de2461ec John Giannelos
                break
1016 de2461ec John Giannelos
            elif time.time() > fail_tmout:
1017 65462ca9 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1018 65462ca9 John Giannelos
            else:
1019 65462ca9 John Giannelos
                time.sleep(self.query_interval)
1020 6e168615 Ilias Tsitsimpis
1021 daac4017 John Giannelos
        #Adding private IPs to class attributes
1022 daac4017 John Giannelos
        cls = type(self)
1023 daac4017 John Giannelos
        cls.priv_ip = dict()
1024 daac4017 John Giannelos
1025 6e168615 Ilias Tsitsimpis
        nicsA = self.client.get_server_details(
1026 6e168615 Ilias Tsitsimpis
            self.serverid['A'])['attachments']['values']
1027 6e168615 Ilias Tsitsimpis
        nicsB = self.client.get_server_details(
1028 6e168615 Ilias Tsitsimpis
            self.serverid['B'])['attachments']['values']
1029 daac4017 John Giannelos
1030 daac4017 John Giannelos
        if conn_exists:
1031 daac4017 John Giannelos
            for nic in nicsA:
1032 daac4017 John Giannelos
                if nic["network_id"] == self.networkid:
1033 daac4017 John Giannelos
                    cls.priv_ip["A"] = nic["ipv4"]
1034 daac4017 John Giannelos
1035 daac4017 John Giannelos
            for nic in nicsB:
1036 daac4017 John Giannelos
                if nic["network_id"] == self.networkid:
1037 daac4017 John Giannelos
                    cls.priv_ip["B"] = nic["ipv4"]
1038 65462ca9 John Giannelos
1039 65462ca9 John Giannelos
        self.assertTrue(conn_exists)
1040 9e4682b5 John Giannelos
1041 88736f65 John Giannelos
    def test_002a_reboot(self):
1042 f89d0238 John Giannelos
        """Rebooting server A"""
1043 f89d0238 John Giannelos
1044 f89d0238 John Giannelos
        log.info("Rebooting server A")
1045 f89d0238 John Giannelos
1046 8252d64f John Giannelos
        self.client.shutdown_server(self.serverid['A'])
1047 8252d64f John Giannelos
1048 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1049 4573ea07 John Giannelos
        while True:
1050 4573ea07 John Giannelos
            d = self.client.get_server_details(self.serverid['A'])
1051 4573ea07 John Giannelos
            status = d['status']
1052 81e8cbf6 John Giannelos
            if status == 'STOPPED':
1053 81e8cbf6 John Giannelos
                break
1054 81e8cbf6 John Giannelos
            elif time.time() > fail_tmout:
1055 81e8cbf6 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1056 81e8cbf6 John Giannelos
            else:
1057 81e8cbf6 John Giannelos
                time.sleep(self.query_interval)
1058 81e8cbf6 John Giannelos
1059 81e8cbf6 John Giannelos
        self.client.start_server(self.serverid['A'])
1060 81e8cbf6 John Giannelos
1061 81e8cbf6 John Giannelos
        while True:
1062 81e8cbf6 John Giannelos
            d = self.client.get_server_details(self.serverid['A'])
1063 81e8cbf6 John Giannelos
            status = d['status']
1064 4573ea07 John Giannelos
            if status == 'ACTIVE':
1065 4573ea07 John Giannelos
                active = True
1066 4573ea07 John Giannelos
                break
1067 4573ea07 John Giannelos
            elif time.time() > fail_tmout:
1068 4573ea07 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1069 4573ea07 John Giannelos
            else:
1070 4573ea07 John Giannelos
                time.sleep(self.query_interval)
1071 8252d64f John Giannelos
1072 4573ea07 John Giannelos
        self.assertTrue(active)
1073 88736f65 John Giannelos
1074 daac4017 John Giannelos
    def test_002b_ping_server_A(self):
1075 daac4017 John Giannelos
        "Test if server A responds to IPv4 pings"
1076 4573ea07 John Giannelos
1077 daac4017 John Giannelos
        log.info("Testing if server A responds to IPv4 pings ")
1078 66eba2cf John Giannelos
        self.result_dict.clear()
1079 f89d0238 John Giannelos
1080 daac4017 John Giannelos
        server = self.client.get_server_details(self.serverid['A'])
1081 daac4017 John Giannelos
        ip = self._get_ipv4(server)
1082 8252d64f John Giannelos
1083 daac4017 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1084 8252d64f John Giannelos
1085 daac4017 John Giannelos
        s = False
1086 6e168615 Ilias Tsitsimpis
1087 66eba2cf John Giannelos
        self.result_dict["Server A public IP"] = str(ip)
1088 88736f65 John Giannelos
1089 daac4017 John Giannelos
        while True:
1090 88736f65 John Giannelos
1091 daac4017 John Giannelos
            if self._ping_once(ip):
1092 daac4017 John Giannelos
                s = True
1093 daac4017 John Giannelos
                break
1094 88736f65 John Giannelos
1095 daac4017 John Giannelos
            elif time.time() > fail_tmout:
1096 daac4017 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1097 88736f65 John Giannelos
1098 daac4017 John Giannelos
            else:
1099 daac4017 John Giannelos
                time.sleep(self.query_interval)
1100 88736f65 John Giannelos
1101 daac4017 John Giannelos
        self.assertTrue(s)
1102 4573ea07 John Giannelos
1103 4573ea07 John Giannelos
    def test_002c_reboot(self):
1104 f89d0238 John Giannelos
        """Reboot server B"""
1105 f89d0238 John Giannelos
1106 f89d0238 John Giannelos
        log.info("Rebooting server B")
1107 66eba2cf John Giannelos
        self.result_dict.clear()
1108 f89d0238 John Giannelos
1109 8252d64f John Giannelos
        self.client.shutdown_server(self.serverid['B'])
1110 8252d64f John Giannelos
1111 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1112 4573ea07 John Giannelos
        while True:
1113 4573ea07 John Giannelos
            d = self.client.get_server_details(self.serverid['B'])
1114 4573ea07 John Giannelos
            status = d['status']
1115 81e8cbf6 John Giannelos
            if status == 'STOPPED':
1116 81e8cbf6 John Giannelos
                break
1117 81e8cbf6 John Giannelos
            elif time.time() > fail_tmout:
1118 81e8cbf6 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1119 81e8cbf6 John Giannelos
            else:
1120 81e8cbf6 John Giannelos
                time.sleep(self.query_interval)
1121 81e8cbf6 John Giannelos
1122 81e8cbf6 John Giannelos
        self.client.start_server(self.serverid['B'])
1123 81e8cbf6 John Giannelos
1124 81e8cbf6 John Giannelos
        while True:
1125 81e8cbf6 John Giannelos
            d = self.client.get_server_details(self.serverid['B'])
1126 81e8cbf6 John Giannelos
            status = d['status']
1127 4573ea07 John Giannelos
            if status == 'ACTIVE':
1128 4573ea07 John Giannelos
                active = True
1129 4573ea07 John Giannelos
                break
1130 4573ea07 John Giannelos
            elif time.time() > fail_tmout:
1131 4573ea07 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1132 4573ea07 John Giannelos
            else:
1133 4573ea07 John Giannelos
                time.sleep(self.query_interval)
1134 8252d64f John Giannelos
1135 4573ea07 John Giannelos
        self.assertTrue(active)
1136 8252d64f John Giannelos
1137 daac4017 John Giannelos
    def test_002d_ping_server_B(self):
1138 daac4017 John Giannelos
        """Test if server B responds to IPv4 pings"""
1139 4573ea07 John Giannelos
1140 daac4017 John Giannelos
        log.info("Testing if server B responds to IPv4 pings")
1141 66eba2cf John Giannelos
        self.result_dict.clear()
1142 6e168615 Ilias Tsitsimpis
1143 daac4017 John Giannelos
        server = self.client.get_server_details(self.serverid['B'])
1144 daac4017 John Giannelos
        ip = self._get_ipv4(server)
1145 8252d64f John Giannelos
1146 daac4017 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1147 8252d64f John Giannelos
1148 daac4017 John Giannelos
        s = False
1149 88736f65 John Giannelos
1150 66eba2cf John Giannelos
        self.result_dict["Server B public IP"] = str(ip)
1151 66eba2cf John Giannelos
1152 daac4017 John Giannelos
        while True:
1153 daac4017 John Giannelos
            if self._ping_once(ip):
1154 daac4017 John Giannelos
                s = True
1155 daac4017 John Giannelos
                break
1156 88736f65 John Giannelos
1157 daac4017 John Giannelos
            elif time.time() > fail_tmout:
1158 daac4017 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1159 88736f65 John Giannelos
1160 daac4017 John Giannelos
            else:
1161 daac4017 John Giannelos
                time.sleep(self.query_interval)
1162 88736f65 John Giannelos
1163 daac4017 John Giannelos
        self.assertTrue(s)
1164 88736f65 John Giannelos
1165 daac4017 John Giannelos
    def test_003a_setup_interface_A(self):
1166 daac4017 John Giannelos
        """Set up eth1 for server A"""
1167 f89d0238 John Giannelos
1168 daac4017 John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
1169 e49bdb7c John Giannelos
1170 daac4017 John Giannelos
        log.info("Setting up interface eth1 for server A")
1171 66eba2cf John Giannelos
        self.result_dict.clear()
1172 ae139e8a John Giannelos
1173 daac4017 John Giannelos
        server = self.client.get_server_details(self.serverid['A'])
1174 daac4017 John Giannelos
        image = self.client.get_image_details(self.imageid)
1175 6e168615 Ilias Tsitsimpis
        os_value = image['metadata']['values']['os']
1176 8252d64f John Giannelos
1177 daac4017 John Giannelos
        users = image["metadata"]["values"].get("users", None)
1178 daac4017 John Giannelos
        userlist = users.split()
1179 d5cc50b3 John Giannelos
1180 daac4017 John Giannelos
        if "root" in userlist:
1181 daac4017 John Giannelos
            loginname = "root"
1182 6e168615 Ilias Tsitsimpis
        elif users is None:
1183 6e168615 Ilias Tsitsimpis
            loginname = self._connect_loginname(os_value)
1184 daac4017 John Giannelos
        else:
1185 daac4017 John Giannelos
            loginname = choice(userlist)
1186 1b40b5e3 John Giannelos
1187 daac4017 John Giannelos
        hostip = self._get_ipv4(server)
1188 daac4017 John Giannelos
        myPass = self.password['A']
1189 8252d64f John Giannelos
1190 daac4017 John Giannelos
        log.info("SSH in server A as %s/%s" % (loginname, myPass))
1191 2a410f76 Ilias Tsitsimpis
        command = "ifconfig eth1 %s" % self.priv_ip["A"]
1192 2a410f76 Ilias Tsitsimpis
        output, status = _ssh_execute(
1193 2a410f76 Ilias Tsitsimpis
            hostip, loginname, myPass, command)
1194 8252d64f John Giannelos
1195 2a410f76 Ilias Tsitsimpis
        self.assertEquals(status, 0)
1196 1b40b5e3 John Giannelos
1197 daac4017 John Giannelos
    def test_003b_setup_interface_B(self):
1198 daac4017 John Giannelos
        """Setup eth1 for server B"""
1199 1b40b5e3 John Giannelos
1200 daac4017 John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
1201 e49bdb7c John Giannelos
1202 daac4017 John Giannelos
        log.info("Setting up interface eth1 for server B")
1203 ae139e8a John Giannelos
1204 daac4017 John Giannelos
        server = self.client.get_server_details(self.serverid['B'])
1205 daac4017 John Giannelos
        image = self.client.get_image_details(self.imageid)
1206 6e168615 Ilias Tsitsimpis
        os_value = image['metadata']['values']['os']
1207 8252d64f John Giannelos
1208 daac4017 John Giannelos
        users = image["metadata"]["values"].get("users", None)
1209 daac4017 John Giannelos
        userlist = users.split()
1210 d5cc50b3 John Giannelos
1211 daac4017 John Giannelos
        if "root" in userlist:
1212 daac4017 John Giannelos
            loginname = "root"
1213 6e168615 Ilias Tsitsimpis
        elif users is None:
1214 6e168615 Ilias Tsitsimpis
            loginname = self._connect_loginname(os_value)
1215 daac4017 John Giannelos
        else:
1216 daac4017 John Giannelos
            loginname = choice(userlist)
1217 d5cc50b3 John Giannelos
1218 daac4017 John Giannelos
        hostip = self._get_ipv4(server)
1219 daac4017 John Giannelos
        myPass = self.password['B']
1220 740a5649 John Giannelos
1221 daac4017 John Giannelos
        log.info("SSH in server B as %s/%s" % (loginname, myPass))
1222 2a410f76 Ilias Tsitsimpis
        command = "ifconfig eth1 %s" % self.priv_ip["B"]
1223 2a410f76 Ilias Tsitsimpis
        output, status = _ssh_execute(
1224 2a410f76 Ilias Tsitsimpis
            hostip, loginname, myPass, command)
1225 1b40b5e3 John Giannelos
1226 2a410f76 Ilias Tsitsimpis
        self.assertEquals(status, 0)
1227 ae139e8a John Giannelos
1228 daac4017 John Giannelos
    def test_003c_test_connection_exists(self):
1229 daac4017 John Giannelos
        """Ping server B from server A to test if connection exists"""
1230 1b40b5e3 John Giannelos
1231 daac4017 John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
1232 e49bdb7c John Giannelos
1233 daac4017 John Giannelos
        log.info("Testing if server A is actually connected to server B")
1234 f89d0238 John Giannelos
1235 daac4017 John Giannelos
        server = self.client.get_server_details(self.serverid['A'])
1236 daac4017 John Giannelos
        image = self.client.get_image_details(self.imageid)
1237 6e168615 Ilias Tsitsimpis
        os_value = image['metadata']['values']['os']
1238 daac4017 John Giannelos
        hostip = self._get_ipv4(server)
1239 d5cc50b3 John Giannelos
1240 daac4017 John Giannelos
        users = image["metadata"]["values"].get("users", None)
1241 daac4017 John Giannelos
        userlist = users.split()
1242 d5cc50b3 John Giannelos
1243 daac4017 John Giannelos
        if "root" in userlist:
1244 daac4017 John Giannelos
            loginname = "root"
1245 6e168615 Ilias Tsitsimpis
        elif users is None:
1246 6e168615 Ilias Tsitsimpis
            loginname = self._connect_loginname(os_value)
1247 daac4017 John Giannelos
        else:
1248 daac4017 John Giannelos
            loginname = choice(userlist)
1249 1b40b5e3 John Giannelos
1250 daac4017 John Giannelos
        myPass = self.password['A']
1251 88736f65 John Giannelos
1252 daac4017 John Giannelos
        cmd = "if ping -c 2 -w 3 %s >/dev/null; \
1253 daac4017 John Giannelos
               then echo \'True\'; fi;" % self.priv_ip["B"]
1254 2a410f76 Ilias Tsitsimpis
        lines, status = _ssh_execute(
1255 2a410f76 Ilias Tsitsimpis
            hostip, loginname, myPass, cmd)
1256 1b40b5e3 John Giannelos
1257 daac4017 John Giannelos
        exists = False
1258 4573ea07 John Giannelos
1259 daac4017 John Giannelos
        if 'True\n' in lines:
1260 daac4017 John Giannelos
            exists = True
1261 1b40b5e3 John Giannelos
1262 daac4017 John Giannelos
        self.assertTrue(exists)
1263 1b40b5e3 John Giannelos
1264 88736f65 John Giannelos
    def test_004_disconnect_from_network(self):
1265 4573ea07 John Giannelos
        "Disconnecting server A and B from network"
1266 4573ea07 John Giannelos
1267 f89d0238 John Giannelos
        log.info("Disconnecting servers from private network")
1268 f89d0238 John Giannelos
1269 f97dce4d John Giannelos
        prev_state = self.client.get_network_details(self.networkid)
1270 2aaa1336 John Giannelos
        prev_nics = prev_state['attachments']['values']
1271 6e168615 Ilias Tsitsimpis
        #prev_conn = len(prev_nics)
1272 2aaa1336 John Giannelos
1273 6e168615 Ilias Tsitsimpis
        nicsA = [x['id']
1274 6e168615 Ilias Tsitsimpis
                 for x in self.client.get_server_details(
1275 6e168615 Ilias Tsitsimpis
                     self.serverid['A'])['attachments']['values']]
1276 6e168615 Ilias Tsitsimpis
        nicsB = [x['id']
1277 6e168615 Ilias Tsitsimpis
                 for x in self.client.get_server_details(
1278 6e168615 Ilias Tsitsimpis
                     self.serverid['B'])['attachments']['values']]
1279 2aaa1336 John Giannelos
1280 2aaa1336 John Giannelos
        for nic in prev_nics:
1281 2aaa1336 John Giannelos
            if nic in nicsA:
1282 2aaa1336 John Giannelos
                self.client.disconnect_server(self.serverid['A'], nic)
1283 2aaa1336 John Giannelos
            if nic in nicsB:
1284 2aaa1336 John Giannelos
                self.client.disconnect_server(self.serverid['B'], nic)
1285 e94a9d8c John Giannelos
1286 65462ca9 John Giannelos
        #Insist on deleting until action timeout
1287 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1288 9e4682b5 John Giannelos
1289 65462ca9 John Giannelos
        while True:
1290 6e168615 Ilias Tsitsimpis
            netsA = [x['network_id']
1291 6e168615 Ilias Tsitsimpis
                     for x in self.client.get_server_details(
1292 6e168615 Ilias Tsitsimpis
                         self.serverid['A'])['attachments']['values']]
1293 6e168615 Ilias Tsitsimpis
            netsB = [x['network_id']
1294 6e168615 Ilias Tsitsimpis
                     for x in self.client.get_server_details(
1295 6e168615 Ilias Tsitsimpis
                         self.serverid['B'])['attachments']['values']]
1296 6e168615 Ilias Tsitsimpis
1297 6e168615 Ilias Tsitsimpis
            #connected = (self.client.get_network_details(self.networkid))
1298 6e168615 Ilias Tsitsimpis
            #connections = connected['attachments']['values']
1299 2aaa1336 John Giannelos
            if (self.networkid not in netsA) and (self.networkid not in netsB):
1300 65462ca9 John Giannelos
                conn_exists = False
1301 de2461ec John Giannelos
                break
1302 de2461ec John Giannelos
            elif time.time() > fail_tmout:
1303 65462ca9 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1304 65462ca9 John Giannelos
            else:
1305 65462ca9 John Giannelos
                time.sleep(self.query_interval)
1306 65462ca9 John Giannelos
1307 65462ca9 John Giannelos
        self.assertFalse(conn_exists)
1308 9e4682b5 John Giannelos
1309 88736f65 John Giannelos
    def test_005_destroy_network(self):
1310 e94a9d8c John Giannelos
        """Test submit delete network request"""
1311 f89d0238 John Giannelos
1312 f89d0238 John Giannelos
        log.info("Submitting delete network request")
1313 f89d0238 John Giannelos
1314 8252d64f John Giannelos
        self.client.delete_network(self.networkid)
1315 e50133da John Giannelos
1316 2aaa1336 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1317 2aaa1336 John Giannelos
1318 2aaa1336 John Giannelos
        while True:
1319 e94a9d8c John Giannelos
1320 2aaa1336 John Giannelos
            curr_net = []
1321 2aaa1336 John Giannelos
            networks = self.client.list_networks()
1322 2aaa1336 John Giannelos
1323 2aaa1336 John Giannelos
            for net in networks:
1324 2aaa1336 John Giannelos
                curr_net.append(net['id'])
1325 2aaa1336 John Giannelos
1326 2aaa1336 John Giannelos
            if self.networkid not in curr_net:
1327 2aaa1336 John Giannelos
                self.assertTrue(self.networkid not in curr_net)
1328 2aaa1336 John Giannelos
                break
1329 65462ca9 John Giannelos
1330 2aaa1336 John Giannelos
            elif time.time() > fail_tmout:
1331 2aaa1336 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1332 2aaa1336 John Giannelos
1333 2aaa1336 John Giannelos
            else:
1334 2aaa1336 John Giannelos
                time.sleep(self.query_interval)
1335 2aaa1336 John Giannelos
1336 88736f65 John Giannelos
    def test_006_cleanup_servers(self):
1337 65462ca9 John Giannelos
        """Cleanup servers created for this test"""
1338 f89d0238 John Giannelos
1339 f89d0238 John Giannelos
        log.info("Delete servers created for this test")
1340 f89d0238 John Giannelos
1341 91de9b55 John Giannelos
        self.compute.delete_server(self.serverid['A'])
1342 91de9b55 John Giannelos
        self.compute.delete_server(self.serverid['B'])
1343 91de9b55 John Giannelos
1344 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1345 65462ca9 John Giannelos
1346 65462ca9 John Giannelos
        #Ensure server gets deleted
1347 8252d64f John Giannelos
        status = dict()
1348 91de9b55 John Giannelos
1349 65462ca9 John Giannelos
        while True:
1350 91de9b55 John Giannelos
            details = self.compute.get_server_details(self.serverid['A'])
1351 91de9b55 John Giannelos
            status['A'] = details['status']
1352 91de9b55 John Giannelos
            details = self.compute.get_server_details(self.serverid['B'])
1353 91de9b55 John Giannelos
            status['B'] = details['status']
1354 91de9b55 John Giannelos
            if (status['A'] == 'DELETED') and (status['B'] == 'DELETED'):
1355 65462ca9 John Giannelos
                deleted = True
1356 de2461ec John Giannelos
                break
1357 8252d64f John Giannelos
            elif time.time() > fail_tmout:
1358 65462ca9 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1359 65462ca9 John Giannelos
            else:
1360 65462ca9 John Giannelos
                time.sleep(self.query_interval)
1361 8252d64f John Giannelos
1362 65462ca9 John Giannelos
        self.assertTrue(deleted)
1363 e94a9d8c John Giannelos
1364 4573ea07 John Giannelos
1365 21bbbc9b Vangelis Koukis
class TestRunnerProcess(Process):
1366 21bbbc9b Vangelis Koukis
    """A distinct process used to execute part of the tests in parallel"""
1367 21bbbc9b Vangelis Koukis
    def __init__(self, **kw):
1368 21bbbc9b Vangelis Koukis
        Process.__init__(self, **kw)
1369 96da37c8 John Giannelos
        kwargs = kw["kwargs"]
1370 21bbbc9b Vangelis Koukis
        self.testq = kwargs["testq"]
1371 2aaa1336 John Giannelos
        self.worker_folder = kwargs["worker_folder"]
1372 21bbbc9b Vangelis Koukis
1373 21bbbc9b Vangelis Koukis
    def run(self):
1374 21bbbc9b Vangelis Koukis
        # Make sure this test runner process dies with the parent
1375 21bbbc9b Vangelis Koukis
        # and is not left behind.
1376 21bbbc9b Vangelis Koukis
        #
1377 21bbbc9b Vangelis Koukis
        # WARNING: This uses the prctl(2) call and is
1378 21bbbc9b Vangelis Koukis
        # Linux-specific.
1379 2aaa1336 John Giannelos
1380 21bbbc9b Vangelis Koukis
        prctl.set_pdeathsig(signal.SIGHUP)
1381 21bbbc9b Vangelis Koukis
1382 2aaa1336 John Giannelos
        multi = logging.getLogger("multiprocess")
1383 2aaa1336 John Giannelos
1384 21bbbc9b Vangelis Koukis
        while True:
1385 2aaa1336 John Giannelos
            multi.debug("I am process %d, GETting from queue is %s" %
1386 6e168615 Ilias Tsitsimpis
                        (os.getpid(), self.testq))
1387 21bbbc9b Vangelis Koukis
            msg = self.testq.get()
1388 2aaa1336 John Giannelos
1389 2aaa1336 John Giannelos
            multi.debug("Dequeued msg: %s" % msg)
1390 21bbbc9b Vangelis Koukis
1391 21bbbc9b Vangelis Koukis
            if msg == "TEST_RUNNER_TERMINATE":
1392 21bbbc9b Vangelis Koukis
                raise SystemExit
1393 2aaa1336 John Giannelos
1394 21bbbc9b Vangelis Koukis
            elif issubclass(msg, unittest.TestCase):
1395 21bbbc9b Vangelis Koukis
                # Assemble a TestSuite, and run it
1396 2aaa1336 John Giannelos
1397 2aaa1336 John Giannelos
                log_file = os.path.join(self.worker_folder, 'details_' +
1398 2aaa1336 John Giannelos
                                        (msg.__name__) + "_" +
1399 2aaa1336 John Giannelos
                                        TEST_RUN_ID + '.log')
1400 e50133da John Giannelos
1401 2aaa1336 John Giannelos
                fail_file = os.path.join(self.worker_folder, 'failed_' +
1402 2aaa1336 John Giannelos
                                         (msg.__name__) + "_" +
1403 2aaa1336 John Giannelos
                                         TEST_RUN_ID + '.log')
1404 2aaa1336 John Giannelos
                error_file = os.path.join(self.worker_folder, 'error_' +
1405 2aaa1336 John Giannelos
                                          (msg.__name__) + "_" +
1406 2aaa1336 John Giannelos
                                          TEST_RUN_ID + '.log')
1407 2aaa1336 John Giannelos
1408 2aaa1336 John Giannelos
                f = open(log_file, 'w')
1409 6e168615 Ilias Tsitsimpis
                fail = open(fail_file, 'w')
1410 2aaa1336 John Giannelos
                error = open(error_file, 'w')
1411 2aaa1336 John Giannelos
1412 2aaa1336 John Giannelos
                log.info(yellow + '* Starting testcase: %s' % msg + normal)
1413 2aaa1336 John Giannelos
1414 6e168615 Ilias Tsitsimpis
                runner = unittest.TextTestRunner(
1415 6e168615 Ilias Tsitsimpis
                    f, verbosity=2, failfast=True,
1416 6e168615 Ilias Tsitsimpis
                    resultclass=BurninTestResult)
1417 21bbbc9b Vangelis Koukis
                suite = unittest.TestLoader().loadTestsFromTestCase(msg)
1418 2aaa1336 John Giannelos
                result = runner.run(suite)
1419 2aaa1336 John Giannelos
1420 2aaa1336 John Giannelos
                for res in result.errors:
1421 6e168615 Ilias Tsitsimpis
                    log.error("snf-burnin encountered an error in "
1422 6e168615 Ilias Tsitsimpis
                              "testcase: %s" % msg)
1423 2aaa1336 John Giannelos
                    log.error("See log for details")
1424 2aaa1336 John Giannelos
                    error.write(str(res[0]) + '\n')
1425 2aaa1336 John Giannelos
                    error.write(str(res[0].shortDescription()) + '\n')
1426 2aaa1336 John Giannelos
                    error.write('\n')
1427 2aaa1336 John Giannelos
1428 2aaa1336 John Giannelos
                for res in result.failures:
1429 6e168615 Ilias Tsitsimpis
                    log.error("snf-burnin failed in testcase: %s" % msg)
1430 2aaa1336 John Giannelos
                    log.error("See log for details")
1431 2aaa1336 John Giannelos
                    fail.write(str(res[0]) + '\n')
1432 2aaa1336 John Giannelos
                    fail.write(str(res[0].shortDescription()) + '\n')
1433 2aaa1336 John Giannelos
                    fail.write('\n')
1434 6e168615 Ilias Tsitsimpis
                    if not NOFAILFAST:
1435 2aaa1336 John Giannelos
                        sys.exit()
1436 2aaa1336 John Giannelos
1437 2aaa1336 John Giannelos
                if (len(result.failures) == 0) and (len(result.errors) == 0):
1438 6e168615 Ilias Tsitsimpis
                    log.debug("Passed testcase: %s" % msg)
1439 2aaa1336 John Giannelos
1440 2aaa1336 John Giannelos
                f.close()
1441 2aaa1336 John Giannelos
                fail.close()
1442 2aaa1336 John Giannelos
                error.close()
1443 2aaa1336 John Giannelos
1444 21bbbc9b Vangelis Koukis
            else:
1445 21bbbc9b Vangelis Koukis
                raise Exception("Cannot handle msg: %s" % msg)
1446 21bbbc9b Vangelis Koukis
1447 6e168615 Ilias Tsitsimpis
1448 6e168615 Ilias Tsitsimpis
def _run_cases_in_series(cases, image_folder):
1449 3e4c5c32 John Giannelos
    """Run instances of TestCase in series"""
1450 3e4c5c32 John Giannelos
1451 3e4c5c32 John Giannelos
    for case in cases:
1452 3e4c5c32 John Giannelos
1453 3e4c5c32 John Giannelos
        test = case.__name__
1454 3e4c5c32 John Giannelos
1455 6e168615 Ilias Tsitsimpis
        log.info(yellow + '* Starting testcase: %s' % test + normal)
1456 3e4c5c32 John Giannelos
        log_file = os.path.join(image_folder, 'details_' +
1457 3e4c5c32 John Giannelos
                                (case.__name__) + "_" +
1458 3e4c5c32 John Giannelos
                                TEST_RUN_ID + '.log')
1459 3e4c5c32 John Giannelos
        fail_file = os.path.join(image_folder, 'failed_' +
1460 3e4c5c32 John Giannelos
                                 (case.__name__) + "_" +
1461 3e4c5c32 John Giannelos
                                 TEST_RUN_ID + '.log')
1462 3e4c5c32 John Giannelos
        error_file = os.path.join(image_folder, 'error_' +
1463 3e4c5c32 John Giannelos
                                  (case.__name__) + "_" +
1464 3e4c5c32 John Giannelos
                                  TEST_RUN_ID + '.log')
1465 3e4c5c32 John Giannelos
1466 3e4c5c32 John Giannelos
        f = open(log_file, "w")
1467 3e4c5c32 John Giannelos
        fail = open(fail_file, "w")
1468 3e4c5c32 John Giannelos
        error = open(error_file, "w")
1469 3e4c5c32 John Giannelos
1470 3e4c5c32 John Giannelos
        suite = unittest.TestLoader().loadTestsFromTestCase(case)
1471 6e168615 Ilias Tsitsimpis
        runner = unittest.TextTestRunner(
1472 6e168615 Ilias Tsitsimpis
            f, verbosity=2, failfast=True,
1473 6e168615 Ilias Tsitsimpis
            resultclass=BurninTestResult)
1474 3e4c5c32 John Giannelos
        result = runner.run(suite)
1475 3e4c5c32 John Giannelos
1476 3e4c5c32 John Giannelos
        for res in result.errors:
1477 6e168615 Ilias Tsitsimpis
            log.error("snf-burnin encountered an error in "
1478 6e168615 Ilias Tsitsimpis
                      "testcase: %s" % test)
1479 3e4c5c32 John Giannelos
            log.error("See log for details")
1480 3e4c5c32 John Giannelos
            error.write(str(res[0]) + '\n')
1481 3e4c5c32 John Giannelos
            error.write(str(res[0].shortDescription()) + '\n')
1482 3e4c5c32 John Giannelos
            error.write('\n')
1483 3e4c5c32 John Giannelos
1484 3e4c5c32 John Giannelos
        for res in result.failures:
1485 6e168615 Ilias Tsitsimpis
            log.error("snf-burnin failed in testcase: %s" % test)
1486 3e4c5c32 John Giannelos
            log.error("See log for details")
1487 3e4c5c32 John Giannelos
            fail.write(str(res[0]) + '\n')
1488 3e4c5c32 John Giannelos
            fail.write(str(res[0].shortDescription()) + '\n')
1489 3e4c5c32 John Giannelos
            fail.write('\n')
1490 6e168615 Ilias Tsitsimpis
            if not NOFAILFAST:
1491 3e4c5c32 John Giannelos
                sys.exit()
1492 3e4c5c32 John Giannelos
1493 3e4c5c32 John Giannelos
        if (len(result.failures) == 0) and (len(result.errors) == 0):
1494 6e168615 Ilias Tsitsimpis
            log.debug("Passed testcase: %s" % test)
1495 3e4c5c32 John Giannelos
1496 21bbbc9b Vangelis Koukis
1497 2aaa1336 John Giannelos
def _run_cases_in_parallel(cases, fanout, image_folder):
1498 21bbbc9b Vangelis Koukis
    """Run instances of TestCase in parallel, in a number of distinct processes
1499 21bbbc9b Vangelis Koukis

1500 21bbbc9b Vangelis Koukis
    The cases iterable specifies the TestCases to be executed in parallel,
1501 21bbbc9b Vangelis Koukis
    by test runners running in distinct processes.
1502 21bbbc9b Vangelis Koukis
    The fanout parameter specifies the number of processes to spawn,
1503 21bbbc9b Vangelis Koukis
    and defaults to 1.
1504 21bbbc9b Vangelis Koukis
    The runner argument specifies the test runner class to use inside each
1505 21bbbc9b Vangelis Koukis
    runner process.
1506 21bbbc9b Vangelis Koukis

1507 21bbbc9b Vangelis Koukis
    """
1508 e50133da John Giannelos
1509 2aaa1336 John Giannelos
    multi = logging.getLogger("multiprocess")
1510 2aaa1336 John Giannelos
    handler = logging.StreamHandler()
1511 2aaa1336 John Giannelos
    multi.addHandler(handler)
1512 21bbbc9b Vangelis Koukis
1513 2aaa1336 John Giannelos
    if VERBOSE:
1514 2aaa1336 John Giannelos
        multi.setLevel(logging.DEBUG)
1515 2aaa1336 John Giannelos
    else:
1516 2aaa1336 John Giannelos
        multi.setLevel(logging.INFO)
1517 2aaa1336 John Giannelos
1518 2aaa1336 John Giannelos
    testq = []
1519 2aaa1336 John Giannelos
    worker_folder = []
1520 21bbbc9b Vangelis Koukis
    runners = []
1521 2aaa1336 John Giannelos
1522 6e168615 Ilias Tsitsimpis
    for i in xrange(0, fanout):
1523 2aaa1336 John Giannelos
        testq.append(Queue())
1524 2aaa1336 John Giannelos
        worker_folder.append(os.path.join(image_folder, 'process'+str(i)))
1525 2aaa1336 John Giannelos
        os.mkdir(worker_folder[i])
1526 2aaa1336 John Giannelos
1527 21bbbc9b Vangelis Koukis
    for i in xrange(0, fanout):
1528 2aaa1336 John Giannelos
        kwargs = dict(testq=testq[i], worker_folder=worker_folder[i])
1529 21bbbc9b Vangelis Koukis
        runners.append(TestRunnerProcess(kwargs=kwargs))
1530 21bbbc9b Vangelis Koukis
1531 6e168615 Ilias Tsitsimpis
    multi.debug("Spawning %d test runner processes" % len(runners))
1532 2aaa1336 John Giannelos
1533 21bbbc9b Vangelis Koukis
    for p in runners:
1534 21bbbc9b Vangelis Koukis
        p.start()
1535 21bbbc9b Vangelis Koukis
1536 21bbbc9b Vangelis Koukis
    # Enqueue test cases
1537 2aaa1336 John Giannelos
    for i in xrange(0, fanout):
1538 2aaa1336 John Giannelos
        map(testq[i].put, cases)
1539 2aaa1336 John Giannelos
        testq[i].put("TEST_RUNNER_TERMINATE")
1540 2aaa1336 John Giannelos
1541 2aaa1336 John Giannelos
    multi.debug("Spawned %d test runners, PIDs are %s" %
1542 6e168615 Ilias Tsitsimpis
                (len(runners), [p.pid for p in runners]))
1543 21bbbc9b Vangelis Koukis
1544 2aaa1336 John Giannelos
    multi.debug("Joining %d processes" % len(runners))
1545 e50133da John Giannelos
1546 21bbbc9b Vangelis Koukis
    for p in runners:
1547 21bbbc9b Vangelis Koukis
        p.join()
1548 2aaa1336 John Giannelos
1549 2aaa1336 John Giannelos
    multi.debug("Done joining %d processes" % len(runners))
1550 4fdd25ab Vangelis Koukis
1551 5a140b23 Vangelis Koukis
1552 5a140b23 Vangelis Koukis
def _spawn_server_test_case(**kwargs):
1553 5a140b23 Vangelis Koukis
    """Construct a new unit test case class from SpawnServerTestCase"""
1554 5a140b23 Vangelis Koukis
1555 c1d11f96 John Giannelos
    name = "SpawnServerTestCase_%s" % kwargs["imageid"]
1556 5a140b23 Vangelis Koukis
    cls = type(name, (SpawnServerTestCase,), kwargs)
1557 5a140b23 Vangelis Koukis
1558 5a140b23 Vangelis Koukis
    # Patch extra parameters into test names by manipulating method docstrings
1559 5a140b23 Vangelis Koukis
    for (mname, m) in \
1560 6e168615 Ilias Tsitsimpis
            inspect.getmembers(cls, lambda x: inspect.ismethod(x)):
1561 74ec726f John Giannelos
        if hasattr(m, __doc__):
1562 6e168615 Ilias Tsitsimpis
            m.__func__.__doc__ = "[%s] %s" % (cls.imagename, m.__doc__)
1563 e72bcf60 Vangelis Koukis
1564 e72bcf60 Vangelis Koukis
    # Make sure the class can be pickled, by listing it among
1565 e72bcf60 Vangelis Koukis
    # the attributes of __main__. A PicklingError is raised otherwise.
1566 2aaa1336 John Giannelos
1567 2aaa1336 John Giannelos
    thismodule = sys.modules[__name__]
1568 2aaa1336 John Giannelos
    setattr(thismodule, name, cls)
1569 8252d64f John Giannelos
    return cls
1570 65462ca9 John Giannelos
1571 2bcfb712 John Giannelos
1572 65462ca9 John Giannelos
def _spawn_network_test_case(**kwargs):
1573 65462ca9 John Giannelos
    """Construct a new unit test case class from NetworkTestCase"""
1574 65462ca9 John Giannelos
1575 2bcfb712 John Giannelos
    name = "NetworkTestCase" + TEST_RUN_ID
1576 65462ca9 John Giannelos
    cls = type(name, (NetworkTestCase,), kwargs)
1577 65462ca9 John Giannelos
1578 65462ca9 John Giannelos
    # Make sure the class can be pickled, by listing it among
1579 65462ca9 John Giannelos
    # the attributes of __main__. A PicklingError is raised otherwise.
1580 e50133da John Giannelos
1581 2aaa1336 John Giannelos
    thismodule = sys.modules[__name__]
1582 2aaa1336 John Giannelos
    setattr(thismodule, name, cls)
1583 8252d64f John Giannelos
    return cls
1584 5a140b23 Vangelis Koukis
1585 5a140b23 Vangelis Koukis
1586 8792bb97 Ilias Tsitsimpis
# --------------------------------------------------------------------
1587 8792bb97 Ilias Tsitsimpis
# Clean up servers/networks functions
1588 c0448f4f John Giannelos
def cleanup_servers(timeout, query_interval, delete_stale=False):
1589 74193008 John Giannelos
1590 567ffb85 John Giannelos
    c = ComputeClient(API, TOKEN)
1591 74193008 John Giannelos
1592 5a140b23 Vangelis Koukis
    servers = c.list_servers()
1593 5a140b23 Vangelis Koukis
    stale = [s for s in servers if s["name"].startswith(SNF_TEST_PREFIX)]
1594 5a140b23 Vangelis Koukis
1595 4fdd25ab Vangelis Koukis
    if len(stale) == 0:
1596 4fdd25ab Vangelis Koukis
        return
1597 4fdd25ab Vangelis Koukis
1598 8792bb97 Ilias Tsitsimpis
    # Show staled servers
1599 8792bb97 Ilias Tsitsimpis
    print >>sys.stderr, yellow + \
1600 6e168615 Ilias Tsitsimpis
        "Found these stale servers from previous runs:" + \
1601 6e168615 Ilias Tsitsimpis
        normal
1602 8792bb97 Ilias Tsitsimpis
    print >>sys.stderr, "    " + \
1603 6e168615 Ilias Tsitsimpis
        "\n    ".join(["%d: %s" % (s["id"], s["name"]) for s in stale])
1604 5a140b23 Vangelis Koukis
1605 8792bb97 Ilias Tsitsimpis
    # Delete staled servers
1606 5a140b23 Vangelis Koukis
    if delete_stale:
1607 5a140b23 Vangelis Koukis
        print >> sys.stderr, "Deleting %d stale servers:" % len(stale)
1608 c0448f4f John Giannelos
        fail_tmout = time.time() + timeout
1609 c0448f4f John Giannelos
        for s in stale:
1610 c0448f4f John Giannelos
            c.delete_server(s["id"])
1611 8792bb97 Ilias Tsitsimpis
        # Wait for all servers to be deleted
1612 c0448f4f John Giannelos
        while True:
1613 c0448f4f John Giannelos
            servers = c.list_servers()
1614 6e168615 Ilias Tsitsimpis
            stale = [s for s in servers
1615 6e168615 Ilias Tsitsimpis
                     if s["name"].startswith(SNF_TEST_PREFIX)]
1616 6e168615 Ilias Tsitsimpis
            if len(stale) == 0:
1617 c0448f4f John Giannelos
                print >> sys.stderr, green + "    ...done" + normal
1618 c0448f4f John Giannelos
                break
1619 c0448f4f John Giannelos
            elif time.time() > fail_tmout:
1620 8792bb97 Ilias Tsitsimpis
                print >> sys.stderr, red + \
1621 6e168615 Ilias Tsitsimpis
                    "Not all stale servers deleted. Action timed out." + \
1622 6e168615 Ilias Tsitsimpis
                    normal
1623 6e168615 Ilias Tsitsimpis
                sys.exit(1)
1624 c0448f4f John Giannelos
            else:
1625 c0448f4f John Giannelos
                time.sleep(query_interval)
1626 5a140b23 Vangelis Koukis
    else:
1627 5a140b23 Vangelis Koukis
        print >> sys.stderr, "Use --delete-stale to delete them."
1628 5a140b23 Vangelis Koukis
1629 2bcfb712 John Giannelos
1630 f752215c John Giannelos
def cleanup_networks(action_timeout, query_interval, delete_stale=False):
1631 74ec726f John Giannelos
1632 74ec726f John Giannelos
    c = CycladesClient(API, TOKEN)
1633 e50133da John Giannelos
1634 74ec726f John Giannelos
    networks = c.list_networks()
1635 74ec726f John Giannelos
    stale = [n for n in networks if n["name"].startswith(SNF_TEST_PREFIX)]
1636 74ec726f John Giannelos
1637 74ec726f John Giannelos
    if len(stale) == 0:
1638 74ec726f John Giannelos
        return
1639 e50133da John Giannelos
1640 8792bb97 Ilias Tsitsimpis
    # Show staled networks
1641 8792bb97 Ilias Tsitsimpis
    print >> sys.stderr, yellow + \
1642 6e168615 Ilias Tsitsimpis
        "Found these stale networks from previous runs:" + \
1643 6e168615 Ilias Tsitsimpis
        normal
1644 74ec726f John Giannelos
    print "    " + \
1645 6e168615 Ilias Tsitsimpis
        "\n    ".join(["%s: %s" % (str(n["id"]), n["name"]) for n in stale])
1646 74ec726f John Giannelos
1647 8792bb97 Ilias Tsitsimpis
    # Delete staled networks
1648 74ec726f John Giannelos
    if delete_stale:
1649 74ec726f John Giannelos
        print >> sys.stderr, "Deleting %d stale networks:" % len(stale)
1650 f752215c John Giannelos
        fail_tmout = time.time() + action_timeout
1651 c0448f4f John Giannelos
        for n in stale:
1652 c0448f4f John Giannelos
            c.delete_network(n["id"])
1653 8792bb97 Ilias Tsitsimpis
        # Wait for all networks to be deleted
1654 c0448f4f John Giannelos
        while True:
1655 c0448f4f John Giannelos
            networks = c.list_networks()
1656 6e168615 Ilias Tsitsimpis
            stale = [n for n in networks
1657 6e168615 Ilias Tsitsimpis
                     if n["name"].startswith(SNF_TEST_PREFIX)]
1658 6e168615 Ilias Tsitsimpis
            if len(stale) == 0:
1659 c0448f4f John Giannelos
                print >> sys.stderr, green + "    ...done" + normal
1660 c0448f4f John Giannelos
                break
1661 c0448f4f John Giannelos
            elif time.time() > fail_tmout:
1662 8792bb97 Ilias Tsitsimpis
                print >> sys.stderr, red + \
1663 6e168615 Ilias Tsitsimpis
                    "Not all stale networks deleted. Action timed out." + \
1664 6e168615 Ilias Tsitsimpis
                    normal
1665 6e168615 Ilias Tsitsimpis
                sys.exit(1)
1666 c0448f4f John Giannelos
            else:
1667 c0448f4f John Giannelos
                time.sleep(query_interval)
1668 74ec726f John Giannelos
    else:
1669 74ec726f John Giannelos
        print >> sys.stderr, "Use --delete-stale to delete them."
1670 74ec726f John Giannelos
1671 746540cd John Giannelos
1672 8792bb97 Ilias Tsitsimpis
# --------------------------------------------------------------------
1673 8792bb97 Ilias Tsitsimpis
# Parse arguments functions
1674 22efe1fe John Giannelos
def parse_comma(option, opt, value, parser):
1675 746540cd John Giannelos
    tests = set(['all', 'auth', 'images', 'flavors',
1676 6e168615 Ilias Tsitsimpis
                 'servers', 'server_spawn', 'network_spawn'])
1677 22efe1fe John Giannelos
    parse_input = value.split(',')
1678 22efe1fe John Giannelos
1679 22efe1fe John Giannelos
    if not (set(parse_input)).issubset(tests):
1680 22efe1fe John Giannelos
        raise OptionValueError("The selected set of tests is invalid")
1681 22efe1fe John Giannelos
1682 22efe1fe John Giannelos
    setattr(parser.values, option.dest, value.split(','))
1683 22efe1fe John Giannelos
1684 74ec726f John Giannelos
1685 5a140b23 Vangelis Koukis
def parse_arguments(args):
1686 5a140b23 Vangelis Koukis
1687 5a140b23 Vangelis Koukis
    kw = {}
1688 5a140b23 Vangelis Koukis
    kw["usage"] = "%prog [options]"
1689 5a140b23 Vangelis Koukis
    kw["description"] = \
1690 5a140b23 Vangelis Koukis
        "%prog runs a number of test scenarios on a " \
1691 5a140b23 Vangelis Koukis
        "Synnefo deployment."
1692 5a140b23 Vangelis Koukis
1693 5a140b23 Vangelis Koukis
    parser = OptionParser(**kw)
1694 5a140b23 Vangelis Koukis
    parser.disable_interspersed_args()
1695 22efe1fe John Giannelos
1696 21bbbc9b Vangelis Koukis
    parser.add_option("--api",
1697 21bbbc9b Vangelis Koukis
                      action="store", type="string", dest="api",
1698 21bbbc9b Vangelis Koukis
                      help="The API URI to use to reach the Synnefo API",
1699 21bbbc9b Vangelis Koukis
                      default=DEFAULT_API)
1700 946da8b6 John Giannelos
    parser.add_option("--plankton",
1701 946da8b6 John Giannelos
                      action="store", type="string", dest="plankton",
1702 946da8b6 John Giannelos
                      help="The API URI to use to reach the Plankton API",
1703 946da8b6 John Giannelos
                      default=DEFAULT_PLANKTON)
1704 946da8b6 John Giannelos
    parser.add_option("--plankton-user",
1705 946da8b6 John Giannelos
                      action="store", type="string", dest="plankton_user",
1706 946da8b6 John Giannelos
                      help="Owner of system images",
1707 946da8b6 John Giannelos
                      default=DEFAULT_PLANKTON_USER)
1708 21bbbc9b Vangelis Koukis
    parser.add_option("--token",
1709 21bbbc9b Vangelis Koukis
                      action="store", type="string", dest="token",
1710 38d247df Kostas Papadimitriou
                      help="The token to use for authentication to the API")
1711 00f87624 Vangelis Koukis
    parser.add_option("--nofailfast",
1712 00f87624 Vangelis Koukis
                      action="store_true", dest="nofailfast",
1713 6e168615 Ilias Tsitsimpis
                      help="Do not fail immediately if one of the tests "
1714 00f87624 Vangelis Koukis
                           "fails (EXPERIMENTAL)",
1715 bc14ba88 Vangelis Koukis
                      default=False)
1716 946da8b6 John Giannelos
    parser.add_option("--no-ipv6",
1717 946da8b6 John Giannelos
                      action="store_true", dest="no_ipv6",
1718 946da8b6 John Giannelos
                      help="Disables ipv6 related tests",
1719 946da8b6 John Giannelos
                      default=False)
1720 5a140b23 Vangelis Koukis
    parser.add_option("--action-timeout",
1721 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="action_timeout",
1722 5a140b23 Vangelis Koukis
                      metavar="TIMEOUT",
1723 6e168615 Ilias Tsitsimpis
                      help="Wait SECONDS seconds for a server action to "
1724 5a140b23 Vangelis Koukis
                           "complete, then the test is considered failed",
1725 9e4682b5 John Giannelos
                      default=100)
1726 5a140b23 Vangelis Koukis
    parser.add_option("--build-warning",
1727 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="build_warning",
1728 5a140b23 Vangelis Koukis
                      metavar="TIMEOUT",
1729 6e168615 Ilias Tsitsimpis
                      help="Warn if TIMEOUT seconds have passed and a "
1730 5a140b23 Vangelis Koukis
                           "build operation is still pending",
1731 5a140b23 Vangelis Koukis
                      default=600)
1732 5a140b23 Vangelis Koukis
    parser.add_option("--build-fail",
1733 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="build_fail",
1734 5a140b23 Vangelis Koukis
                      metavar="BUILD_TIMEOUT",
1735 6e168615 Ilias Tsitsimpis
                      help="Fail the test if TIMEOUT seconds have passed "
1736 5a140b23 Vangelis Koukis
                           "and a build operation is still incomplete",
1737 5a140b23 Vangelis Koukis
                      default=900)
1738 5a140b23 Vangelis Koukis
    parser.add_option("--query-interval",
1739 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="query_interval",
1740 5a140b23 Vangelis Koukis
                      metavar="INTERVAL",
1741 6e168615 Ilias Tsitsimpis
                      help="Query server status when requests are pending "
1742 5a140b23 Vangelis Koukis
                           "every INTERVAL seconds",
1743 5a140b23 Vangelis Koukis
                      default=3)
1744 21bbbc9b Vangelis Koukis
    parser.add_option("--fanout",
1745 21bbbc9b Vangelis Koukis
                      action="store", type="int", dest="fanout",
1746 5a140b23 Vangelis Koukis
                      metavar="COUNT",
1747 6e168615 Ilias Tsitsimpis
                      help="Spawn up to COUNT child processes to execute "
1748 6e168615 Ilias Tsitsimpis
                           "in parallel, essentially have up to COUNT "
1749 00f87624 Vangelis Koukis
                           "server build requests outstanding (EXPERIMENTAL)",
1750 5a140b23 Vangelis Koukis
                      default=1)
1751 5a140b23 Vangelis Koukis
    parser.add_option("--force-flavor",
1752 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="force_flavorid",
1753 5a140b23 Vangelis Koukis
                      metavar="FLAVOR ID",
1754 6e168615 Ilias Tsitsimpis
                      help="Force all server creations to use the specified "
1755 6e168615 Ilias Tsitsimpis
                           "FLAVOR ID instead of a randomly chosen one, "
1756 5a140b23 Vangelis Koukis
                           "useful if disk space is scarce",
1757 00f87624 Vangelis Koukis
                      default=None)
1758 7f62a0b5 Vangelis Koukis
    parser.add_option("--image-id",
1759 7f62a0b5 Vangelis Koukis
                      action="store", type="string", dest="force_imageid",
1760 00f87624 Vangelis Koukis
                      metavar="IMAGE ID",
1761 6e168615 Ilias Tsitsimpis
                      help="Test the specified image id, use 'all' to test "
1762 7f62a0b5 Vangelis Koukis
                           "all available images (mandatory argument)",
1763 00f87624 Vangelis Koukis
                      default=None)
1764 5a140b23 Vangelis Koukis
    parser.add_option("--show-stale",
1765 5a140b23 Vangelis Koukis
                      action="store_true", dest="show_stale",
1766 6e168615 Ilias Tsitsimpis
                      help="Show stale servers from previous runs, whose "
1767 21bbbc9b Vangelis Koukis
                           "name starts with `%s'" % SNF_TEST_PREFIX,
1768 5a140b23 Vangelis Koukis
                      default=False)
1769 5a140b23 Vangelis Koukis
    parser.add_option("--delete-stale",
1770 5a140b23 Vangelis Koukis
                      action="store_true", dest="delete_stale",
1771 6e168615 Ilias Tsitsimpis
                      help="Delete stale servers from previous runs, whose "
1772 21bbbc9b Vangelis Koukis
                           "name starts with `%s'" % SNF_TEST_PREFIX,
1773 5a140b23 Vangelis Koukis
                      default=False)
1774 9659e075 John Giannelos
    parser.add_option("--force-personality",
1775 65462ca9 John Giannelos
                      action="store", type="string", dest="personality_path",
1776 8252d64f John Giannelos
                      help="Force a personality file injection.\
1777 8252d64f John Giannelos
                            File path required. ",
1778 9659e075 John Giannelos
                      default=None)
1779 74ec726f John Giannelos
    parser.add_option("--log-folder",
1780 74ec726f John Giannelos
                      action="store", type="string", dest="log_folder",
1781 8252d64f John Giannelos
                      help="Define the absolute path where the output \
1782 8252d64f John Giannelos
                            log is stored. ",
1783 2bcfb712 John Giannelos
                      default="/var/log/burnin/")
1784 2aaa1336 John Giannelos
    parser.add_option("--verbose", "-V",
1785 2aaa1336 John Giannelos
                      action="store_true", dest="verbose",
1786 6e168615 Ilias Tsitsimpis
                      help="Print detailed output about multiple "
1787 8792bb97 Ilias Tsitsimpis
                           "processes spawning",
1788 2aaa1336 John Giannelos
                      default=False)
1789 22efe1fe John Giannelos
    parser.add_option("--set-tests",
1790 22efe1fe John Giannelos
                      action="callback",
1791 746540cd John Giannelos
                      dest="tests",
1792 22efe1fe John Giannelos
                      type="string",
1793 22efe1fe John Giannelos
                      help='Set comma seperated tests for this run. \
1794 22efe1fe John Giannelos
                            Available tests: auth, images, flavors, \
1795 746540cd John Giannelos
                                             servers, server_spawn, \
1796 746540cd John Giannelos
                                             network_spawn. \
1797 22efe1fe John Giannelos
                            Default = all',
1798 22efe1fe John Giannelos
                      default='all',
1799 22efe1fe John Giannelos
                      callback=parse_comma)
1800 22efe1fe John Giannelos
1801 5a140b23 Vangelis Koukis
    (opts, args) = parser.parse_args(args)
1802 5a140b23 Vangelis Koukis
1803 8792bb97 Ilias Tsitsimpis
    # -----------------------
1804 5a140b23 Vangelis Koukis
    # Verify arguments
1805 8792bb97 Ilias Tsitsimpis
1806 8792bb97 Ilias Tsitsimpis
    # `delete_stale' implies `show_stale'
1807 5a140b23 Vangelis Koukis
    if opts.delete_stale:
1808 5a140b23 Vangelis Koukis
        opts.show_stale = True
1809 5a140b23 Vangelis Koukis
1810 8792bb97 Ilias Tsitsimpis
    # `image-id' is mandatory
1811 7f62a0b5 Vangelis Koukis
    if not opts.show_stale:
1812 7f62a0b5 Vangelis Koukis
        if not opts.force_imageid:
1813 8792bb97 Ilias Tsitsimpis
            print >>sys.stderr, red + \
1814 6e168615 Ilias Tsitsimpis
                "The --image-id argument is mandatory.\n" + \
1815 6e168615 Ilias Tsitsimpis
                normal
1816 7f62a0b5 Vangelis Koukis
            parser.print_help()
1817 7f62a0b5 Vangelis Koukis
            sys.exit(1)
1818 7f62a0b5 Vangelis Koukis
        if opts.force_imageid != 'all':
1819 7f62a0b5 Vangelis Koukis
            try:
1820 99d41650 John Giannelos
                opts.force_imageid = str(opts.force_imageid)
1821 7f62a0b5 Vangelis Koukis
            except ValueError:
1822 8792bb97 Ilias Tsitsimpis
                print >>sys.stderr, red + \
1823 6e168615 Ilias Tsitsimpis
                    "Invalid value specified for" + \
1824 6e168615 Ilias Tsitsimpis
                    "--image-id. Use a valid id, or `all'." + \
1825 6e168615 Ilias Tsitsimpis
                    normal
1826 7f62a0b5 Vangelis Koukis
                sys.exit(1)
1827 7f62a0b5 Vangelis Koukis
1828 8792bb97 Ilias Tsitsimpis
    # `token' is mandatory
1829 8792bb97 Ilias Tsitsimpis
    if not opts.token:
1830 8792bb97 Ilias Tsitsimpis
        print >>sys.stderr, red + \
1831 6e168615 Ilias Tsitsimpis
            "The --token argument is mandatory.\n" + \
1832 6e168615 Ilias Tsitsimpis
            normal
1833 8792bb97 Ilias Tsitsimpis
        parser.print_help()
1834 8792bb97 Ilias Tsitsimpis
        sys.exit(1)
1835 8792bb97 Ilias Tsitsimpis
1836 5a140b23 Vangelis Koukis
    return (opts, args)
1837 5a140b23 Vangelis Koukis
1838 5a140b23 Vangelis Koukis
1839 8792bb97 Ilias Tsitsimpis
# --------------------------------------------------------------------
1840 8792bb97 Ilias Tsitsimpis
# Burnin main function
1841 5a140b23 Vangelis Koukis
def main():
1842 5a140b23 Vangelis Koukis
    """Assemble test cases into a test suite, and run it
1843 5a140b23 Vangelis Koukis

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

1850 5a140b23 Vangelis Koukis
    """
1851 ae139e8a John Giannelos
1852 8792bb97 Ilias Tsitsimpis
    # Parse arguments using `optparse'
1853 5a140b23 Vangelis Koukis
    (opts, args) = parse_arguments(sys.argv[1:])
1854 5a140b23 Vangelis Koukis
1855 8792bb97 Ilias Tsitsimpis
    # Some global variables
1856 2aaa1336 John Giannelos
    global API, TOKEN, PLANKTON, PLANKTON_USER, NO_IPV6, VERBOSE, NOFAILFAST
1857 21bbbc9b Vangelis Koukis
    API = opts.api
1858 21bbbc9b Vangelis Koukis
    TOKEN = opts.token
1859 946da8b6 John Giannelos
    PLANKTON = opts.plankton
1860 946da8b6 John Giannelos
    PLANKTON_USER = opts.plankton_user
1861 946da8b6 John Giannelos
    NO_IPV6 = opts.no_ipv6
1862 2aaa1336 John Giannelos
    VERBOSE = opts.verbose
1863 2aaa1336 John Giannelos
    NOFAILFAST = opts.nofailfast
1864 21bbbc9b Vangelis Koukis
1865 8792bb97 Ilias Tsitsimpis
    # If `show_stale', cleanup stale servers
1866 8792bb97 Ilias Tsitsimpis
    # from previous runs and exit
1867 5a140b23 Vangelis Koukis
    if opts.show_stale:
1868 8792bb97 Ilias Tsitsimpis
        # We must clean the servers first
1869 8792bb97 Ilias Tsitsimpis
        cleanup_servers(opts.action_timeout, opts.query_interval,
1870 8792bb97 Ilias Tsitsimpis
                        delete_stale=opts.delete_stale)
1871 8792bb97 Ilias Tsitsimpis
        cleanup_networks(opts.action_timeout, opts.query_interval,
1872 8792bb97 Ilias Tsitsimpis
                         delete_stale=opts.delete_stale)
1873 74ec726f John Giannelos
        return 0
1874 5a140b23 Vangelis Koukis
1875 5a140b23 Vangelis Koukis
    # Initialize a kamaki instance, get flavors, images
1876 96da37c8 John Giannelos
    c = ComputeClient(API, TOKEN)
1877 5a140b23 Vangelis Koukis
    DIMAGES = c.list_images(detail=True)
1878 5a140b23 Vangelis Koukis
    DFLAVORS = c.list_flavors(detail=True)
1879 5a140b23 Vangelis Koukis
1880 21bbbc9b Vangelis Koukis
    # FIXME: logging, log, LOG PID, TEST_RUN_ID, arguments
1881 5a140b23 Vangelis Koukis
    # Run them: FIXME: In parallel, FAILEARLY, catchbreak?
1882 5a140b23 Vangelis Koukis
    #unittest.main(verbosity=2, catchbreak=True)
1883 5a140b23 Vangelis Koukis
1884 6e168615 Ilias Tsitsimpis
    # Get a list of images we are going to test
1885 e94a9d8c John Giannelos
    if opts.force_imageid == 'all':
1886 e94a9d8c John Giannelos
        test_images = DIMAGES
1887 e94a9d8c John Giannelos
    else:
1888 e94a9d8c John Giannelos
        test_images = filter(lambda x: x["id"] == opts.force_imageid, DIMAGES)
1889 e94a9d8c John Giannelos
1890 6e168615 Ilias Tsitsimpis
    # Create output (logging) folder
1891 74ec726f John Giannelos
    if not os.path.exists(opts.log_folder):
1892 74ec726f John Giannelos
        os.mkdir(opts.log_folder)
1893 2bcfb712 John Giannelos
    test_folder = os.path.join(opts.log_folder, TEST_RUN_ID)
1894 74ec726f John Giannelos
    os.mkdir(test_folder)
1895 81e8cbf6 John Giannelos
1896 00f87624 Vangelis Koukis
    for image in test_images:
1897 99d41650 John Giannelos
        imageid = str(image["id"])
1898 6e168615 Ilias Tsitsimpis
        imagename = image["name"]
1899 6e168615 Ilias Tsitsimpis
        # Choose a flavor (given from user or random)
1900 81e8cbf6 John Giannelos
        if opts.force_flavorid:
1901 81e8cbf6 John Giannelos
            flavorid = opts.force_flavorid
1902 81e8cbf6 John Giannelos
        else:
1903 81e8cbf6 John Giannelos
            flavorid = choice([f["id"] for f in DFLAVORS if f["disk"] >= 20])
1904 6e168615 Ilias Tsitsimpis
        # Personality dictionary for file injection test
1905 6e168615 Ilias Tsitsimpis
        if opts.personality_path is not None:
1906 9659e075 John Giannelos
            f = open(opts.personality_path)
1907 9659e075 John Giannelos
            content = b64encode(f.read())
1908 9659e075 John Giannelos
            personality = []
1909 9659e075 John Giannelos
            st = os.stat(opts.personality_path)
1910 9659e075 John Giannelos
            personality.append({
1911 6e168615 Ilias Tsitsimpis
                'path': '/root/test_inj_file',
1912 6e168615 Ilias Tsitsimpis
                'owner': 'root',
1913 6e168615 Ilias Tsitsimpis
                'group': 'root',
1914 6e168615 Ilias Tsitsimpis
                'mode': 0x7777 & st.st_mode,
1915 6e168615 Ilias Tsitsimpis
                'contents': content})
1916 9659e075 John Giannelos
        else:
1917 9659e075 John Giannelos
            personality = None
1918 6e168615 Ilias Tsitsimpis
        # Give a name to our test servers
1919 21bbbc9b Vangelis Koukis
        servername = "%s%s for %s" % (SNF_TEST_PREFIX, TEST_RUN_ID, imagename)
1920 21bbbc9b Vangelis Koukis
        is_windows = imagename.lower().find("windows") >= 0
1921 8252d64f John Giannelos
1922 6e168615 Ilias Tsitsimpis
        # Create Server TestCases
1923 8252d64f John Giannelos
        ServerTestCase = _spawn_server_test_case(
1924 8252d64f John Giannelos
            imageid=imageid,
1925 8252d64f John Giannelos
            flavorid=flavorid,
1926 8252d64f John Giannelos
            imagename=imagename,
1927 8252d64f John Giannelos
            personality=personality,
1928 8252d64f John Giannelos
            servername=servername,
1929 8252d64f John Giannelos
            is_windows=is_windows,
1930 8252d64f John Giannelos
            action_timeout=opts.action_timeout,
1931 8252d64f John Giannelos
            build_warning=opts.build_warning,
1932 8252d64f John Giannelos
            build_fail=opts.build_fail,
1933 6e168615 Ilias Tsitsimpis
            query_interval=opts.query_interval)
1934 6e168615 Ilias Tsitsimpis
        # Create Network TestCases
1935 8252d64f John Giannelos
        NetworkTestCase = _spawn_network_test_case(
1936 8252d64f John Giannelos
            action_timeout=opts.action_timeout,
1937 8252d64f John Giannelos
            imageid=imageid,
1938 8252d64f John Giannelos
            flavorid=flavorid,
1939 8252d64f John Giannelos
            imagename=imagename,
1940 6e168615 Ilias Tsitsimpis
            query_interval=opts.query_interval)
1941 8252d64f John Giannelos
1942 6e168615 Ilias Tsitsimpis
        # Choose the tests we are going to run
1943 746540cd John Giannelos
        test_dict = {'auth': UnauthorizedTestCase,
1944 746540cd John Giannelos
                     'images': ImagesTestCase,
1945 746540cd John Giannelos
                     'flavors': FlavorsTestCase,
1946 746540cd John Giannelos
                     'servers': ServersTestCase,
1947 746540cd John Giannelos
                     'server_spawn': ServerTestCase,
1948 746540cd John Giannelos
                     'network_spawn': NetworkTestCase}
1949 22efe1fe John Giannelos
        seq_cases = []
1950 22efe1fe John Giannelos
        if 'all' in opts.tests:
1951 22efe1fe John Giannelos
            seq_cases = [UnauthorizedTestCase, ImagesTestCase, FlavorsTestCase,
1952 22efe1fe John Giannelos
                         ServersTestCase, ServerTestCase, NetworkTestCase]
1953 22efe1fe John Giannelos
        else:
1954 22efe1fe John Giannelos
            for test in opts.tests:
1955 22efe1fe John Giannelos
                seq_cases.append(test_dict[test])
1956 22efe1fe John Giannelos
1957 6e168615 Ilias Tsitsimpis
        # Folder for each image
1958 2bcfb712 John Giannelos
        image_folder = os.path.join(test_folder, imageid)
1959 81e8cbf6 John Giannelos
        os.mkdir(image_folder)
1960 81e8cbf6 John Giannelos
1961 6e168615 Ilias Tsitsimpis
        # Run each test
1962 6e168615 Ilias Tsitsimpis
        if opts.fanout > 1:
1963 3e4c5c32 John Giannelos
            _run_cases_in_parallel(seq_cases, opts.fanout, image_folder)
1964 3e4c5c32 John Giannelos
        else:
1965 6e168615 Ilias Tsitsimpis
            _run_cases_in_series(seq_cases, image_folder)
1966 6e168615 Ilias Tsitsimpis
1967 746540cd John Giannelos
1968 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
1969 6e168615 Ilias Tsitsimpis
# Call main
1970 5a140b23 Vangelis Koukis
if __name__ == "__main__":
1971 5a140b23 Vangelis Koukis
    sys.exit(main())