Statistics
| Branch: | Tag: | Revision:

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

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

588 f752215c John Giannelos
        Implementation of RFB protocol follows
589 f752215c John Giannelos
        http://www.realvnc.com/docs/rfbproto.pdf.
590 bc14ba88 Vangelis Koukis

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

1533 21bbbc9b Vangelis Koukis
    The cases iterable specifies the TestCases to be executed in parallel,
1534 21bbbc9b Vangelis Koukis
    by test runners running in distinct processes.
1535 21bbbc9b Vangelis Koukis
    The fanout parameter specifies the number of processes to spawn,
1536 21bbbc9b Vangelis Koukis
    and defaults to 1.
1537 21bbbc9b Vangelis Koukis
    The runner argument specifies the test runner class to use inside each
1538 21bbbc9b Vangelis Koukis
    runner process.
1539 21bbbc9b Vangelis Koukis

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

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

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