Statistics
| Branch: | Tag: | Revision:

root / snf-tools / synnefo_tools / burnin.py @ 536a1f14

History | View | Annotate | Download (80.7 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 11779b6c Ilias Tsitsimpis
import os.path
44 5a140b23 Vangelis Koukis
import paramiko
45 21bbbc9b Vangelis Koukis
import prctl
46 5a140b23 Vangelis Koukis
import subprocess
47 21bbbc9b Vangelis Koukis
import signal
48 5a140b23 Vangelis Koukis
import socket
49 5a140b23 Vangelis Koukis
import sys
50 5a140b23 Vangelis Koukis
import time
51 11779b6c Ilias Tsitsimpis
import tempfile
52 9659e075 John Giannelos
from base64 import b64encode
53 5a140b23 Vangelis Koukis
from IPy import IP
54 21bbbc9b Vangelis Koukis
from multiprocessing import Process, Queue
55 11779b6c Ilias Tsitsimpis
from random import choice, randint
56 22efe1fe John Giannelos
from optparse import OptionParser, OptionValueError
57 21bbbc9b Vangelis Koukis
58 96da37c8 John Giannelos
from kamaki.clients.compute import ComputeClient
59 96da37c8 John Giannelos
from kamaki.clients.cyclades import CycladesClient
60 946da8b6 John Giannelos
from kamaki.clients.image import ImageClient
61 11779b6c Ilias Tsitsimpis
from kamaki.clients.pithos import PithosClient
62 bacb7c87 Ilias Tsitsimpis
from kamaki.clients.astakos import AstakosClient
63 21dcb666 John Giannelos
from kamaki.clients import ClientError
64 96da37c8 John Giannelos
65 bc14ba88 Vangelis Koukis
from vncauthproxy.d3des import generate_response as d3des_generate_response
66 5a140b23 Vangelis Koukis
67 5a140b23 Vangelis Koukis
# Use backported unittest functionality if Python < 2.7
68 5a140b23 Vangelis Koukis
try:
69 5a140b23 Vangelis Koukis
    import unittest2 as unittest
70 5a140b23 Vangelis Koukis
except ImportError:
71 bc14ba88 Vangelis Koukis
    if sys.version_info < (2, 7):
72 bc14ba88 Vangelis Koukis
        raise Exception("The unittest2 package is required for Python < 2.7")
73 5a140b23 Vangelis Koukis
    import unittest
74 5a140b23 Vangelis Koukis
75 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
76 6e168615 Ilias Tsitsimpis
# Global Variables
77 186428b0 Ilias Tsitsimpis
AUTH_URL = None
78 6e168615 Ilias Tsitsimpis
TOKEN = None
79 6e168615 Ilias Tsitsimpis
PLANKTON_USER = None
80 6e168615 Ilias Tsitsimpis
NO_IPV6 = None
81 6e168615 Ilias Tsitsimpis
DEFAULT_PLANKTON_USER = "images@okeanos.grnet.gr"
82 6e168615 Ilias Tsitsimpis
NOFAILFAST = None
83 6e168615 Ilias Tsitsimpis
VERBOSE = None
84 6e168615 Ilias Tsitsimpis
85 6e168615 Ilias Tsitsimpis
# A unique id identifying this test run
86 6e168615 Ilias Tsitsimpis
TEST_RUN_ID = datetime.datetime.strftime(datetime.datetime.now(),
87 6e168615 Ilias Tsitsimpis
                                         "%Y%m%d%H%M%S")
88 6e168615 Ilias Tsitsimpis
SNF_TEST_PREFIX = "snf-test-"
89 6e168615 Ilias Tsitsimpis
90 6e168615 Ilias Tsitsimpis
red = '\x1b[31m'
91 6e168615 Ilias Tsitsimpis
yellow = '\x1b[33m'
92 6e168615 Ilias Tsitsimpis
green = '\x1b[32m'
93 6e168615 Ilias Tsitsimpis
normal = '\x1b[0m'
94 6e168615 Ilias Tsitsimpis
95 5a140b23 Vangelis Koukis
96 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
97 2a410f76 Ilias Tsitsimpis
# Global functions
98 2a410f76 Ilias Tsitsimpis
def _ssh_execute(hostip, username, password, command):
99 2a410f76 Ilias Tsitsimpis
    """Execute a command via ssh"""
100 2a410f76 Ilias Tsitsimpis
    ssh = paramiko.SSHClient()
101 2a410f76 Ilias Tsitsimpis
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
102 2a410f76 Ilias Tsitsimpis
    try:
103 2a410f76 Ilias Tsitsimpis
        ssh.connect(hostip, username=username, password=password)
104 4fed2379 Ilias Tsitsimpis
    except socket.error, err:
105 4fed2379 Ilias Tsitsimpis
        raise AssertionError(err)
106 2a410f76 Ilias Tsitsimpis
    try:
107 2a410f76 Ilias Tsitsimpis
        stdin, stdout, stderr = ssh.exec_command(command)
108 4fed2379 Ilias Tsitsimpis
    except paramiko.SSHException, err:
109 4fed2379 Ilias Tsitsimpis
        raise AssertionError(err)
110 2a410f76 Ilias Tsitsimpis
    status = stdout.channel.recv_exit_status()
111 2a410f76 Ilias Tsitsimpis
    output = stdout.readlines()
112 2a410f76 Ilias Tsitsimpis
    ssh.close()
113 2a410f76 Ilias Tsitsimpis
    return output, status
114 2a410f76 Ilias Tsitsimpis
115 2a410f76 Ilias Tsitsimpis
116 bacb7c87 Ilias Tsitsimpis
def _get_user_id():
117 bacb7c87 Ilias Tsitsimpis
    """Authenticate to astakos and get unique users id"""
118 186428b0 Ilias Tsitsimpis
    astakos = AstakosClient(AUTH_URL, TOKEN)
119 965b25af Ilias Tsitsimpis
    authenticate = astakos.authenticate()
120 186428b0 Ilias Tsitsimpis
    return authenticate['access']['user']['id']
121 bacb7c87 Ilias Tsitsimpis
122 bacb7c87 Ilias Tsitsimpis
123 2a410f76 Ilias Tsitsimpis
# --------------------------------------------------------------------
124 6e168615 Ilias Tsitsimpis
# BurninTestReulst class
125 66eba2cf John Giannelos
class BurninTestResult(unittest.TextTestResult):
126 66eba2cf John Giannelos
    def addSuccess(self, test):
127 66eba2cf John Giannelos
        super(BurninTestResult, self).addSuccess(test)
128 66eba2cf John Giannelos
        if self.showAll:
129 3e4c5c32 John Giannelos
            if hasattr(test, 'result_dict'):
130 66eba2cf John Giannelos
                run_details = test.result_dict
131 66eba2cf John Giannelos
132 66eba2cf John Giannelos
                self.stream.write("\n")
133 66eba2cf John Giannelos
                for i in run_details:
134 66eba2cf John Giannelos
                    self.stream.write("%s : %s \n" % (i, run_details[i]))
135 66eba2cf John Giannelos
                self.stream.write("\n")
136 66eba2cf John Giannelos
137 66eba2cf John Giannelos
        elif self.dots:
138 66eba2cf John Giannelos
            self.stream.write('.')
139 6e168615 Ilias Tsitsimpis
            self.stream.flush()
140 6e168615 Ilias Tsitsimpis
141 66eba2cf John Giannelos
    def addError(self, test, err):
142 66eba2cf John Giannelos
        super(BurninTestResult, self).addError(test, err)
143 66eba2cf John Giannelos
        if self.showAll:
144 66eba2cf John Giannelos
            self.stream.writeln("ERROR")
145 3e4c5c32 John Giannelos
            if hasattr(test, 'result_dict'):
146 3e4c5c32 John Giannelos
                run_details = test.result_dict
147 66eba2cf John Giannelos
148 3e4c5c32 John Giannelos
                self.stream.write("\n")
149 3e4c5c32 John Giannelos
                for i in run_details:
150 3e4c5c32 John Giannelos
                    self.stream.write("%s : %s \n" % (i, run_details[i]))
151 3e4c5c32 John Giannelos
                self.stream.write("\n")
152 66eba2cf John Giannelos
153 66eba2cf John Giannelos
        elif self.dots:
154 66eba2cf John Giannelos
            self.stream.write('E')
155 66eba2cf John Giannelos
            self.stream.flush()
156 66eba2cf John Giannelos
157 66eba2cf John Giannelos
    def addFailure(self, test, err):
158 66eba2cf John Giannelos
        super(BurninTestResult, self).addFailure(test, err)
159 66eba2cf John Giannelos
        if self.showAll:
160 66eba2cf John Giannelos
            self.stream.writeln("FAIL")
161 3e4c5c32 John Giannelos
            if hasattr(test, 'result_dict'):
162 3e4c5c32 John Giannelos
                run_details = test.result_dict
163 66eba2cf John Giannelos
164 3e4c5c32 John Giannelos
                self.stream.write("\n")
165 3e4c5c32 John Giannelos
                for i in run_details:
166 3e4c5c32 John Giannelos
                    self.stream.write("%s : %s \n" % (i, run_details[i]))
167 3e4c5c32 John Giannelos
                self.stream.write("\n")
168 66eba2cf John Giannelos
169 66eba2cf John Giannelos
        elif self.dots:
170 66eba2cf John Giannelos
            self.stream.write('F')
171 66eba2cf John Giannelos
            self.stream.flush()
172 66eba2cf John Giannelos
173 66eba2cf John Giannelos
174 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
175 6e168615 Ilias Tsitsimpis
# Format Results
176 746540cd John Giannelos
class burninFormatter(logging.Formatter):
177 746540cd John Giannelos
    err_fmt = red + "ERROR: %(msg)s" + normal
178 9b013c3a John Giannelos
    dbg_fmt = green + "* %(msg)s" + normal
179 746540cd John Giannelos
    info_fmt = "%(msg)s"
180 746540cd John Giannelos
181 746540cd John Giannelos
    def __init__(self, fmt="%(levelno)s: %(msg)s"):
182 746540cd John Giannelos
        logging.Formatter.__init__(self, fmt)
183 746540cd John Giannelos
184 746540cd John Giannelos
    def format(self, record):
185 746540cd John Giannelos
        format_orig = self._fmt
186 746540cd John Giannelos
        # Replace the original format with one customized by logging level
187 746540cd John Giannelos
        if record.levelno == 10:    # DEBUG
188 746540cd John Giannelos
            self._fmt = burninFormatter.dbg_fmt
189 746540cd John Giannelos
        elif record.levelno == 20:  # INFO
190 746540cd John Giannelos
            self._fmt = burninFormatter.info_fmt
191 746540cd John Giannelos
        elif record.levelno == 40:  # ERROR
192 746540cd John Giannelos
            self._fmt = burninFormatter.err_fmt
193 746540cd John Giannelos
        result = logging.Formatter.format(self, record)
194 746540cd John Giannelos
        self._fmt = format_orig
195 746540cd John Giannelos
        return result
196 746540cd John Giannelos
197 00f87624 Vangelis Koukis
log = logging.getLogger("burnin")
198 746540cd John Giannelos
log.setLevel(logging.DEBUG)
199 746540cd John Giannelos
handler = logging.StreamHandler()
200 746540cd John Giannelos
handler.setFormatter(burninFormatter())
201 746540cd John Giannelos
log.addHandler(handler)
202 5a140b23 Vangelis Koukis
203 2bcfb712 John Giannelos
204 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
205 6e168615 Ilias Tsitsimpis
# UnauthorizedTestCase class
206 5a140b23 Vangelis Koukis
class UnauthorizedTestCase(unittest.TestCase):
207 6e168615 Ilias Tsitsimpis
    """Test unauthorized access"""
208 66eba2cf John Giannelos
    @classmethod
209 66eba2cf John Giannelos
    def setUpClass(cls):
210 186428b0 Ilias Tsitsimpis
        cls.astakos = AstakosClient(AUTH_URL, TOKEN)
211 186428b0 Ilias Tsitsimpis
        cls.compute_url = \
212 186428b0 Ilias Tsitsimpis
            cls.astakos.get_service_endpoints('compute')['publicURL']
213 66eba2cf John Giannelos
        cls.result_dict = dict()
214 66eba2cf John Giannelos
215 5a140b23 Vangelis Koukis
    def test_unauthorized_access(self):
216 5a140b23 Vangelis Koukis
        """Test access without a valid token fails"""
217 81e8cbf6 John Giannelos
        log.info("Authentication test")
218 1c636ad6 John Giannelos
        falseToken = '12345'
219 186428b0 Ilias Tsitsimpis
        c = ComputeClient(self.compute_url, falseToken)
220 1c636ad6 John Giannelos
221 5a140b23 Vangelis Koukis
        with self.assertRaises(ClientError) as cm:
222 5a140b23 Vangelis Koukis
            c.list_servers()
223 21dcb666 John Giannelos
            self.assertEqual(cm.exception.status, 401)
224 5a140b23 Vangelis Koukis
225 5a140b23 Vangelis Koukis
226 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
227 95a87099 Ilias Tsitsimpis
# This class gest replicated into Images TestCases dynamically
228 5a140b23 Vangelis Koukis
class ImagesTestCase(unittest.TestCase):
229 5a140b23 Vangelis Koukis
    """Test image lists for consistency"""
230 5a140b23 Vangelis Koukis
    @classmethod
231 5a140b23 Vangelis Koukis
    def setUpClass(cls):
232 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of images"""
233 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of images")
234 186428b0 Ilias Tsitsimpis
        cls.astakos_client = AstakosClient(AUTH_URL, TOKEN)
235 186428b0 Ilias Tsitsimpis
        # Compute Client
236 186428b0 Ilias Tsitsimpis
        compute_url = \
237 186428b0 Ilias Tsitsimpis
            cls.astakos_client.get_service_endpoints('compute')['publicURL']
238 186428b0 Ilias Tsitsimpis
        cls.compute_client = ComputeClient(compute_url, TOKEN)
239 186428b0 Ilias Tsitsimpis
        # Image Client
240 186428b0 Ilias Tsitsimpis
        image_url = \
241 186428b0 Ilias Tsitsimpis
            cls.astakos_client.get_service_endpoints('image')['publicURL']
242 186428b0 Ilias Tsitsimpis
        cls.image_client = ImageClient(image_url, TOKEN)
243 186428b0 Ilias Tsitsimpis
        # Pithos Client
244 186428b0 Ilias Tsitsimpis
        pithos_url = cls.astakos_client.\
245 186428b0 Ilias Tsitsimpis
            get_service_endpoints('object-store')['publicURL']
246 186428b0 Ilias Tsitsimpis
        cls.pithos_client = PithosClient(pithos_url, TOKEN)
247 536a1f14 Ilias Tsitsimpis
        cls.pithos_client.CONNECTION_RETRY_LIMIT = 2
248 186428b0 Ilias Tsitsimpis
249 186428b0 Ilias Tsitsimpis
        # Get images
250 a352f80f Ilias Tsitsimpis
        cls.images = \
251 a352f80f Ilias Tsitsimpis
            filter(lambda x: not x['name'].startswith(SNF_TEST_PREFIX),
252 186428b0 Ilias Tsitsimpis
                   cls.image_client.list_public())
253 a352f80f Ilias Tsitsimpis
        cls.dimages = \
254 a352f80f Ilias Tsitsimpis
            filter(lambda x: not x['name'].startswith(SNF_TEST_PREFIX),
255 186428b0 Ilias Tsitsimpis
                   cls.image_client.list_public(detail=True))
256 66eba2cf John Giannelos
        cls.result_dict = dict()
257 bacb7c87 Ilias Tsitsimpis
        # Get uniq user id
258 bacb7c87 Ilias Tsitsimpis
        cls.uuid = _get_user_id()
259 bacb7c87 Ilias Tsitsimpis
        log.info("Uniq user id = %s" % cls.uuid)
260 95a87099 Ilias Tsitsimpis
        # Create temp directory and store it inside our class
261 95a87099 Ilias Tsitsimpis
        # XXX: In my machine /tmp has not enough space
262 95a87099 Ilias Tsitsimpis
        #      so use current directory to be sure.
263 95a87099 Ilias Tsitsimpis
        cls.temp_dir = tempfile.mkdtemp(dir=os.getcwd())
264 95a87099 Ilias Tsitsimpis
        cls.temp_image_name = \
265 95a87099 Ilias Tsitsimpis
            SNF_TEST_PREFIX + cls.imageid + ".diskdump"
266 5a140b23 Vangelis Koukis
267 4d72f9ab Ilias Tsitsimpis
    @classmethod
268 4d72f9ab Ilias Tsitsimpis
    def tearDownClass(cls):
269 4d72f9ab Ilias Tsitsimpis
        """Remove local files"""
270 4d72f9ab Ilias Tsitsimpis
        try:
271 4d72f9ab Ilias Tsitsimpis
            temp_file = os.path.join(cls.temp_dir, cls.temp_image_name)
272 4d72f9ab Ilias Tsitsimpis
            os.unlink(temp_file)
273 4d72f9ab Ilias Tsitsimpis
        except:
274 4d72f9ab Ilias Tsitsimpis
            pass
275 4d72f9ab Ilias Tsitsimpis
        try:
276 4d72f9ab Ilias Tsitsimpis
            os.rmdir(cls.temp_dir)
277 4d72f9ab Ilias Tsitsimpis
        except:
278 4d72f9ab Ilias Tsitsimpis
            pass
279 4d72f9ab Ilias Tsitsimpis
280 5a140b23 Vangelis Koukis
    def test_001_list_images(self):
281 5a140b23 Vangelis Koukis
        """Test image list actually returns images"""
282 6207533f John Giannelos
        self.assertGreater(len(self.images), 0)
283 74ec726f John Giannelos
284 5a140b23 Vangelis Koukis
    def test_002_list_images_detailed(self):
285 5a140b23 Vangelis Koukis
        """Test detailed image list is the same length as list"""
286 6207533f John Giannelos
        self.assertEqual(len(self.dimages), len(self.images))
287 74ec726f John Giannelos
288 5a140b23 Vangelis Koukis
    def test_003_same_image_names(self):
289 5a140b23 Vangelis Koukis
        """Test detailed and simple image list contain same names"""
290 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.images))
291 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dimages))
292 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
293 5a140b23 Vangelis Koukis
294 186428b0 Ilias Tsitsimpis
# XXX: Find a way to resolve owner's uuid to username.
295 186428b0 Ilias Tsitsimpis
#      (maybe use astakosclient)
296 186428b0 Ilias Tsitsimpis
#    def test_004_unique_image_names(self):
297 186428b0 Ilias Tsitsimpis
#        """Test system images have unique names"""
298 186428b0 Ilias Tsitsimpis
#        sys_images = filter(lambda x: x['owner'] == PLANKTON_USER,
299 186428b0 Ilias Tsitsimpis
#                            self.dimages)
300 186428b0 Ilias Tsitsimpis
#        names = sorted(map(lambda x: x["name"], sys_images))
301 186428b0 Ilias Tsitsimpis
#        self.assertEqual(sorted(list(set(names))), names)
302 5a140b23 Vangelis Koukis
303 5a140b23 Vangelis Koukis
    def test_005_image_metadata(self):
304 5a140b23 Vangelis Koukis
        """Test every image has specific metadata defined"""
305 2e3b7dc8 John Giannelos
        keys = frozenset(["osfamily", "root_partition"])
306 186428b0 Ilias Tsitsimpis
        details = self.compute_client.list_images(detail=True)
307 846980fe John Giannelos
        for i in details:
308 bcb7c357 Ilias Tsitsimpis
            self.assertTrue(keys.issubset(i["metadata"].keys()))
309 5a140b23 Vangelis Koukis
310 95a87099 Ilias Tsitsimpis
    def test_006_download_image(self):
311 95a87099 Ilias Tsitsimpis
        """Download image from pithos+"""
312 95a87099 Ilias Tsitsimpis
        # Get image location
313 95a87099 Ilias Tsitsimpis
        image = filter(
314 95a87099 Ilias Tsitsimpis
            lambda x: x['id'] == self.imageid, self.dimages)[0]
315 95a87099 Ilias Tsitsimpis
        image_location = \
316 95a87099 Ilias Tsitsimpis
            image['location'].replace("://", " ").replace("/", " ").split()
317 95a87099 Ilias Tsitsimpis
        log.info("Download image, with owner %s\n\tcontainer %s, and name %s"
318 95a87099 Ilias Tsitsimpis
                 % (image_location[1], image_location[2], image_location[3]))
319 186428b0 Ilias Tsitsimpis
        self.pithos_client.account = image_location[1]
320 186428b0 Ilias Tsitsimpis
        self.pithos_client.container = image_location[2]
321 95a87099 Ilias Tsitsimpis
        temp_file = os.path.join(self.temp_dir, self.temp_image_name)
322 95a87099 Ilias Tsitsimpis
        with open(temp_file, "wb+") as f:
323 186428b0 Ilias Tsitsimpis
            self.pithos_client.download_object(image_location[3], f)
324 95a87099 Ilias Tsitsimpis
325 95a87099 Ilias Tsitsimpis
    def test_007_upload_image(self):
326 95a87099 Ilias Tsitsimpis
        """Upload and register image"""
327 95a87099 Ilias Tsitsimpis
        temp_file = os.path.join(self.temp_dir, self.temp_image_name)
328 95a87099 Ilias Tsitsimpis
        log.info("Upload image to pithos+")
329 95a87099 Ilias Tsitsimpis
        # Create container `images'
330 186428b0 Ilias Tsitsimpis
        self.pithos_client.account = self.uuid
331 186428b0 Ilias Tsitsimpis
        self.pithos_client.container = "images"
332 186428b0 Ilias Tsitsimpis
        self.pithos_client.container_put()
333 95a87099 Ilias Tsitsimpis
        with open(temp_file, "rb+") as f:
334 186428b0 Ilias Tsitsimpis
            self.pithos_client.upload_object(self.temp_image_name, f)
335 95a87099 Ilias Tsitsimpis
        log.info("Register image to plankton")
336 bacb7c87 Ilias Tsitsimpis
        location = "pithos://" + self.uuid + \
337 95a87099 Ilias Tsitsimpis
            "/images/" + self.temp_image_name
338 95a87099 Ilias Tsitsimpis
        params = {'is_public': True}
339 95a87099 Ilias Tsitsimpis
        properties = {'OSFAMILY': "linux", 'ROOT_PARTITION': 1}
340 186428b0 Ilias Tsitsimpis
        self.image_client.register(
341 186428b0 Ilias Tsitsimpis
            self.temp_image_name, location, params, properties)
342 4d72f9ab Ilias Tsitsimpis
        # Get image id
343 186428b0 Ilias Tsitsimpis
        details = self.image_client.list_public(detail=True)
344 4c9918f9 Ilias Tsitsimpis
        detail = filter(lambda x: x['location'] == location, details)
345 4d72f9ab Ilias Tsitsimpis
        self.assertEqual(len(detail), 1)
346 4d72f9ab Ilias Tsitsimpis
        cls = type(self)
347 4d72f9ab Ilias Tsitsimpis
        cls.temp_image_id = detail[0]['id']
348 4d72f9ab Ilias Tsitsimpis
        log.info("Image registered with id %s" % detail[0]['id'])
349 4d72f9ab Ilias Tsitsimpis
350 4d72f9ab Ilias Tsitsimpis
    def test_008_cleanup_image(self):
351 4d72f9ab Ilias Tsitsimpis
        """Cleanup image test"""
352 4d72f9ab Ilias Tsitsimpis
        log.info("Cleanup image test")
353 4d72f9ab Ilias Tsitsimpis
        # Remove image from pithos+
354 186428b0 Ilias Tsitsimpis
        self.pithos_client.account = self.uuid
355 186428b0 Ilias Tsitsimpis
        self.pithos_client.container = "images"
356 186428b0 Ilias Tsitsimpis
        self.pithos_client.del_object(self.temp_image_name)
357 95a87099 Ilias Tsitsimpis
358 5a140b23 Vangelis Koukis
359 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
360 6e168615 Ilias Tsitsimpis
# FlavorsTestCase class
361 5a140b23 Vangelis Koukis
class FlavorsTestCase(unittest.TestCase):
362 5a140b23 Vangelis Koukis
    """Test flavor lists for consistency"""
363 5a140b23 Vangelis Koukis
    @classmethod
364 5a140b23 Vangelis Koukis
    def setUpClass(cls):
365 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of flavors"""
366 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of flavors")
367 186428b0 Ilias Tsitsimpis
        cls.astakos_client = AstakosClient(AUTH_URL, TOKEN)
368 186428b0 Ilias Tsitsimpis
        # Compute Client
369 186428b0 Ilias Tsitsimpis
        compute_url = \
370 186428b0 Ilias Tsitsimpis
            cls.astakos_client.get_service_endpoints('compute')['publicURL']
371 186428b0 Ilias Tsitsimpis
        cls.compute_client = ComputeClient(compute_url, TOKEN)
372 186428b0 Ilias Tsitsimpis
        cls.flavors = cls.compute_client.list_flavors()
373 186428b0 Ilias Tsitsimpis
        cls.dflavors = cls.compute_client.list_flavors(detail=True)
374 66eba2cf John Giannelos
        cls.result_dict = dict()
375 5a140b23 Vangelis Koukis
376 5a140b23 Vangelis Koukis
    def test_001_list_flavors(self):
377 5a140b23 Vangelis Koukis
        """Test flavor list actually returns flavors"""
378 5a140b23 Vangelis Koukis
        self.assertGreater(len(self.flavors), 0)
379 5a140b23 Vangelis Koukis
380 5a140b23 Vangelis Koukis
    def test_002_list_flavors_detailed(self):
381 5a140b23 Vangelis Koukis
        """Test detailed flavor list is the same length as list"""
382 5a140b23 Vangelis Koukis
        self.assertEquals(len(self.dflavors), len(self.flavors))
383 5a140b23 Vangelis Koukis
384 5a140b23 Vangelis Koukis
    def test_003_same_flavor_names(self):
385 5a140b23 Vangelis Koukis
        """Test detailed and simple flavor list contain same names"""
386 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.flavors))
387 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dflavors))
388 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
389 5a140b23 Vangelis Koukis
390 5a140b23 Vangelis Koukis
    def test_004_unique_flavor_names(self):
391 5a140b23 Vangelis Koukis
        """Test flavors have unique names"""
392 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.flavors))
393 5a140b23 Vangelis Koukis
        self.assertEqual(sorted(list(set(names))), names)
394 5a140b23 Vangelis Koukis
395 5a140b23 Vangelis Koukis
    def test_005_well_formed_flavor_names(self):
396 5a140b23 Vangelis Koukis
        """Test flavors have names of the form CxxRyyDzz
397 5a140b23 Vangelis Koukis
        Where xx is vCPU count, yy is RAM in MiB, zz is Disk in GiB
398 5a140b23 Vangelis Koukis
        """
399 5a140b23 Vangelis Koukis
        for f in self.dflavors:
400 186428b0 Ilias Tsitsimpis
            flavor = (f["vcpus"], f["ram"], f["disk"], f["SNF:disk_template"])
401 95b36b00 Christos Stavrakakis
            self.assertEqual("C%dR%dD%d%s" % flavor,
402 5a140b23 Vangelis Koukis
                             f["name"],
403 5a140b23 Vangelis Koukis
                             "Flavor %s does not match its specs." % f["name"])
404 5a140b23 Vangelis Koukis
405 5a140b23 Vangelis Koukis
406 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
407 6e168615 Ilias Tsitsimpis
# ServersTestCase class
408 5a140b23 Vangelis Koukis
class ServersTestCase(unittest.TestCase):
409 5a140b23 Vangelis Koukis
    """Test server lists for consistency"""
410 5a140b23 Vangelis Koukis
    @classmethod
411 5a140b23 Vangelis Koukis
    def setUpClass(cls):
412 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of servers"""
413 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of servers")
414 1c636ad6 John Giannelos
415 186428b0 Ilias Tsitsimpis
        cls.astakos_client = AstakosClient(AUTH_URL, TOKEN)
416 186428b0 Ilias Tsitsimpis
        # Compute Client
417 186428b0 Ilias Tsitsimpis
        compute_url = \
418 186428b0 Ilias Tsitsimpis
            cls.astakos_client.get_service_endpoints('compute')['publicURL']
419 186428b0 Ilias Tsitsimpis
        cls.compute_client = ComputeClient(compute_url, TOKEN)
420 186428b0 Ilias Tsitsimpis
        cls.servers = cls.compute_client.list_servers()
421 186428b0 Ilias Tsitsimpis
        cls.dservers = cls.compute_client.list_servers(detail=True)
422 66eba2cf John Giannelos
        cls.result_dict = dict()
423 5a140b23 Vangelis Koukis
424 139d3a0b Ilias Tsitsimpis
    # def test_001_list_servers(self):
425 139d3a0b Ilias Tsitsimpis
    #     """Test server list actually returns servers"""
426 139d3a0b Ilias Tsitsimpis
    #     self.assertGreater(len(self.servers), 0)
427 5a140b23 Vangelis Koukis
428 5a140b23 Vangelis Koukis
    def test_002_list_servers_detailed(self):
429 5a140b23 Vangelis Koukis
        """Test detailed server list is the same length as list"""
430 5a140b23 Vangelis Koukis
        self.assertEqual(len(self.dservers), len(self.servers))
431 5a140b23 Vangelis Koukis
432 5a140b23 Vangelis Koukis
    def test_003_same_server_names(self):
433 5a140b23 Vangelis Koukis
        """Test detailed and simple flavor list contain same names"""
434 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.servers))
435 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dservers))
436 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
437 5a140b23 Vangelis Koukis
438 5a140b23 Vangelis Koukis
439 11779b6c Ilias Tsitsimpis
# --------------------------------------------------------------------
440 11779b6c Ilias Tsitsimpis
# Pithos Test Cases
441 11779b6c Ilias Tsitsimpis
class PithosTestCase(unittest.TestCase):
442 11779b6c Ilias Tsitsimpis
    """Test pithos functionality"""
443 11779b6c Ilias Tsitsimpis
    @classmethod
444 11779b6c Ilias Tsitsimpis
    def setUpClass(cls):
445 11779b6c Ilias Tsitsimpis
        """Initialize kamaki, get list of containers"""
446 bacb7c87 Ilias Tsitsimpis
        # Get uniq user id
447 bacb7c87 Ilias Tsitsimpis
        cls.uuid = _get_user_id()
448 bacb7c87 Ilias Tsitsimpis
        log.info("Uniq user id = %s" % cls.uuid)
449 11779b6c Ilias Tsitsimpis
        log.info("Getting list of containers")
450 186428b0 Ilias Tsitsimpis
451 186428b0 Ilias Tsitsimpis
        cls.astakos_client = AstakosClient(AUTH_URL, TOKEN)
452 186428b0 Ilias Tsitsimpis
        # Pithos Client
453 186428b0 Ilias Tsitsimpis
        pithos_url = cls.astakos_client.\
454 186428b0 Ilias Tsitsimpis
            get_service_endpoints('object-store')['publicURL']
455 186428b0 Ilias Tsitsimpis
        cls.pithos_client = PithosClient(pithos_url, TOKEN, cls.uuid)
456 536a1f14 Ilias Tsitsimpis
        cls.pithos_client.CONNECTION_RETRY_LIMIT = 2
457 186428b0 Ilias Tsitsimpis
458 186428b0 Ilias Tsitsimpis
        cls.containers = cls.pithos_client.list_containers()
459 11779b6c Ilias Tsitsimpis
        cls.result_dict = dict()
460 11779b6c Ilias Tsitsimpis
461 11779b6c Ilias Tsitsimpis
    def test_001_list_containers(self):
462 11779b6c Ilias Tsitsimpis
        """Test container list actually returns containers"""
463 11779b6c Ilias Tsitsimpis
        self.assertGreater(len(self.containers), 0)
464 11779b6c Ilias Tsitsimpis
465 11779b6c Ilias Tsitsimpis
    def test_002_unique_containers(self):
466 11779b6c Ilias Tsitsimpis
        """Test if containers have unique names"""
467 11779b6c Ilias Tsitsimpis
        names = [n['name'] for n in self.containers]
468 11779b6c Ilias Tsitsimpis
        names = sorted(names)
469 11779b6c Ilias Tsitsimpis
        self.assertEqual(sorted(list(set(names))), names)
470 11779b6c Ilias Tsitsimpis
471 11779b6c Ilias Tsitsimpis
    def test_003_create_container(self):
472 11779b6c Ilias Tsitsimpis
        """Test create a container"""
473 11779b6c Ilias Tsitsimpis
        rand_num = randint(1000, 9999)
474 11779b6c Ilias Tsitsimpis
        rand_name = "%s%s" % (SNF_TEST_PREFIX, rand_num)
475 11779b6c Ilias Tsitsimpis
        names = [n['name'] for n in self.containers]
476 11779b6c Ilias Tsitsimpis
        while rand_name in names:
477 11779b6c Ilias Tsitsimpis
            rand_num = randint(1000, 9999)
478 11779b6c Ilias Tsitsimpis
            rand_name = "%s%s" % (SNF_TEST_PREFIX, rand_num)
479 11779b6c Ilias Tsitsimpis
        # Create container
480 186428b0 Ilias Tsitsimpis
        self.pithos_client.container = rand_name
481 186428b0 Ilias Tsitsimpis
        self.pithos_client.container_put()
482 11779b6c Ilias Tsitsimpis
        # Get list of containers
483 186428b0 Ilias Tsitsimpis
        new_containers = self.pithos_client.list_containers()
484 11779b6c Ilias Tsitsimpis
        new_container_names = [n['name'] for n in new_containers]
485 11779b6c Ilias Tsitsimpis
        self.assertIn(rand_name, new_container_names)
486 11779b6c Ilias Tsitsimpis
487 11779b6c Ilias Tsitsimpis
    def test_004_upload(self):
488 11779b6c Ilias Tsitsimpis
        """Test uploading something to pithos+"""
489 11779b6c Ilias Tsitsimpis
        # Create a tmp file
490 11779b6c Ilias Tsitsimpis
        with tempfile.TemporaryFile() as f:
491 11779b6c Ilias Tsitsimpis
            f.write("This is a temp file")
492 11779b6c Ilias Tsitsimpis
            f.seek(0, 0)
493 11779b6c Ilias Tsitsimpis
            # Where to save file
494 186428b0 Ilias Tsitsimpis
            self.pithos_client.upload_object("test.txt", f)
495 11779b6c Ilias Tsitsimpis
496 11779b6c Ilias Tsitsimpis
    def test_005_download(self):
497 11779b6c Ilias Tsitsimpis
        """Test download something from pithos+"""
498 11779b6c Ilias Tsitsimpis
        # Create tmp directory to save file
499 11779b6c Ilias Tsitsimpis
        tmp_dir = tempfile.mkdtemp()
500 11779b6c Ilias Tsitsimpis
        tmp_file = os.path.join(tmp_dir, "test.txt")
501 11779b6c Ilias Tsitsimpis
        with open(tmp_file, "wb+") as f:
502 186428b0 Ilias Tsitsimpis
            self.pithos_client.download_object("test.txt", f)
503 11779b6c Ilias Tsitsimpis
            # Read file
504 11779b6c Ilias Tsitsimpis
            f.seek(0, 0)
505 11779b6c Ilias Tsitsimpis
            content = f.read()
506 11779b6c Ilias Tsitsimpis
        # Remove files
507 11779b6c Ilias Tsitsimpis
        os.unlink(tmp_file)
508 11779b6c Ilias Tsitsimpis
        os.rmdir(tmp_dir)
509 11779b6c Ilias Tsitsimpis
        # Compare results
510 11779b6c Ilias Tsitsimpis
        self.assertEqual(content, "This is a temp file")
511 11779b6c Ilias Tsitsimpis
512 11779b6c Ilias Tsitsimpis
    def test_006_remove(self):
513 11779b6c Ilias Tsitsimpis
        """Test removing files and containers"""
514 186428b0 Ilias Tsitsimpis
        cont_name = self.pithos_client.container
515 186428b0 Ilias Tsitsimpis
        self.pithos_client.del_object("test.txt")
516 186428b0 Ilias Tsitsimpis
        self.pithos_client.purge_container()
517 11779b6c Ilias Tsitsimpis
        # List containers
518 186428b0 Ilias Tsitsimpis
        containers = self.pithos_client.list_containers()
519 11779b6c Ilias Tsitsimpis
        cont_names = [n['name'] for n in containers]
520 11779b6c Ilias Tsitsimpis
        self.assertNotIn(cont_name, cont_names)
521 11779b6c Ilias Tsitsimpis
522 11779b6c Ilias Tsitsimpis
523 11779b6c Ilias Tsitsimpis
# --------------------------------------------------------------------
524 5a140b23 Vangelis Koukis
# This class gets replicated into actual TestCases dynamically
525 5a140b23 Vangelis Koukis
class SpawnServerTestCase(unittest.TestCase):
526 5a140b23 Vangelis Koukis
    """Test scenario for server of the specified image"""
527 5a140b23 Vangelis Koukis
    @classmethod
528 5a140b23 Vangelis Koukis
    def setUpClass(cls):
529 5a140b23 Vangelis Koukis
        """Initialize a kamaki instance"""
530 6e168615 Ilias Tsitsimpis
        log.info("Spawning server for image `%s'" % cls.imagename)
531 186428b0 Ilias Tsitsimpis
532 186428b0 Ilias Tsitsimpis
        cls.astakos_client = AstakosClient(AUTH_URL, TOKEN)
533 186428b0 Ilias Tsitsimpis
        # Cyclades Client
534 186428b0 Ilias Tsitsimpis
        compute_url = \
535 186428b0 Ilias Tsitsimpis
            cls.astakos_client.get_service_endpoints('compute')['publicURL']
536 186428b0 Ilias Tsitsimpis
        cls.cyclades_client = CycladesClient(compute_url, TOKEN)
537 186428b0 Ilias Tsitsimpis
538 66eba2cf John Giannelos
        cls.result_dict = dict()
539 5a140b23 Vangelis Koukis
540 5a140b23 Vangelis Koukis
    def _get_ipv4(self, server):
541 bc14ba88 Vangelis Koukis
        """Get the public IPv4 of a server from the detailed server info"""
542 1c636ad6 John Giannelos
543 bcb7c357 Ilias Tsitsimpis
        nics = server["attachments"]
544 2aaa1336 John Giannelos
545 e50133da John Giannelos
        for nic in nics:
546 e50133da John Giannelos
            net_id = nic["network_id"]
547 186428b0 Ilias Tsitsimpis
            if self.cyclades_client.get_network_details(net_id)["public"]:
548 e50133da John Giannelos
                public_addrs = nic["ipv4"]
549 6e168615 Ilias Tsitsimpis
550 6e168615 Ilias Tsitsimpis
        self.assertTrue(public_addrs is not None)
551 2aaa1336 John Giannelos
552 e50133da John Giannelos
        return public_addrs
553 5a140b23 Vangelis Koukis
554 5a140b23 Vangelis Koukis
    def _get_ipv6(self, server):
555 bc14ba88 Vangelis Koukis
        """Get the public IPv6 of a server from the detailed server info"""
556 2aaa1336 John Giannelos
557 bcb7c357 Ilias Tsitsimpis
        nics = server["attachments"]
558 2aaa1336 John Giannelos
559 e50133da John Giannelos
        for nic in nics:
560 e50133da John Giannelos
            net_id = nic["network_id"]
561 186428b0 Ilias Tsitsimpis
            if self.cyclades_client.get_network_details(net_id)["public"]:
562 e50133da John Giannelos
                public_addrs = nic["ipv6"]
563 2aaa1336 John Giannelos
564 6e168615 Ilias Tsitsimpis
        self.assertTrue(public_addrs is not None)
565 2aaa1336 John Giannelos
566 6e168615 Ilias Tsitsimpis
        return public_addrs
567 5a140b23 Vangelis Koukis
568 6e168615 Ilias Tsitsimpis
    def _connect_loginname(self, os_value):
569 bc14ba88 Vangelis Koukis
        """Return the login name for connections based on the server OS"""
570 6e168615 Ilias Tsitsimpis
        if os_value in ("Ubuntu", "Kubuntu", "Fedora"):
571 21bbbc9b Vangelis Koukis
            return "user"
572 6e168615 Ilias Tsitsimpis
        elif os_value in ("windows", "windows_alpha1"):
573 21bbbc9b Vangelis Koukis
            return "Administrator"
574 bc14ba88 Vangelis Koukis
        else:
575 21bbbc9b Vangelis Koukis
            return "root"
576 bc14ba88 Vangelis Koukis
577 bc14ba88 Vangelis Koukis
    def _verify_server_status(self, current_status, new_status):
578 bc14ba88 Vangelis Koukis
        """Verify a server has switched to a specified status"""
579 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
580 21bbbc9b Vangelis Koukis
        if server["status"] not in (current_status, new_status):
581 21bbbc9b Vangelis Koukis
            return None  # Do not raise exception, return so the test fails
582 bc14ba88 Vangelis Koukis
        self.assertEquals(server["status"], new_status)
583 bc14ba88 Vangelis Koukis
584 bc14ba88 Vangelis Koukis
    def _get_connected_tcp_socket(self, family, host, port):
585 bc14ba88 Vangelis Koukis
        """Get a connected socket from the specified family to host:port"""
586 bc14ba88 Vangelis Koukis
        sock = None
587 bc14ba88 Vangelis Koukis
        for res in \
588 bc14ba88 Vangelis Koukis
            socket.getaddrinfo(host, port, family, socket.SOCK_STREAM, 0,
589 bc14ba88 Vangelis Koukis
                               socket.AI_PASSIVE):
590 bc14ba88 Vangelis Koukis
            af, socktype, proto, canonname, sa = res
591 bc14ba88 Vangelis Koukis
            try:
592 bc14ba88 Vangelis Koukis
                sock = socket.socket(af, socktype, proto)
593 6e168615 Ilias Tsitsimpis
            except socket.error:
594 bc14ba88 Vangelis Koukis
                sock = None
595 bc14ba88 Vangelis Koukis
                continue
596 bc14ba88 Vangelis Koukis
            try:
597 bc14ba88 Vangelis Koukis
                sock.connect(sa)
598 6e168615 Ilias Tsitsimpis
            except socket.error:
599 bc14ba88 Vangelis Koukis
                sock.close()
600 bc14ba88 Vangelis Koukis
                sock = None
601 bc14ba88 Vangelis Koukis
                continue
602 bc14ba88 Vangelis Koukis
        self.assertIsNotNone(sock)
603 bc14ba88 Vangelis Koukis
        return sock
604 bc14ba88 Vangelis Koukis
605 bc14ba88 Vangelis Koukis
    def _ping_once(self, ipv6, ip):
606 bc14ba88 Vangelis Koukis
        """Test server responds to a single IPv4 or IPv6 ping"""
607 bc14ba88 Vangelis Koukis
        cmd = "ping%s -c 2 -w 3 %s" % ("6" if ipv6 else "", ip)
608 bc14ba88 Vangelis Koukis
        ping = subprocess.Popen(cmd, shell=True,
609 bc14ba88 Vangelis Koukis
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
610 bc14ba88 Vangelis Koukis
        (stdout, stderr) = ping.communicate()
611 bc14ba88 Vangelis Koukis
        ret = ping.wait()
612 bc14ba88 Vangelis Koukis
        self.assertEquals(ret, 0)
613 5a140b23 Vangelis Koukis
614 bc14ba88 Vangelis Koukis
    def _get_hostname_over_ssh(self, hostip, username, password):
615 2a410f76 Ilias Tsitsimpis
        lines, status = _ssh_execute(
616 2a410f76 Ilias Tsitsimpis
            hostip, username, password, "hostname")
617 bc14ba88 Vangelis Koukis
        self.assertEqual(len(lines), 1)
618 4fdd25ab Vangelis Koukis
        return lines[0]
619 bc14ba88 Vangelis Koukis
620 bc14ba88 Vangelis Koukis
    def _try_until_timeout_expires(self, warn_timeout, fail_timeout,
621 bc14ba88 Vangelis Koukis
                                   opmsg, callable, *args, **kwargs):
622 bc14ba88 Vangelis Koukis
        if warn_timeout == fail_timeout:
623 5a140b23 Vangelis Koukis
            warn_timeout = fail_timeout + 1
624 5a140b23 Vangelis Koukis
        warn_tmout = time.time() + warn_timeout
625 5a140b23 Vangelis Koukis
        fail_tmout = time.time() + fail_timeout
626 5a140b23 Vangelis Koukis
        while True:
627 4fdd25ab Vangelis Koukis
            self.assertLess(time.time(), fail_tmout,
628 21bbbc9b Vangelis Koukis
                            "operation `%s' timed out" % opmsg)
629 5a140b23 Vangelis Koukis
            if time.time() > warn_tmout:
630 4fdd25ab Vangelis Koukis
                log.warning("Server %d: `%s' operation `%s' not done yet",
631 4fdd25ab Vangelis Koukis
                            self.serverid, self.servername, opmsg)
632 bc14ba88 Vangelis Koukis
            try:
633 4fdd25ab Vangelis Koukis
                log.info("%s... " % opmsg)
634 bc14ba88 Vangelis Koukis
                return callable(*args, **kwargs)
635 bc14ba88 Vangelis Koukis
            except AssertionError:
636 bc14ba88 Vangelis Koukis
                pass
637 5a140b23 Vangelis Koukis
            time.sleep(self.query_interval)
638 5a140b23 Vangelis Koukis
639 bc14ba88 Vangelis Koukis
    def _insist_on_tcp_connection(self, family, host, port):
640 21bbbc9b Vangelis Koukis
        familystr = {socket.AF_INET: "IPv4", socket.AF_INET6: "IPv6",
641 21bbbc9b Vangelis Koukis
                     socket.AF_UNSPEC: "Unspecified-IPv4/6"}
642 bc14ba88 Vangelis Koukis
        msg = "connect over %s to %s:%s" % \
643 bc14ba88 Vangelis Koukis
              (familystr.get(family, "Unknown"), host, port)
644 bc14ba88 Vangelis Koukis
        sock = self._try_until_timeout_expires(
645 6e168615 Ilias Tsitsimpis
            self.action_timeout, self.action_timeout,
646 6e168615 Ilias Tsitsimpis
            msg, self._get_connected_tcp_socket,
647 6e168615 Ilias Tsitsimpis
            family, host, port)
648 bc14ba88 Vangelis Koukis
        return sock
649 bc14ba88 Vangelis Koukis
650 bc14ba88 Vangelis Koukis
    def _insist_on_status_transition(self, current_status, new_status,
651 6e168615 Ilias Tsitsimpis
                                     fail_timeout, warn_timeout=None):
652 4fdd25ab Vangelis Koukis
        msg = "Server %d: `%s', waiting for %s -> %s" % \
653 4fdd25ab Vangelis Koukis
              (self.serverid, self.servername, current_status, new_status)
654 bc14ba88 Vangelis Koukis
        if warn_timeout is None:
655 bc14ba88 Vangelis Koukis
            warn_timeout = fail_timeout
656 bc14ba88 Vangelis Koukis
        self._try_until_timeout_expires(warn_timeout, fail_timeout,
657 bc14ba88 Vangelis Koukis
                                        msg, self._verify_server_status,
658 bc14ba88 Vangelis Koukis
                                        current_status, new_status)
659 21bbbc9b Vangelis Koukis
        # Ensure the status is actually the expected one
660 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
661 21bbbc9b Vangelis Koukis
        self.assertEquals(server["status"], new_status)
662 bc14ba88 Vangelis Koukis
663 bc14ba88 Vangelis Koukis
    def _insist_on_ssh_hostname(self, hostip, username, password):
664 4fdd25ab Vangelis Koukis
        msg = "SSH to %s, as %s/%s" % (hostip, username, password)
665 bc14ba88 Vangelis Koukis
        hostname = self._try_until_timeout_expires(
666 6e168615 Ilias Tsitsimpis
            self.action_timeout, self.action_timeout,
667 6e168615 Ilias Tsitsimpis
            msg, self._get_hostname_over_ssh,
668 6e168615 Ilias Tsitsimpis
            hostip, username, password)
669 bc14ba88 Vangelis Koukis
670 bc14ba88 Vangelis Koukis
        # The hostname must be of the form 'prefix-id'
671 bc14ba88 Vangelis Koukis
        self.assertTrue(hostname.endswith("-%d\n" % self.serverid))
672 5a140b23 Vangelis Koukis
673 8252d64f John Giannelos
    def _check_file_through_ssh(self, hostip, username, password,
674 8252d64f John Giannelos
                                remotepath, content):
675 8252d64f John Giannelos
        msg = "Trying file injection through SSH to %s, as %s/%s" % \
676 8252d64f John Giannelos
            (hostip, username, password)
677 f97dce4d John Giannelos
        log.info(msg)
678 77054bf5 John Giannelos
        try:
679 77054bf5 John Giannelos
            ssh = paramiko.SSHClient()
680 77054bf5 John Giannelos
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
681 77054bf5 John Giannelos
            ssh.connect(hostip, username=username, password=password)
682 2a410f76 Ilias Tsitsimpis
            ssh.close()
683 4fed2379 Ilias Tsitsimpis
        except socket.error, err:
684 4fed2379 Ilias Tsitsimpis
            raise AssertionError(err)
685 9659e075 John Giannelos
686 2bcfb712 John Giannelos
        transport = paramiko.Transport((hostip, 22))
687 2bcfb712 John Giannelos
        transport.connect(username=username, password=password)
688 2bcfb712 John Giannelos
689 2bcfb712 John Giannelos
        localpath = '/tmp/' + SNF_TEST_PREFIX + 'injection'
690 77054bf5 John Giannelos
        sftp = paramiko.SFTPClient.from_transport(transport)
691 8252d64f John Giannelos
        sftp.get(remotepath, localpath)
692 77054bf5 John Giannelos
        sftp.close()
693 77054bf5 John Giannelos
        transport.close()
694 77054bf5 John Giannelos
695 9659e075 John Giannelos
        f = open(localpath)
696 9659e075 John Giannelos
        remote_content = b64encode(f.read())
697 9659e075 John Giannelos
698 77054bf5 John Giannelos
        # Check if files are the same
699 65462ca9 John Giannelos
        return (remote_content == content)
700 77054bf5 John Giannelos
701 5a140b23 Vangelis Koukis
    def _skipIf(self, condition, msg):
702 5a140b23 Vangelis Koukis
        if condition:
703 5a140b23 Vangelis Koukis
            self.skipTest(msg)
704 5a140b23 Vangelis Koukis
705 5a140b23 Vangelis Koukis
    def test_001_submit_create_server(self):
706 5a140b23 Vangelis Koukis
        """Test submit create server request"""
707 f89d0238 John Giannelos
708 f89d0238 John Giannelos
        log.info("Submit new server request")
709 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.create_server(
710 186428b0 Ilias Tsitsimpis
            self.servername, self.flavorid, self.imageid, self.personality)
711 9659e075 John Giannelos
712 81e8cbf6 John Giannelos
        log.info("Server id: " + str(server["id"]))
713 81e8cbf6 John Giannelos
        log.info("Server password: " + server["adminPass"])
714 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
715 bcc21c50 Christos Stavrakakis
        self.assertEqual(server["flavor"]["id"], self.flavorid)
716 bcc21c50 Christos Stavrakakis
        self.assertEqual(server["image"]["id"], self.imageid)
717 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
718 5a140b23 Vangelis Koukis
719 5a140b23 Vangelis Koukis
        # Update class attributes to reflect data on building server
720 5a140b23 Vangelis Koukis
        cls = type(self)
721 5a140b23 Vangelis Koukis
        cls.serverid = server["id"]
722 bc14ba88 Vangelis Koukis
        cls.username = None
723 5a140b23 Vangelis Koukis
        cls.passwd = server["adminPass"]
724 5a140b23 Vangelis Koukis
725 66eba2cf John Giannelos
        self.result_dict["Server ID"] = str(server["id"])
726 66eba2cf John Giannelos
        self.result_dict["Password"] = str(server["adminPass"])
727 66eba2cf John Giannelos
728 5a140b23 Vangelis Koukis
    def test_002a_server_is_building_in_list(self):
729 5a140b23 Vangelis Koukis
        """Test server is in BUILD state, in server list"""
730 f89d0238 John Giannelos
        log.info("Server in BUILD state in server list")
731 f89d0238 John Giannelos
732 66eba2cf John Giannelos
        self.result_dict.clear()
733 66eba2cf John Giannelos
734 186428b0 Ilias Tsitsimpis
        servers = self.cyclades_client.list_servers(detail=True)
735 5a140b23 Vangelis Koukis
        servers = filter(lambda x: x["name"] == self.servername, servers)
736 2aaa1336 John Giannelos
737 5a140b23 Vangelis Koukis
        server = servers[0]
738 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
739 bcc21c50 Christos Stavrakakis
        self.assertEqual(server["flavor"]["id"], self.flavorid)
740 bcc21c50 Christos Stavrakakis
        self.assertEqual(server["image"]["id"], self.imageid)
741 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
742 5a140b23 Vangelis Koukis
743 5a140b23 Vangelis Koukis
    def test_002b_server_is_building_in_details(self):
744 5a140b23 Vangelis Koukis
        """Test server is in BUILD state, in details"""
745 f89d0238 John Giannelos
746 f89d0238 John Giannelos
        log.info("Server in BUILD state in details")
747 f89d0238 John Giannelos
748 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
749 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
750 bcc21c50 Christos Stavrakakis
        self.assertEqual(server["flavor"]["id"], self.flavorid)
751 bcc21c50 Christos Stavrakakis
        self.assertEqual(server["image"]["id"], self.imageid)
752 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
753 5a140b23 Vangelis Koukis
754 5a140b23 Vangelis Koukis
    def test_002c_set_server_metadata(self):
755 f89d0238 John Giannelos
756 f89d0238 John Giannelos
        log.info("Creating server metadata")
757 f89d0238 John Giannelos
758 186428b0 Ilias Tsitsimpis
        image = self.cyclades_client.get_image_details(self.imageid)
759 bcb7c357 Ilias Tsitsimpis
        os_value = image["metadata"]["os"]
760 bcb7c357 Ilias Tsitsimpis
        users = image["metadata"].get("users", None)
761 186428b0 Ilias Tsitsimpis
        self.cyclades_client.update_server_metadata(self.serverid, OS=os_value)
762 746540cd John Giannelos
763 e49bdb7c John Giannelos
        userlist = users.split()
764 81e8cbf6 John Giannelos
765 bc14ba88 Vangelis Koukis
        # Determine the username to use for future connections
766 bc14ba88 Vangelis Koukis
        # to this host
767 bc14ba88 Vangelis Koukis
        cls = type(self)
768 81e8cbf6 John Giannelos
769 81e8cbf6 John Giannelos
        if "root" in userlist:
770 81e8cbf6 John Giannelos
            cls.username = "root"
771 6e168615 Ilias Tsitsimpis
        elif users is None:
772 6e168615 Ilias Tsitsimpis
            cls.username = self._connect_loginname(os_value)
773 81e8cbf6 John Giannelos
        else:
774 81e8cbf6 John Giannelos
            cls.username = choice(userlist)
775 81e8cbf6 John Giannelos
776 bc14ba88 Vangelis Koukis
        self.assertIsNotNone(cls.username)
777 5a140b23 Vangelis Koukis
778 5a140b23 Vangelis Koukis
    def test_002d_verify_server_metadata(self):
779 5a140b23 Vangelis Koukis
        """Test server metadata keys are set based on image metadata"""
780 f89d0238 John Giannelos
781 f89d0238 John Giannelos
        log.info("Verifying image metadata")
782 f89d0238 John Giannelos
783 186428b0 Ilias Tsitsimpis
        servermeta = self.cyclades_client.get_server_metadata(self.serverid)
784 186428b0 Ilias Tsitsimpis
        imagemeta = self.cyclades_client.get_image_metadata(self.imageid)
785 81e8cbf6 John Giannelos
786 99d41650 John Giannelos
        self.assertEqual(servermeta["OS"], imagemeta["os"])
787 5a140b23 Vangelis Koukis
788 5a140b23 Vangelis Koukis
    def test_003_server_becomes_active(self):
789 5a140b23 Vangelis Koukis
        """Test server becomes ACTIVE"""
790 f89d0238 John Giannelos
791 f89d0238 John Giannelos
        log.info("Waiting for server to become ACTIVE")
792 f89d0238 John Giannelos
793 6e168615 Ilias Tsitsimpis
        self._insist_on_status_transition(
794 6e168615 Ilias Tsitsimpis
            "BUILD", "ACTIVE", self.build_fail, self.build_warning)
795 5a140b23 Vangelis Koukis
796 f752215c John Giannelos
    def test_003a_get_server_oob_console(self):
797 f752215c John Giannelos
        """Test getting OOB server console over VNC
798 bc14ba88 Vangelis Koukis

799 f752215c John Giannelos
        Implementation of RFB protocol follows
800 f752215c John Giannelos
        http://www.realvnc.com/docs/rfbproto.pdf.
801 bc14ba88 Vangelis Koukis

802 f752215c John Giannelos
        """
803 186428b0 Ilias Tsitsimpis
        console = self.cyclades_client.get_server_console(self.serverid)
804 f752215c John Giannelos
        self.assertEquals(console['type'], "vnc")
805 6e168615 Ilias Tsitsimpis
        sock = self._insist_on_tcp_connection(
806 6e168615 Ilias Tsitsimpis
            socket.AF_INET, console["host"], console["port"])
807 f752215c John Giannelos
808 f752215c John Giannelos
        # Step 1. ProtocolVersion message (par. 6.1.1)
809 f752215c John Giannelos
        version = sock.recv(1024)
810 f752215c John Giannelos
        self.assertEquals(version, 'RFB 003.008\n')
811 f752215c John Giannelos
        sock.send(version)
812 f752215c John Giannelos
813 f752215c John Giannelos
        # Step 2. Security (par 6.1.2): Only VNC Authentication supported
814 f752215c John Giannelos
        sec = sock.recv(1024)
815 f752215c John Giannelos
        self.assertEquals(list(sec), ['\x01', '\x02'])
816 f752215c John Giannelos
817 f752215c John Giannelos
        # Step 3. Request VNC Authentication (par 6.1.2)
818 f752215c John Giannelos
        sock.send('\x02')
819 f752215c John Giannelos
820 f752215c John Giannelos
        # Step 4. Receive Challenge (par 6.2.2)
821 f752215c John Giannelos
        challenge = sock.recv(1024)
822 f752215c John Giannelos
        self.assertEquals(len(challenge), 16)
823 f752215c John Giannelos
824 f752215c John Giannelos
        # Step 5. DES-Encrypt challenge, use password as key (par 6.2.2)
825 f752215c John Giannelos
        response = d3des_generate_response(
826 f752215c John Giannelos
            (console["password"] + '\0' * 8)[:8], challenge)
827 f752215c John Giannelos
        sock.send(response)
828 f752215c John Giannelos
829 f752215c John Giannelos
        # Step 6. SecurityResult (par 6.1.3)
830 f752215c John Giannelos
        result = sock.recv(4)
831 f752215c John Giannelos
        self.assertEquals(list(result), ['\x00', '\x00', '\x00', '\x00'])
832 f752215c John Giannelos
        sock.close()
833 8252d64f John Giannelos
834 5a140b23 Vangelis Koukis
    def test_004_server_has_ipv4(self):
835 5a140b23 Vangelis Koukis
        """Test active server has a valid IPv4 address"""
836 f89d0238 John Giannelos
837 81e8cbf6 John Giannelos
        log.info("Validate server's IPv4")
838 f89d0238 John Giannelos
839 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
840 5a140b23 Vangelis Koukis
        ipv4 = self._get_ipv4(server)
841 66eba2cf John Giannelos
842 66eba2cf John Giannelos
        self.result_dict.clear()
843 66eba2cf John Giannelos
        self.result_dict["IPv4"] = str(ipv4)
844 66eba2cf John Giannelos
845 5a140b23 Vangelis Koukis
        self.assertEquals(IP(ipv4).version(), 4)
846 5a140b23 Vangelis Koukis
847 65462ca9 John Giannelos
    def test_005_server_has_ipv6(self):
848 65462ca9 John Giannelos
        """Test active server has a valid IPv6 address"""
849 946da8b6 John Giannelos
        self._skipIf(NO_IPV6, "--no-ipv6 flag enabled")
850 f89d0238 John Giannelos
851 81e8cbf6 John Giannelos
        log.info("Validate server's IPv6")
852 f89d0238 John Giannelos
853 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
854 65462ca9 John Giannelos
        ipv6 = self._get_ipv6(server)
855 66eba2cf John Giannelos
856 66eba2cf John Giannelos
        self.result_dict.clear()
857 66eba2cf John Giannelos
        self.result_dict["IPv6"] = str(ipv6)
858 66eba2cf John Giannelos
859 65462ca9 John Giannelos
        self.assertEquals(IP(ipv6).version(), 6)
860 5a140b23 Vangelis Koukis
861 daac4017 John Giannelos
    def test_006_server_responds_to_ping_IPv4(self):
862 daac4017 John Giannelos
        """Test server responds to ping on IPv4 address"""
863 daac4017 John Giannelos
864 daac4017 John Giannelos
        log.info("Testing if server responds to pings in IPv4")
865 66eba2cf John Giannelos
        self.result_dict.clear()
866 daac4017 John Giannelos
867 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
868 daac4017 John Giannelos
        ip = self._get_ipv4(server)
869 daac4017 John Giannelos
        self._try_until_timeout_expires(self.action_timeout,
870 daac4017 John Giannelos
                                        self.action_timeout,
871 daac4017 John Giannelos
                                        "PING IPv4 to %s" % ip,
872 daac4017 John Giannelos
                                        self._ping_once,
873 daac4017 John Giannelos
                                        False, ip)
874 daac4017 John Giannelos
875 daac4017 John Giannelos
    def test_007_server_responds_to_ping_IPv6(self):
876 daac4017 John Giannelos
        """Test server responds to ping on IPv6 address"""
877 daac4017 John Giannelos
        self._skipIf(NO_IPV6, "--no-ipv6 flag enabled")
878 daac4017 John Giannelos
        log.info("Testing if server responds to pings in IPv6")
879 daac4017 John Giannelos
880 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
881 daac4017 John Giannelos
        ip = self._get_ipv6(server)
882 daac4017 John Giannelos
        self._try_until_timeout_expires(self.action_timeout,
883 daac4017 John Giannelos
                                        self.action_timeout,
884 daac4017 John Giannelos
                                        "PING IPv6 to %s" % ip,
885 daac4017 John Giannelos
                                        self._ping_once,
886 daac4017 John Giannelos
                                        True, ip)
887 5a140b23 Vangelis Koukis
888 5a140b23 Vangelis Koukis
    def test_008_submit_shutdown_request(self):
889 5a140b23 Vangelis Koukis
        """Test submit request to shutdown server"""
890 f89d0238 John Giannelos
891 f89d0238 John Giannelos
        log.info("Shutting down server")
892 f89d0238 John Giannelos
893 186428b0 Ilias Tsitsimpis
        self.cyclades_client.shutdown_server(self.serverid)
894 5a140b23 Vangelis Koukis
895 5a140b23 Vangelis Koukis
    def test_009_server_becomes_stopped(self):
896 5a140b23 Vangelis Koukis
        """Test server becomes STOPPED"""
897 f89d0238 John Giannelos
898 f89d0238 John Giannelos
        log.info("Waiting until server becomes STOPPED")
899 6e168615 Ilias Tsitsimpis
        self._insist_on_status_transition(
900 6e168615 Ilias Tsitsimpis
            "ACTIVE", "STOPPED", self.action_timeout, self.action_timeout)
901 5a140b23 Vangelis Koukis
902 5a140b23 Vangelis Koukis
    def test_010_submit_start_request(self):
903 5a140b23 Vangelis Koukis
        """Test submit start server request"""
904 f89d0238 John Giannelos
905 f89d0238 John Giannelos
        log.info("Starting server")
906 f89d0238 John Giannelos
907 186428b0 Ilias Tsitsimpis
        self.cyclades_client.start_server(self.serverid)
908 5a140b23 Vangelis Koukis
909 5a140b23 Vangelis Koukis
    def test_011_server_becomes_active(self):
910 5a140b23 Vangelis Koukis
        """Test server becomes ACTIVE again"""
911 f89d0238 John Giannelos
912 f89d0238 John Giannelos
        log.info("Waiting until server becomes ACTIVE")
913 6e168615 Ilias Tsitsimpis
        self._insist_on_status_transition(
914 6e168615 Ilias Tsitsimpis
            "STOPPED", "ACTIVE", self.action_timeout, self.action_timeout)
915 5a140b23 Vangelis Koukis
916 daac4017 John Giannelos
    def test_011a_server_responds_to_ping_IPv4(self):
917 daac4017 John Giannelos
        """Test server OS is actually up and running again"""
918 f89d0238 John Giannelos
919 daac4017 John Giannelos
        log.info("Testing if server is actually up and running")
920 f89d0238 John Giannelos
921 daac4017 John Giannelos
        self.test_006_server_responds_to_ping_IPv4()
922 5a140b23 Vangelis Koukis
923 daac4017 John Giannelos
    def test_012_ssh_to_server_IPv4(self):
924 daac4017 John Giannelos
        """Test SSH to server public IPv4 works, verify hostname"""
925 f89d0238 John Giannelos
926 daac4017 John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
927 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
928 daac4017 John Giannelos
        self._insist_on_ssh_hostname(self._get_ipv4(server),
929 daac4017 John Giannelos
                                     self.username, self.passwd)
930 5a140b23 Vangelis Koukis
931 daac4017 John Giannelos
    def test_013_ssh_to_server_IPv6(self):
932 daac4017 John Giannelos
        """Test SSH to server public IPv6 works, verify hostname"""
933 daac4017 John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
934 daac4017 John Giannelos
        self._skipIf(NO_IPV6, "--no-ipv6 flag enabled")
935 946da8b6 John Giannelos
936 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
937 daac4017 John Giannelos
        self._insist_on_ssh_hostname(self._get_ipv6(server),
938 daac4017 John Giannelos
                                     self.username, self.passwd)
939 5a140b23 Vangelis Koukis
940 daac4017 John Giannelos
    def test_014_rdp_to_server_IPv4(self):
941 daac4017 John Giannelos
        "Test RDP connection to server public IPv4 works"""
942 daac4017 John Giannelos
        self._skipIf(not self.is_windows, "only valid for Windows servers")
943 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
944 daac4017 John Giannelos
        ipv4 = self._get_ipv4(server)
945 6e168615 Ilias Tsitsimpis
        sock = self._insist_on_tcp_connection(socket.AF_INET, ipv4, 3389)
946 5a140b23 Vangelis Koukis
947 daac4017 John Giannelos
        # No actual RDP processing done. We assume the RDP server is there
948 daac4017 John Giannelos
        # if the connection to the RDP port is successful.
949 daac4017 John Giannelos
        # FIXME: Use rdesktop, analyze exit code? see manpage [costasd]
950 daac4017 John Giannelos
        sock.close()
951 5a140b23 Vangelis Koukis
952 daac4017 John Giannelos
    def test_015_rdp_to_server_IPv6(self):
953 daac4017 John Giannelos
        "Test RDP connection to server public IPv6 works"""
954 daac4017 John Giannelos
        self._skipIf(not self.is_windows, "only valid for Windows servers")
955 daac4017 John Giannelos
        self._skipIf(NO_IPV6, "--no-ipv6 flag enabled")
956 946da8b6 John Giannelos
957 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
958 daac4017 John Giannelos
        ipv6 = self._get_ipv6(server)
959 6e168615 Ilias Tsitsimpis
        sock = self._get_tcp_connection(socket.AF_INET6, ipv6, 3389)
960 5a140b23 Vangelis Koukis
961 daac4017 John Giannelos
        # No actual RDP processing done. We assume the RDP server is there
962 daac4017 John Giannelos
        # if the connection to the RDP port is successful.
963 daac4017 John Giannelos
        sock.close()
964 5a140b23 Vangelis Koukis
965 daac4017 John Giannelos
    def test_016_personality_is_enforced(self):
966 daac4017 John Giannelos
        """Test file injection for personality enforcement"""
967 daac4017 John Giannelos
        self._skipIf(self.is_windows, "only implemented for Linux servers")
968 6e168615 Ilias Tsitsimpis
        self._skipIf(self.personality is None, "No personality file selected")
969 f89d0238 John Giannelos
970 daac4017 John Giannelos
        log.info("Trying to inject file for personality enforcement")
971 f89d0238 John Giannelos
972 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
973 77054bf5 John Giannelos
974 daac4017 John Giannelos
        for inj_file in self.personality:
975 daac4017 John Giannelos
            equal_files = self._check_file_through_ssh(self._get_ipv4(server),
976 daac4017 John Giannelos
                                                       inj_file['owner'],
977 daac4017 John Giannelos
                                                       self.passwd,
978 daac4017 John Giannelos
                                                       inj_file['path'],
979 daac4017 John Giannelos
                                                       inj_file['contents'])
980 daac4017 John Giannelos
            self.assertTrue(equal_files)
981 8252d64f John Giannelos
982 4fdd25ab Vangelis Koukis
    def test_017_submit_delete_request(self):
983 4fdd25ab Vangelis Koukis
        """Test submit request to delete server"""
984 f89d0238 John Giannelos
985 f89d0238 John Giannelos
        log.info("Deleting server")
986 f89d0238 John Giannelos
987 186428b0 Ilias Tsitsimpis
        self.cyclades_client.delete_server(self.serverid)
988 4fdd25ab Vangelis Koukis
989 4fdd25ab Vangelis Koukis
    def test_018_server_becomes_deleted(self):
990 4fdd25ab Vangelis Koukis
        """Test server becomes DELETED"""
991 f89d0238 John Giannelos
992 f89d0238 John Giannelos
        log.info("Testing if server becomes DELETED")
993 f89d0238 John Giannelos
994 6e168615 Ilias Tsitsimpis
        self._insist_on_status_transition(
995 6e168615 Ilias Tsitsimpis
            "ACTIVE", "DELETED", self.action_timeout, self.action_timeout)
996 4fdd25ab Vangelis Koukis
997 4fdd25ab Vangelis Koukis
    def test_019_server_no_longer_in_server_list(self):
998 4fdd25ab Vangelis Koukis
        """Test server is no longer in server list"""
999 f89d0238 John Giannelos
1000 f89d0238 John Giannelos
        log.info("Test if server is no longer listed")
1001 f89d0238 John Giannelos
1002 186428b0 Ilias Tsitsimpis
        servers = self.cyclades_client.list_servers()
1003 21bbbc9b Vangelis Koukis
        self.assertNotIn(self.serverid, [s["id"] for s in servers])
1004 21bbbc9b Vangelis Koukis
1005 21bbbc9b Vangelis Koukis
1006 9e4682b5 John Giannelos
class NetworkTestCase(unittest.TestCase):
1007 e94a9d8c John Giannelos
    """ Testing networking in cyclades """
1008 8252d64f John Giannelos
1009 9e4682b5 John Giannelos
    @classmethod
1010 e94a9d8c John Giannelos
    def setUpClass(cls):
1011 e94a9d8c John Giannelos
        "Initialize kamaki, get list of current networks"
1012 567ffb85 John Giannelos
1013 186428b0 Ilias Tsitsimpis
        cls.astakos_client = AstakosClient(AUTH_URL, TOKEN)
1014 186428b0 Ilias Tsitsimpis
        # Cyclades Client
1015 186428b0 Ilias Tsitsimpis
        compute_url = \
1016 186428b0 Ilias Tsitsimpis
            cls.astakos_client.get_service_endpoints('compute')['publicURL']
1017 186428b0 Ilias Tsitsimpis
        cls.cyclades_client = CycladesClient(compute_url, TOKEN)
1018 9e4682b5 John Giannelos
1019 8252d64f John Giannelos
        cls.servername = "%s%s for %s" % (SNF_TEST_PREFIX,
1020 8252d64f John Giannelos
                                          TEST_RUN_ID,
1021 8252d64f John Giannelos
                                          cls.imagename)
1022 91de9b55 John Giannelos
1023 91de9b55 John Giannelos
        #Dictionary initialization for the vms credentials
1024 91de9b55 John Giannelos
        cls.serverid = dict()
1025 91de9b55 John Giannelos
        cls.username = dict()
1026 91de9b55 John Giannelos
        cls.password = dict()
1027 846980fe John Giannelos
        cls.is_windows = cls.imagename.lower().find("windows") >= 0
1028 e49bdb7c John Giannelos
1029 66eba2cf John Giannelos
        cls.result_dict = dict()
1030 66eba2cf John Giannelos
1031 e49bdb7c John Giannelos
    def _skipIf(self, condition, msg):
1032 e49bdb7c John Giannelos
        if condition:
1033 e49bdb7c John Giannelos
            self.skipTest(msg)
1034 91de9b55 John Giannelos
1035 1b40b5e3 John Giannelos
    def _get_ipv4(self, server):
1036 1b40b5e3 John Giannelos
        """Get the public IPv4 of a server from the detailed server info"""
1037 1b40b5e3 John Giannelos
1038 bcb7c357 Ilias Tsitsimpis
        nics = server["attachments"]
1039 2aaa1336 John Giannelos
1040 e50133da John Giannelos
        for nic in nics:
1041 e50133da John Giannelos
            net_id = nic["network_id"]
1042 186428b0 Ilias Tsitsimpis
            if self.cyclades_client.get_network_details(net_id)["public"]:
1043 e50133da John Giannelos
                public_addrs = nic["ipv4"]
1044 2aaa1336 John Giannelos
1045 6e168615 Ilias Tsitsimpis
        self.assertTrue(public_addrs is not None)
1046 2aaa1336 John Giannelos
1047 6e168615 Ilias Tsitsimpis
        return public_addrs
1048 8252d64f John Giannelos
1049 6e168615 Ilias Tsitsimpis
    def _connect_loginname(self, os_value):
1050 1b40b5e3 John Giannelos
        """Return the login name for connections based on the server OS"""
1051 6e168615 Ilias Tsitsimpis
        if os_value in ("Ubuntu", "Kubuntu", "Fedora"):
1052 1b40b5e3 John Giannelos
            return "user"
1053 6e168615 Ilias Tsitsimpis
        elif os_value in ("windows", "windows_alpha1"):
1054 1b40b5e3 John Giannelos
            return "Administrator"
1055 1b40b5e3 John Giannelos
        else:
1056 1b40b5e3 John Giannelos
            return "root"
1057 1b40b5e3 John Giannelos
1058 88736f65 John Giannelos
    def _ping_once(self, ip):
1059 8252d64f John Giannelos
1060 88736f65 John Giannelos
        """Test server responds to a single IPv4 or IPv6 ping"""
1061 88736f65 John Giannelos
        cmd = "ping -c 2 -w 3 %s" % (ip)
1062 88736f65 John Giannelos
        ping = subprocess.Popen(cmd, shell=True,
1063 88736f65 John Giannelos
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
1064 88736f65 John Giannelos
        (stdout, stderr) = ping.communicate()
1065 88736f65 John Giannelos
        ret = ping.wait()
1066 8252d64f John Giannelos
1067 88736f65 John Giannelos
        return (ret == 0)
1068 88736f65 John Giannelos
1069 740a5649 John Giannelos
    def test_00001a_submit_create_server_A(self):
1070 91de9b55 John Giannelos
        """Test submit create server request"""
1071 f89d0238 John Giannelos
1072 f89d0238 John Giannelos
        log.info("Creating test server A")
1073 f89d0238 John Giannelos
1074 186428b0 Ilias Tsitsimpis
        serverA = self.cyclades_client.create_server(
1075 186428b0 Ilias Tsitsimpis
            self.servername, self.flavorid, self.imageid, personality=None)
1076 91de9b55 John Giannelos
1077 c54e3d4c John Giannelos
        self.assertEqual(serverA["name"], self.servername)
1078 bcc21c50 Christos Stavrakakis
        self.assertEqual(serverA["flavor"]["id"], self.flavorid)
1079 bcc21c50 Christos Stavrakakis
        self.assertEqual(serverA["image"]["id"], self.imageid)
1080 c54e3d4c John Giannelos
        self.assertEqual(serverA["status"], "BUILD")
1081 91de9b55 John Giannelos
1082 91de9b55 John Giannelos
        # Update class attributes to reflect data on building server
1083 08748d73 John Giannelos
        self.serverid['A'] = serverA["id"]
1084 08748d73 John Giannelos
        self.username['A'] = None
1085 08748d73 John Giannelos
        self.password['A'] = serverA["adminPass"]
1086 91de9b55 John Giannelos
1087 81e8cbf6 John Giannelos
        log.info("Server A id:" + str(serverA["id"]))
1088 81e8cbf6 John Giannelos
        log.info("Server password " + (self.password['A']))
1089 8252d64f John Giannelos
1090 66eba2cf John Giannelos
        self.result_dict["Server A ID"] = str(serverA["id"])
1091 66eba2cf John Giannelos
        self.result_dict["Server A password"] = serverA["adminPass"]
1092 6e168615 Ilias Tsitsimpis
1093 740a5649 John Giannelos
    def test_00001b_serverA_becomes_active(self):
1094 91de9b55 John Giannelos
        """Test server becomes ACTIVE"""
1095 8252d64f John Giannelos
1096 f89d0238 John Giannelos
        log.info("Waiting until test server A becomes ACTIVE")
1097 66eba2cf John Giannelos
        self.result_dict.clear()
1098 91de9b55 John Giannelos
1099 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1100 91de9b55 John Giannelos
        while True:
1101 186428b0 Ilias Tsitsimpis
            d = self.cyclades_client.get_server_details(self.serverid['A'])
1102 91de9b55 John Giannelos
            status = d['status']
1103 91de9b55 John Giannelos
            if status == 'ACTIVE':
1104 91de9b55 John Giannelos
                active = True
1105 91de9b55 John Giannelos
                break
1106 91de9b55 John Giannelos
            elif time.time() > fail_tmout:
1107 91de9b55 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1108 91de9b55 John Giannelos
            else:
1109 91de9b55 John Giannelos
                time.sleep(self.query_interval)
1110 91de9b55 John Giannelos
1111 91de9b55 John Giannelos
        self.assertTrue(active)
1112 91de9b55 John Giannelos
1113 740a5649 John Giannelos
    def test_00002a_submit_create_server_B(self):
1114 fade8dab John Giannelos
        """Test submit create server request"""
1115 8252d64f John Giannelos
1116 f89d0238 John Giannelos
        log.info("Creating test server B")
1117 6e168615 Ilias Tsitsimpis
1118 186428b0 Ilias Tsitsimpis
        serverB = self.cyclades_client.create_server(
1119 186428b0 Ilias Tsitsimpis
            self.servername, self.flavorid, self.imageid, personality=None)
1120 ae139e8a John Giannelos
1121 fade8dab John Giannelos
        self.assertEqual(serverB["name"], self.servername)
1122 bcc21c50 Christos Stavrakakis
        self.assertEqual(serverB["flavor"]["id"], self.flavorid)
1123 bcc21c50 Christos Stavrakakis
        self.assertEqual(serverB["image"]["id"], self.imageid)
1124 fade8dab John Giannelos
        self.assertEqual(serverB["status"], "BUILD")
1125 fade8dab John Giannelos
1126 fade8dab John Giannelos
        # Update class attributes to reflect data on building server
1127 fade8dab John Giannelos
        self.serverid['B'] = serverB["id"]
1128 fade8dab John Giannelos
        self.username['B'] = None
1129 fade8dab John Giannelos
        self.password['B'] = serverB["adminPass"]
1130 fade8dab John Giannelos
1131 81e8cbf6 John Giannelos
        log.info("Server B id: " + str(serverB["id"]))
1132 81e8cbf6 John Giannelos
        log.info("Password " + (self.password['B']))
1133 ae139e8a John Giannelos
1134 66eba2cf John Giannelos
        self.result_dict.clear()
1135 66eba2cf John Giannelos
        self.result_dict["Server B ID"] = str(serverB["id"])
1136 66eba2cf John Giannelos
        self.result_dict["Server B password"] = serverB["adminPass"]
1137 66eba2cf John Giannelos
1138 740a5649 John Giannelos
    def test_00002b_serverB_becomes_active(self):
1139 91de9b55 John Giannelos
        """Test server becomes ACTIVE"""
1140 91de9b55 John Giannelos
1141 f89d0238 John Giannelos
        log.info("Waiting until test server B becomes ACTIVE")
1142 66eba2cf John Giannelos
        self.result_dict.clear()
1143 f89d0238 John Giannelos
1144 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1145 91de9b55 John Giannelos
        while True:
1146 186428b0 Ilias Tsitsimpis
            d = self.cyclades_client.get_server_details(self.serverid['B'])
1147 91de9b55 John Giannelos
            status = d['status']
1148 91de9b55 John Giannelos
            if status == 'ACTIVE':
1149 91de9b55 John Giannelos
                active = True
1150 91de9b55 John Giannelos
                break
1151 91de9b55 John Giannelos
            elif time.time() > fail_tmout:
1152 91de9b55 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1153 91de9b55 John Giannelos
            else:
1154 91de9b55 John Giannelos
                time.sleep(self.query_interval)
1155 91de9b55 John Giannelos
1156 91de9b55 John Giannelos
        self.assertTrue(active)
1157 567ffb85 John Giannelos
1158 9e4682b5 John Giannelos
    def test_001_create_network(self):
1159 e94a9d8c John Giannelos
        """Test submit create network request"""
1160 f89d0238 John Giannelos
1161 f89d0238 John Giannelos
        log.info("Submit new network request")
1162 66eba2cf John Giannelos
        self.result_dict.clear()
1163 6e168615 Ilias Tsitsimpis
1164 2bcfb712 John Giannelos
        name = SNF_TEST_PREFIX + TEST_RUN_ID
1165 6e168615 Ilias Tsitsimpis
        #previous_num = len(self.client.list_networks())
1166 186428b0 Ilias Tsitsimpis
        network = self.cyclades_client.create_network(
1167 186428b0 Ilias Tsitsimpis
            name, cidr='10.0.1.0/28', dhcp=True)
1168 8252d64f John Giannelos
1169 9e4682b5 John Giannelos
        #Test if right name is assigned
1170 e94a9d8c John Giannelos
        self.assertEqual(network['name'], name)
1171 8252d64f John Giannelos
1172 9e4682b5 John Giannelos
        # Update class attributes
1173 e94a9d8c John Giannelos
        cls = type(self)
1174 e94a9d8c John Giannelos
        cls.networkid = network['id']
1175 6e168615 Ilias Tsitsimpis
        #networks = self.client.list_networks()
1176 9e4682b5 John Giannelos
1177 2aaa1336 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1178 2aaa1336 John Giannelos
1179 9e4682b5 John Giannelos
        #Test if new network is created
1180 2aaa1336 John Giannelos
        while True:
1181 186428b0 Ilias Tsitsimpis
            d = self.cyclades_client.get_network_details(network['id'])
1182 2aaa1336 John Giannelos
            if d['status'] == 'ACTIVE':
1183 2aaa1336 John Giannelos
                connected = True
1184 2aaa1336 John Giannelos
                break
1185 2aaa1336 John Giannelos
            elif time.time() > fail_tmout:
1186 2aaa1336 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1187 2aaa1336 John Giannelos
            else:
1188 2aaa1336 John Giannelos
                log.info("Waiting for network to become ACTIVE")
1189 2aaa1336 John Giannelos
                time.sleep(self.query_interval)
1190 2aaa1336 John Giannelos
1191 2aaa1336 John Giannelos
        self.assertTrue(connected)
1192 8252d64f John Giannelos
1193 66eba2cf John Giannelos
        self.result_dict["Private network ID"] = str(network['id'])
1194 66eba2cf John Giannelos
1195 9e4682b5 John Giannelos
    def test_002_connect_to_network(self):
1196 4573ea07 John Giannelos
        """Test connect VMs to network"""
1197 9e4682b5 John Giannelos
1198 f89d0238 John Giannelos
        log.info("Connect VMs to private network")
1199 66eba2cf John Giannelos
        self.result_dict.clear()
1200 f89d0238 John Giannelos
1201 186428b0 Ilias Tsitsimpis
        self.cyclades_client.connect_server(self.serverid['A'], self.networkid)
1202 186428b0 Ilias Tsitsimpis
        self.cyclades_client.connect_server(self.serverid['B'], self.networkid)
1203 8252d64f John Giannelos
1204 65462ca9 John Giannelos
        #Insist on connecting until action timeout
1205 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1206 9e4682b5 John Giannelos
1207 65462ca9 John Giannelos
        while True:
1208 2aaa1336 John Giannelos
1209 6e168615 Ilias Tsitsimpis
            netsA = [x['network_id']
1210 186428b0 Ilias Tsitsimpis
                     for x in self.cyclades_client.get_server_details(
1211 bcb7c357 Ilias Tsitsimpis
                         self.serverid['A'])['attachments']]
1212 6e168615 Ilias Tsitsimpis
            netsB = [x['network_id']
1213 186428b0 Ilias Tsitsimpis
                     for x in self.cyclades_client.get_server_details(
1214 bcb7c357 Ilias Tsitsimpis
                         self.serverid['B'])['attachments']]
1215 2aaa1336 John Giannelos
1216 2aaa1336 John Giannelos
            if (self.networkid in netsA) and (self.networkid in netsB):
1217 65462ca9 John Giannelos
                conn_exists = True
1218 de2461ec John Giannelos
                break
1219 de2461ec John Giannelos
            elif time.time() > fail_tmout:
1220 65462ca9 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1221 65462ca9 John Giannelos
            else:
1222 65462ca9 John Giannelos
                time.sleep(self.query_interval)
1223 6e168615 Ilias Tsitsimpis
1224 daac4017 John Giannelos
        #Adding private IPs to class attributes
1225 daac4017 John Giannelos
        cls = type(self)
1226 daac4017 John Giannelos
        cls.priv_ip = dict()
1227 daac4017 John Giannelos
1228 186428b0 Ilias Tsitsimpis
        nicsA = self.cyclades_client.get_server_details(
1229 bcb7c357 Ilias Tsitsimpis
            self.serverid['A'])['attachments']
1230 186428b0 Ilias Tsitsimpis
        nicsB = self.cyclades_client.get_server_details(
1231 bcb7c357 Ilias Tsitsimpis
            self.serverid['B'])['attachments']
1232 daac4017 John Giannelos
1233 daac4017 John Giannelos
        if conn_exists:
1234 daac4017 John Giannelos
            for nic in nicsA:
1235 daac4017 John Giannelos
                if nic["network_id"] == self.networkid:
1236 daac4017 John Giannelos
                    cls.priv_ip["A"] = nic["ipv4"]
1237 8bf886d0 Ilias Tsitsimpis
            self.result_dict["Server A private IP"] = str(cls.priv_ip["A"])
1238 daac4017 John Giannelos
1239 daac4017 John Giannelos
            for nic in nicsB:
1240 daac4017 John Giannelos
                if nic["network_id"] == self.networkid:
1241 daac4017 John Giannelos
                    cls.priv_ip["B"] = nic["ipv4"]
1242 8bf886d0 Ilias Tsitsimpis
            self.result_dict["Server B private IP"] = str(cls.priv_ip["B"])
1243 65462ca9 John Giannelos
1244 65462ca9 John Giannelos
        self.assertTrue(conn_exists)
1245 9b1e6145 Christos Stavrakakis
        self.assertIsNot(cls.priv_ip["A"], None)
1246 9b1e6145 Christos Stavrakakis
        self.assertIsNot(cls.priv_ip["B"], None)
1247 9e4682b5 John Giannelos
1248 88736f65 John Giannelos
    def test_002a_reboot(self):
1249 f89d0238 John Giannelos
        """Rebooting server A"""
1250 f89d0238 John Giannelos
1251 f89d0238 John Giannelos
        log.info("Rebooting server A")
1252 f89d0238 John Giannelos
1253 186428b0 Ilias Tsitsimpis
        self.cyclades_client.shutdown_server(self.serverid['A'])
1254 8252d64f John Giannelos
1255 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1256 4573ea07 John Giannelos
        while True:
1257 186428b0 Ilias Tsitsimpis
            d = self.cyclades_client.get_server_details(self.serverid['A'])
1258 4573ea07 John Giannelos
            status = d['status']
1259 81e8cbf6 John Giannelos
            if status == 'STOPPED':
1260 81e8cbf6 John Giannelos
                break
1261 81e8cbf6 John Giannelos
            elif time.time() > fail_tmout:
1262 81e8cbf6 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1263 81e8cbf6 John Giannelos
            else:
1264 81e8cbf6 John Giannelos
                time.sleep(self.query_interval)
1265 81e8cbf6 John Giannelos
1266 186428b0 Ilias Tsitsimpis
        self.cyclades_client.start_server(self.serverid['A'])
1267 81e8cbf6 John Giannelos
1268 81e8cbf6 John Giannelos
        while True:
1269 186428b0 Ilias Tsitsimpis
            d = self.cyclades_client.get_server_details(self.serverid['A'])
1270 81e8cbf6 John Giannelos
            status = d['status']
1271 4573ea07 John Giannelos
            if status == 'ACTIVE':
1272 4573ea07 John Giannelos
                active = True
1273 4573ea07 John Giannelos
                break
1274 4573ea07 John Giannelos
            elif time.time() > fail_tmout:
1275 4573ea07 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1276 4573ea07 John Giannelos
            else:
1277 4573ea07 John Giannelos
                time.sleep(self.query_interval)
1278 8252d64f John Giannelos
1279 4573ea07 John Giannelos
        self.assertTrue(active)
1280 88736f65 John Giannelos
1281 daac4017 John Giannelos
    def test_002b_ping_server_A(self):
1282 daac4017 John Giannelos
        "Test if server A responds to IPv4 pings"
1283 4573ea07 John Giannelos
1284 daac4017 John Giannelos
        log.info("Testing if server A responds to IPv4 pings ")
1285 66eba2cf John Giannelos
        self.result_dict.clear()
1286 f89d0238 John Giannelos
1287 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid['A'])
1288 daac4017 John Giannelos
        ip = self._get_ipv4(server)
1289 8252d64f John Giannelos
1290 daac4017 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1291 8252d64f John Giannelos
1292 daac4017 John Giannelos
        s = False
1293 6e168615 Ilias Tsitsimpis
1294 66eba2cf John Giannelos
        self.result_dict["Server A public IP"] = str(ip)
1295 88736f65 John Giannelos
1296 daac4017 John Giannelos
        while True:
1297 88736f65 John Giannelos
1298 daac4017 John Giannelos
            if self._ping_once(ip):
1299 daac4017 John Giannelos
                s = True
1300 daac4017 John Giannelos
                break
1301 88736f65 John Giannelos
1302 daac4017 John Giannelos
            elif time.time() > fail_tmout:
1303 daac4017 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1304 88736f65 John Giannelos
1305 daac4017 John Giannelos
            else:
1306 daac4017 John Giannelos
                time.sleep(self.query_interval)
1307 88736f65 John Giannelos
1308 daac4017 John Giannelos
        self.assertTrue(s)
1309 4573ea07 John Giannelos
1310 4573ea07 John Giannelos
    def test_002c_reboot(self):
1311 f89d0238 John Giannelos
        """Reboot server B"""
1312 f89d0238 John Giannelos
1313 f89d0238 John Giannelos
        log.info("Rebooting server B")
1314 66eba2cf John Giannelos
        self.result_dict.clear()
1315 f89d0238 John Giannelos
1316 186428b0 Ilias Tsitsimpis
        self.cyclades_client.shutdown_server(self.serverid['B'])
1317 8252d64f John Giannelos
1318 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1319 4573ea07 John Giannelos
        while True:
1320 186428b0 Ilias Tsitsimpis
            d = self.cyclades_client.get_server_details(self.serverid['B'])
1321 4573ea07 John Giannelos
            status = d['status']
1322 81e8cbf6 John Giannelos
            if status == 'STOPPED':
1323 81e8cbf6 John Giannelos
                break
1324 81e8cbf6 John Giannelos
            elif time.time() > fail_tmout:
1325 81e8cbf6 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1326 81e8cbf6 John Giannelos
            else:
1327 81e8cbf6 John Giannelos
                time.sleep(self.query_interval)
1328 81e8cbf6 John Giannelos
1329 186428b0 Ilias Tsitsimpis
        self.cyclades_client.start_server(self.serverid['B'])
1330 81e8cbf6 John Giannelos
1331 81e8cbf6 John Giannelos
        while True:
1332 186428b0 Ilias Tsitsimpis
            d = self.cyclades_client.get_server_details(self.serverid['B'])
1333 81e8cbf6 John Giannelos
            status = d['status']
1334 4573ea07 John Giannelos
            if status == 'ACTIVE':
1335 4573ea07 John Giannelos
                active = True
1336 4573ea07 John Giannelos
                break
1337 4573ea07 John Giannelos
            elif time.time() > fail_tmout:
1338 4573ea07 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1339 4573ea07 John Giannelos
            else:
1340 4573ea07 John Giannelos
                time.sleep(self.query_interval)
1341 8252d64f John Giannelos
1342 4573ea07 John Giannelos
        self.assertTrue(active)
1343 8252d64f John Giannelos
1344 daac4017 John Giannelos
    def test_002d_ping_server_B(self):
1345 daac4017 John Giannelos
        """Test if server B responds to IPv4 pings"""
1346 4573ea07 John Giannelos
1347 daac4017 John Giannelos
        log.info("Testing if server B responds to IPv4 pings")
1348 66eba2cf John Giannelos
        self.result_dict.clear()
1349 6e168615 Ilias Tsitsimpis
1350 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid['B'])
1351 daac4017 John Giannelos
        ip = self._get_ipv4(server)
1352 8252d64f John Giannelos
1353 daac4017 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1354 8252d64f John Giannelos
1355 daac4017 John Giannelos
        s = False
1356 88736f65 John Giannelos
1357 66eba2cf John Giannelos
        self.result_dict["Server B public IP"] = str(ip)
1358 66eba2cf John Giannelos
1359 daac4017 John Giannelos
        while True:
1360 daac4017 John Giannelos
            if self._ping_once(ip):
1361 daac4017 John Giannelos
                s = True
1362 daac4017 John Giannelos
                break
1363 88736f65 John Giannelos
1364 daac4017 John Giannelos
            elif time.time() > fail_tmout:
1365 daac4017 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1366 88736f65 John Giannelos
1367 daac4017 John Giannelos
            else:
1368 daac4017 John Giannelos
                time.sleep(self.query_interval)
1369 88736f65 John Giannelos
1370 daac4017 John Giannelos
        self.assertTrue(s)
1371 88736f65 John Giannelos
1372 daac4017 John Giannelos
    def test_003a_setup_interface_A(self):
1373 8bf886d0 Ilias Tsitsimpis
        """Setup eth1 for server A"""
1374 f89d0238 John Giannelos
1375 daac4017 John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
1376 e49bdb7c John Giannelos
1377 daac4017 John Giannelos
        log.info("Setting up interface eth1 for server A")
1378 66eba2cf John Giannelos
        self.result_dict.clear()
1379 ae139e8a John Giannelos
1380 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid['A'])
1381 186428b0 Ilias Tsitsimpis
        image = self.cyclades_client.get_image_details(self.imageid)
1382 bcb7c357 Ilias Tsitsimpis
        os_value = image['metadata']['os']
1383 8252d64f John Giannelos
1384 bcb7c357 Ilias Tsitsimpis
        users = image["metadata"].get("users", None)
1385 daac4017 John Giannelos
        userlist = users.split()
1386 d5cc50b3 John Giannelos
1387 daac4017 John Giannelos
        if "root" in userlist:
1388 daac4017 John Giannelos
            loginname = "root"
1389 6e168615 Ilias Tsitsimpis
        elif users is None:
1390 6e168615 Ilias Tsitsimpis
            loginname = self._connect_loginname(os_value)
1391 daac4017 John Giannelos
        else:
1392 daac4017 John Giannelos
            loginname = choice(userlist)
1393 1b40b5e3 John Giannelos
1394 daac4017 John Giannelos
        hostip = self._get_ipv4(server)
1395 daac4017 John Giannelos
        myPass = self.password['A']
1396 8252d64f John Giannelos
1397 daac4017 John Giannelos
        log.info("SSH in server A as %s/%s" % (loginname, myPass))
1398 8bf886d0 Ilias Tsitsimpis
        command = "ifconfig eth1 %s && ifconfig eth1 | " \
1399 8bf886d0 Ilias Tsitsimpis
                  "grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'" \
1400 8bf886d0 Ilias Tsitsimpis
                  % self.priv_ip["A"]
1401 2a410f76 Ilias Tsitsimpis
        output, status = _ssh_execute(
1402 2a410f76 Ilias Tsitsimpis
            hostip, loginname, myPass, command)
1403 8252d64f John Giannelos
1404 2a410f76 Ilias Tsitsimpis
        self.assertEquals(status, 0)
1405 8bf886d0 Ilias Tsitsimpis
        self.assertEquals(output[0].strip(), self.priv_ip["A"])
1406 1b40b5e3 John Giannelos
1407 daac4017 John Giannelos
    def test_003b_setup_interface_B(self):
1408 daac4017 John Giannelos
        """Setup eth1 for server B"""
1409 1b40b5e3 John Giannelos
1410 daac4017 John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
1411 e49bdb7c John Giannelos
1412 daac4017 John Giannelos
        log.info("Setting up interface eth1 for server B")
1413 ae139e8a John Giannelos
1414 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid['B'])
1415 186428b0 Ilias Tsitsimpis
        image = self.cyclades_client.get_image_details(self.imageid)
1416 bcb7c357 Ilias Tsitsimpis
        os_value = image['metadata']['os']
1417 8252d64f John Giannelos
1418 bcb7c357 Ilias Tsitsimpis
        users = image["metadata"].get("users", None)
1419 daac4017 John Giannelos
        userlist = users.split()
1420 d5cc50b3 John Giannelos
1421 daac4017 John Giannelos
        if "root" in userlist:
1422 daac4017 John Giannelos
            loginname = "root"
1423 6e168615 Ilias Tsitsimpis
        elif users is None:
1424 6e168615 Ilias Tsitsimpis
            loginname = self._connect_loginname(os_value)
1425 daac4017 John Giannelos
        else:
1426 daac4017 John Giannelos
            loginname = choice(userlist)
1427 d5cc50b3 John Giannelos
1428 daac4017 John Giannelos
        hostip = self._get_ipv4(server)
1429 daac4017 John Giannelos
        myPass = self.password['B']
1430 740a5649 John Giannelos
1431 daac4017 John Giannelos
        log.info("SSH in server B as %s/%s" % (loginname, myPass))
1432 8bf886d0 Ilias Tsitsimpis
        command = "ifconfig eth1 %s && ifconfig eth1 | " \
1433 8bf886d0 Ilias Tsitsimpis
                  "grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'" \
1434 8bf886d0 Ilias Tsitsimpis
                  % self.priv_ip["B"]
1435 2a410f76 Ilias Tsitsimpis
        output, status = _ssh_execute(
1436 2a410f76 Ilias Tsitsimpis
            hostip, loginname, myPass, command)
1437 1b40b5e3 John Giannelos
1438 2a410f76 Ilias Tsitsimpis
        self.assertEquals(status, 0)
1439 8bf886d0 Ilias Tsitsimpis
        self.assertEquals(output[0].strip(), self.priv_ip["B"])
1440 ae139e8a John Giannelos
1441 daac4017 John Giannelos
    def test_003c_test_connection_exists(self):
1442 daac4017 John Giannelos
        """Ping server B from server A to test if connection exists"""
1443 1b40b5e3 John Giannelos
1444 daac4017 John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
1445 e49bdb7c John Giannelos
1446 daac4017 John Giannelos
        log.info("Testing if server A is actually connected to server B")
1447 f89d0238 John Giannelos
1448 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid['A'])
1449 186428b0 Ilias Tsitsimpis
        image = self.cyclades_client.get_image_details(self.imageid)
1450 bcb7c357 Ilias Tsitsimpis
        os_value = image['metadata']['os']
1451 daac4017 John Giannelos
        hostip = self._get_ipv4(server)
1452 d5cc50b3 John Giannelos
1453 bcb7c357 Ilias Tsitsimpis
        users = image["metadata"].get("users", None)
1454 daac4017 John Giannelos
        userlist = users.split()
1455 d5cc50b3 John Giannelos
1456 daac4017 John Giannelos
        if "root" in userlist:
1457 daac4017 John Giannelos
            loginname = "root"
1458 6e168615 Ilias Tsitsimpis
        elif users is None:
1459 6e168615 Ilias Tsitsimpis
            loginname = self._connect_loginname(os_value)
1460 daac4017 John Giannelos
        else:
1461 daac4017 John Giannelos
            loginname = choice(userlist)
1462 1b40b5e3 John Giannelos
1463 daac4017 John Giannelos
        myPass = self.password['A']
1464 88736f65 John Giannelos
1465 daac4017 John Giannelos
        cmd = "if ping -c 2 -w 3 %s >/dev/null; \
1466 daac4017 John Giannelos
               then echo \'True\'; fi;" % self.priv_ip["B"]
1467 2a410f76 Ilias Tsitsimpis
        lines, status = _ssh_execute(
1468 2a410f76 Ilias Tsitsimpis
            hostip, loginname, myPass, cmd)
1469 1b40b5e3 John Giannelos
1470 daac4017 John Giannelos
        exists = False
1471 4573ea07 John Giannelos
1472 daac4017 John Giannelos
        if 'True\n' in lines:
1473 daac4017 John Giannelos
            exists = True
1474 1b40b5e3 John Giannelos
1475 daac4017 John Giannelos
        self.assertTrue(exists)
1476 1b40b5e3 John Giannelos
1477 88736f65 John Giannelos
    def test_004_disconnect_from_network(self):
1478 4573ea07 John Giannelos
        "Disconnecting server A and B from network"
1479 4573ea07 John Giannelos
1480 f89d0238 John Giannelos
        log.info("Disconnecting servers from private network")
1481 f89d0238 John Giannelos
1482 186428b0 Ilias Tsitsimpis
        prev_state = self.cyclades_client.get_network_details(self.networkid)
1483 bcb7c357 Ilias Tsitsimpis
        prev_nics = prev_state['attachments']
1484 6e168615 Ilias Tsitsimpis
        #prev_conn = len(prev_nics)
1485 2aaa1336 John Giannelos
1486 6e168615 Ilias Tsitsimpis
        nicsA = [x['id']
1487 186428b0 Ilias Tsitsimpis
                 for x in self.cyclades_client.get_server_details(
1488 bcb7c357 Ilias Tsitsimpis
                     self.serverid['A'])['attachments']]
1489 6e168615 Ilias Tsitsimpis
        nicsB = [x['id']
1490 186428b0 Ilias Tsitsimpis
                 for x in self.cyclades_client.get_server_details(
1491 bcb7c357 Ilias Tsitsimpis
                     self.serverid['B'])['attachments']]
1492 2aaa1336 John Giannelos
1493 2aaa1336 John Giannelos
        for nic in prev_nics:
1494 2aaa1336 John Giannelos
            if nic in nicsA:
1495 186428b0 Ilias Tsitsimpis
                self.cyclades_client.disconnect_server(self.serverid['A'], nic)
1496 2aaa1336 John Giannelos
            if nic in nicsB:
1497 186428b0 Ilias Tsitsimpis
                self.cyclades_client.disconnect_server(self.serverid['B'], nic)
1498 e94a9d8c John Giannelos
1499 65462ca9 John Giannelos
        #Insist on deleting until action timeout
1500 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1501 9e4682b5 John Giannelos
1502 65462ca9 John Giannelos
        while True:
1503 6e168615 Ilias Tsitsimpis
            netsA = [x['network_id']
1504 186428b0 Ilias Tsitsimpis
                     for x in self.cyclades_client.get_server_details(
1505 bcb7c357 Ilias Tsitsimpis
                         self.serverid['A'])['attachments']]
1506 6e168615 Ilias Tsitsimpis
            netsB = [x['network_id']
1507 186428b0 Ilias Tsitsimpis
                     for x in self.cyclades_client.get_server_details(
1508 bcb7c357 Ilias Tsitsimpis
                         self.serverid['B'])['attachments']]
1509 6e168615 Ilias Tsitsimpis
1510 6e168615 Ilias Tsitsimpis
            #connected = (self.client.get_network_details(self.networkid))
1511 bcb7c357 Ilias Tsitsimpis
            #connections = connected['attachments']
1512 2aaa1336 John Giannelos
            if (self.networkid not in netsA) and (self.networkid not in netsB):
1513 65462ca9 John Giannelos
                conn_exists = False
1514 de2461ec John Giannelos
                break
1515 de2461ec John Giannelos
            elif time.time() > fail_tmout:
1516 65462ca9 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1517 65462ca9 John Giannelos
            else:
1518 65462ca9 John Giannelos
                time.sleep(self.query_interval)
1519 65462ca9 John Giannelos
1520 65462ca9 John Giannelos
        self.assertFalse(conn_exists)
1521 9e4682b5 John Giannelos
1522 88736f65 John Giannelos
    def test_005_destroy_network(self):
1523 e94a9d8c John Giannelos
        """Test submit delete network request"""
1524 f89d0238 John Giannelos
1525 f89d0238 John Giannelos
        log.info("Submitting delete network request")
1526 f89d0238 John Giannelos
1527 186428b0 Ilias Tsitsimpis
        self.cyclades_client.delete_network(self.networkid)
1528 e50133da John Giannelos
1529 2aaa1336 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1530 2aaa1336 John Giannelos
1531 2aaa1336 John Giannelos
        while True:
1532 e94a9d8c John Giannelos
1533 2aaa1336 John Giannelos
            curr_net = []
1534 186428b0 Ilias Tsitsimpis
            networks = self.cyclades_client.list_networks()
1535 2aaa1336 John Giannelos
1536 2aaa1336 John Giannelos
            for net in networks:
1537 2aaa1336 John Giannelos
                curr_net.append(net['id'])
1538 2aaa1336 John Giannelos
1539 2aaa1336 John Giannelos
            if self.networkid not in curr_net:
1540 2aaa1336 John Giannelos
                self.assertTrue(self.networkid not in curr_net)
1541 2aaa1336 John Giannelos
                break
1542 65462ca9 John Giannelos
1543 2aaa1336 John Giannelos
            elif time.time() > fail_tmout:
1544 2aaa1336 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1545 2aaa1336 John Giannelos
1546 2aaa1336 John Giannelos
            else:
1547 2aaa1336 John Giannelos
                time.sleep(self.query_interval)
1548 2aaa1336 John Giannelos
1549 88736f65 John Giannelos
    def test_006_cleanup_servers(self):
1550 65462ca9 John Giannelos
        """Cleanup servers created for this test"""
1551 f89d0238 John Giannelos
1552 f89d0238 John Giannelos
        log.info("Delete servers created for this test")
1553 f89d0238 John Giannelos
1554 186428b0 Ilias Tsitsimpis
        self.cyclades_client.delete_server(self.serverid['A'])
1555 186428b0 Ilias Tsitsimpis
        self.cyclades_client.delete_server(self.serverid['B'])
1556 91de9b55 John Giannelos
1557 2bcfb712 John Giannelos
        fail_tmout = time.time() + self.action_timeout
1558 65462ca9 John Giannelos
1559 65462ca9 John Giannelos
        #Ensure server gets deleted
1560 8252d64f John Giannelos
        status = dict()
1561 91de9b55 John Giannelos
1562 65462ca9 John Giannelos
        while True:
1563 186428b0 Ilias Tsitsimpis
            details = \
1564 186428b0 Ilias Tsitsimpis
                self.cyclades_client.get_server_details(self.serverid['A'])
1565 91de9b55 John Giannelos
            status['A'] = details['status']
1566 186428b0 Ilias Tsitsimpis
            details = \
1567 186428b0 Ilias Tsitsimpis
                self.cyclades_client.get_server_details(self.serverid['B'])
1568 91de9b55 John Giannelos
            status['B'] = details['status']
1569 91de9b55 John Giannelos
            if (status['A'] == 'DELETED') and (status['B'] == 'DELETED'):
1570 65462ca9 John Giannelos
                deleted = True
1571 de2461ec John Giannelos
                break
1572 8252d64f John Giannelos
            elif time.time() > fail_tmout:
1573 65462ca9 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1574 65462ca9 John Giannelos
            else:
1575 65462ca9 John Giannelos
                time.sleep(self.query_interval)
1576 8252d64f John Giannelos
1577 65462ca9 John Giannelos
        self.assertTrue(deleted)
1578 e94a9d8c John Giannelos
1579 4573ea07 John Giannelos
1580 21bbbc9b Vangelis Koukis
class TestRunnerProcess(Process):
1581 21bbbc9b Vangelis Koukis
    """A distinct process used to execute part of the tests in parallel"""
1582 21bbbc9b Vangelis Koukis
    def __init__(self, **kw):
1583 21bbbc9b Vangelis Koukis
        Process.__init__(self, **kw)
1584 96da37c8 John Giannelos
        kwargs = kw["kwargs"]
1585 21bbbc9b Vangelis Koukis
        self.testq = kwargs["testq"]
1586 2aaa1336 John Giannelos
        self.worker_folder = kwargs["worker_folder"]
1587 21bbbc9b Vangelis Koukis
1588 21bbbc9b Vangelis Koukis
    def run(self):
1589 21bbbc9b Vangelis Koukis
        # Make sure this test runner process dies with the parent
1590 21bbbc9b Vangelis Koukis
        # and is not left behind.
1591 21bbbc9b Vangelis Koukis
        #
1592 21bbbc9b Vangelis Koukis
        # WARNING: This uses the prctl(2) call and is
1593 21bbbc9b Vangelis Koukis
        # Linux-specific.
1594 2aaa1336 John Giannelos
1595 21bbbc9b Vangelis Koukis
        prctl.set_pdeathsig(signal.SIGHUP)
1596 21bbbc9b Vangelis Koukis
1597 2aaa1336 John Giannelos
        multi = logging.getLogger("multiprocess")
1598 2aaa1336 John Giannelos
1599 21bbbc9b Vangelis Koukis
        while True:
1600 2aaa1336 John Giannelos
            multi.debug("I am process %d, GETting from queue is %s" %
1601 6e168615 Ilias Tsitsimpis
                        (os.getpid(), self.testq))
1602 21bbbc9b Vangelis Koukis
            msg = self.testq.get()
1603 2aaa1336 John Giannelos
1604 2aaa1336 John Giannelos
            multi.debug("Dequeued msg: %s" % msg)
1605 21bbbc9b Vangelis Koukis
1606 21bbbc9b Vangelis Koukis
            if msg == "TEST_RUNNER_TERMINATE":
1607 21bbbc9b Vangelis Koukis
                raise SystemExit
1608 2aaa1336 John Giannelos
1609 21bbbc9b Vangelis Koukis
            elif issubclass(msg, unittest.TestCase):
1610 21bbbc9b Vangelis Koukis
                # Assemble a TestSuite, and run it
1611 2aaa1336 John Giannelos
1612 2aaa1336 John Giannelos
                log_file = os.path.join(self.worker_folder, 'details_' +
1613 2aaa1336 John Giannelos
                                        (msg.__name__) + "_" +
1614 2aaa1336 John Giannelos
                                        TEST_RUN_ID + '.log')
1615 e50133da John Giannelos
1616 2aaa1336 John Giannelos
                fail_file = os.path.join(self.worker_folder, 'failed_' +
1617 2aaa1336 John Giannelos
                                         (msg.__name__) + "_" +
1618 2aaa1336 John Giannelos
                                         TEST_RUN_ID + '.log')
1619 2aaa1336 John Giannelos
                error_file = os.path.join(self.worker_folder, 'error_' +
1620 2aaa1336 John Giannelos
                                          (msg.__name__) + "_" +
1621 2aaa1336 John Giannelos
                                          TEST_RUN_ID + '.log')
1622 2aaa1336 John Giannelos
1623 2aaa1336 John Giannelos
                f = open(log_file, 'w')
1624 6e168615 Ilias Tsitsimpis
                fail = open(fail_file, 'w')
1625 2aaa1336 John Giannelos
                error = open(error_file, 'w')
1626 2aaa1336 John Giannelos
1627 2aaa1336 John Giannelos
                log.info(yellow + '* Starting testcase: %s' % msg + normal)
1628 2aaa1336 John Giannelos
1629 6e168615 Ilias Tsitsimpis
                runner = unittest.TextTestRunner(
1630 6e168615 Ilias Tsitsimpis
                    f, verbosity=2, failfast=True,
1631 6e168615 Ilias Tsitsimpis
                    resultclass=BurninTestResult)
1632 21bbbc9b Vangelis Koukis
                suite = unittest.TestLoader().loadTestsFromTestCase(msg)
1633 2aaa1336 John Giannelos
                result = runner.run(suite)
1634 2aaa1336 John Giannelos
1635 2aaa1336 John Giannelos
                for res in result.errors:
1636 6e168615 Ilias Tsitsimpis
                    log.error("snf-burnin encountered an error in "
1637 6e168615 Ilias Tsitsimpis
                              "testcase: %s" % msg)
1638 2aaa1336 John Giannelos
                    log.error("See log for details")
1639 2aaa1336 John Giannelos
                    error.write(str(res[0]) + '\n')
1640 2aaa1336 John Giannelos
                    error.write(str(res[0].shortDescription()) + '\n')
1641 2aaa1336 John Giannelos
                    error.write('\n')
1642 2aaa1336 John Giannelos
1643 2aaa1336 John Giannelos
                for res in result.failures:
1644 6e168615 Ilias Tsitsimpis
                    log.error("snf-burnin failed in testcase: %s" % msg)
1645 2aaa1336 John Giannelos
                    log.error("See log for details")
1646 2aaa1336 John Giannelos
                    fail.write(str(res[0]) + '\n')
1647 2aaa1336 John Giannelos
                    fail.write(str(res[0].shortDescription()) + '\n')
1648 2aaa1336 John Giannelos
                    fail.write('\n')
1649 6e168615 Ilias Tsitsimpis
                    if not NOFAILFAST:
1650 2aaa1336 John Giannelos
                        sys.exit()
1651 2aaa1336 John Giannelos
1652 2aaa1336 John Giannelos
                if (len(result.failures) == 0) and (len(result.errors) == 0):
1653 6e168615 Ilias Tsitsimpis
                    log.debug("Passed testcase: %s" % msg)
1654 2aaa1336 John Giannelos
1655 2aaa1336 John Giannelos
                f.close()
1656 2aaa1336 John Giannelos
                fail.close()
1657 2aaa1336 John Giannelos
                error.close()
1658 2aaa1336 John Giannelos
1659 21bbbc9b Vangelis Koukis
            else:
1660 21bbbc9b Vangelis Koukis
                raise Exception("Cannot handle msg: %s" % msg)
1661 21bbbc9b Vangelis Koukis
1662 6e168615 Ilias Tsitsimpis
1663 6e168615 Ilias Tsitsimpis
def _run_cases_in_series(cases, image_folder):
1664 3e4c5c32 John Giannelos
    """Run instances of TestCase in series"""
1665 3e4c5c32 John Giannelos
1666 3e4c5c32 John Giannelos
    for case in cases:
1667 3e4c5c32 John Giannelos
1668 3e4c5c32 John Giannelos
        test = case.__name__
1669 3e4c5c32 John Giannelos
1670 6e168615 Ilias Tsitsimpis
        log.info(yellow + '* Starting testcase: %s' % test + normal)
1671 3e4c5c32 John Giannelos
        log_file = os.path.join(image_folder, 'details_' +
1672 3e4c5c32 John Giannelos
                                (case.__name__) + "_" +
1673 3e4c5c32 John Giannelos
                                TEST_RUN_ID + '.log')
1674 3e4c5c32 John Giannelos
        fail_file = os.path.join(image_folder, 'failed_' +
1675 3e4c5c32 John Giannelos
                                 (case.__name__) + "_" +
1676 3e4c5c32 John Giannelos
                                 TEST_RUN_ID + '.log')
1677 3e4c5c32 John Giannelos
        error_file = os.path.join(image_folder, 'error_' +
1678 3e4c5c32 John Giannelos
                                  (case.__name__) + "_" +
1679 3e4c5c32 John Giannelos
                                  TEST_RUN_ID + '.log')
1680 3e4c5c32 John Giannelos
1681 3e4c5c32 John Giannelos
        f = open(log_file, "w")
1682 3e4c5c32 John Giannelos
        fail = open(fail_file, "w")
1683 3e4c5c32 John Giannelos
        error = open(error_file, "w")
1684 3e4c5c32 John Giannelos
1685 3e4c5c32 John Giannelos
        suite = unittest.TestLoader().loadTestsFromTestCase(case)
1686 6e168615 Ilias Tsitsimpis
        runner = unittest.TextTestRunner(
1687 6e168615 Ilias Tsitsimpis
            f, verbosity=2, failfast=True,
1688 6e168615 Ilias Tsitsimpis
            resultclass=BurninTestResult)
1689 3e4c5c32 John Giannelos
        result = runner.run(suite)
1690 3e4c5c32 John Giannelos
1691 3e4c5c32 John Giannelos
        for res in result.errors:
1692 6e168615 Ilias Tsitsimpis
            log.error("snf-burnin encountered an error in "
1693 6e168615 Ilias Tsitsimpis
                      "testcase: %s" % test)
1694 3e4c5c32 John Giannelos
            log.error("See log for details")
1695 3e4c5c32 John Giannelos
            error.write(str(res[0]) + '\n')
1696 3e4c5c32 John Giannelos
            error.write(str(res[0].shortDescription()) + '\n')
1697 3e4c5c32 John Giannelos
            error.write('\n')
1698 3e4c5c32 John Giannelos
1699 3e4c5c32 John Giannelos
        for res in result.failures:
1700 6e168615 Ilias Tsitsimpis
            log.error("snf-burnin failed in testcase: %s" % test)
1701 3e4c5c32 John Giannelos
            log.error("See log for details")
1702 3e4c5c32 John Giannelos
            fail.write(str(res[0]) + '\n')
1703 3e4c5c32 John Giannelos
            fail.write(str(res[0].shortDescription()) + '\n')
1704 3e4c5c32 John Giannelos
            fail.write('\n')
1705 6e168615 Ilias Tsitsimpis
            if not NOFAILFAST:
1706 3e4c5c32 John Giannelos
                sys.exit()
1707 3e4c5c32 John Giannelos
1708 3e4c5c32 John Giannelos
        if (len(result.failures) == 0) and (len(result.errors) == 0):
1709 6e168615 Ilias Tsitsimpis
            log.debug("Passed testcase: %s" % test)
1710 3e4c5c32 John Giannelos
1711 21bbbc9b Vangelis Koukis
1712 2aaa1336 John Giannelos
def _run_cases_in_parallel(cases, fanout, image_folder):
1713 21bbbc9b Vangelis Koukis
    """Run instances of TestCase in parallel, in a number of distinct processes
1714 21bbbc9b Vangelis Koukis

1715 21bbbc9b Vangelis Koukis
    The cases iterable specifies the TestCases to be executed in parallel,
1716 21bbbc9b Vangelis Koukis
    by test runners running in distinct processes.
1717 21bbbc9b Vangelis Koukis
    The fanout parameter specifies the number of processes to spawn,
1718 21bbbc9b Vangelis Koukis
    and defaults to 1.
1719 21bbbc9b Vangelis Koukis
    The runner argument specifies the test runner class to use inside each
1720 21bbbc9b Vangelis Koukis
    runner process.
1721 21bbbc9b Vangelis Koukis

1722 21bbbc9b Vangelis Koukis
    """
1723 e50133da John Giannelos
1724 2aaa1336 John Giannelos
    multi = logging.getLogger("multiprocess")
1725 2aaa1336 John Giannelos
    handler = logging.StreamHandler()
1726 2aaa1336 John Giannelos
    multi.addHandler(handler)
1727 21bbbc9b Vangelis Koukis
1728 2aaa1336 John Giannelos
    if VERBOSE:
1729 2aaa1336 John Giannelos
        multi.setLevel(logging.DEBUG)
1730 2aaa1336 John Giannelos
    else:
1731 2aaa1336 John Giannelos
        multi.setLevel(logging.INFO)
1732 2aaa1336 John Giannelos
1733 2aaa1336 John Giannelos
    testq = []
1734 2aaa1336 John Giannelos
    worker_folder = []
1735 21bbbc9b Vangelis Koukis
    runners = []
1736 2aaa1336 John Giannelos
1737 6e168615 Ilias Tsitsimpis
    for i in xrange(0, fanout):
1738 2aaa1336 John Giannelos
        testq.append(Queue())
1739 2aaa1336 John Giannelos
        worker_folder.append(os.path.join(image_folder, 'process'+str(i)))
1740 2aaa1336 John Giannelos
        os.mkdir(worker_folder[i])
1741 2aaa1336 John Giannelos
1742 21bbbc9b Vangelis Koukis
    for i in xrange(0, fanout):
1743 2aaa1336 John Giannelos
        kwargs = dict(testq=testq[i], worker_folder=worker_folder[i])
1744 21bbbc9b Vangelis Koukis
        runners.append(TestRunnerProcess(kwargs=kwargs))
1745 21bbbc9b Vangelis Koukis
1746 6e168615 Ilias Tsitsimpis
    multi.debug("Spawning %d test runner processes" % len(runners))
1747 2aaa1336 John Giannelos
1748 21bbbc9b Vangelis Koukis
    for p in runners:
1749 21bbbc9b Vangelis Koukis
        p.start()
1750 21bbbc9b Vangelis Koukis
1751 21bbbc9b Vangelis Koukis
    # Enqueue test cases
1752 2aaa1336 John Giannelos
    for i in xrange(0, fanout):
1753 2aaa1336 John Giannelos
        map(testq[i].put, cases)
1754 2aaa1336 John Giannelos
        testq[i].put("TEST_RUNNER_TERMINATE")
1755 2aaa1336 John Giannelos
1756 2aaa1336 John Giannelos
    multi.debug("Spawned %d test runners, PIDs are %s" %
1757 6e168615 Ilias Tsitsimpis
                (len(runners), [p.pid for p in runners]))
1758 21bbbc9b Vangelis Koukis
1759 2aaa1336 John Giannelos
    multi.debug("Joining %d processes" % len(runners))
1760 e50133da John Giannelos
1761 21bbbc9b Vangelis Koukis
    for p in runners:
1762 21bbbc9b Vangelis Koukis
        p.join()
1763 2aaa1336 John Giannelos
1764 2aaa1336 John Giannelos
    multi.debug("Done joining %d processes" % len(runners))
1765 4fdd25ab Vangelis Koukis
1766 5a140b23 Vangelis Koukis
1767 95a87099 Ilias Tsitsimpis
def _images_test_case(**kwargs):
1768 95a87099 Ilias Tsitsimpis
    """Construct a new unit test case class from ImagesTestCase"""
1769 95a87099 Ilias Tsitsimpis
    name = "ImagesTestCase_%s" % kwargs["imageid"]
1770 95a87099 Ilias Tsitsimpis
    cls = type(name, (ImagesTestCase,), kwargs)
1771 95a87099 Ilias Tsitsimpis
1772 95a87099 Ilias Tsitsimpis
    #Patch extra parameters into test names by manipulating method docstrings
1773 95a87099 Ilias Tsitsimpis
    for (mname, m) in \
1774 95a87099 Ilias Tsitsimpis
            inspect.getmembers(cls, lambda x: inspect.ismethod(x)):
1775 95a87099 Ilias Tsitsimpis
        if hasattr(m, __doc__):
1776 95a87099 Ilias Tsitsimpis
            m.__func__.__doc__ = "[%s] %s" % (cls.imagename, m.__doc__)
1777 95a87099 Ilias Tsitsimpis
1778 95a87099 Ilias Tsitsimpis
    # Make sure the class can be pickled, by listing it among
1779 95a87099 Ilias Tsitsimpis
    # the attributes of __main__. A PicklingError is raised otherwise.
1780 95a87099 Ilias Tsitsimpis
    thismodule = sys.modules[__name__]
1781 95a87099 Ilias Tsitsimpis
    setattr(thismodule, name, cls)
1782 95a87099 Ilias Tsitsimpis
    return cls
1783 95a87099 Ilias Tsitsimpis
1784 95a87099 Ilias Tsitsimpis
1785 5a140b23 Vangelis Koukis
def _spawn_server_test_case(**kwargs):
1786 5a140b23 Vangelis Koukis
    """Construct a new unit test case class from SpawnServerTestCase"""
1787 5a140b23 Vangelis Koukis
1788 c1d11f96 John Giannelos
    name = "SpawnServerTestCase_%s" % kwargs["imageid"]
1789 5a140b23 Vangelis Koukis
    cls = type(name, (SpawnServerTestCase,), kwargs)
1790 5a140b23 Vangelis Koukis
1791 5a140b23 Vangelis Koukis
    # Patch extra parameters into test names by manipulating method docstrings
1792 5a140b23 Vangelis Koukis
    for (mname, m) in \
1793 6e168615 Ilias Tsitsimpis
            inspect.getmembers(cls, lambda x: inspect.ismethod(x)):
1794 74ec726f John Giannelos
        if hasattr(m, __doc__):
1795 6e168615 Ilias Tsitsimpis
            m.__func__.__doc__ = "[%s] %s" % (cls.imagename, m.__doc__)
1796 e72bcf60 Vangelis Koukis
1797 e72bcf60 Vangelis Koukis
    # Make sure the class can be pickled, by listing it among
1798 e72bcf60 Vangelis Koukis
    # the attributes of __main__. A PicklingError is raised otherwise.
1799 2aaa1336 John Giannelos
1800 2aaa1336 John Giannelos
    thismodule = sys.modules[__name__]
1801 2aaa1336 John Giannelos
    setattr(thismodule, name, cls)
1802 8252d64f John Giannelos
    return cls
1803 65462ca9 John Giannelos
1804 2bcfb712 John Giannelos
1805 65462ca9 John Giannelos
def _spawn_network_test_case(**kwargs):
1806 65462ca9 John Giannelos
    """Construct a new unit test case class from NetworkTestCase"""
1807 65462ca9 John Giannelos
1808 2bcfb712 John Giannelos
    name = "NetworkTestCase" + TEST_RUN_ID
1809 65462ca9 John Giannelos
    cls = type(name, (NetworkTestCase,), kwargs)
1810 65462ca9 John Giannelos
1811 65462ca9 John Giannelos
    # Make sure the class can be pickled, by listing it among
1812 65462ca9 John Giannelos
    # the attributes of __main__. A PicklingError is raised otherwise.
1813 e50133da John Giannelos
1814 2aaa1336 John Giannelos
    thismodule = sys.modules[__name__]
1815 2aaa1336 John Giannelos
    setattr(thismodule, name, cls)
1816 8252d64f John Giannelos
    return cls
1817 5a140b23 Vangelis Koukis
1818 5a140b23 Vangelis Koukis
1819 8792bb97 Ilias Tsitsimpis
# --------------------------------------------------------------------
1820 8792bb97 Ilias Tsitsimpis
# Clean up servers/networks functions
1821 c0448f4f John Giannelos
def cleanup_servers(timeout, query_interval, delete_stale=False):
1822 74193008 John Giannelos
1823 186428b0 Ilias Tsitsimpis
    astakos_client = AstakosClient(AUTH_URL, TOKEN)
1824 186428b0 Ilias Tsitsimpis
    # Compute Client
1825 186428b0 Ilias Tsitsimpis
    compute_url = astakos_client.get_service_endpoints('compute')['publicURL']
1826 186428b0 Ilias Tsitsimpis
    compute_client = ComputeClient(compute_url, TOKEN)
1827 74193008 John Giannelos
1828 186428b0 Ilias Tsitsimpis
    servers = compute_client.list_servers()
1829 5a140b23 Vangelis Koukis
    stale = [s for s in servers if s["name"].startswith(SNF_TEST_PREFIX)]
1830 5a140b23 Vangelis Koukis
1831 4fdd25ab Vangelis Koukis
    if len(stale) == 0:
1832 4fdd25ab Vangelis Koukis
        return
1833 4fdd25ab Vangelis Koukis
1834 8792bb97 Ilias Tsitsimpis
    # Show staled servers
1835 8792bb97 Ilias Tsitsimpis
    print >>sys.stderr, yellow + \
1836 6e168615 Ilias Tsitsimpis
        "Found these stale servers from previous runs:" + \
1837 6e168615 Ilias Tsitsimpis
        normal
1838 8792bb97 Ilias Tsitsimpis
    print >>sys.stderr, "    " + \
1839 6e168615 Ilias Tsitsimpis
        "\n    ".join(["%d: %s" % (s["id"], s["name"]) for s in stale])
1840 5a140b23 Vangelis Koukis
1841 8792bb97 Ilias Tsitsimpis
    # Delete staled servers
1842 5a140b23 Vangelis Koukis
    if delete_stale:
1843 5a140b23 Vangelis Koukis
        print >> sys.stderr, "Deleting %d stale servers:" % len(stale)
1844 c0448f4f John Giannelos
        fail_tmout = time.time() + timeout
1845 c0448f4f John Giannelos
        for s in stale:
1846 186428b0 Ilias Tsitsimpis
            compute_client.delete_server(s["id"])
1847 8792bb97 Ilias Tsitsimpis
        # Wait for all servers to be deleted
1848 c0448f4f John Giannelos
        while True:
1849 186428b0 Ilias Tsitsimpis
            servers = compute_client.list_servers()
1850 6e168615 Ilias Tsitsimpis
            stale = [s for s in servers
1851 6e168615 Ilias Tsitsimpis
                     if s["name"].startswith(SNF_TEST_PREFIX)]
1852 6e168615 Ilias Tsitsimpis
            if len(stale) == 0:
1853 c0448f4f John Giannelos
                print >> sys.stderr, green + "    ...done" + normal
1854 c0448f4f John Giannelos
                break
1855 c0448f4f John Giannelos
            elif time.time() > fail_tmout:
1856 8792bb97 Ilias Tsitsimpis
                print >> sys.stderr, red + \
1857 6e168615 Ilias Tsitsimpis
                    "Not all stale servers deleted. Action timed out." + \
1858 6e168615 Ilias Tsitsimpis
                    normal
1859 6e168615 Ilias Tsitsimpis
                sys.exit(1)
1860 c0448f4f John Giannelos
            else:
1861 c0448f4f John Giannelos
                time.sleep(query_interval)
1862 5a140b23 Vangelis Koukis
    else:
1863 5a140b23 Vangelis Koukis
        print >> sys.stderr, "Use --delete-stale to delete them."
1864 5a140b23 Vangelis Koukis
1865 2bcfb712 John Giannelos
1866 f752215c John Giannelos
def cleanup_networks(action_timeout, query_interval, delete_stale=False):
1867 74ec726f John Giannelos
1868 186428b0 Ilias Tsitsimpis
    astakos_client = AstakosClient(AUTH_URL, TOKEN)
1869 186428b0 Ilias Tsitsimpis
    # Cyclades Client
1870 186428b0 Ilias Tsitsimpis
    compute_url = astakos_client.get_service_endpoints('compute')['publicURL']
1871 186428b0 Ilias Tsitsimpis
    cyclades_client = CycladesClient(compute_url, TOKEN)
1872 e50133da John Giannelos
1873 186428b0 Ilias Tsitsimpis
    networks = cyclades_client.list_networks()
1874 74ec726f John Giannelos
    stale = [n for n in networks if n["name"].startswith(SNF_TEST_PREFIX)]
1875 74ec726f John Giannelos
1876 74ec726f John Giannelos
    if len(stale) == 0:
1877 74ec726f John Giannelos
        return
1878 e50133da John Giannelos
1879 8792bb97 Ilias Tsitsimpis
    # Show staled networks
1880 8792bb97 Ilias Tsitsimpis
    print >> sys.stderr, yellow + \
1881 6e168615 Ilias Tsitsimpis
        "Found these stale networks from previous runs:" + \
1882 6e168615 Ilias Tsitsimpis
        normal
1883 74ec726f John Giannelos
    print "    " + \
1884 6e168615 Ilias Tsitsimpis
        "\n    ".join(["%s: %s" % (str(n["id"]), n["name"]) for n in stale])
1885 74ec726f John Giannelos
1886 8792bb97 Ilias Tsitsimpis
    # Delete staled networks
1887 74ec726f John Giannelos
    if delete_stale:
1888 74ec726f John Giannelos
        print >> sys.stderr, "Deleting %d stale networks:" % len(stale)
1889 f752215c John Giannelos
        fail_tmout = time.time() + action_timeout
1890 c0448f4f John Giannelos
        for n in stale:
1891 186428b0 Ilias Tsitsimpis
            cyclades_client.delete_network(n["id"])
1892 8792bb97 Ilias Tsitsimpis
        # Wait for all networks to be deleted
1893 c0448f4f John Giannelos
        while True:
1894 186428b0 Ilias Tsitsimpis
            networks = cyclades_client.list_networks()
1895 6e168615 Ilias Tsitsimpis
            stale = [n for n in networks
1896 6e168615 Ilias Tsitsimpis
                     if n["name"].startswith(SNF_TEST_PREFIX)]
1897 6e168615 Ilias Tsitsimpis
            if len(stale) == 0:
1898 c0448f4f John Giannelos
                print >> sys.stderr, green + "    ...done" + normal
1899 c0448f4f John Giannelos
                break
1900 c0448f4f John Giannelos
            elif time.time() > fail_tmout:
1901 8792bb97 Ilias Tsitsimpis
                print >> sys.stderr, red + \
1902 6e168615 Ilias Tsitsimpis
                    "Not all stale networks deleted. Action timed out." + \
1903 6e168615 Ilias Tsitsimpis
                    normal
1904 6e168615 Ilias Tsitsimpis
                sys.exit(1)
1905 c0448f4f John Giannelos
            else:
1906 c0448f4f John Giannelos
                time.sleep(query_interval)
1907 74ec726f John Giannelos
    else:
1908 74ec726f John Giannelos
        print >> sys.stderr, "Use --delete-stale to delete them."
1909 74ec726f John Giannelos
1910 746540cd John Giannelos
1911 8792bb97 Ilias Tsitsimpis
# --------------------------------------------------------------------
1912 8792bb97 Ilias Tsitsimpis
# Parse arguments functions
1913 22efe1fe John Giannelos
def parse_comma(option, opt, value, parser):
1914 746540cd John Giannelos
    tests = set(['all', 'auth', 'images', 'flavors',
1915 11779b6c Ilias Tsitsimpis
                 'pithos', 'servers', 'server_spawn',
1916 11779b6c Ilias Tsitsimpis
                 'network_spawn'])
1917 22efe1fe John Giannelos
    parse_input = value.split(',')
1918 22efe1fe John Giannelos
1919 22efe1fe John Giannelos
    if not (set(parse_input)).issubset(tests):
1920 22efe1fe John Giannelos
        raise OptionValueError("The selected set of tests is invalid")
1921 22efe1fe John Giannelos
1922 22efe1fe John Giannelos
    setattr(parser.values, option.dest, value.split(','))
1923 22efe1fe John Giannelos
1924 74ec726f John Giannelos
1925 5a140b23 Vangelis Koukis
def parse_arguments(args):
1926 5a140b23 Vangelis Koukis
1927 5a140b23 Vangelis Koukis
    kw = {}
1928 5a140b23 Vangelis Koukis
    kw["usage"] = "%prog [options]"
1929 5a140b23 Vangelis Koukis
    kw["description"] = \
1930 5a140b23 Vangelis Koukis
        "%prog runs a number of test scenarios on a " \
1931 5a140b23 Vangelis Koukis
        "Synnefo deployment."
1932 5a140b23 Vangelis Koukis
1933 5a140b23 Vangelis Koukis
    parser = OptionParser(**kw)
1934 5a140b23 Vangelis Koukis
    parser.disable_interspersed_args()
1935 22efe1fe John Giannelos
1936 186428b0 Ilias Tsitsimpis
    parser.add_option("--auth-url",
1937 186428b0 Ilias Tsitsimpis
                      action="store", type="string", dest="auth_url",
1938 186428b0 Ilias Tsitsimpis
                      help="The AUTH URI to use to reach the Synnefo API",
1939 11779b6c Ilias Tsitsimpis
                      default=None)
1940 946da8b6 John Giannelos
    parser.add_option("--plankton-user",
1941 946da8b6 John Giannelos
                      action="store", type="string", dest="plankton_user",
1942 946da8b6 John Giannelos
                      help="Owner of system images",
1943 946da8b6 John Giannelos
                      default=DEFAULT_PLANKTON_USER)
1944 21bbbc9b Vangelis Koukis
    parser.add_option("--token",
1945 21bbbc9b Vangelis Koukis
                      action="store", type="string", dest="token",
1946 38d247df Kostas Papadimitriou
                      help="The token to use for authentication to the API")
1947 00f87624 Vangelis Koukis
    parser.add_option("--nofailfast",
1948 00f87624 Vangelis Koukis
                      action="store_true", dest="nofailfast",
1949 6e168615 Ilias Tsitsimpis
                      help="Do not fail immediately if one of the tests "
1950 00f87624 Vangelis Koukis
                           "fails (EXPERIMENTAL)",
1951 bc14ba88 Vangelis Koukis
                      default=False)
1952 946da8b6 John Giannelos
    parser.add_option("--no-ipv6",
1953 946da8b6 John Giannelos
                      action="store_true", dest="no_ipv6",
1954 946da8b6 John Giannelos
                      help="Disables ipv6 related tests",
1955 946da8b6 John Giannelos
                      default=False)
1956 5a140b23 Vangelis Koukis
    parser.add_option("--action-timeout",
1957 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="action_timeout",
1958 5a140b23 Vangelis Koukis
                      metavar="TIMEOUT",
1959 6e168615 Ilias Tsitsimpis
                      help="Wait SECONDS seconds for a server action to "
1960 5a140b23 Vangelis Koukis
                           "complete, then the test is considered failed",
1961 9e4682b5 John Giannelos
                      default=100)
1962 5a140b23 Vangelis Koukis
    parser.add_option("--build-warning",
1963 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="build_warning",
1964 5a140b23 Vangelis Koukis
                      metavar="TIMEOUT",
1965 6e168615 Ilias Tsitsimpis
                      help="Warn if TIMEOUT seconds have passed and a "
1966 5a140b23 Vangelis Koukis
                           "build operation is still pending",
1967 5a140b23 Vangelis Koukis
                      default=600)
1968 5a140b23 Vangelis Koukis
    parser.add_option("--build-fail",
1969 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="build_fail",
1970 5a140b23 Vangelis Koukis
                      metavar="BUILD_TIMEOUT",
1971 6e168615 Ilias Tsitsimpis
                      help="Fail the test if TIMEOUT seconds have passed "
1972 5a140b23 Vangelis Koukis
                           "and a build operation is still incomplete",
1973 5a140b23 Vangelis Koukis
                      default=900)
1974 5a140b23 Vangelis Koukis
    parser.add_option("--query-interval",
1975 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="query_interval",
1976 5a140b23 Vangelis Koukis
                      metavar="INTERVAL",
1977 6e168615 Ilias Tsitsimpis
                      help="Query server status when requests are pending "
1978 5a140b23 Vangelis Koukis
                           "every INTERVAL seconds",
1979 5a140b23 Vangelis Koukis
                      default=3)
1980 21bbbc9b Vangelis Koukis
    parser.add_option("--fanout",
1981 21bbbc9b Vangelis Koukis
                      action="store", type="int", dest="fanout",
1982 5a140b23 Vangelis Koukis
                      metavar="COUNT",
1983 6e168615 Ilias Tsitsimpis
                      help="Spawn up to COUNT child processes to execute "
1984 6e168615 Ilias Tsitsimpis
                           "in parallel, essentially have up to COUNT "
1985 00f87624 Vangelis Koukis
                           "server build requests outstanding (EXPERIMENTAL)",
1986 5a140b23 Vangelis Koukis
                      default=1)
1987 5a140b23 Vangelis Koukis
    parser.add_option("--force-flavor",
1988 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="force_flavorid",
1989 5a140b23 Vangelis Koukis
                      metavar="FLAVOR ID",
1990 6e168615 Ilias Tsitsimpis
                      help="Force all server creations to use the specified "
1991 6e168615 Ilias Tsitsimpis
                           "FLAVOR ID instead of a randomly chosen one, "
1992 5a140b23 Vangelis Koukis
                           "useful if disk space is scarce",
1993 00f87624 Vangelis Koukis
                      default=None)
1994 7f62a0b5 Vangelis Koukis
    parser.add_option("--image-id",
1995 7f62a0b5 Vangelis Koukis
                      action="store", type="string", dest="force_imageid",
1996 00f87624 Vangelis Koukis
                      metavar="IMAGE ID",
1997 6e168615 Ilias Tsitsimpis
                      help="Test the specified image id, use 'all' to test "
1998 7f62a0b5 Vangelis Koukis
                           "all available images (mandatory argument)",
1999 00f87624 Vangelis Koukis
                      default=None)
2000 5a140b23 Vangelis Koukis
    parser.add_option("--show-stale",
2001 5a140b23 Vangelis Koukis
                      action="store_true", dest="show_stale",
2002 6e168615 Ilias Tsitsimpis
                      help="Show stale servers from previous runs, whose "
2003 21bbbc9b Vangelis Koukis
                           "name starts with `%s'" % SNF_TEST_PREFIX,
2004 5a140b23 Vangelis Koukis
                      default=False)
2005 5a140b23 Vangelis Koukis
    parser.add_option("--delete-stale",
2006 5a140b23 Vangelis Koukis
                      action="store_true", dest="delete_stale",
2007 6e168615 Ilias Tsitsimpis
                      help="Delete stale servers from previous runs, whose "
2008 21bbbc9b Vangelis Koukis
                           "name starts with `%s'" % SNF_TEST_PREFIX,
2009 5a140b23 Vangelis Koukis
                      default=False)
2010 9659e075 John Giannelos
    parser.add_option("--force-personality",
2011 65462ca9 John Giannelos
                      action="store", type="string", dest="personality_path",
2012 8252d64f John Giannelos
                      help="Force a personality file injection.\
2013 8252d64f John Giannelos
                            File path required. ",
2014 9659e075 John Giannelos
                      default=None)
2015 74ec726f John Giannelos
    parser.add_option("--log-folder",
2016 74ec726f John Giannelos
                      action="store", type="string", dest="log_folder",
2017 8252d64f John Giannelos
                      help="Define the absolute path where the output \
2018 8252d64f John Giannelos
                            log is stored. ",
2019 2bcfb712 John Giannelos
                      default="/var/log/burnin/")
2020 2aaa1336 John Giannelos
    parser.add_option("--verbose", "-V",
2021 2aaa1336 John Giannelos
                      action="store_true", dest="verbose",
2022 6e168615 Ilias Tsitsimpis
                      help="Print detailed output about multiple "
2023 8792bb97 Ilias Tsitsimpis
                           "processes spawning",
2024 2aaa1336 John Giannelos
                      default=False)
2025 22efe1fe John Giannelos
    parser.add_option("--set-tests",
2026 22efe1fe John Giannelos
                      action="callback",
2027 746540cd John Giannelos
                      dest="tests",
2028 22efe1fe John Giannelos
                      type="string",
2029 22efe1fe John Giannelos
                      help='Set comma seperated tests for this run. \
2030 22efe1fe John Giannelos
                            Available tests: auth, images, flavors, \
2031 746540cd John Giannelos
                                             servers, server_spawn, \
2032 11779b6c Ilias Tsitsimpis
                                             network_spawn, pithos. \
2033 22efe1fe John Giannelos
                            Default = all',
2034 22efe1fe John Giannelos
                      default='all',
2035 22efe1fe John Giannelos
                      callback=parse_comma)
2036 22efe1fe John Giannelos
2037 5a140b23 Vangelis Koukis
    (opts, args) = parser.parse_args(args)
2038 5a140b23 Vangelis Koukis
2039 8792bb97 Ilias Tsitsimpis
    # -----------------------
2040 5a140b23 Vangelis Koukis
    # Verify arguments
2041 8792bb97 Ilias Tsitsimpis
2042 8792bb97 Ilias Tsitsimpis
    # `delete_stale' implies `show_stale'
2043 5a140b23 Vangelis Koukis
    if opts.delete_stale:
2044 5a140b23 Vangelis Koukis
        opts.show_stale = True
2045 5a140b23 Vangelis Koukis
2046 11779b6c Ilias Tsitsimpis
    # `token' is mandatory
2047 11779b6c Ilias Tsitsimpis
    _mandatory_argument(opts.token, "--token")
2048 186428b0 Ilias Tsitsimpis
    # `auth_url' is mandatory
2049 186428b0 Ilias Tsitsimpis
    _mandatory_argument(opts.auth_url, "--auth-url")
2050 11779b6c Ilias Tsitsimpis
2051 7f62a0b5 Vangelis Koukis
    if not opts.show_stale:
2052 11779b6c Ilias Tsitsimpis
        # `image-id' is mandatory
2053 d9647bf1 Ilias Tsitsimpis
        _mandatory_argument(opts.force_imageid, "--image-id")
2054 7f62a0b5 Vangelis Koukis
        if opts.force_imageid != 'all':
2055 7f62a0b5 Vangelis Koukis
            try:
2056 99d41650 John Giannelos
                opts.force_imageid = str(opts.force_imageid)
2057 7f62a0b5 Vangelis Koukis
            except ValueError:
2058 8792bb97 Ilias Tsitsimpis
                print >>sys.stderr, red + \
2059 6e168615 Ilias Tsitsimpis
                    "Invalid value specified for" + \
2060 6e168615 Ilias Tsitsimpis
                    "--image-id. Use a valid id, or `all'." + \
2061 6e168615 Ilias Tsitsimpis
                    normal
2062 7f62a0b5 Vangelis Koukis
                sys.exit(1)
2063 7f62a0b5 Vangelis Koukis
2064 11779b6c Ilias Tsitsimpis
    return (opts, args)
2065 11779b6c Ilias Tsitsimpis
2066 11779b6c Ilias Tsitsimpis
2067 11779b6c Ilias Tsitsimpis
def _mandatory_argument(Arg, Str):
2068 186428b0 Ilias Tsitsimpis
    if (Arg is None) or (Arg == ""):
2069 8792bb97 Ilias Tsitsimpis
        print >>sys.stderr, red + \
2070 11779b6c Ilias Tsitsimpis
            "The " + Str + " argument is mandatory.\n" + \
2071 6e168615 Ilias Tsitsimpis
            normal
2072 8792bb97 Ilias Tsitsimpis
        sys.exit(1)
2073 8792bb97 Ilias Tsitsimpis
2074 5a140b23 Vangelis Koukis
2075 8792bb97 Ilias Tsitsimpis
# --------------------------------------------------------------------
2076 8792bb97 Ilias Tsitsimpis
# Burnin main function
2077 5a140b23 Vangelis Koukis
def main():
2078 5a140b23 Vangelis Koukis
    """Assemble test cases into a test suite, and run it
2079 5a140b23 Vangelis Koukis

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

2086 5a140b23 Vangelis Koukis
    """
2087 ae139e8a John Giannelos
2088 8792bb97 Ilias Tsitsimpis
    # Parse arguments using `optparse'
2089 5a140b23 Vangelis Koukis
    (opts, args) = parse_arguments(sys.argv[1:])
2090 5a140b23 Vangelis Koukis
2091 8792bb97 Ilias Tsitsimpis
    # Some global variables
2092 186428b0 Ilias Tsitsimpis
    global AUTH_URL, TOKEN, PLANKTON_USER
2093 186428b0 Ilias Tsitsimpis
    global NO_IPV6, VERBOSE, NOFAILFAST
2094 186428b0 Ilias Tsitsimpis
    AUTH_URL = opts.auth_url
2095 21bbbc9b Vangelis Koukis
    TOKEN = opts.token
2096 946da8b6 John Giannelos
    PLANKTON_USER = opts.plankton_user
2097 946da8b6 John Giannelos
    NO_IPV6 = opts.no_ipv6
2098 2aaa1336 John Giannelos
    VERBOSE = opts.verbose
2099 2aaa1336 John Giannelos
    NOFAILFAST = opts.nofailfast
2100 21bbbc9b Vangelis Koukis
2101 8792bb97 Ilias Tsitsimpis
    # If `show_stale', cleanup stale servers
2102 8792bb97 Ilias Tsitsimpis
    # from previous runs and exit
2103 5a140b23 Vangelis Koukis
    if opts.show_stale:
2104 8792bb97 Ilias Tsitsimpis
        # We must clean the servers first
2105 8792bb97 Ilias Tsitsimpis
        cleanup_servers(opts.action_timeout, opts.query_interval,
2106 8792bb97 Ilias Tsitsimpis
                        delete_stale=opts.delete_stale)
2107 8792bb97 Ilias Tsitsimpis
        cleanup_networks(opts.action_timeout, opts.query_interval,
2108 8792bb97 Ilias Tsitsimpis
                         delete_stale=opts.delete_stale)
2109 74ec726f John Giannelos
        return 0
2110 5a140b23 Vangelis Koukis
2111 5a140b23 Vangelis Koukis
    # Initialize a kamaki instance, get flavors, images
2112 186428b0 Ilias Tsitsimpis
    astakos_client = AstakosClient(AUTH_URL, TOKEN)
2113 186428b0 Ilias Tsitsimpis
    # Compute Client
2114 186428b0 Ilias Tsitsimpis
    compute_url = astakos_client.get_service_endpoints('compute')['publicURL']
2115 186428b0 Ilias Tsitsimpis
    compute_client = ComputeClient(compute_url, TOKEN)
2116 186428b0 Ilias Tsitsimpis
    DIMAGES = compute_client.list_images(detail=True)
2117 186428b0 Ilias Tsitsimpis
    DFLAVORS = compute_client.list_flavors(detail=True)
2118 5a140b23 Vangelis Koukis
2119 21bbbc9b Vangelis Koukis
    # FIXME: logging, log, LOG PID, TEST_RUN_ID, arguments
2120 5a140b23 Vangelis Koukis
    # Run them: FIXME: In parallel, FAILEARLY, catchbreak?
2121 5a140b23 Vangelis Koukis
    #unittest.main(verbosity=2, catchbreak=True)
2122 5a140b23 Vangelis Koukis
2123 6e168615 Ilias Tsitsimpis
    # Get a list of images we are going to test
2124 e94a9d8c John Giannelos
    if opts.force_imageid == 'all':
2125 e94a9d8c John Giannelos
        test_images = DIMAGES
2126 e94a9d8c John Giannelos
    else:
2127 e94a9d8c John Giannelos
        test_images = filter(lambda x: x["id"] == opts.force_imageid, DIMAGES)
2128 e94a9d8c John Giannelos
2129 6e168615 Ilias Tsitsimpis
    # Create output (logging) folder
2130 74ec726f John Giannelos
    if not os.path.exists(opts.log_folder):
2131 74ec726f John Giannelos
        os.mkdir(opts.log_folder)
2132 2bcfb712 John Giannelos
    test_folder = os.path.join(opts.log_folder, TEST_RUN_ID)
2133 74ec726f John Giannelos
    os.mkdir(test_folder)
2134 81e8cbf6 John Giannelos
2135 00f87624 Vangelis Koukis
    for image in test_images:
2136 99d41650 John Giannelos
        imageid = str(image["id"])
2137 6e168615 Ilias Tsitsimpis
        imagename = image["name"]
2138 6e168615 Ilias Tsitsimpis
        # Choose a flavor (given from user or random)
2139 81e8cbf6 John Giannelos
        if opts.force_flavorid:
2140 81e8cbf6 John Giannelos
            flavorid = opts.force_flavorid
2141 81e8cbf6 John Giannelos
        else:
2142 81e8cbf6 John Giannelos
            flavorid = choice([f["id"] for f in DFLAVORS if f["disk"] >= 20])
2143 6e168615 Ilias Tsitsimpis
        # Personality dictionary for file injection test
2144 6e168615 Ilias Tsitsimpis
        if opts.personality_path is not None:
2145 9659e075 John Giannelos
            f = open(opts.personality_path)
2146 9659e075 John Giannelos
            content = b64encode(f.read())
2147 9659e075 John Giannelos
            personality = []
2148 9659e075 John Giannelos
            st = os.stat(opts.personality_path)
2149 9659e075 John Giannelos
            personality.append({
2150 6e168615 Ilias Tsitsimpis
                'path': '/root/test_inj_file',
2151 6e168615 Ilias Tsitsimpis
                'owner': 'root',
2152 6e168615 Ilias Tsitsimpis
                'group': 'root',
2153 6e168615 Ilias Tsitsimpis
                'mode': 0x7777 & st.st_mode,
2154 6e168615 Ilias Tsitsimpis
                'contents': content})
2155 9659e075 John Giannelos
        else:
2156 9659e075 John Giannelos
            personality = None
2157 6e168615 Ilias Tsitsimpis
        # Give a name to our test servers
2158 21bbbc9b Vangelis Koukis
        servername = "%s%s for %s" % (SNF_TEST_PREFIX, TEST_RUN_ID, imagename)
2159 21bbbc9b Vangelis Koukis
        is_windows = imagename.lower().find("windows") >= 0
2160 8252d64f John Giannelos
2161 6e168615 Ilias Tsitsimpis
        # Create Server TestCases
2162 8252d64f John Giannelos
        ServerTestCase = _spawn_server_test_case(
2163 8252d64f John Giannelos
            imageid=imageid,
2164 8252d64f John Giannelos
            flavorid=flavorid,
2165 8252d64f John Giannelos
            imagename=imagename,
2166 8252d64f John Giannelos
            personality=personality,
2167 8252d64f John Giannelos
            servername=servername,
2168 8252d64f John Giannelos
            is_windows=is_windows,
2169 8252d64f John Giannelos
            action_timeout=opts.action_timeout,
2170 8252d64f John Giannelos
            build_warning=opts.build_warning,
2171 8252d64f John Giannelos
            build_fail=opts.build_fail,
2172 6e168615 Ilias Tsitsimpis
            query_interval=opts.query_interval)
2173 6e168615 Ilias Tsitsimpis
        # Create Network TestCases
2174 8252d64f John Giannelos
        NetworkTestCase = _spawn_network_test_case(
2175 8252d64f John Giannelos
            action_timeout=opts.action_timeout,
2176 8252d64f John Giannelos
            imageid=imageid,
2177 8252d64f John Giannelos
            flavorid=flavorid,
2178 8252d64f John Giannelos
            imagename=imagename,
2179 6e168615 Ilias Tsitsimpis
            query_interval=opts.query_interval)
2180 95a87099 Ilias Tsitsimpis
        # Create Images TestCase
2181 95a87099 Ilias Tsitsimpis
        CImagesTestCase = _images_test_case(
2182 95a87099 Ilias Tsitsimpis
            action_timeout=opts.action_timeout,
2183 95a87099 Ilias Tsitsimpis
            imageid=imageid,
2184 95a87099 Ilias Tsitsimpis
            flavorid=flavorid,
2185 95a87099 Ilias Tsitsimpis
            imagename=imagename,
2186 95a87099 Ilias Tsitsimpis
            query_interval=opts.query_interval)
2187 8252d64f John Giannelos
2188 6e168615 Ilias Tsitsimpis
        # Choose the tests we are going to run
2189 746540cd John Giannelos
        test_dict = {'auth': UnauthorizedTestCase,
2190 95a87099 Ilias Tsitsimpis
                     'images': CImagesTestCase,
2191 746540cd John Giannelos
                     'flavors': FlavorsTestCase,
2192 746540cd John Giannelos
                     'servers': ServersTestCase,
2193 11779b6c Ilias Tsitsimpis
                     'pithos': PithosTestCase,
2194 746540cd John Giannelos
                     'server_spawn': ServerTestCase,
2195 746540cd John Giannelos
                     'network_spawn': NetworkTestCase}
2196 22efe1fe John Giannelos
        seq_cases = []
2197 22efe1fe John Giannelos
        if 'all' in opts.tests:
2198 4d72f9ab Ilias Tsitsimpis
            seq_cases = [UnauthorizedTestCase, CImagesTestCase,
2199 11779b6c Ilias Tsitsimpis
                         FlavorsTestCase, ServersTestCase,
2200 11779b6c Ilias Tsitsimpis
                         PithosTestCase, ServerTestCase,
2201 11779b6c Ilias Tsitsimpis
                         NetworkTestCase]
2202 22efe1fe John Giannelos
        else:
2203 22efe1fe John Giannelos
            for test in opts.tests:
2204 22efe1fe John Giannelos
                seq_cases.append(test_dict[test])
2205 22efe1fe John Giannelos
2206 6e168615 Ilias Tsitsimpis
        # Folder for each image
2207 2bcfb712 John Giannelos
        image_folder = os.path.join(test_folder, imageid)
2208 81e8cbf6 John Giannelos
        os.mkdir(image_folder)
2209 81e8cbf6 John Giannelos
2210 6e168615 Ilias Tsitsimpis
        # Run each test
2211 6e168615 Ilias Tsitsimpis
        if opts.fanout > 1:
2212 3e4c5c32 John Giannelos
            _run_cases_in_parallel(seq_cases, opts.fanout, image_folder)
2213 3e4c5c32 John Giannelos
        else:
2214 6e168615 Ilias Tsitsimpis
            _run_cases_in_series(seq_cases, image_folder)
2215 6e168615 Ilias Tsitsimpis
2216 746540cd John Giannelos
2217 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
2218 6e168615 Ilias Tsitsimpis
# Call main
2219 5a140b23 Vangelis Koukis
if __name__ == "__main__":
2220 5a140b23 Vangelis Koukis
    sys.exit(main())