Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (81.8 kB)

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

812 f752215c John Giannelos
        Implementation of RFB protocol follows
813 f752215c John Giannelos
        http://www.realvnc.com/docs/rfbproto.pdf.
814 bc14ba88 Vangelis Koukis

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

1730 21bbbc9b Vangelis Koukis
    The cases iterable specifies the TestCases to be executed in parallel,
1731 21bbbc9b Vangelis Koukis
    by test runners running in distinct processes.
1732 21bbbc9b Vangelis Koukis
    The fanout parameter specifies the number of processes to spawn,
1733 21bbbc9b Vangelis Koukis
    and defaults to 1.
1734 21bbbc9b Vangelis Koukis
    The runner argument specifies the test runner class to use inside each
1735 21bbbc9b Vangelis Koukis
    runner process.
1736 21bbbc9b Vangelis Koukis

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

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

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