Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (80.6 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 186428b0 Ilias Tsitsimpis
248 186428b0 Ilias Tsitsimpis
        # Get images
249 a352f80f Ilias Tsitsimpis
        cls.images = \
250 a352f80f Ilias Tsitsimpis
            filter(lambda x: not x['name'].startswith(SNF_TEST_PREFIX),
251 186428b0 Ilias Tsitsimpis
                   cls.image_client.list_public())
252 a352f80f Ilias Tsitsimpis
        cls.dimages = \
253 a352f80f Ilias Tsitsimpis
            filter(lambda x: not x['name'].startswith(SNF_TEST_PREFIX),
254 186428b0 Ilias Tsitsimpis
                   cls.image_client.list_public(detail=True))
255 66eba2cf John Giannelos
        cls.result_dict = dict()
256 bacb7c87 Ilias Tsitsimpis
        # Get uniq user id
257 bacb7c87 Ilias Tsitsimpis
        cls.uuid = _get_user_id()
258 bacb7c87 Ilias Tsitsimpis
        log.info("Uniq user id = %s" % cls.uuid)
259 95a87099 Ilias Tsitsimpis
        # Create temp directory and store it inside our class
260 95a87099 Ilias Tsitsimpis
        # XXX: In my machine /tmp has not enough space
261 95a87099 Ilias Tsitsimpis
        #      so use current directory to be sure.
262 95a87099 Ilias Tsitsimpis
        cls.temp_dir = tempfile.mkdtemp(dir=os.getcwd())
263 95a87099 Ilias Tsitsimpis
        cls.temp_image_name = \
264 95a87099 Ilias Tsitsimpis
            SNF_TEST_PREFIX + cls.imageid + ".diskdump"
265 5a140b23 Vangelis Koukis
266 4d72f9ab Ilias Tsitsimpis
    @classmethod
267 4d72f9ab Ilias Tsitsimpis
    def tearDownClass(cls):
268 4d72f9ab Ilias Tsitsimpis
        """Remove local files"""
269 4d72f9ab Ilias Tsitsimpis
        try:
270 4d72f9ab Ilias Tsitsimpis
            temp_file = os.path.join(cls.temp_dir, cls.temp_image_name)
271 4d72f9ab Ilias Tsitsimpis
            os.unlink(temp_file)
272 4d72f9ab Ilias Tsitsimpis
        except:
273 4d72f9ab Ilias Tsitsimpis
            pass
274 4d72f9ab Ilias Tsitsimpis
        try:
275 4d72f9ab Ilias Tsitsimpis
            os.rmdir(cls.temp_dir)
276 4d72f9ab Ilias Tsitsimpis
        except:
277 4d72f9ab Ilias Tsitsimpis
            pass
278 4d72f9ab Ilias Tsitsimpis
279 5a140b23 Vangelis Koukis
    def test_001_list_images(self):
280 5a140b23 Vangelis Koukis
        """Test image list actually returns images"""
281 6207533f John Giannelos
        self.assertGreater(len(self.images), 0)
282 74ec726f John Giannelos
283 5a140b23 Vangelis Koukis
    def test_002_list_images_detailed(self):
284 5a140b23 Vangelis Koukis
        """Test detailed image list is the same length as list"""
285 6207533f John Giannelos
        self.assertEqual(len(self.dimages), len(self.images))
286 74ec726f John Giannelos
287 5a140b23 Vangelis Koukis
    def test_003_same_image_names(self):
288 5a140b23 Vangelis Koukis
        """Test detailed and simple image list contain same names"""
289 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.images))
290 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dimages))
291 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
292 5a140b23 Vangelis Koukis
293 186428b0 Ilias Tsitsimpis
# XXX: Find a way to resolve owner's uuid to username.
294 186428b0 Ilias Tsitsimpis
#      (maybe use astakosclient)
295 186428b0 Ilias Tsitsimpis
#    def test_004_unique_image_names(self):
296 186428b0 Ilias Tsitsimpis
#        """Test system images have unique names"""
297 186428b0 Ilias Tsitsimpis
#        sys_images = filter(lambda x: x['owner'] == PLANKTON_USER,
298 186428b0 Ilias Tsitsimpis
#                            self.dimages)
299 186428b0 Ilias Tsitsimpis
#        names = sorted(map(lambda x: x["name"], sys_images))
300 186428b0 Ilias Tsitsimpis
#        self.assertEqual(sorted(list(set(names))), names)
301 5a140b23 Vangelis Koukis
302 5a140b23 Vangelis Koukis
    def test_005_image_metadata(self):
303 5a140b23 Vangelis Koukis
        """Test every image has specific metadata defined"""
304 2e3b7dc8 John Giannelos
        keys = frozenset(["osfamily", "root_partition"])
305 186428b0 Ilias Tsitsimpis
        details = self.compute_client.list_images(detail=True)
306 846980fe John Giannelos
        for i in details:
307 bcb7c357 Ilias Tsitsimpis
            self.assertTrue(keys.issubset(i["metadata"].keys()))
308 5a140b23 Vangelis Koukis
309 95a87099 Ilias Tsitsimpis
    def test_006_download_image(self):
310 95a87099 Ilias Tsitsimpis
        """Download image from pithos+"""
311 95a87099 Ilias Tsitsimpis
        # Get image location
312 95a87099 Ilias Tsitsimpis
        image = filter(
313 95a87099 Ilias Tsitsimpis
            lambda x: x['id'] == self.imageid, self.dimages)[0]
314 95a87099 Ilias Tsitsimpis
        image_location = \
315 95a87099 Ilias Tsitsimpis
            image['location'].replace("://", " ").replace("/", " ").split()
316 95a87099 Ilias Tsitsimpis
        log.info("Download image, with owner %s\n\tcontainer %s, and name %s"
317 95a87099 Ilias Tsitsimpis
                 % (image_location[1], image_location[2], image_location[3]))
318 186428b0 Ilias Tsitsimpis
        self.pithos_client.account = image_location[1]
319 186428b0 Ilias Tsitsimpis
        self.pithos_client.container = image_location[2]
320 95a87099 Ilias Tsitsimpis
        temp_file = os.path.join(self.temp_dir, self.temp_image_name)
321 95a87099 Ilias Tsitsimpis
        with open(temp_file, "wb+") as f:
322 186428b0 Ilias Tsitsimpis
            self.pithos_client.download_object(image_location[3], f)
323 95a87099 Ilias Tsitsimpis
324 95a87099 Ilias Tsitsimpis
    def test_007_upload_image(self):
325 95a87099 Ilias Tsitsimpis
        """Upload and register image"""
326 95a87099 Ilias Tsitsimpis
        temp_file = os.path.join(self.temp_dir, self.temp_image_name)
327 95a87099 Ilias Tsitsimpis
        log.info("Upload image to pithos+")
328 95a87099 Ilias Tsitsimpis
        # Create container `images'
329 186428b0 Ilias Tsitsimpis
        self.pithos_client.account = self.uuid
330 186428b0 Ilias Tsitsimpis
        self.pithos_client.container = "images"
331 186428b0 Ilias Tsitsimpis
        self.pithos_client.container_put()
332 95a87099 Ilias Tsitsimpis
        with open(temp_file, "rb+") as f:
333 186428b0 Ilias Tsitsimpis
            self.pithos_client.upload_object(self.temp_image_name, f)
334 95a87099 Ilias Tsitsimpis
        log.info("Register image to plankton")
335 bacb7c87 Ilias Tsitsimpis
        location = "pithos://" + self.uuid + \
336 95a87099 Ilias Tsitsimpis
            "/images/" + self.temp_image_name
337 95a87099 Ilias Tsitsimpis
        params = {'is_public': True}
338 95a87099 Ilias Tsitsimpis
        properties = {'OSFAMILY': "linux", 'ROOT_PARTITION': 1}
339 186428b0 Ilias Tsitsimpis
        self.image_client.register(
340 186428b0 Ilias Tsitsimpis
            self.temp_image_name, location, params, properties)
341 4d72f9ab Ilias Tsitsimpis
        # Get image id
342 186428b0 Ilias Tsitsimpis
        details = self.image_client.list_public(detail=True)
343 4c9918f9 Ilias Tsitsimpis
        detail = filter(lambda x: x['location'] == location, details)
344 4d72f9ab Ilias Tsitsimpis
        self.assertEqual(len(detail), 1)
345 4d72f9ab Ilias Tsitsimpis
        cls = type(self)
346 4d72f9ab Ilias Tsitsimpis
        cls.temp_image_id = detail[0]['id']
347 4d72f9ab Ilias Tsitsimpis
        log.info("Image registered with id %s" % detail[0]['id'])
348 4d72f9ab Ilias Tsitsimpis
349 4d72f9ab Ilias Tsitsimpis
    def test_008_cleanup_image(self):
350 4d72f9ab Ilias Tsitsimpis
        """Cleanup image test"""
351 4d72f9ab Ilias Tsitsimpis
        log.info("Cleanup image test")
352 4d72f9ab Ilias Tsitsimpis
        # Remove image from pithos+
353 186428b0 Ilias Tsitsimpis
        self.pithos_client.account = self.uuid
354 186428b0 Ilias Tsitsimpis
        self.pithos_client.container = "images"
355 186428b0 Ilias Tsitsimpis
        self.pithos_client.del_object(self.temp_image_name)
356 95a87099 Ilias Tsitsimpis
357 5a140b23 Vangelis Koukis
358 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
359 6e168615 Ilias Tsitsimpis
# FlavorsTestCase class
360 5a140b23 Vangelis Koukis
class FlavorsTestCase(unittest.TestCase):
361 5a140b23 Vangelis Koukis
    """Test flavor lists for consistency"""
362 5a140b23 Vangelis Koukis
    @classmethod
363 5a140b23 Vangelis Koukis
    def setUpClass(cls):
364 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of flavors"""
365 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of flavors")
366 186428b0 Ilias Tsitsimpis
        cls.astakos_client = AstakosClient(AUTH_URL, TOKEN)
367 186428b0 Ilias Tsitsimpis
        # Compute Client
368 186428b0 Ilias Tsitsimpis
        compute_url = \
369 186428b0 Ilias Tsitsimpis
            cls.astakos_client.get_service_endpoints('compute')['publicURL']
370 186428b0 Ilias Tsitsimpis
        cls.compute_client = ComputeClient(compute_url, TOKEN)
371 186428b0 Ilias Tsitsimpis
        cls.flavors = cls.compute_client.list_flavors()
372 186428b0 Ilias Tsitsimpis
        cls.dflavors = cls.compute_client.list_flavors(detail=True)
373 66eba2cf John Giannelos
        cls.result_dict = dict()
374 5a140b23 Vangelis Koukis
375 5a140b23 Vangelis Koukis
    def test_001_list_flavors(self):
376 5a140b23 Vangelis Koukis
        """Test flavor list actually returns flavors"""
377 5a140b23 Vangelis Koukis
        self.assertGreater(len(self.flavors), 0)
378 5a140b23 Vangelis Koukis
379 5a140b23 Vangelis Koukis
    def test_002_list_flavors_detailed(self):
380 5a140b23 Vangelis Koukis
        """Test detailed flavor list is the same length as list"""
381 5a140b23 Vangelis Koukis
        self.assertEquals(len(self.dflavors), len(self.flavors))
382 5a140b23 Vangelis Koukis
383 5a140b23 Vangelis Koukis
    def test_003_same_flavor_names(self):
384 5a140b23 Vangelis Koukis
        """Test detailed and simple flavor list contain same names"""
385 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.flavors))
386 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dflavors))
387 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
388 5a140b23 Vangelis Koukis
389 5a140b23 Vangelis Koukis
    def test_004_unique_flavor_names(self):
390 5a140b23 Vangelis Koukis
        """Test flavors have unique names"""
391 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.flavors))
392 5a140b23 Vangelis Koukis
        self.assertEqual(sorted(list(set(names))), names)
393 5a140b23 Vangelis Koukis
394 5a140b23 Vangelis Koukis
    def test_005_well_formed_flavor_names(self):
395 5a140b23 Vangelis Koukis
        """Test flavors have names of the form CxxRyyDzz
396 5a140b23 Vangelis Koukis
        Where xx is vCPU count, yy is RAM in MiB, zz is Disk in GiB
397 5a140b23 Vangelis Koukis
        """
398 5a140b23 Vangelis Koukis
        for f in self.dflavors:
399 186428b0 Ilias Tsitsimpis
            flavor = (f["vcpus"], f["ram"], f["disk"], f["SNF:disk_template"])
400 95b36b00 Christos Stavrakakis
            self.assertEqual("C%dR%dD%d%s" % flavor,
401 5a140b23 Vangelis Koukis
                             f["name"],
402 5a140b23 Vangelis Koukis
                             "Flavor %s does not match its specs." % f["name"])
403 5a140b23 Vangelis Koukis
404 5a140b23 Vangelis Koukis
405 6e168615 Ilias Tsitsimpis
# --------------------------------------------------------------------
406 6e168615 Ilias Tsitsimpis
# ServersTestCase class
407 5a140b23 Vangelis Koukis
class ServersTestCase(unittest.TestCase):
408 5a140b23 Vangelis Koukis
    """Test server lists for consistency"""
409 5a140b23 Vangelis Koukis
    @classmethod
410 5a140b23 Vangelis Koukis
    def setUpClass(cls):
411 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of servers"""
412 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of servers")
413 1c636ad6 John Giannelos
414 186428b0 Ilias Tsitsimpis
        cls.astakos_client = AstakosClient(AUTH_URL, TOKEN)
415 186428b0 Ilias Tsitsimpis
        # Compute Client
416 186428b0 Ilias Tsitsimpis
        compute_url = \
417 186428b0 Ilias Tsitsimpis
            cls.astakos_client.get_service_endpoints('compute')['publicURL']
418 186428b0 Ilias Tsitsimpis
        cls.compute_client = ComputeClient(compute_url, TOKEN)
419 186428b0 Ilias Tsitsimpis
        cls.servers = cls.compute_client.list_servers()
420 186428b0 Ilias Tsitsimpis
        cls.dservers = cls.compute_client.list_servers(detail=True)
421 66eba2cf John Giannelos
        cls.result_dict = dict()
422 5a140b23 Vangelis Koukis
423 139d3a0b Ilias Tsitsimpis
    # def test_001_list_servers(self):
424 139d3a0b Ilias Tsitsimpis
    #     """Test server list actually returns servers"""
425 139d3a0b Ilias Tsitsimpis
    #     self.assertGreater(len(self.servers), 0)
426 5a140b23 Vangelis Koukis
427 5a140b23 Vangelis Koukis
    def test_002_list_servers_detailed(self):
428 5a140b23 Vangelis Koukis
        """Test detailed server list is the same length as list"""
429 5a140b23 Vangelis Koukis
        self.assertEqual(len(self.dservers), len(self.servers))
430 5a140b23 Vangelis Koukis
431 5a140b23 Vangelis Koukis
    def test_003_same_server_names(self):
432 5a140b23 Vangelis Koukis
        """Test detailed and simple flavor list contain same names"""
433 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.servers))
434 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dservers))
435 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
436 5a140b23 Vangelis Koukis
437 5a140b23 Vangelis Koukis
438 11779b6c Ilias Tsitsimpis
# --------------------------------------------------------------------
439 11779b6c Ilias Tsitsimpis
# Pithos Test Cases
440 11779b6c Ilias Tsitsimpis
class PithosTestCase(unittest.TestCase):
441 11779b6c Ilias Tsitsimpis
    """Test pithos functionality"""
442 11779b6c Ilias Tsitsimpis
    @classmethod
443 11779b6c Ilias Tsitsimpis
    def setUpClass(cls):
444 11779b6c Ilias Tsitsimpis
        """Initialize kamaki, get list of containers"""
445 bacb7c87 Ilias Tsitsimpis
        # Get uniq user id
446 bacb7c87 Ilias Tsitsimpis
        cls.uuid = _get_user_id()
447 bacb7c87 Ilias Tsitsimpis
        log.info("Uniq user id = %s" % cls.uuid)
448 11779b6c Ilias Tsitsimpis
        log.info("Getting list of containers")
449 186428b0 Ilias Tsitsimpis
450 186428b0 Ilias Tsitsimpis
        cls.astakos_client = AstakosClient(AUTH_URL, TOKEN)
451 186428b0 Ilias Tsitsimpis
        # Pithos Client
452 186428b0 Ilias Tsitsimpis
        pithos_url = cls.astakos_client.\
453 186428b0 Ilias Tsitsimpis
            get_service_endpoints('object-store')['publicURL']
454 186428b0 Ilias Tsitsimpis
        cls.pithos_client = PithosClient(pithos_url, TOKEN, cls.uuid)
455 186428b0 Ilias Tsitsimpis
456 186428b0 Ilias Tsitsimpis
        cls.containers = cls.pithos_client.list_containers()
457 11779b6c Ilias Tsitsimpis
        cls.result_dict = dict()
458 11779b6c Ilias Tsitsimpis
459 11779b6c Ilias Tsitsimpis
    def test_001_list_containers(self):
460 11779b6c Ilias Tsitsimpis
        """Test container list actually returns containers"""
461 11779b6c Ilias Tsitsimpis
        self.assertGreater(len(self.containers), 0)
462 11779b6c Ilias Tsitsimpis
463 11779b6c Ilias Tsitsimpis
    def test_002_unique_containers(self):
464 11779b6c Ilias Tsitsimpis
        """Test if containers have unique names"""
465 11779b6c Ilias Tsitsimpis
        names = [n['name'] for n in self.containers]
466 11779b6c Ilias Tsitsimpis
        names = sorted(names)
467 11779b6c Ilias Tsitsimpis
        self.assertEqual(sorted(list(set(names))), names)
468 11779b6c Ilias Tsitsimpis
469 11779b6c Ilias Tsitsimpis
    def test_003_create_container(self):
470 11779b6c Ilias Tsitsimpis
        """Test create a container"""
471 11779b6c Ilias Tsitsimpis
        rand_num = randint(1000, 9999)
472 11779b6c Ilias Tsitsimpis
        rand_name = "%s%s" % (SNF_TEST_PREFIX, rand_num)
473 11779b6c Ilias Tsitsimpis
        names = [n['name'] for n in self.containers]
474 11779b6c Ilias Tsitsimpis
        while rand_name in names:
475 11779b6c Ilias Tsitsimpis
            rand_num = randint(1000, 9999)
476 11779b6c Ilias Tsitsimpis
            rand_name = "%s%s" % (SNF_TEST_PREFIX, rand_num)
477 11779b6c Ilias Tsitsimpis
        # Create container
478 186428b0 Ilias Tsitsimpis
        self.pithos_client.container = rand_name
479 186428b0 Ilias Tsitsimpis
        self.pithos_client.container_put()
480 11779b6c Ilias Tsitsimpis
        # Get list of containers
481 186428b0 Ilias Tsitsimpis
        new_containers = self.pithos_client.list_containers()
482 11779b6c Ilias Tsitsimpis
        new_container_names = [n['name'] for n in new_containers]
483 11779b6c Ilias Tsitsimpis
        self.assertIn(rand_name, new_container_names)
484 11779b6c Ilias Tsitsimpis
485 11779b6c Ilias Tsitsimpis
    def test_004_upload(self):
486 11779b6c Ilias Tsitsimpis
        """Test uploading something to pithos+"""
487 11779b6c Ilias Tsitsimpis
        # Create a tmp file
488 11779b6c Ilias Tsitsimpis
        with tempfile.TemporaryFile() as f:
489 11779b6c Ilias Tsitsimpis
            f.write("This is a temp file")
490 11779b6c Ilias Tsitsimpis
            f.seek(0, 0)
491 11779b6c Ilias Tsitsimpis
            # Where to save file
492 186428b0 Ilias Tsitsimpis
            self.pithos_client.upload_object("test.txt", f)
493 11779b6c Ilias Tsitsimpis
494 11779b6c Ilias Tsitsimpis
    def test_005_download(self):
495 11779b6c Ilias Tsitsimpis
        """Test download something from pithos+"""
496 11779b6c Ilias Tsitsimpis
        # Create tmp directory to save file
497 11779b6c Ilias Tsitsimpis
        tmp_dir = tempfile.mkdtemp()
498 11779b6c Ilias Tsitsimpis
        tmp_file = os.path.join(tmp_dir, "test.txt")
499 11779b6c Ilias Tsitsimpis
        with open(tmp_file, "wb+") as f:
500 186428b0 Ilias Tsitsimpis
            self.pithos_client.download_object("test.txt", f)
501 11779b6c Ilias Tsitsimpis
            # Read file
502 11779b6c Ilias Tsitsimpis
            f.seek(0, 0)
503 11779b6c Ilias Tsitsimpis
            content = f.read()
504 11779b6c Ilias Tsitsimpis
        # Remove files
505 11779b6c Ilias Tsitsimpis
        os.unlink(tmp_file)
506 11779b6c Ilias Tsitsimpis
        os.rmdir(tmp_dir)
507 11779b6c Ilias Tsitsimpis
        # Compare results
508 11779b6c Ilias Tsitsimpis
        self.assertEqual(content, "This is a temp file")
509 11779b6c Ilias Tsitsimpis
510 11779b6c Ilias Tsitsimpis
    def test_006_remove(self):
511 11779b6c Ilias Tsitsimpis
        """Test removing files and containers"""
512 186428b0 Ilias Tsitsimpis
        cont_name = self.pithos_client.container
513 186428b0 Ilias Tsitsimpis
        self.pithos_client.del_object("test.txt")
514 186428b0 Ilias Tsitsimpis
        self.pithos_client.purge_container()
515 11779b6c Ilias Tsitsimpis
        # List containers
516 186428b0 Ilias Tsitsimpis
        containers = self.pithos_client.list_containers()
517 11779b6c Ilias Tsitsimpis
        cont_names = [n['name'] for n in containers]
518 11779b6c Ilias Tsitsimpis
        self.assertNotIn(cont_name, cont_names)
519 11779b6c Ilias Tsitsimpis
520 11779b6c Ilias Tsitsimpis
521 11779b6c Ilias Tsitsimpis
# --------------------------------------------------------------------
522 5a140b23 Vangelis Koukis
# This class gets replicated into actual TestCases dynamically
523 5a140b23 Vangelis Koukis
class SpawnServerTestCase(unittest.TestCase):
524 5a140b23 Vangelis Koukis
    """Test scenario for server of the specified image"""
525 5a140b23 Vangelis Koukis
    @classmethod
526 5a140b23 Vangelis Koukis
    def setUpClass(cls):
527 5a140b23 Vangelis Koukis
        """Initialize a kamaki instance"""
528 6e168615 Ilias Tsitsimpis
        log.info("Spawning server for image `%s'" % cls.imagename)
529 186428b0 Ilias Tsitsimpis
530 186428b0 Ilias Tsitsimpis
        cls.astakos_client = AstakosClient(AUTH_URL, TOKEN)
531 186428b0 Ilias Tsitsimpis
        # Cyclades Client
532 186428b0 Ilias Tsitsimpis
        compute_url = \
533 186428b0 Ilias Tsitsimpis
            cls.astakos_client.get_service_endpoints('compute')['publicURL']
534 186428b0 Ilias Tsitsimpis
        cls.cyclades_client = CycladesClient(compute_url, TOKEN)
535 186428b0 Ilias Tsitsimpis
536 66eba2cf John Giannelos
        cls.result_dict = dict()
537 5a140b23 Vangelis Koukis
538 5a140b23 Vangelis Koukis
    def _get_ipv4(self, server):
539 bc14ba88 Vangelis Koukis
        """Get the public IPv4 of a server from the detailed server info"""
540 1c636ad6 John Giannelos
541 bcb7c357 Ilias Tsitsimpis
        nics = server["attachments"]
542 2aaa1336 John Giannelos
543 e50133da John Giannelos
        for nic in nics:
544 e50133da John Giannelos
            net_id = nic["network_id"]
545 186428b0 Ilias Tsitsimpis
            if self.cyclades_client.get_network_details(net_id)["public"]:
546 e50133da John Giannelos
                public_addrs = nic["ipv4"]
547 6e168615 Ilias Tsitsimpis
548 6e168615 Ilias Tsitsimpis
        self.assertTrue(public_addrs is not None)
549 2aaa1336 John Giannelos
550 e50133da John Giannelos
        return public_addrs
551 5a140b23 Vangelis Koukis
552 5a140b23 Vangelis Koukis
    def _get_ipv6(self, server):
553 bc14ba88 Vangelis Koukis
        """Get the public IPv6 of a server from the detailed server info"""
554 2aaa1336 John Giannelos
555 bcb7c357 Ilias Tsitsimpis
        nics = server["attachments"]
556 2aaa1336 John Giannelos
557 e50133da John Giannelos
        for nic in nics:
558 e50133da John Giannelos
            net_id = nic["network_id"]
559 186428b0 Ilias Tsitsimpis
            if self.cyclades_client.get_network_details(net_id)["public"]:
560 e50133da John Giannelos
                public_addrs = nic["ipv6"]
561 2aaa1336 John Giannelos
562 6e168615 Ilias Tsitsimpis
        self.assertTrue(public_addrs is not None)
563 2aaa1336 John Giannelos
564 6e168615 Ilias Tsitsimpis
        return public_addrs
565 5a140b23 Vangelis Koukis
566 6e168615 Ilias Tsitsimpis
    def _connect_loginname(self, os_value):
567 bc14ba88 Vangelis Koukis
        """Return the login name for connections based on the server OS"""
568 6e168615 Ilias Tsitsimpis
        if os_value in ("Ubuntu", "Kubuntu", "Fedora"):
569 21bbbc9b Vangelis Koukis
            return "user"
570 6e168615 Ilias Tsitsimpis
        elif os_value in ("windows", "windows_alpha1"):
571 21bbbc9b Vangelis Koukis
            return "Administrator"
572 bc14ba88 Vangelis Koukis
        else:
573 21bbbc9b Vangelis Koukis
            return "root"
574 bc14ba88 Vangelis Koukis
575 bc14ba88 Vangelis Koukis
    def _verify_server_status(self, current_status, new_status):
576 bc14ba88 Vangelis Koukis
        """Verify a server has switched to a specified status"""
577 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
578 21bbbc9b Vangelis Koukis
        if server["status"] not in (current_status, new_status):
579 21bbbc9b Vangelis Koukis
            return None  # Do not raise exception, return so the test fails
580 bc14ba88 Vangelis Koukis
        self.assertEquals(server["status"], new_status)
581 bc14ba88 Vangelis Koukis
582 bc14ba88 Vangelis Koukis
    def _get_connected_tcp_socket(self, family, host, port):
583 bc14ba88 Vangelis Koukis
        """Get a connected socket from the specified family to host:port"""
584 bc14ba88 Vangelis Koukis
        sock = None
585 bc14ba88 Vangelis Koukis
        for res in \
586 bc14ba88 Vangelis Koukis
            socket.getaddrinfo(host, port, family, socket.SOCK_STREAM, 0,
587 bc14ba88 Vangelis Koukis
                               socket.AI_PASSIVE):
588 bc14ba88 Vangelis Koukis
            af, socktype, proto, canonname, sa = res
589 bc14ba88 Vangelis Koukis
            try:
590 bc14ba88 Vangelis Koukis
                sock = socket.socket(af, socktype, proto)
591 6e168615 Ilias Tsitsimpis
            except socket.error:
592 bc14ba88 Vangelis Koukis
                sock = None
593 bc14ba88 Vangelis Koukis
                continue
594 bc14ba88 Vangelis Koukis
            try:
595 bc14ba88 Vangelis Koukis
                sock.connect(sa)
596 6e168615 Ilias Tsitsimpis
            except socket.error:
597 bc14ba88 Vangelis Koukis
                sock.close()
598 bc14ba88 Vangelis Koukis
                sock = None
599 bc14ba88 Vangelis Koukis
                continue
600 bc14ba88 Vangelis Koukis
        self.assertIsNotNone(sock)
601 bc14ba88 Vangelis Koukis
        return sock
602 bc14ba88 Vangelis Koukis
603 bc14ba88 Vangelis Koukis
    def _ping_once(self, ipv6, ip):
604 bc14ba88 Vangelis Koukis
        """Test server responds to a single IPv4 or IPv6 ping"""
605 bc14ba88 Vangelis Koukis
        cmd = "ping%s -c 2 -w 3 %s" % ("6" if ipv6 else "", ip)
606 bc14ba88 Vangelis Koukis
        ping = subprocess.Popen(cmd, shell=True,
607 bc14ba88 Vangelis Koukis
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
608 bc14ba88 Vangelis Koukis
        (stdout, stderr) = ping.communicate()
609 bc14ba88 Vangelis Koukis
        ret = ping.wait()
610 bc14ba88 Vangelis Koukis
        self.assertEquals(ret, 0)
611 5a140b23 Vangelis Koukis
612 bc14ba88 Vangelis Koukis
    def _get_hostname_over_ssh(self, hostip, username, password):
613 2a410f76 Ilias Tsitsimpis
        lines, status = _ssh_execute(
614 2a410f76 Ilias Tsitsimpis
            hostip, username, password, "hostname")
615 bc14ba88 Vangelis Koukis
        self.assertEqual(len(lines), 1)
616 4fdd25ab Vangelis Koukis
        return lines[0]
617 bc14ba88 Vangelis Koukis
618 bc14ba88 Vangelis Koukis
    def _try_until_timeout_expires(self, warn_timeout, fail_timeout,
619 bc14ba88 Vangelis Koukis
                                   opmsg, callable, *args, **kwargs):
620 bc14ba88 Vangelis Koukis
        if warn_timeout == fail_timeout:
621 5a140b23 Vangelis Koukis
            warn_timeout = fail_timeout + 1
622 5a140b23 Vangelis Koukis
        warn_tmout = time.time() + warn_timeout
623 5a140b23 Vangelis Koukis
        fail_tmout = time.time() + fail_timeout
624 5a140b23 Vangelis Koukis
        while True:
625 4fdd25ab Vangelis Koukis
            self.assertLess(time.time(), fail_tmout,
626 21bbbc9b Vangelis Koukis
                            "operation `%s' timed out" % opmsg)
627 5a140b23 Vangelis Koukis
            if time.time() > warn_tmout:
628 4fdd25ab Vangelis Koukis
                log.warning("Server %d: `%s' operation `%s' not done yet",
629 4fdd25ab Vangelis Koukis
                            self.serverid, self.servername, opmsg)
630 bc14ba88 Vangelis Koukis
            try:
631 4fdd25ab Vangelis Koukis
                log.info("%s... " % opmsg)
632 bc14ba88 Vangelis Koukis
                return callable(*args, **kwargs)
633 bc14ba88 Vangelis Koukis
            except AssertionError:
634 bc14ba88 Vangelis Koukis
                pass
635 5a140b23 Vangelis Koukis
            time.sleep(self.query_interval)
636 5a140b23 Vangelis Koukis
637 bc14ba88 Vangelis Koukis
    def _insist_on_tcp_connection(self, family, host, port):
638 21bbbc9b Vangelis Koukis
        familystr = {socket.AF_INET: "IPv4", socket.AF_INET6: "IPv6",
639 21bbbc9b Vangelis Koukis
                     socket.AF_UNSPEC: "Unspecified-IPv4/6"}
640 bc14ba88 Vangelis Koukis
        msg = "connect over %s to %s:%s" % \
641 bc14ba88 Vangelis Koukis
              (familystr.get(family, "Unknown"), host, port)
642 bc14ba88 Vangelis Koukis
        sock = self._try_until_timeout_expires(
643 6e168615 Ilias Tsitsimpis
            self.action_timeout, self.action_timeout,
644 6e168615 Ilias Tsitsimpis
            msg, self._get_connected_tcp_socket,
645 6e168615 Ilias Tsitsimpis
            family, host, port)
646 bc14ba88 Vangelis Koukis
        return sock
647 bc14ba88 Vangelis Koukis
648 bc14ba88 Vangelis Koukis
    def _insist_on_status_transition(self, current_status, new_status,
649 6e168615 Ilias Tsitsimpis
                                     fail_timeout, warn_timeout=None):
650 4fdd25ab Vangelis Koukis
        msg = "Server %d: `%s', waiting for %s -> %s" % \
651 4fdd25ab Vangelis Koukis
              (self.serverid, self.servername, current_status, new_status)
652 bc14ba88 Vangelis Koukis
        if warn_timeout is None:
653 bc14ba88 Vangelis Koukis
            warn_timeout = fail_timeout
654 bc14ba88 Vangelis Koukis
        self._try_until_timeout_expires(warn_timeout, fail_timeout,
655 bc14ba88 Vangelis Koukis
                                        msg, self._verify_server_status,
656 bc14ba88 Vangelis Koukis
                                        current_status, new_status)
657 21bbbc9b Vangelis Koukis
        # Ensure the status is actually the expected one
658 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
659 21bbbc9b Vangelis Koukis
        self.assertEquals(server["status"], new_status)
660 bc14ba88 Vangelis Koukis
661 bc14ba88 Vangelis Koukis
    def _insist_on_ssh_hostname(self, hostip, username, password):
662 4fdd25ab Vangelis Koukis
        msg = "SSH to %s, as %s/%s" % (hostip, username, password)
663 bc14ba88 Vangelis Koukis
        hostname = self._try_until_timeout_expires(
664 6e168615 Ilias Tsitsimpis
            self.action_timeout, self.action_timeout,
665 6e168615 Ilias Tsitsimpis
            msg, self._get_hostname_over_ssh,
666 6e168615 Ilias Tsitsimpis
            hostip, username, password)
667 bc14ba88 Vangelis Koukis
668 bc14ba88 Vangelis Koukis
        # The hostname must be of the form 'prefix-id'
669 bc14ba88 Vangelis Koukis
        self.assertTrue(hostname.endswith("-%d\n" % self.serverid))
670 5a140b23 Vangelis Koukis
671 8252d64f John Giannelos
    def _check_file_through_ssh(self, hostip, username, password,
672 8252d64f John Giannelos
                                remotepath, content):
673 8252d64f John Giannelos
        msg = "Trying file injection through SSH to %s, as %s/%s" % \
674 8252d64f John Giannelos
            (hostip, username, password)
675 f97dce4d John Giannelos
        log.info(msg)
676 77054bf5 John Giannelos
        try:
677 77054bf5 John Giannelos
            ssh = paramiko.SSHClient()
678 77054bf5 John Giannelos
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
679 77054bf5 John Giannelos
            ssh.connect(hostip, username=username, password=password)
680 2a410f76 Ilias Tsitsimpis
            ssh.close()
681 4fed2379 Ilias Tsitsimpis
        except socket.error, err:
682 4fed2379 Ilias Tsitsimpis
            raise AssertionError(err)
683 9659e075 John Giannelos
684 2bcfb712 John Giannelos
        transport = paramiko.Transport((hostip, 22))
685 2bcfb712 John Giannelos
        transport.connect(username=username, password=password)
686 2bcfb712 John Giannelos
687 2bcfb712 John Giannelos
        localpath = '/tmp/' + SNF_TEST_PREFIX + 'injection'
688 77054bf5 John Giannelos
        sftp = paramiko.SFTPClient.from_transport(transport)
689 8252d64f John Giannelos
        sftp.get(remotepath, localpath)
690 77054bf5 John Giannelos
        sftp.close()
691 77054bf5 John Giannelos
        transport.close()
692 77054bf5 John Giannelos
693 9659e075 John Giannelos
        f = open(localpath)
694 9659e075 John Giannelos
        remote_content = b64encode(f.read())
695 9659e075 John Giannelos
696 77054bf5 John Giannelos
        # Check if files are the same
697 65462ca9 John Giannelos
        return (remote_content == content)
698 77054bf5 John Giannelos
699 5a140b23 Vangelis Koukis
    def _skipIf(self, condition, msg):
700 5a140b23 Vangelis Koukis
        if condition:
701 5a140b23 Vangelis Koukis
            self.skipTest(msg)
702 5a140b23 Vangelis Koukis
703 5a140b23 Vangelis Koukis
    def test_001_submit_create_server(self):
704 5a140b23 Vangelis Koukis
        """Test submit create server request"""
705 f89d0238 John Giannelos
706 f89d0238 John Giannelos
        log.info("Submit new server request")
707 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.create_server(
708 186428b0 Ilias Tsitsimpis
            self.servername, self.flavorid, self.imageid, self.personality)
709 9659e075 John Giannelos
710 81e8cbf6 John Giannelos
        log.info("Server id: " + str(server["id"]))
711 81e8cbf6 John Giannelos
        log.info("Server password: " + server["adminPass"])
712 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
713 bcc21c50 Christos Stavrakakis
        self.assertEqual(server["flavor"]["id"], self.flavorid)
714 bcc21c50 Christos Stavrakakis
        self.assertEqual(server["image"]["id"], self.imageid)
715 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
716 5a140b23 Vangelis Koukis
717 5a140b23 Vangelis Koukis
        # Update class attributes to reflect data on building server
718 5a140b23 Vangelis Koukis
        cls = type(self)
719 5a140b23 Vangelis Koukis
        cls.serverid = server["id"]
720 bc14ba88 Vangelis Koukis
        cls.username = None
721 5a140b23 Vangelis Koukis
        cls.passwd = server["adminPass"]
722 5a140b23 Vangelis Koukis
723 66eba2cf John Giannelos
        self.result_dict["Server ID"] = str(server["id"])
724 66eba2cf John Giannelos
        self.result_dict["Password"] = str(server["adminPass"])
725 66eba2cf John Giannelos
726 5a140b23 Vangelis Koukis
    def test_002a_server_is_building_in_list(self):
727 5a140b23 Vangelis Koukis
        """Test server is in BUILD state, in server list"""
728 f89d0238 John Giannelos
        log.info("Server in BUILD state in server list")
729 f89d0238 John Giannelos
730 66eba2cf John Giannelos
        self.result_dict.clear()
731 66eba2cf John Giannelos
732 186428b0 Ilias Tsitsimpis
        servers = self.cyclades_client.list_servers(detail=True)
733 5a140b23 Vangelis Koukis
        servers = filter(lambda x: x["name"] == self.servername, servers)
734 2aaa1336 John Giannelos
735 5a140b23 Vangelis Koukis
        server = servers[0]
736 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
737 bcc21c50 Christos Stavrakakis
        self.assertEqual(server["flavor"]["id"], self.flavorid)
738 bcc21c50 Christos Stavrakakis
        self.assertEqual(server["image"]["id"], self.imageid)
739 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
740 5a140b23 Vangelis Koukis
741 5a140b23 Vangelis Koukis
    def test_002b_server_is_building_in_details(self):
742 5a140b23 Vangelis Koukis
        """Test server is in BUILD state, in details"""
743 f89d0238 John Giannelos
744 f89d0238 John Giannelos
        log.info("Server in BUILD state in details")
745 f89d0238 John Giannelos
746 186428b0 Ilias Tsitsimpis
        server = self.cyclades_client.get_server_details(self.serverid)
747 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
748 bcc21c50 Christos Stavrakakis
        self.assertEqual(server["flavor"]["id"], self.flavorid)
749 bcc21c50 Christos Stavrakakis
        self.assertEqual(server["image"]["id"], self.imageid)
750 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
751 5a140b23 Vangelis Koukis
752 5a140b23 Vangelis Koukis
    def test_002c_set_server_metadata(self):
753 f89d0238 John Giannelos
754 f89d0238 John Giannelos
        log.info("Creating server metadata")
755 f89d0238 John Giannelos
756 186428b0 Ilias Tsitsimpis
        image = self.cyclades_client.get_image_details(self.imageid)
757 bcb7c357 Ilias Tsitsimpis
        os_value = image["metadata"]["os"]
758 bcb7c357 Ilias Tsitsimpis
        users = image["metadata"].get("users", None)
759 186428b0 Ilias Tsitsimpis
        self.cyclades_client.update_server_metadata(self.serverid, OS=os_value)
760 746540cd John Giannelos
761 e49bdb7c John Giannelos
        userlist = users.split()
762 81e8cbf6 John Giannelos
763 bc14ba88 Vangelis Koukis
        # Determine the username to use for future connections
764 bc14ba88 Vangelis Koukis
        # to this host
765 bc14ba88 Vangelis Koukis
        cls = type(self)
766 81e8cbf6 John Giannelos
767 81e8cbf6 John Giannelos
        if "root" in userlist:
768 81e8cbf6 John Giannelos
            cls.username = "root"
769 6e168615 Ilias Tsitsimpis
        elif users is None:
770 6e168615 Ilias Tsitsimpis
            cls.username = self._connect_loginname(os_value)
771 81e8cbf6 John Giannelos
        else:
772 81e8cbf6 John Giannelos
            cls.username = choice(userlist)
773 81e8cbf6 John Giannelos
774 bc14ba88 Vangelis Koukis
        self.assertIsNotNone(cls.username)
775 5a140b23 Vangelis Koukis
776 5a140b23 Vangelis Koukis
    def test_002d_verify_server_metadata(self):
777 5a140b23 Vangelis Koukis
        """Test server metadata keys are set based on image metadata"""
778 f89d0238 John Giannelos
779 f89d0238 John Giannelos
        log.info("Verifying image metadata")
780 f89d0238 John Giannelos
781 186428b0 Ilias Tsitsimpis
        servermeta = self.cyclades_client.get_server_metadata(self.serverid)
782 186428b0 Ilias Tsitsimpis
        imagemeta = self.cyclades_client.get_image_metadata(self.imageid)
783 81e8cbf6 John Giannelos
784 99d41650 John Giannelos
        self.assertEqual(servermeta["OS"], imagemeta["os"])
785 5a140b23 Vangelis Koukis
786 5a140b23 Vangelis Koukis
    def test_003_server_becomes_active(self):
787 5a140b23 Vangelis Koukis
        """Test server becomes ACTIVE"""
788 f89d0238 John Giannelos
789 f89d0238 John Giannelos
        log.info("Waiting for server to become ACTIVE")
790 f89d0238 John Giannelos
791 6e168615 Ilias Tsitsimpis
        self._insist_on_status_transition(
792 6e168615 Ilias Tsitsimpis
            "BUILD", "ACTIVE", self.build_fail, self.build_warning)
793 5a140b23 Vangelis Koukis
794 f752215c John Giannelos
    def test_003a_get_server_oob_console(self):
795 f752215c John Giannelos
        """Test getting OOB server console over VNC
796 bc14ba88 Vangelis Koukis

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

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

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

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

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

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