Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / tools / burnin.py @ f89d0238

History | View | Annotate | Download (53.7 kB)

1 65462ca9 John Giannelos
#!/usr/bin/env python
2 5a140b23 Vangelis Koukis
3 5a140b23 Vangelis Koukis
# Copyright 2011 GRNET S.A. All rights reserved.
4 5a140b23 Vangelis Koukis
#
5 5a140b23 Vangelis Koukis
# Redistribution and use in source and binary forms, with or
6 5a140b23 Vangelis Koukis
# without modification, are permitted provided that the following
7 5a140b23 Vangelis Koukis
# conditions are met:
8 5a140b23 Vangelis Koukis
#
9 5a140b23 Vangelis Koukis
#   1. Redistributions of source code must retain the above
10 5a140b23 Vangelis Koukis
#      copyright notice, this list of conditions and the following
11 5a140b23 Vangelis Koukis
#      disclaimer.
12 5a140b23 Vangelis Koukis
#
13 5a140b23 Vangelis Koukis
#   2. Redistributions in binary form must reproduce the above
14 5a140b23 Vangelis Koukis
#      copyright notice, this list of conditions and the following
15 5a140b23 Vangelis Koukis
#      disclaimer in the documentation and/or other materials
16 5a140b23 Vangelis Koukis
#      provided with the distribution.
17 5a140b23 Vangelis Koukis
#
18 5a140b23 Vangelis Koukis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 5a140b23 Vangelis Koukis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 5a140b23 Vangelis Koukis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 5a140b23 Vangelis Koukis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 5a140b23 Vangelis Koukis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 5a140b23 Vangelis Koukis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 5a140b23 Vangelis Koukis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 5a140b23 Vangelis Koukis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 5a140b23 Vangelis Koukis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 5a140b23 Vangelis Koukis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 5a140b23 Vangelis Koukis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 5a140b23 Vangelis Koukis
# POSSIBILITY OF SUCH DAMAGE.
30 5a140b23 Vangelis Koukis
#
31 5a140b23 Vangelis Koukis
# The views and conclusions contained in the software and
32 5a140b23 Vangelis Koukis
# documentation are those of the authors and should not be
33 5a140b23 Vangelis Koukis
# interpreted as representing official policies, either expressed
34 5a140b23 Vangelis Koukis
# or implied, of GRNET S.A.
35 5a140b23 Vangelis Koukis
36 5a140b23 Vangelis Koukis
"""Perform integration testing on a running Synnefo deployment"""
37 5a140b23 Vangelis Koukis
38 21bbbc9b Vangelis Koukis
import __main__
39 5a140b23 Vangelis Koukis
import datetime
40 5a140b23 Vangelis Koukis
import inspect
41 5a140b23 Vangelis Koukis
import logging
42 5a140b23 Vangelis Koukis
import os
43 5a140b23 Vangelis Koukis
import paramiko
44 21bbbc9b Vangelis Koukis
import prctl
45 5a140b23 Vangelis Koukis
import subprocess
46 21bbbc9b Vangelis Koukis
import signal
47 5a140b23 Vangelis Koukis
import socket
48 bc14ba88 Vangelis Koukis
import struct
49 5a140b23 Vangelis Koukis
import sys
50 5a140b23 Vangelis Koukis
import time
51 77054bf5 John Giannelos
import hashlib
52 9659e075 John Giannelos
from base64 import b64encode
53 9659e075 John Giannelos
from pwd import getpwuid
54 9659e075 John Giannelos
from grp import getgrgid
55 5a140b23 Vangelis Koukis
from IPy import IP
56 21bbbc9b Vangelis Koukis
from multiprocessing import Process, Queue
57 bc14ba88 Vangelis Koukis
from random import choice
58 21bbbc9b Vangelis Koukis
59 96da37c8 John Giannelos
from kamaki.clients.compute import ComputeClient
60 96da37c8 John Giannelos
from kamaki.clients.cyclades import CycladesClient
61 96da37c8 John Giannelos
62 88736f65 John Giannelos
from fabric.api import *
63 1c636ad6 John Giannelos
64 bc14ba88 Vangelis Koukis
from vncauthproxy.d3des import generate_response as d3des_generate_response
65 5a140b23 Vangelis Koukis
66 5a140b23 Vangelis Koukis
# Use backported unittest functionality if Python < 2.7
67 5a140b23 Vangelis Koukis
try:
68 5a140b23 Vangelis Koukis
    import unittest2 as unittest
69 5a140b23 Vangelis Koukis
except ImportError:
70 bc14ba88 Vangelis Koukis
    if sys.version_info < (2, 7):
71 bc14ba88 Vangelis Koukis
        raise Exception("The unittest2 package is required for Python < 2.7")
72 5a140b23 Vangelis Koukis
    import unittest
73 5a140b23 Vangelis Koukis
74 5a140b23 Vangelis Koukis
75 21bbbc9b Vangelis Koukis
API = None
76 21bbbc9b Vangelis Koukis
TOKEN = None
77 567ffb85 John Giannelos
DEFAULT_API = "https://cyclades.okeanos.grnet.gr/api/v1.1"
78 38d247df Kostas Papadimitriou
79 5a140b23 Vangelis Koukis
# A unique id identifying this test run
80 21bbbc9b Vangelis Koukis
TEST_RUN_ID = datetime.datetime.strftime(datetime.datetime.now(),
81 21bbbc9b Vangelis Koukis
                                         "%Y%m%d%H%M%S")
82 21bbbc9b Vangelis Koukis
SNF_TEST_PREFIX = "snf-test-"
83 5a140b23 Vangelis Koukis
84 5a140b23 Vangelis Koukis
# Setup logging (FIXME - verigak)
85 5a140b23 Vangelis Koukis
logging.basicConfig(format="%(message)s")
86 00f87624 Vangelis Koukis
log = logging.getLogger("burnin")
87 5a140b23 Vangelis Koukis
log.setLevel(logging.INFO)
88 5a140b23 Vangelis Koukis
89 5a140b23 Vangelis Koukis
class UnauthorizedTestCase(unittest.TestCase):
90 5a140b23 Vangelis Koukis
    def test_unauthorized_access(self):
91 5a140b23 Vangelis Koukis
        """Test access without a valid token fails"""
92 1c636ad6 John Giannelos
        falseToken = '12345'
93 567ffb85 John Giannelos
        c=ComputeClient(API, falseToken)
94 1c636ad6 John Giannelos
95 5a140b23 Vangelis Koukis
        with self.assertRaises(ClientError) as cm:
96 5a140b23 Vangelis Koukis
            c.list_servers()
97 5a140b23 Vangelis Koukis
        self.assertEqual(cm.exception.status, 401)
98 5a140b23 Vangelis Koukis
99 5a140b23 Vangelis Koukis
100 5a140b23 Vangelis Koukis
class ImagesTestCase(unittest.TestCase):
101 5a140b23 Vangelis Koukis
    """Test image lists for consistency"""
102 5a140b23 Vangelis Koukis
    @classmethod
103 5a140b23 Vangelis Koukis
    def setUpClass(cls):
104 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of images"""
105 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of images")
106 1c636ad6 John Giannelos
107 567ffb85 John Giannelos
        cls.client = ComputeClient(API, TOKEN)
108 5a140b23 Vangelis Koukis
        cls.images = cls.client.list_images()
109 5a140b23 Vangelis Koukis
        cls.dimages = cls.client.list_images(detail=True)
110 5a140b23 Vangelis Koukis
111 5a140b23 Vangelis Koukis
    def test_001_list_images(self):
112 5a140b23 Vangelis Koukis
        """Test image list actually returns images"""
113 6207533f John Giannelos
        self.assertGreater(len(self.images), 0)
114 4d6e355c John Giannelos
        self.assertEqual(len(self.images), -1)
115 5a140b23 Vangelis Koukis
116 5a140b23 Vangelis Koukis
    def test_002_list_images_detailed(self):
117 5a140b23 Vangelis Koukis
        """Test detailed image list is the same length as list"""
118 6207533f John Giannelos
        self.assertEqual(len(self.dimages), len(self.images))
119 4d6e355c John Giannelos
        self.assertEqual(len(self.dimages), 0)
120 5a140b23 Vangelis Koukis
121 5a140b23 Vangelis Koukis
    def test_003_same_image_names(self):
122 5a140b23 Vangelis Koukis
        """Test detailed and simple image list contain same names"""
123 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.images))
124 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dimages))
125 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
126 5a140b23 Vangelis Koukis
127 5a140b23 Vangelis Koukis
    def test_004_unique_image_names(self):
128 5a140b23 Vangelis Koukis
        """Test images have unique names"""
129 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.images))
130 5a140b23 Vangelis Koukis
        self.assertEqual(sorted(list(set(names))), names)
131 5a140b23 Vangelis Koukis
132 5a140b23 Vangelis Koukis
    def test_005_image_metadata(self):
133 5a140b23 Vangelis Koukis
        """Test every image has specific metadata defined"""
134 1c636ad6 John Giannelos
        keys = frozenset(["os", "description", "size"])
135 5a140b23 Vangelis Koukis
        for i in self.dimages:
136 5a140b23 Vangelis Koukis
            self.assertTrue(keys.issubset(i["metadata"]["values"].keys()))
137 5a140b23 Vangelis Koukis
138 5a140b23 Vangelis Koukis
139 5a140b23 Vangelis Koukis
class FlavorsTestCase(unittest.TestCase):
140 5a140b23 Vangelis Koukis
    """Test flavor lists for consistency"""
141 5a140b23 Vangelis Koukis
    @classmethod
142 5a140b23 Vangelis Koukis
    def setUpClass(cls):
143 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of flavors"""
144 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of flavors")
145 1c636ad6 John Giannelos
146 567ffb85 John Giannelos
        cls.client = ComputeClient(API, TOKEN)
147 5a140b23 Vangelis Koukis
        cls.flavors = cls.client.list_flavors()
148 5a140b23 Vangelis Koukis
        cls.dflavors = cls.client.list_flavors(detail=True)
149 5a140b23 Vangelis Koukis
150 5a140b23 Vangelis Koukis
    def test_001_list_flavors(self):
151 5a140b23 Vangelis Koukis
        """Test flavor list actually returns flavors"""
152 5a140b23 Vangelis Koukis
        self.assertGreater(len(self.flavors), 0)
153 5a140b23 Vangelis Koukis
154 5a140b23 Vangelis Koukis
    def test_002_list_flavors_detailed(self):
155 5a140b23 Vangelis Koukis
        """Test detailed flavor list is the same length as list"""
156 5a140b23 Vangelis Koukis
        self.assertEquals(len(self.dflavors), len(self.flavors))
157 5a140b23 Vangelis Koukis
158 5a140b23 Vangelis Koukis
    def test_003_same_flavor_names(self):
159 5a140b23 Vangelis Koukis
        """Test detailed and simple flavor list contain same names"""
160 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.flavors))
161 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dflavors))
162 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
163 5a140b23 Vangelis Koukis
164 5a140b23 Vangelis Koukis
    def test_004_unique_flavor_names(self):
165 5a140b23 Vangelis Koukis
        """Test flavors have unique names"""
166 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.flavors))
167 5a140b23 Vangelis Koukis
        self.assertEqual(sorted(list(set(names))), names)
168 5a140b23 Vangelis Koukis
169 5a140b23 Vangelis Koukis
    def test_005_well_formed_flavor_names(self):
170 5a140b23 Vangelis Koukis
        """Test flavors have names of the form CxxRyyDzz
171 5a140b23 Vangelis Koukis

172 5a140b23 Vangelis Koukis
        Where xx is vCPU count, yy is RAM in MiB, zz is Disk in GiB
173 5a140b23 Vangelis Koukis

174 5a140b23 Vangelis Koukis
        """
175 5a140b23 Vangelis Koukis
        for f in self.dflavors:
176 5a140b23 Vangelis Koukis
            self.assertEqual("C%dR%dD%d" % (f["cpu"], f["ram"], f["disk"]),
177 5a140b23 Vangelis Koukis
                             f["name"],
178 5a140b23 Vangelis Koukis
                             "Flavor %s does not match its specs." % f["name"])
179 5a140b23 Vangelis Koukis
180 5a140b23 Vangelis Koukis
181 5a140b23 Vangelis Koukis
class ServersTestCase(unittest.TestCase):
182 5a140b23 Vangelis Koukis
    """Test server lists for consistency"""
183 5a140b23 Vangelis Koukis
    @classmethod
184 5a140b23 Vangelis Koukis
    def setUpClass(cls):
185 5a140b23 Vangelis Koukis
        """Initialize kamaki, get (detailed) list of servers"""
186 5a140b23 Vangelis Koukis
        log.info("Getting simple and detailed list of servers")
187 1c636ad6 John Giannelos
188 567ffb85 John Giannelos
        cls.client = ComputeClient(API, TOKEN)
189 5a140b23 Vangelis Koukis
        cls.servers = cls.client.list_servers()
190 5a140b23 Vangelis Koukis
        cls.dservers = cls.client.list_servers(detail=True)
191 5a140b23 Vangelis Koukis
192 5a140b23 Vangelis Koukis
    def test_001_list_servers(self):
193 5a140b23 Vangelis Koukis
        """Test server list actually returns servers"""
194 5a140b23 Vangelis Koukis
        self.assertGreater(len(self.servers), 0)
195 5a140b23 Vangelis Koukis
196 5a140b23 Vangelis Koukis
    def test_002_list_servers_detailed(self):
197 5a140b23 Vangelis Koukis
        """Test detailed server list is the same length as list"""
198 5a140b23 Vangelis Koukis
        self.assertEqual(len(self.dservers), len(self.servers))
199 5a140b23 Vangelis Koukis
200 5a140b23 Vangelis Koukis
    def test_003_same_server_names(self):
201 5a140b23 Vangelis Koukis
        """Test detailed and simple flavor list contain same names"""
202 5a140b23 Vangelis Koukis
        names = sorted(map(lambda x: x["name"], self.servers))
203 5a140b23 Vangelis Koukis
        dnames = sorted(map(lambda x: x["name"], self.dservers))
204 5a140b23 Vangelis Koukis
        self.assertEqual(names, dnames)
205 5a140b23 Vangelis Koukis
206 5a140b23 Vangelis Koukis
207 5a140b23 Vangelis Koukis
# This class gets replicated into actual TestCases dynamically
208 5a140b23 Vangelis Koukis
class SpawnServerTestCase(unittest.TestCase):
209 5a140b23 Vangelis Koukis
    """Test scenario for server of the specified image"""
210 5a140b23 Vangelis Koukis
211 5a140b23 Vangelis Koukis
    @classmethod
212 5a140b23 Vangelis Koukis
    def setUpClass(cls):
213 5a140b23 Vangelis Koukis
        """Initialize a kamaki instance"""
214 bc14ba88 Vangelis Koukis
        log.info("Spawning server for image `%s'", cls.imagename)
215 1c636ad6 John Giannelos
216 567ffb85 John Giannelos
        cls.client = ComputeClient(API, TOKEN)
217 567ffb85 John Giannelos
        cls.cyclades = CycladesClient(API, TOKEN)
218 5a140b23 Vangelis Koukis
219 5a140b23 Vangelis Koukis
    def _get_ipv4(self, server):
220 bc14ba88 Vangelis Koukis
        """Get the public IPv4 of a server from the detailed server info"""
221 1c636ad6 John Giannelos
222 5a140b23 Vangelis Koukis
        public_addrs = filter(lambda x: x["id"] == "public",
223 5a140b23 Vangelis Koukis
                              server["addresses"]["values"])
224 5a140b23 Vangelis Koukis
        self.assertEqual(len(public_addrs), 1)
225 5a140b23 Vangelis Koukis
        ipv4_addrs = filter(lambda x: x["version"] == 4,
226 5a140b23 Vangelis Koukis
                            public_addrs[0]["values"])
227 5a140b23 Vangelis Koukis
        self.assertEqual(len(ipv4_addrs), 1)
228 5a140b23 Vangelis Koukis
        return ipv4_addrs[0]["addr"]
229 5a140b23 Vangelis Koukis
230 5a140b23 Vangelis Koukis
    def _get_ipv6(self, server):
231 bc14ba88 Vangelis Koukis
        """Get the public IPv6 of a server from the detailed server info"""
232 5a140b23 Vangelis Koukis
        public_addrs = filter(lambda x: x["id"] == "public",
233 5a140b23 Vangelis Koukis
                              server["addresses"]["values"])
234 5a140b23 Vangelis Koukis
        self.assertEqual(len(public_addrs), 1)
235 5a140b23 Vangelis Koukis
        ipv6_addrs = filter(lambda x: x["version"] == 6,
236 5a140b23 Vangelis Koukis
                            public_addrs[0]["values"])
237 5a140b23 Vangelis Koukis
        self.assertEqual(len(ipv6_addrs), 1)
238 5a140b23 Vangelis Koukis
        return ipv6_addrs[0]["addr"]
239 5a140b23 Vangelis Koukis
240 bc14ba88 Vangelis Koukis
    def _connect_loginname(self, os):
241 bc14ba88 Vangelis Koukis
        """Return the login name for connections based on the server OS"""
242 1c636ad6 John Giannelos
        if os in ("Ubuntu", "Kubuntu", "Fedora"):
243 21bbbc9b Vangelis Koukis
            return "user"
244 1c636ad6 John Giannelos
        elif os in ("windows", "windows_alpha1"):
245 21bbbc9b Vangelis Koukis
            return "Administrator"
246 bc14ba88 Vangelis Koukis
        else:
247 21bbbc9b Vangelis Koukis
            return "root"
248 bc14ba88 Vangelis Koukis
249 bc14ba88 Vangelis Koukis
    def _verify_server_status(self, current_status, new_status):
250 bc14ba88 Vangelis Koukis
        """Verify a server has switched to a specified status"""
251 bc14ba88 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
252 21bbbc9b Vangelis Koukis
        if server["status"] not in (current_status, new_status):
253 21bbbc9b Vangelis Koukis
            return None  # Do not raise exception, return so the test fails
254 bc14ba88 Vangelis Koukis
        self.assertEquals(server["status"], new_status)
255 bc14ba88 Vangelis Koukis
256 bc14ba88 Vangelis Koukis
    def _get_connected_tcp_socket(self, family, host, port):
257 bc14ba88 Vangelis Koukis
        """Get a connected socket from the specified family to host:port"""
258 bc14ba88 Vangelis Koukis
        sock = None
259 bc14ba88 Vangelis Koukis
        for res in \
260 bc14ba88 Vangelis Koukis
            socket.getaddrinfo(host, port, family, socket.SOCK_STREAM, 0,
261 bc14ba88 Vangelis Koukis
                               socket.AI_PASSIVE):
262 bc14ba88 Vangelis Koukis
            af, socktype, proto, canonname, sa = res
263 bc14ba88 Vangelis Koukis
            try:
264 bc14ba88 Vangelis Koukis
                sock = socket.socket(af, socktype, proto)
265 bc14ba88 Vangelis Koukis
            except socket.error as msg:
266 bc14ba88 Vangelis Koukis
                sock = None
267 bc14ba88 Vangelis Koukis
                continue
268 bc14ba88 Vangelis Koukis
            try:
269 bc14ba88 Vangelis Koukis
                sock.connect(sa)
270 bc14ba88 Vangelis Koukis
            except socket.error as msg:
271 bc14ba88 Vangelis Koukis
                sock.close()
272 bc14ba88 Vangelis Koukis
                sock = None
273 bc14ba88 Vangelis Koukis
                continue
274 bc14ba88 Vangelis Koukis
        self.assertIsNotNone(sock)
275 bc14ba88 Vangelis Koukis
        return sock
276 bc14ba88 Vangelis Koukis
277 bc14ba88 Vangelis Koukis
    def _ping_once(self, ipv6, ip):
278 bc14ba88 Vangelis Koukis
        """Test server responds to a single IPv4 or IPv6 ping"""
279 bc14ba88 Vangelis Koukis
        cmd = "ping%s -c 2 -w 3 %s" % ("6" if ipv6 else "", ip)
280 bc14ba88 Vangelis Koukis
        ping = subprocess.Popen(cmd, shell=True,
281 bc14ba88 Vangelis Koukis
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
282 bc14ba88 Vangelis Koukis
        (stdout, stderr) = ping.communicate()
283 bc14ba88 Vangelis Koukis
        ret = ping.wait()
284 bc14ba88 Vangelis Koukis
        self.assertEquals(ret, 0)
285 5a140b23 Vangelis Koukis
286 bc14ba88 Vangelis Koukis
    def _get_hostname_over_ssh(self, hostip, username, password):
287 bc14ba88 Vangelis Koukis
        ssh = paramiko.SSHClient()
288 bc14ba88 Vangelis Koukis
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
289 bc14ba88 Vangelis Koukis
        try:
290 bc14ba88 Vangelis Koukis
            ssh.connect(hostip, username=username, password=password)
291 bc14ba88 Vangelis Koukis
        except socket.error:
292 bc14ba88 Vangelis Koukis
            raise AssertionError
293 bc14ba88 Vangelis Koukis
        stdin, stdout, stderr = ssh.exec_command("hostname")
294 bc14ba88 Vangelis Koukis
        lines = stdout.readlines()
295 bc14ba88 Vangelis Koukis
        self.assertEqual(len(lines), 1)
296 4fdd25ab Vangelis Koukis
        return lines[0]
297 bc14ba88 Vangelis Koukis
298 bc14ba88 Vangelis Koukis
    def _try_until_timeout_expires(self, warn_timeout, fail_timeout,
299 bc14ba88 Vangelis Koukis
                                   opmsg, callable, *args, **kwargs):
300 bc14ba88 Vangelis Koukis
        if warn_timeout == fail_timeout:
301 5a140b23 Vangelis Koukis
            warn_timeout = fail_timeout + 1
302 5a140b23 Vangelis Koukis
        warn_tmout = time.time() + warn_timeout
303 5a140b23 Vangelis Koukis
        fail_tmout = time.time() + fail_timeout
304 5a140b23 Vangelis Koukis
        while True:
305 4fdd25ab Vangelis Koukis
            self.assertLess(time.time(), fail_tmout,
306 21bbbc9b Vangelis Koukis
                            "operation `%s' timed out" % opmsg)
307 5a140b23 Vangelis Koukis
            if time.time() > warn_tmout:
308 4fdd25ab Vangelis Koukis
                log.warning("Server %d: `%s' operation `%s' not done yet",
309 4fdd25ab Vangelis Koukis
                            self.serverid, self.servername, opmsg)
310 bc14ba88 Vangelis Koukis
            try:
311 4fdd25ab Vangelis Koukis
                log.info("%s... " % opmsg)
312 bc14ba88 Vangelis Koukis
                return callable(*args, **kwargs)
313 bc14ba88 Vangelis Koukis
            except AssertionError:
314 bc14ba88 Vangelis Koukis
                pass
315 5a140b23 Vangelis Koukis
            time.sleep(self.query_interval)
316 5a140b23 Vangelis Koukis
317 bc14ba88 Vangelis Koukis
    def _insist_on_tcp_connection(self, family, host, port):
318 21bbbc9b Vangelis Koukis
        familystr = {socket.AF_INET: "IPv4", socket.AF_INET6: "IPv6",
319 21bbbc9b Vangelis Koukis
                     socket.AF_UNSPEC: "Unspecified-IPv4/6"}
320 bc14ba88 Vangelis Koukis
        msg = "connect over %s to %s:%s" % \
321 bc14ba88 Vangelis Koukis
              (familystr.get(family, "Unknown"), host, port)
322 bc14ba88 Vangelis Koukis
        sock = self._try_until_timeout_expires(
323 bc14ba88 Vangelis Koukis
                self.action_timeout, self.action_timeout,
324 bc14ba88 Vangelis Koukis
                msg, self._get_connected_tcp_socket,
325 bc14ba88 Vangelis Koukis
                family, host, port)
326 bc14ba88 Vangelis Koukis
        return sock
327 bc14ba88 Vangelis Koukis
328 bc14ba88 Vangelis Koukis
    def _insist_on_status_transition(self, current_status, new_status,
329 bc14ba88 Vangelis Koukis
                                    fail_timeout, warn_timeout=None):
330 4fdd25ab Vangelis Koukis
        msg = "Server %d: `%s', waiting for %s -> %s" % \
331 4fdd25ab Vangelis Koukis
              (self.serverid, self.servername, current_status, new_status)
332 bc14ba88 Vangelis Koukis
        if warn_timeout is None:
333 bc14ba88 Vangelis Koukis
            warn_timeout = fail_timeout
334 bc14ba88 Vangelis Koukis
        self._try_until_timeout_expires(warn_timeout, fail_timeout,
335 bc14ba88 Vangelis Koukis
                                        msg, self._verify_server_status,
336 bc14ba88 Vangelis Koukis
                                        current_status, new_status)
337 21bbbc9b Vangelis Koukis
        # Ensure the status is actually the expected one
338 21bbbc9b Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
339 21bbbc9b Vangelis Koukis
        self.assertEquals(server["status"], new_status)
340 bc14ba88 Vangelis Koukis
341 bc14ba88 Vangelis Koukis
    def _insist_on_ssh_hostname(self, hostip, username, password):
342 4fdd25ab Vangelis Koukis
        msg = "SSH to %s, as %s/%s" % (hostip, username, password)
343 bc14ba88 Vangelis Koukis
        hostname = self._try_until_timeout_expires(
344 bc14ba88 Vangelis Koukis
                self.action_timeout, self.action_timeout,
345 bc14ba88 Vangelis Koukis
                msg, self._get_hostname_over_ssh,
346 bc14ba88 Vangelis Koukis
                hostip, username, password)
347 bc14ba88 Vangelis Koukis
348 bc14ba88 Vangelis Koukis
        # The hostname must be of the form 'prefix-id'
349 bc14ba88 Vangelis Koukis
        self.assertTrue(hostname.endswith("-%d\n" % self.serverid))
350 5a140b23 Vangelis Koukis
351 9659e075 John Giannelos
    def _check_file_through_ssh(self, hostip, username, password, remotepath, content):
352 9659e075 John Giannelos
        msg = "Trying file injection through SSH to %s, as %s/%s" % (hostip, username, password)
353 f97dce4d John Giannelos
        log.info(msg)
354 77054bf5 John Giannelos
        try:
355 77054bf5 John Giannelos
            ssh = paramiko.SSHClient()
356 77054bf5 John Giannelos
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
357 77054bf5 John Giannelos
            ssh.connect(hostip, username=username, password=password)
358 77054bf5 John Giannelos
        except socket.error:
359 77054bf5 John Giannelos
            raise AssertionError
360 77054bf5 John Giannelos
        
361 9659e075 John Giannelos
        transport = paramiko.Transport((hostip,22))
362 77054bf5 John Giannelos
        transport.connect(username = username, password = password)
363 9659e075 John Giannelos
364 77054bf5 John Giannelos
        localpath = '/tmp/'+SNF_TEST_PREFIX+'injection'
365 77054bf5 John Giannelos
        sftp = paramiko.SFTPClient.from_transport(transport)
366 77054bf5 John Giannelos
        sftp.get(remotepath, localpath)
367 77054bf5 John Giannelos
        
368 77054bf5 John Giannelos
        sftp.close()
369 77054bf5 John Giannelos
        transport.close()
370 77054bf5 John Giannelos
371 9659e075 John Giannelos
        f = open(localpath)
372 9659e075 John Giannelos
        remote_content = b64encode(f.read())
373 9659e075 John Giannelos
374 77054bf5 John Giannelos
        # Check if files are the same
375 65462ca9 John Giannelos
        return (remote_content == content)
376 77054bf5 John Giannelos
377 5a140b23 Vangelis Koukis
    def _skipIf(self, condition, msg):
378 5a140b23 Vangelis Koukis
        if condition:
379 5a140b23 Vangelis Koukis
            self.skipTest(msg)
380 5a140b23 Vangelis Koukis
381 5a140b23 Vangelis Koukis
    def test_001_submit_create_server(self):
382 5a140b23 Vangelis Koukis
        """Test submit create server request"""
383 f89d0238 John Giannelos
384 f89d0238 John Giannelos
        log.info("Submit new server request")
385 5a140b23 Vangelis Koukis
        server = self.client.create_server(self.servername, self.flavorid,
386 5a140b23 Vangelis Koukis
                                           self.imageid, self.personality)
387 9659e075 John Giannelos
388 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
389 5a140b23 Vangelis Koukis
        self.assertEqual(server["flavorRef"], self.flavorid)
390 5a140b23 Vangelis Koukis
        self.assertEqual(server["imageRef"], self.imageid)
391 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
392 5a140b23 Vangelis Koukis
393 5a140b23 Vangelis Koukis
        # Update class attributes to reflect data on building server
394 5a140b23 Vangelis Koukis
        cls = type(self)
395 5a140b23 Vangelis Koukis
        cls.serverid = server["id"]
396 bc14ba88 Vangelis Koukis
        cls.username = None
397 5a140b23 Vangelis Koukis
        cls.passwd = server["adminPass"]
398 5a140b23 Vangelis Koukis
399 5a140b23 Vangelis Koukis
    def test_002a_server_is_building_in_list(self):
400 5a140b23 Vangelis Koukis
        """Test server is in BUILD state, in server list"""
401 f89d0238 John Giannelos
        
402 f89d0238 John Giannelos
        log.info("Server in BUILD state in server list")
403 f89d0238 John Giannelos
404 5a140b23 Vangelis Koukis
        servers = self.client.list_servers(detail=True)
405 5a140b23 Vangelis Koukis
        servers = filter(lambda x: x["name"] == self.servername, servers)
406 5a140b23 Vangelis Koukis
        self.assertEqual(len(servers), 1)
407 5a140b23 Vangelis Koukis
        server = servers[0]
408 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
409 5a140b23 Vangelis Koukis
        self.assertEqual(server["flavorRef"], self.flavorid)
410 5a140b23 Vangelis Koukis
        self.assertEqual(server["imageRef"], self.imageid)
411 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
412 5a140b23 Vangelis Koukis
413 5a140b23 Vangelis Koukis
    def test_002b_server_is_building_in_details(self):
414 5a140b23 Vangelis Koukis
        """Test server is in BUILD state, in details"""
415 f89d0238 John Giannelos
416 f89d0238 John Giannelos
        log.info("Server in BUILD state in details")
417 f89d0238 John Giannelos
418 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
419 5a140b23 Vangelis Koukis
        self.assertEqual(server["name"], self.servername)
420 5a140b23 Vangelis Koukis
        self.assertEqual(server["flavorRef"], self.flavorid)
421 5a140b23 Vangelis Koukis
        self.assertEqual(server["imageRef"], self.imageid)
422 5a140b23 Vangelis Koukis
        self.assertEqual(server["status"], "BUILD")
423 5a140b23 Vangelis Koukis
424 5a140b23 Vangelis Koukis
    def test_002c_set_server_metadata(self):
425 f89d0238 John Giannelos
426 f89d0238 John Giannelos
        log.info("Creating server metadata")
427 f89d0238 John Giannelos
428 5a140b23 Vangelis Koukis
        image = self.client.get_image_details(self.imageid)
429 74193008 John Giannelos
        os = image["metadata"]["values"]["os"]
430 74193008 John Giannelos
        loginname = image["metadata"]["values"].get("users", None)
431 c1d11f96 John Giannelos
        self.client.update_server_metadata(self.serverid, OS=os)
432 bc14ba88 Vangelis Koukis
433 bc14ba88 Vangelis Koukis
        # Determine the username to use for future connections
434 bc14ba88 Vangelis Koukis
        # to this host
435 bc14ba88 Vangelis Koukis
        cls = type(self)
436 bc14ba88 Vangelis Koukis
        cls.username = loginname
437 bc14ba88 Vangelis Koukis
        if not cls.username:
438 bc14ba88 Vangelis Koukis
            cls.username = self._connect_loginname(os)
439 bc14ba88 Vangelis Koukis
        self.assertIsNotNone(cls.username)
440 5a140b23 Vangelis Koukis
441 5a140b23 Vangelis Koukis
    def test_002d_verify_server_metadata(self):
442 5a140b23 Vangelis Koukis
        """Test server metadata keys are set based on image metadata"""
443 f89d0238 John Giannelos
444 f89d0238 John Giannelos
        log.info("Verifying image metadata")
445 f89d0238 John Giannelos
446 5a140b23 Vangelis Koukis
        servermeta = self.client.get_server_metadata(self.serverid)
447 5a140b23 Vangelis Koukis
        imagemeta = self.client.get_image_metadata(self.imageid)
448 99d41650 John Giannelos
        self.assertEqual(servermeta["OS"], imagemeta["os"])
449 5a140b23 Vangelis Koukis
450 5a140b23 Vangelis Koukis
    def test_003_server_becomes_active(self):
451 5a140b23 Vangelis Koukis
        """Test server becomes ACTIVE"""
452 f89d0238 John Giannelos
453 f89d0238 John Giannelos
        log.info("Waiting for server to become ACTIVE")
454 f89d0238 John Giannelos
455 bc14ba88 Vangelis Koukis
        self._insist_on_status_transition("BUILD", "ACTIVE",
456 5a140b23 Vangelis Koukis
                                         self.build_fail, self.build_warning)
457 5a140b23 Vangelis Koukis
458 65462ca9 John Giannelos
    def test_003a_get_server_oob_console(self):
459 65462ca9 John Giannelos
        """Test getting OOB server console over VNC
460 bc14ba88 Vangelis Koukis

461 65462ca9 John Giannelos
        Implementation of RFB protocol follows
462 65462ca9 John Giannelos
        http://www.realvnc.com/docs/rfbproto.pdf.
463 bc14ba88 Vangelis Koukis

464 65462ca9 John Giannelos
        """
465 9659e075 John Giannelos
        
466 65462ca9 John Giannelos
        console = self.cyclades.get_server_console(self.serverid)
467 65462ca9 John Giannelos
        self.assertEquals(console['type'], "vnc")
468 65462ca9 John Giannelos
        sock = self._insist_on_tcp_connection(socket.AF_UNSPEC,
469 65462ca9 John Giannelos
                                        console["host"], console["port"])
470 65462ca9 John Giannelos
471 65462ca9 John Giannelos
        # Step 1. ProtocolVersion message (par. 6.1.1)
472 65462ca9 John Giannelos
        version = sock.recv(1024)
473 65462ca9 John Giannelos
        self.assertEquals(version, 'RFB 003.008\n')
474 65462ca9 John Giannelos
        sock.send(version)
475 65462ca9 John Giannelos
476 65462ca9 John Giannelos
        # Step 2. Security (par 6.1.2): Only VNC Authentication supported
477 65462ca9 John Giannelos
        sec = sock.recv(1024)
478 65462ca9 John Giannelos
        self.assertEquals(list(sec), ['\x01', '\x02'])
479 65462ca9 John Giannelos
480 65462ca9 John Giannelos
        # Step 3. Request VNC Authentication (par 6.1.2)
481 65462ca9 John Giannelos
        sock.send('\x02')
482 65462ca9 John Giannelos
483 65462ca9 John Giannelos
        # Step 4. Receive Challenge (par 6.2.2)
484 65462ca9 John Giannelos
        challenge = sock.recv(1024)
485 65462ca9 John Giannelos
        self.assertEquals(len(challenge), 16)
486 65462ca9 John Giannelos
487 65462ca9 John Giannelos
        # Step 5. DES-Encrypt challenge, use password as key (par 6.2.2)
488 65462ca9 John Giannelos
        response = d3des_generate_response(
489 65462ca9 John Giannelos
            (console["password"] + '\0' * 8)[:8], challenge)
490 65462ca9 John Giannelos
        sock.send(response)
491 65462ca9 John Giannelos
492 65462ca9 John Giannelos
        # Step 6. SecurityResult (par 6.1.3)
493 65462ca9 John Giannelos
        result = sock.recv(4)
494 65462ca9 John Giannelos
        self.assertEquals(list(result), ['\x00', '\x00', '\x00', '\x00'])
495 65462ca9 John Giannelos
        sock.close()
496 74193008 John Giannelos
        
497 5a140b23 Vangelis Koukis
    def test_004_server_has_ipv4(self):
498 5a140b23 Vangelis Koukis
        """Test active server has a valid IPv4 address"""
499 f89d0238 John Giannelos
500 f89d0238 John Giannelos
        log.info("Testing server's IPv4")
501 f89d0238 John Giannelos
502 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
503 5a140b23 Vangelis Koukis
        ipv4 = self._get_ipv4(server)
504 5a140b23 Vangelis Koukis
        self.assertEquals(IP(ipv4).version(), 4)
505 5a140b23 Vangelis Koukis
506 65462ca9 John Giannelos
    def test_005_server_has_ipv6(self):
507 65462ca9 John Giannelos
        """Test active server has a valid IPv6 address"""
508 f89d0238 John Giannelos
509 f89d0238 John Giannelos
        log.info("Testing server's IPv6")
510 f89d0238 John Giannelos
511 65462ca9 John Giannelos
        server = self.client.get_server_details(self.serverid)
512 65462ca9 John Giannelos
        ipv6 = self._get_ipv6(server)
513 65462ca9 John Giannelos
        self.assertEquals(IP(ipv6).version(), 6)
514 5a140b23 Vangelis Koukis
515 5a140b23 Vangelis Koukis
    def test_006_server_responds_to_ping_IPv4(self):
516 5a140b23 Vangelis Koukis
        """Test server responds to ping on IPv4 address"""
517 f89d0238 John Giannelos
518 f89d0238 John Giannelos
        log.info("Testing if server responds to pings in IPv4")
519 f89d0238 John Giannelos
520 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
521 bc14ba88 Vangelis Koukis
        ip = self._get_ipv4(server)
522 bc14ba88 Vangelis Koukis
        self._try_until_timeout_expires(self.action_timeout,
523 bc14ba88 Vangelis Koukis
                                        self.action_timeout,
524 4fdd25ab Vangelis Koukis
                                        "PING IPv4 to %s" % ip,
525 4fdd25ab Vangelis Koukis
                                        self._ping_once,
526 bc14ba88 Vangelis Koukis
                                        False, ip)
527 5a140b23 Vangelis Koukis
528 65462ca9 John Giannelos
    def test_007_server_responds_to_ping_IPv6(self):
529 65462ca9 John Giannelos
        """Test server responds to ping on IPv6 address"""
530 f89d0238 John Giannelos
531 f89d0238 John Giannelos
        log.info("Testing if server responds to pings in IPv6")
532 f89d0238 John Giannelos
533 65462ca9 John Giannelos
        server = self.client.get_server_details(self.serverid)
534 65462ca9 John Giannelos
        ip = self._get_ipv6(server)
535 65462ca9 John Giannelos
        self._try_until_timeout_expires(self.action_timeout,
536 65462ca9 John Giannelos
                                        self.action_timeout,
537 65462ca9 John Giannelos
                                        "PING IPv6 to %s" % ip,
538 65462ca9 John Giannelos
                                        self._ping_once,
539 65462ca9 John Giannelos
                                        True, ip)
540 5a140b23 Vangelis Koukis
541 5a140b23 Vangelis Koukis
    def test_008_submit_shutdown_request(self):
542 5a140b23 Vangelis Koukis
        """Test submit request to shutdown server"""
543 f89d0238 John Giannelos
544 f89d0238 John Giannelos
        log.info("Shutting down server")
545 f89d0238 John Giannelos
546 74193008 John Giannelos
        self.cyclades.shutdown_server(self.serverid)
547 5a140b23 Vangelis Koukis
548 5a140b23 Vangelis Koukis
    def test_009_server_becomes_stopped(self):
549 5a140b23 Vangelis Koukis
        """Test server becomes STOPPED"""
550 f89d0238 John Giannelos
551 f89d0238 John Giannelos
        log.info("Waiting until server becomes STOPPED")
552 f89d0238 John Giannelos
        
553 bc14ba88 Vangelis Koukis
        self._insist_on_status_transition("ACTIVE", "STOPPED",
554 bc14ba88 Vangelis Koukis
                                         self.action_timeout,
555 5a140b23 Vangelis Koukis
                                         self.action_timeout)
556 5a140b23 Vangelis Koukis
557 5a140b23 Vangelis Koukis
    def test_010_submit_start_request(self):
558 5a140b23 Vangelis Koukis
        """Test submit start server request"""
559 f89d0238 John Giannelos
560 f89d0238 John Giannelos
        log.info("Starting server")
561 f89d0238 John Giannelos
562 74193008 John Giannelos
        self.cyclades.start_server(self.serverid)
563 5a140b23 Vangelis Koukis
564 5a140b23 Vangelis Koukis
    def test_011_server_becomes_active(self):
565 5a140b23 Vangelis Koukis
        """Test server becomes ACTIVE again"""
566 f89d0238 John Giannelos
567 f89d0238 John Giannelos
        log.info("Waiting until server becomes ACTIVE")
568 f89d0238 John Giannelos
        
569 bc14ba88 Vangelis Koukis
        self._insist_on_status_transition("STOPPED", "ACTIVE",
570 bc14ba88 Vangelis Koukis
                                         self.action_timeout,
571 5a140b23 Vangelis Koukis
                                         self.action_timeout)
572 5a140b23 Vangelis Koukis
573 5a140b23 Vangelis Koukis
    def test_011a_server_responds_to_ping_IPv4(self):
574 5a140b23 Vangelis Koukis
        """Test server OS is actually up and running again"""
575 f89d0238 John Giannelos
576 f89d0238 John Giannelos
        log.info("Testing if server is actually up and running")
577 f89d0238 John Giannelos
578 5a140b23 Vangelis Koukis
        self.test_006_server_responds_to_ping_IPv4()
579 5a140b23 Vangelis Koukis
580 5a140b23 Vangelis Koukis
    def test_012_ssh_to_server_IPv4(self):
581 5a140b23 Vangelis Koukis
        """Test SSH to server public IPv4 works, verify hostname"""
582 f89d0238 John Giannelos
583 bc14ba88 Vangelis Koukis
        self._skipIf(self.is_windows, "only valid for Linux servers")
584 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
585 bc14ba88 Vangelis Koukis
        self._insist_on_ssh_hostname(self._get_ipv4(server),
586 bc14ba88 Vangelis Koukis
                                     self.username, self.passwd)
587 5a140b23 Vangelis Koukis
588 65462ca9 John Giannelos
    def test_013_ssh_to_server_IPv6(self):
589 65462ca9 John Giannelos
        """Test SSH to server public IPv6 works, verify hostname"""
590 65462ca9 John Giannelos
        self._skipIf(self.is_windows, "only valid for Linux servers")
591 65462ca9 John Giannelos
        server = self.client.get_server_details(self.serverid)
592 65462ca9 John Giannelos
        self._insist_on_ssh_hostname(self._get_ipv6(server),
593 65462ca9 John Giannelos
                                     self.username, self.passwd)
594 5a140b23 Vangelis Koukis
595 5a140b23 Vangelis Koukis
    def test_014_rdp_to_server_IPv4(self):
596 5a140b23 Vangelis Koukis
        "Test RDP connection to server public IPv4 works"""
597 bc14ba88 Vangelis Koukis
        self._skipIf(not self.is_windows, "only valid for Windows servers")
598 5a140b23 Vangelis Koukis
        server = self.client.get_server_details(self.serverid)
599 5a140b23 Vangelis Koukis
        ipv4 = self._get_ipv4(server)
600 bc14ba88 Vangelis Koukis
        sock = _insist_on_tcp_connection(socket.AF_INET, ipv4, 3389)
601 5a140b23 Vangelis Koukis
602 5a140b23 Vangelis Koukis
        # No actual RDP processing done. We assume the RDP server is there
603 5a140b23 Vangelis Koukis
        # if the connection to the RDP port is successful.
604 cb1fa17c Vangelis Koukis
        # FIXME: Use rdesktop, analyze exit code? see manpage [costasd]
605 5a140b23 Vangelis Koukis
        sock.close()
606 5a140b23 Vangelis Koukis
607 65462ca9 John Giannelos
    def test_015_rdp_to_server_IPv6(self):
608 65462ca9 John Giannelos
        "Test RDP connection to server public IPv6 works"""
609 65462ca9 John Giannelos
        self._skipIf(not self.is_windows, "only valid for Windows servers")
610 65462ca9 John Giannelos
        server = self.client.get_server_details(self.serverid)
611 65462ca9 John Giannelos
        ipv6 = self._get_ipv6(server)
612 65462ca9 John Giannelos
        sock = _get_tcp_connection(socket.AF_INET6, ipv6, 3389)
613 5a140b23 Vangelis Koukis
614 65462ca9 John Giannelos
        # No actual RDP processing done. We assume the RDP server is there
615 65462ca9 John Giannelos
        # if the connection to the RDP port is successful.
616 65462ca9 John Giannelos
        sock.close()
617 5a140b23 Vangelis Koukis
618 5a140b23 Vangelis Koukis
    def test_016_personality_is_enforced(self):
619 5a140b23 Vangelis Koukis
        """Test file injection for personality enforcement"""
620 f89d0238 John Giannelos
621 f89d0238 John Giannelos
        log.info("Trying to inject file for personality enforcement")
622 f89d0238 John Giannelos
623 bc14ba88 Vangelis Koukis
        self._skipIf(self.is_windows, "only implemented for Linux servers")
624 9659e075 John Giannelos
        self._skipIf(self.personality == None, "No personality file selected")
625 77054bf5 John Giannelos
626 77054bf5 John Giannelos
        server = self.client.get_server_details(self.serverid)
627 77054bf5 John Giannelos
628 9659e075 John Giannelos
        for inj_file in self.personality:
629 9659e075 John Giannelos
            equal_files = self._check_file_through_ssh(self._get_ipv4(server), inj_file['owner'], 
630 9659e075 John Giannelos
                                                       self.passwd, inj_file['path'], inj_file['contents'])
631 9659e075 John Giannelos
            self.assertTrue(equal_files)
632 77054bf5 John Giannelos
        
633 5a140b23 Vangelis Koukis
634 4fdd25ab Vangelis Koukis
    def test_017_submit_delete_request(self):
635 4fdd25ab Vangelis Koukis
        """Test submit request to delete server"""
636 f89d0238 John Giannelos
637 f89d0238 John Giannelos
        log.info("Deleting server")
638 f89d0238 John Giannelos
639 4fdd25ab Vangelis Koukis
        self.client.delete_server(self.serverid)
640 4fdd25ab Vangelis Koukis
641 4fdd25ab Vangelis Koukis
    def test_018_server_becomes_deleted(self):
642 4fdd25ab Vangelis Koukis
        """Test server becomes DELETED"""
643 f89d0238 John Giannelos
644 f89d0238 John Giannelos
        log.info("Testing if server becomes DELETED")
645 f89d0238 John Giannelos
646 4fdd25ab Vangelis Koukis
        self._insist_on_status_transition("ACTIVE", "DELETED",
647 4fdd25ab Vangelis Koukis
                                         self.action_timeout,
648 4fdd25ab Vangelis Koukis
                                         self.action_timeout)
649 4fdd25ab Vangelis Koukis
650 4fdd25ab Vangelis Koukis
    def test_019_server_no_longer_in_server_list(self):
651 4fdd25ab Vangelis Koukis
        """Test server is no longer in server list"""
652 f89d0238 John Giannelos
653 f89d0238 John Giannelos
        log.info("Test if server is no longer listed")
654 f89d0238 John Giannelos
655 4fdd25ab Vangelis Koukis
        servers = self.client.list_servers()
656 21bbbc9b Vangelis Koukis
        self.assertNotIn(self.serverid, [s["id"] for s in servers])
657 21bbbc9b Vangelis Koukis
658 21bbbc9b Vangelis Koukis
659 9e4682b5 John Giannelos
class NetworkTestCase(unittest.TestCase):
660 e94a9d8c John Giannelos
    """ Testing networking in cyclades """
661 65462ca9 John Giannelos
  
662 9e4682b5 John Giannelos
    @classmethod
663 e94a9d8c John Giannelos
    def setUpClass(cls):
664 e94a9d8c John Giannelos
        "Initialize kamaki, get list of current networks"
665 567ffb85 John Giannelos
666 567ffb85 John Giannelos
        cls.client = CycladesClient(API, TOKEN)
667 567ffb85 John Giannelos
        cls.compute = ComputeClient(API, TOKEN)
668 9e4682b5 John Giannelos
669 ae139e8a John Giannelos
        cls.servername = "%s%s for %s" % (SNF_TEST_PREFIX, TEST_RUN_ID, cls.imagename)
670 91de9b55 John Giannelos
671 91de9b55 John Giannelos
        #Dictionary initialization for the vms credentials
672 91de9b55 John Giannelos
        cls.serverid = dict()
673 91de9b55 John Giannelos
        cls.username = dict()
674 91de9b55 John Giannelos
        cls.password = dict()
675 91de9b55 John Giannelos
676 1b40b5e3 John Giannelos
    def _get_ipv4(self, server):
677 1b40b5e3 John Giannelos
        """Get the public IPv4 of a server from the detailed server info"""
678 1b40b5e3 John Giannelos
679 1b40b5e3 John Giannelos
        public_addrs = filter(lambda x: x["id"] == "public",
680 1b40b5e3 John Giannelos
                              server["addresses"]["values"])
681 1b40b5e3 John Giannelos
        self.assertEqual(len(public_addrs), 1)
682 1b40b5e3 John Giannelos
        ipv4_addrs = filter(lambda x: x["version"] == 4,
683 1b40b5e3 John Giannelos
                            public_addrs[0]["values"])
684 1b40b5e3 John Giannelos
        self.assertEqual(len(ipv4_addrs), 1)
685 1b40b5e3 John Giannelos
        return ipv4_addrs[0]["addr"]
686 740a5649 John Giannelos
    
687 1b40b5e3 John Giannelos
688 1b40b5e3 John Giannelos
    def _connect_loginname(self, os):
689 1b40b5e3 John Giannelos
        """Return the login name for connections based on the server OS"""
690 1b40b5e3 John Giannelos
        if os in ("Ubuntu", "Kubuntu", "Fedora"):
691 1b40b5e3 John Giannelos
            return "user"
692 1b40b5e3 John Giannelos
        elif os in ("windows", "windows_alpha1"):
693 1b40b5e3 John Giannelos
            return "Administrator"
694 1b40b5e3 John Giannelos
        else:
695 1b40b5e3 John Giannelos
            return "root"
696 1b40b5e3 John Giannelos
697 88736f65 John Giannelos
    def _ping_once(self, ip):
698 88736f65 John Giannelos
    
699 88736f65 John Giannelos
        """Test server responds to a single IPv4 or IPv6 ping"""
700 88736f65 John Giannelos
        cmd = "ping -c 2 -w 3 %s" % (ip)
701 88736f65 John Giannelos
        ping = subprocess.Popen(cmd, shell=True,
702 88736f65 John Giannelos
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
703 88736f65 John Giannelos
        (stdout, stderr) = ping.communicate()
704 88736f65 John Giannelos
        ret = ping.wait()
705 88736f65 John Giannelos
        
706 88736f65 John Giannelos
        return (ret == 0)
707 88736f65 John Giannelos
708 1b40b5e3 John Giannelos
709 740a5649 John Giannelos
    def test_00001a_submit_create_server_A(self):
710 91de9b55 John Giannelos
        """Test submit create server request"""
711 f89d0238 John Giannelos
712 f89d0238 John Giannelos
        log.info("Creating test server A")
713 f89d0238 John Giannelos
714 91de9b55 John Giannelos
        serverA = self.client.create_server(self.servername, self.flavorid,
715 ae139e8a John Giannelos
                                            self.imageid, personality=None)
716 91de9b55 John Giannelos
717 c54e3d4c John Giannelos
        self.assertEqual(serverA["name"], self.servername)
718 c54e3d4c John Giannelos
        self.assertEqual(serverA["flavorRef"], self.flavorid)
719 c54e3d4c John Giannelos
        self.assertEqual(serverA["imageRef"], self.imageid)
720 c54e3d4c John Giannelos
        self.assertEqual(serverA["status"], "BUILD")
721 91de9b55 John Giannelos
722 91de9b55 John Giannelos
        # Update class attributes to reflect data on building server
723 08748d73 John Giannelos
        self.serverid['A'] = serverA["id"]
724 08748d73 John Giannelos
        self.username['A'] = None
725 08748d73 John Giannelos
        self.password['A'] = serverA["adminPass"]
726 91de9b55 John Giannelos
727 ae139e8a John Giannelos
        log.info("Created new server A:")
728 ae139e8a John Giannelos
        log.info("Password " + (self.password['A']) + '\n')
729 ae139e8a John Giannelos
        
730 ae139e8a John Giannelos
731 65462ca9 John Giannelos
732 740a5649 John Giannelos
    def test_00001b_serverA_becomes_active(self):
733 91de9b55 John Giannelos
        """Test server becomes ACTIVE"""
734 f89d0238 John Giannelos
        
735 f89d0238 John Giannelos
        log.info("Waiting until test server A becomes ACTIVE")
736 91de9b55 John Giannelos
737 91de9b55 John Giannelos
        fail_tmout = time.time()+self.action_timeout
738 91de9b55 John Giannelos
        while True:
739 91de9b55 John Giannelos
            d = self.client.get_server_details(self.serverid['A'])
740 91de9b55 John Giannelos
            status = d['status']
741 91de9b55 John Giannelos
            if status == 'ACTIVE':
742 91de9b55 John Giannelos
                active = True
743 91de9b55 John Giannelos
                break
744 91de9b55 John Giannelos
            elif time.time() > fail_tmout:
745 91de9b55 John Giannelos
                self.assertLess(time.time(), fail_tmout)
746 91de9b55 John Giannelos
            else:
747 91de9b55 John Giannelos
                time.sleep(self.query_interval)
748 91de9b55 John Giannelos
749 91de9b55 John Giannelos
        self.assertTrue(active)
750 91de9b55 John Giannelos
751 fade8dab John Giannelos
    
752 740a5649 John Giannelos
    def test_00002a_submit_create_server_B(self):
753 fade8dab John Giannelos
        """Test submit create server request"""
754 ae139e8a John Giannelos
        
755 f89d0238 John Giannelos
        log.info("Creating test server B")
756 f89d0238 John Giannelos
757 fade8dab John Giannelos
        serverB = self.client.create_server(self.servername, self.flavorid,
758 ae139e8a John Giannelos
                                            self.imageid, personality=None)
759 ae139e8a John Giannelos
760 fade8dab John Giannelos
761 fade8dab John Giannelos
        self.assertEqual(serverB["name"], self.servername)
762 fade8dab John Giannelos
        self.assertEqual(serverB["flavorRef"], self.flavorid)
763 fade8dab John Giannelos
        self.assertEqual(serverB["imageRef"], self.imageid)
764 fade8dab John Giannelos
        self.assertEqual(serverB["status"], "BUILD")
765 fade8dab John Giannelos
766 fade8dab John Giannelos
        # Update class attributes to reflect data on building server
767 fade8dab John Giannelos
        self.serverid['B'] = serverB["id"]
768 fade8dab John Giannelos
        self.username['B'] = None
769 fade8dab John Giannelos
        self.password['B'] = serverB["adminPass"]
770 fade8dab John Giannelos
771 ae139e8a John Giannelos
        log.info("Created new server B:")
772 ae139e8a John Giannelos
        log.info("Password " + (self.password['B']) + '\n')
773 ae139e8a John Giannelos
774 ae139e8a John Giannelos
775 fade8dab John Giannelos
776 740a5649 John Giannelos
    def test_00002b_serverB_becomes_active(self):
777 91de9b55 John Giannelos
        """Test server becomes ACTIVE"""
778 91de9b55 John Giannelos
779 f89d0238 John Giannelos
        log.info("Waiting until test server B becomes ACTIVE")
780 f89d0238 John Giannelos
781 91de9b55 John Giannelos
        fail_tmout = time.time()+self.action_timeout
782 91de9b55 John Giannelos
        while True:
783 91de9b55 John Giannelos
            d = self.client.get_server_details(self.serverid['B'])
784 91de9b55 John Giannelos
            status = d['status']
785 91de9b55 John Giannelos
            if status == 'ACTIVE':
786 91de9b55 John Giannelos
                active = True
787 91de9b55 John Giannelos
                break
788 91de9b55 John Giannelos
            elif time.time() > fail_tmout:
789 91de9b55 John Giannelos
                self.assertLess(time.time(), fail_tmout)
790 91de9b55 John Giannelos
            else:
791 91de9b55 John Giannelos
                time.sleep(self.query_interval)
792 91de9b55 John Giannelos
793 91de9b55 John Giannelos
        self.assertTrue(active)
794 567ffb85 John Giannelos
795 e94a9d8c John Giannelos
796 9e4682b5 John Giannelos
    def test_001_create_network(self):
797 e94a9d8c John Giannelos
        """Test submit create network request"""
798 f89d0238 John Giannelos
799 f89d0238 John Giannelos
        log.info("Submit new network request")
800 f89d0238 John Giannelos
801 e94a9d8c John Giannelos
        name = SNF_TEST_PREFIX+TEST_RUN_ID
802 9e4682b5 John Giannelos
        previous_num = len(self.client.list_networks())
803 f97dce4d John Giannelos
        network =  self.client.create_network(name)        
804 f97dce4d John Giannelos
       
805 9e4682b5 John Giannelos
        #Test if right name is assigned
806 e94a9d8c John Giannelos
        self.assertEqual(network['name'], name)
807 e94a9d8c John Giannelos
        
808 9e4682b5 John Giannelos
        # Update class attributes
809 e94a9d8c John Giannelos
        cls = type(self)
810 e94a9d8c John Giannelos
        cls.networkid = network['id']
811 9e4682b5 John Giannelos
        networks = self.client.list_networks()
812 9e4682b5 John Giannelos
813 9e4682b5 John Giannelos
        #Test if new network is created
814 9e4682b5 John Giannelos
        self.assertTrue(len(networks) > previous_num)
815 9e4682b5 John Giannelos
        
816 e94a9d8c John Giannelos
    
817 9e4682b5 John Giannelos
    def test_002_connect_to_network(self):
818 4573ea07 John Giannelos
        """Test connect VMs to network"""
819 9e4682b5 John Giannelos
820 f89d0238 John Giannelos
        log.info("Connect VMs to private network")
821 f89d0238 John Giannelos
822 91de9b55 John Giannelos
        self.client.connect_server(self.serverid['A'], self.networkid)
823 91de9b55 John Giannelos
        self.client.connect_server(self.serverid['B'], self.networkid)
824 91de9b55 John Giannelos
                
825 65462ca9 John Giannelos
        #Insist on connecting until action timeout
826 65462ca9 John Giannelos
        fail_tmout = time.time()+self.action_timeout
827 9e4682b5 John Giannelos
828 65462ca9 John Giannelos
        while True:
829 de2461ec John Giannelos
            connected = (self.client.get_network_details(self.networkid))
830 65462ca9 John Giannelos
            connections = connected['servers']['values']
831 91de9b55 John Giannelos
            if (self.serverid['A'] in connections) and (self.serverid['B'] in connections):
832 65462ca9 John Giannelos
                conn_exists = True
833 de2461ec John Giannelos
                break
834 de2461ec John Giannelos
            elif time.time() > fail_tmout:
835 65462ca9 John Giannelos
                self.assertLess(time.time(), fail_tmout)
836 65462ca9 John Giannelos
            else:
837 65462ca9 John Giannelos
                time.sleep(self.query_interval)
838 65462ca9 John Giannelos
839 65462ca9 John Giannelos
        self.assertTrue(conn_exists)
840 9e4682b5 John Giannelos
841 88736f65 John Giannelos
    
842 88736f65 John Giannelos
    def test_002a_reboot(self):
843 f89d0238 John Giannelos
        """Rebooting server A"""
844 f89d0238 John Giannelos
845 f89d0238 John Giannelos
        log.info("Rebooting server A")
846 f89d0238 John Giannelos
847 4573ea07 John Giannelos
        self.client.reboot_server(self.serverid['A']) 
848 88736f65 John Giannelos
       
849 4573ea07 John Giannelos
        fail_tmout = time.time()+self.action_timeout
850 4573ea07 John Giannelos
        while True:
851 4573ea07 John Giannelos
            d = self.client.get_server_details(self.serverid['A'])
852 4573ea07 John Giannelos
            status = d['status']
853 4573ea07 John Giannelos
            if status == 'ACTIVE':
854 4573ea07 John Giannelos
                active = True
855 4573ea07 John Giannelos
                break
856 4573ea07 John Giannelos
            elif time.time() > fail_tmout:
857 4573ea07 John Giannelos
                self.assertLess(time.time(), fail_tmout)
858 4573ea07 John Giannelos
            else:
859 4573ea07 John Giannelos
                time.sleep(self.query_interval)
860 88736f65 John Giannelos
               
861 4573ea07 John Giannelos
        self.assertTrue(active)
862 88736f65 John Giannelos
863 88736f65 John Giannelos
864 4573ea07 John Giannelos
    def test_002b_ping_server_A(self):
865 4573ea07 John Giannelos
        "Test if server A is pingable"
866 4573ea07 John Giannelos
867 f89d0238 John Giannelos
        log.info("Testing if server A is pingable")
868 f89d0238 John Giannelos
869 88736f65 John Giannelos
        server = self.client.get_server_details(self.serverid['A'])
870 88736f65 John Giannelos
        ip = self._get_ipv4(server)
871 88736f65 John Giannelos
        
872 88736f65 John Giannelos
        fail_tmout = time.time()+self.action_timeout
873 88736f65 John Giannelos
        
874 88736f65 John Giannelos
        s = False
875 88736f65 John Giannelos
876 88736f65 John Giannelos
        while True:
877 88736f65 John Giannelos
878 88736f65 John Giannelos
            if self._ping_once(ip):
879 88736f65 John Giannelos
                s = True
880 88736f65 John Giannelos
                break
881 88736f65 John Giannelos
882 88736f65 John Giannelos
            elif time.time() > fail_tmout:
883 88736f65 John Giannelos
                self.assertLess(time.time(), fail_tmout)
884 88736f65 John Giannelos
885 88736f65 John Giannelos
            else:
886 88736f65 John Giannelos
                time.sleep(self.query_interval)
887 88736f65 John Giannelos
888 88736f65 John Giannelos
        self.assertTrue(s)
889 4573ea07 John Giannelos
890 4573ea07 John Giannelos
891 4573ea07 John Giannelos
    def test_002c_reboot(self):
892 f89d0238 John Giannelos
        """Reboot server B"""
893 f89d0238 John Giannelos
894 f89d0238 John Giannelos
        log.info("Rebooting server B")
895 f89d0238 John Giannelos
896 4573ea07 John Giannelos
        self.client.reboot_server(self.serverid['B']) 
897 4573ea07 John Giannelos
        
898 4573ea07 John Giannelos
        fail_tmout = time.time()+self.action_timeout
899 4573ea07 John Giannelos
        while True:
900 4573ea07 John Giannelos
            d = self.client.get_server_details(self.serverid['B'])
901 4573ea07 John Giannelos
            status = d['status']
902 4573ea07 John Giannelos
            if status == 'ACTIVE':
903 4573ea07 John Giannelos
                active = True
904 4573ea07 John Giannelos
                break
905 4573ea07 John Giannelos
            elif time.time() > fail_tmout:
906 4573ea07 John Giannelos
                self.assertLess(time.time(), fail_tmout)
907 4573ea07 John Giannelos
            else:
908 4573ea07 John Giannelos
                time.sleep(self.query_interval)
909 4573ea07 John Giannelos
                
910 4573ea07 John Giannelos
        self.assertTrue(active)
911 88736f65 John Giannelos
        
912 88736f65 John Giannelos
913 88736f65 John Giannelos
    def test_002d_ping_server_B(self):
914 f89d0238 John Giannelos
        """Test if server B is pingable"""
915 4573ea07 John Giannelos
916 f89d0238 John Giannelos
917 f89d0238 John Giannelos
        log.info("Testing if server B is pingable")
918 88736f65 John Giannelos
        server = self.client.get_server_details(self.serverid['B'])
919 88736f65 John Giannelos
        ip = self._get_ipv4(server)
920 88736f65 John Giannelos
        
921 88736f65 John Giannelos
        fail_tmout = time.time()+self.action_timeout
922 88736f65 John Giannelos
        
923 88736f65 John Giannelos
        s = False
924 88736f65 John Giannelos
925 88736f65 John Giannelos
        while True:
926 88736f65 John Giannelos
            if self._ping_once(ip):
927 88736f65 John Giannelos
                s = True
928 88736f65 John Giannelos
                break
929 88736f65 John Giannelos
930 88736f65 John Giannelos
            elif time.time() > fail_tmout:
931 88736f65 John Giannelos
                self.assertLess(time.time(), fail_tmout)
932 88736f65 John Giannelos
933 88736f65 John Giannelos
            else:
934 88736f65 John Giannelos
                time.sleep(self.query_interval)
935 88736f65 John Giannelos
936 88736f65 John Giannelos
        self.assertTrue(s)
937 88736f65 John Giannelos
938 88736f65 John Giannelos
939 88736f65 John Giannelos
    def test_003a_setup_interface_A(self):
940 f89d0238 John Giannelos
        """Set up eth1 for server A"""
941 f89d0238 John Giannelos
942 f89d0238 John Giannelos
        log.info("Setting up interface eth1 for server A")
943 ae139e8a John Giannelos
944 1b40b5e3 John Giannelos
        server = self.client.get_server_details(self.serverid['A'])
945 08748d73 John Giannelos
        image = self.client.get_image_details(self.imageid)
946 1b40b5e3 John Giannelos
        os = image['metadata']['values']['os']
947 1b40b5e3 John Giannelos
        
948 d5cc50b3 John Giannelos
        users = image["metadata"]["values"].get("users", None)
949 d5cc50b3 John Giannelos
        userlist = users.split()
950 d5cc50b3 John Giannelos
951 d5cc50b3 John Giannelos
        if "root" in userlist:
952 d5cc50b3 John Giannelos
            loginname = "root"
953 d5cc50b3 John Giannelos
        elif users == None:
954 1b40b5e3 John Giannelos
            loginname = self._connect_loginname(os)
955 d5cc50b3 John Giannelos
        else:
956 d5cc50b3 John Giannelos
            loginname = choice(userlist)
957 1b40b5e3 John Giannelos
958 ae139e8a John Giannelos
        hostip = self._get_ipv4(server)
959 740a5649 John Giannelos
        myPass = self.password['A']
960 ae139e8a John Giannelos
        
961 ae139e8a John Giannelos
        log.info("SSH in server A: \n")
962 ae139e8a John Giannelos
        log.info("Username: " + loginname + '\n') 
963 ae139e8a John Giannelos
        log.info("Password " + myPass + '\n')
964 88736f65 John Giannelos
        
965 88736f65 John Giannelos
        res = False
966 1b40b5e3 John Giannelos
967 d5cc50b3 John Giannelos
        if loginname != "root":
968 88736f65 John Giannelos
            with settings(
969 33ae1493 John Giannelos
                hide('warnings', 'running'),
970 88736f65 John Giannelos
                warn_only=True, 
971 88736f65 John Giannelos
                host_string = hostip, 
972 88736f65 John Giannelos
                user = loginname, password = myPass
973 88736f65 John Giannelos
                ):
974 88736f65 John Giannelos
975 33ae1493 John Giannelos
                if len(sudo('ifconfig eth1 192.168.0.12')) == 0: 
976 88736f65 John Giannelos
                    res = True
977 d5cc50b3 John Giannelos
            
978 ae139e8a John Giannelos
        else:
979 ae139e8a John Giannelos
            with settings(
980 33ae1493 John Giannelos
                hide('warnings', 'running'),
981 ae139e8a John Giannelos
                warn_only=True, 
982 ae139e8a John Giannelos
                host_string = hostip, 
983 ae139e8a John Giannelos
                user = loginname, password = myPass
984 ae139e8a John Giannelos
                ):
985 4573ea07 John Giannelos
986 33ae1493 John Giannelos
                if len(run('ifconfig eth1 192.168.0.12')) == 0:
987 ae139e8a John Giannelos
                    res = True
988 88736f65 John Giannelos
989 88736f65 John Giannelos
        self.assertTrue(res)
990 1b40b5e3 John Giannelos
991 88736f65 John Giannelos
992 88736f65 John Giannelos
    def test_003b_setup_interface_B(self):
993 f89d0238 John Giannelos
        """Setup eth1 for server B"""
994 1b40b5e3 John Giannelos
995 f89d0238 John Giannelos
        log.info("Setting up interface eth1 for server B")
996 ae139e8a John Giannelos
997 1b40b5e3 John Giannelos
        server = self.client.get_server_details(self.serverid['B'])
998 08748d73 John Giannelos
        image = self.client.get_image_details(self.imageid)
999 1b40b5e3 John Giannelos
        os = image['metadata']['values']['os']
1000 1b40b5e3 John Giannelos
        
1001 d5cc50b3 John Giannelos
        users = image["metadata"]["values"].get("users", None)
1002 d5cc50b3 John Giannelos
        userlist = users.split()
1003 d5cc50b3 John Giannelos
1004 d5cc50b3 John Giannelos
        if "root" in userlist:
1005 d5cc50b3 John Giannelos
            loginname = "root"
1006 d5cc50b3 John Giannelos
        elif users == None:
1007 1b40b5e3 John Giannelos
            loginname = self._connect_loginname(os)
1008 d5cc50b3 John Giannelos
        else:
1009 d5cc50b3 John Giannelos
            loginname = choice(userlist)
1010 d5cc50b3 John Giannelos
1011 d5cc50b3 John Giannelos
        hostip = self._get_ipv4(server)
1012 740a5649 John Giannelos
        myPass = self.password['B']
1013 740a5649 John Giannelos
1014 ae139e8a John Giannelos
        log.info("SSH in server A: \n")
1015 ae139e8a John Giannelos
        log.info("Username: " + loginname + '\n') 
1016 ae139e8a John Giannelos
        log.info("Password " + myPass + '\n')
1017 1b40b5e3 John Giannelos
1018 88736f65 John Giannelos
        res = False
1019 88736f65 John Giannelos
1020 d5cc50b3 John Giannelos
        if loginname != "root":
1021 88736f65 John Giannelos
            with settings(
1022 33ae1493 John Giannelos
                hide('warnings', 'running'),
1023 88736f65 John Giannelos
                warn_only=True, 
1024 88736f65 John Giannelos
                host_string = hostip, 
1025 88736f65 John Giannelos
                user = loginname, password = myPass
1026 88736f65 John Giannelos
                ):
1027 88736f65 John Giannelos
                
1028 33ae1493 John Giannelos
                if len(sudo('ifconfig eth1 192.168.0.13'))== 0:
1029 88736f65 John Giannelos
                    res = True
1030 d5cc50b3 John Giannelos
            
1031 88736f65 John Giannelos
        else :
1032 ae139e8a John Giannelos
            with settings(
1033 33ae1493 John Giannelos
                hide('warnings', 'running'),
1034 ae139e8a John Giannelos
                warn_only=True, 
1035 ae139e8a John Giannelos
                host_string = hostip, 
1036 ae139e8a John Giannelos
                user = loginname, password = myPass
1037 ae139e8a John Giannelos
                ):
1038 ae139e8a John Giannelos
1039 33ae1493 John Giannelos
                if len(run('ifconfig eth1 192.168.0.13')) == 0:
1040 ae139e8a John Giannelos
                    res = True
1041 ae139e8a John Giannelos
1042 1b40b5e3 John Giannelos
1043 88736f65 John Giannelos
        self.assertTrue(res)
1044 88736f65 John Giannelos
            
1045 1b40b5e3 John Giannelos
1046 ae139e8a John Giannelos
1047 88736f65 John Giannelos
    def test_003c_test_connection_exists(self):
1048 4573ea07 John Giannelos
        """Ping server B from server A to test if connection exists"""
1049 1b40b5e3 John Giannelos
1050 f89d0238 John Giannelos
        log.info("Testing if server A is actually connected to server B")
1051 f89d0238 John Giannelos
1052 1b40b5e3 John Giannelos
        server = self.client.get_server_details(self.serverid['A'])
1053 08748d73 John Giannelos
        image = self.client.get_image_details(self.imageid)
1054 1b40b5e3 John Giannelos
        os = image['metadata']['values']['os']
1055 1b40b5e3 John Giannelos
        hostip = self._get_ipv4(server)
1056 d5cc50b3 John Giannelos
1057 d5cc50b3 John Giannelos
        users = image["metadata"]["values"].get("users", None)
1058 d5cc50b3 John Giannelos
        userlist = users.split()
1059 d5cc50b3 John Giannelos
1060 d5cc50b3 John Giannelos
        if "root" in userlist:
1061 d5cc50b3 John Giannelos
            loginname = "root"
1062 d5cc50b3 John Giannelos
        elif users == None:
1063 1b40b5e3 John Giannelos
            loginname = self._connect_loginname(os)
1064 d5cc50b3 John Giannelos
        else:
1065 d5cc50b3 John Giannelos
            loginname = choice(userlist)
1066 1b40b5e3 John Giannelos
1067 88736f65 John Giannelos
        myPass = self.password['A']
1068 88736f65 John Giannelos
1069 1b40b5e3 John Giannelos
        try:
1070 1b40b5e3 John Giannelos
            ssh = paramiko.SSHClient()
1071 1b40b5e3 John Giannelos
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
1072 88736f65 John Giannelos
            ssh.connect(hostip, username = loginname, password = myPass)
1073 1b40b5e3 John Giannelos
        except socket.error:
1074 1b40b5e3 John Giannelos
            raise AssertionError
1075 1b40b5e3 John Giannelos
1076 4573ea07 John Giannelos
        cmd = "if ping -c 2 -w 3 192.168.0.13 >/dev/null; then echo \'True\'; fi;"
1077 1b40b5e3 John Giannelos
        stdin, stdout, stderr = ssh.exec_command(cmd)
1078 1b40b5e3 John Giannelos
        lines = stdout.readlines()
1079 1b40b5e3 John Giannelos
1080 740a5649 John Giannelos
        exists = False
1081 4573ea07 John Giannelos
1082 88736f65 John Giannelos
        if 'True\n' in lines:
1083 88736f65 John Giannelos
            exists = True
1084 1b40b5e3 John Giannelos
1085 1b40b5e3 John Giannelos
        self.assertTrue(exists)
1086 1b40b5e3 John Giannelos
1087 1b40b5e3 John Giannelos
1088 ae139e8a John Giannelos
#TODO: Test IPv6 private connectity
1089 ae139e8a John Giannelos
1090 ae139e8a John Giannelos
1091 88736f65 John Giannelos
    def test_004_disconnect_from_network(self):
1092 4573ea07 John Giannelos
        "Disconnecting server A and B from network"
1093 4573ea07 John Giannelos
1094 f89d0238 John Giannelos
        log.info("Disconnecting servers from private network")
1095 f89d0238 John Giannelos
1096 f97dce4d John Giannelos
        prev_state = self.client.get_network_details(self.networkid)
1097 9e4682b5 John Giannelos
        prev_conn = len(prev_state['servers']['values'])
1098 e94a9d8c John Giannelos
1099 91de9b55 John Giannelos
        self.client.disconnect_server(self.serverid['A'], self.networkid)
1100 91de9b55 John Giannelos
        self.client.disconnect_server(self.serverid['B'], self.networkid)
1101 f97dce4d John Giannelos
1102 65462ca9 John Giannelos
        #Insist on deleting until action timeout
1103 65462ca9 John Giannelos
        fail_tmout = time.time()+self.action_timeout
1104 9e4682b5 John Giannelos
1105 65462ca9 John Giannelos
        while True:
1106 de2461ec John Giannelos
            connected = (self.client.get_network_details(self.networkid))
1107 65462ca9 John Giannelos
            connections = connected['servers']['values']
1108 91de9b55 John Giannelos
            if (self.serverid['A'] not in connections) and (self.serverid['B'] not in connections):
1109 65462ca9 John Giannelos
                conn_exists = False
1110 de2461ec John Giannelos
                break
1111 de2461ec John Giannelos
            elif time.time() > fail_tmout:
1112 65462ca9 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1113 65462ca9 John Giannelos
            else:
1114 65462ca9 John Giannelos
                time.sleep(self.query_interval)
1115 65462ca9 John Giannelos
1116 65462ca9 John Giannelos
        self.assertFalse(conn_exists)
1117 9e4682b5 John Giannelos
1118 88736f65 John Giannelos
    def test_005_destroy_network(self):
1119 e94a9d8c John Giannelos
        """Test submit delete network request"""
1120 f89d0238 John Giannelos
1121 f89d0238 John Giannelos
        log.info("Submitting delete network request")
1122 f89d0238 John Giannelos
1123 65462ca9 John Giannelos
        self.client.delete_network(self.networkid)        
1124 9e4682b5 John Giannelos
        networks = self.client.list_networks()
1125 e94a9d8c John Giannelos
1126 65462ca9 John Giannelos
        curr_net = []
1127 65462ca9 John Giannelos
        for net in networks:
1128 de2461ec John Giannelos
            curr_net.append(net['id'])
1129 65462ca9 John Giannelos
1130 65462ca9 John Giannelos
        self.assertTrue(self.networkid not in curr_net)
1131 65462ca9 John Giannelos
        
1132 88736f65 John Giannelos
    def test_006_cleanup_servers(self):
1133 65462ca9 John Giannelos
        """Cleanup servers created for this test"""
1134 f89d0238 John Giannelos
1135 f89d0238 John Giannelos
        log.info("Delete servers created for this test")
1136 f89d0238 John Giannelos
1137 91de9b55 John Giannelos
        self.compute.delete_server(self.serverid['A'])
1138 91de9b55 John Giannelos
        self.compute.delete_server(self.serverid['B'])
1139 91de9b55 John Giannelos
1140 65462ca9 John Giannelos
        fail_tmout = time.time()+self.action_timeout
1141 65462ca9 John Giannelos
1142 65462ca9 John Giannelos
        #Ensure server gets deleted
1143 91de9b55 John Giannelos
        status = dict() 
1144 91de9b55 John Giannelos
1145 65462ca9 John Giannelos
        while True:
1146 91de9b55 John Giannelos
            details = self.compute.get_server_details(self.serverid['A'])
1147 91de9b55 John Giannelos
            status['A'] = details['status']
1148 91de9b55 John Giannelos
            details = self.compute.get_server_details(self.serverid['B'])
1149 91de9b55 John Giannelos
            status['B'] = details['status']
1150 91de9b55 John Giannelos
            if (status['A'] == 'DELETED') and (status['B'] == 'DELETED'):
1151 65462ca9 John Giannelos
                deleted = True
1152 de2461ec John Giannelos
                break
1153 65462ca9 John Giannelos
            elif time.time() > fail_tmout: 
1154 65462ca9 John Giannelos
                self.assertLess(time.time(), fail_tmout)
1155 65462ca9 John Giannelos
            else:
1156 65462ca9 John Giannelos
                time.sleep(self.query_interval)
1157 d5cc50b3 John Giannelos
                
1158 65462ca9 John Giannelos
        self.assertTrue(deleted)
1159 e94a9d8c John Giannelos
1160 4573ea07 John Giannelos
1161 21bbbc9b Vangelis Koukis
class TestRunnerProcess(Process):
1162 21bbbc9b Vangelis Koukis
    """A distinct process used to execute part of the tests in parallel"""
1163 21bbbc9b Vangelis Koukis
    def __init__(self, **kw):
1164 21bbbc9b Vangelis Koukis
        Process.__init__(self, **kw)
1165 96da37c8 John Giannelos
        kwargs = kw["kwargs"]
1166 21bbbc9b Vangelis Koukis
        self.testq = kwargs["testq"]
1167 21bbbc9b Vangelis Koukis
        self.runner = kwargs["runner"]
1168 21bbbc9b Vangelis Koukis
1169 21bbbc9b Vangelis Koukis
    def run(self):
1170 21bbbc9b Vangelis Koukis
        # Make sure this test runner process dies with the parent
1171 21bbbc9b Vangelis Koukis
        # and is not left behind.
1172 21bbbc9b Vangelis Koukis
        #
1173 21bbbc9b Vangelis Koukis
        # WARNING: This uses the prctl(2) call and is
1174 21bbbc9b Vangelis Koukis
        # Linux-specific.
1175 21bbbc9b Vangelis Koukis
        prctl.set_pdeathsig(signal.SIGHUP)
1176 21bbbc9b Vangelis Koukis
1177 21bbbc9b Vangelis Koukis
        while True:
1178 21bbbc9b Vangelis Koukis
            log.debug("I am process %d, GETting from queue is %s",
1179 21bbbc9b Vangelis Koukis
                     os.getpid(), self.testq)
1180 21bbbc9b Vangelis Koukis
            msg = self.testq.get()
1181 21bbbc9b Vangelis Koukis
            log.debug("Dequeued msg: %s", msg)
1182 21bbbc9b Vangelis Koukis
1183 21bbbc9b Vangelis Koukis
            if msg == "TEST_RUNNER_TERMINATE":
1184 21bbbc9b Vangelis Koukis
                raise SystemExit
1185 21bbbc9b Vangelis Koukis
            elif issubclass(msg, unittest.TestCase):
1186 21bbbc9b Vangelis Koukis
                # Assemble a TestSuite, and run it
1187 21bbbc9b Vangelis Koukis
                suite = unittest.TestLoader().loadTestsFromTestCase(msg)
1188 21bbbc9b Vangelis Koukis
                self.runner.run(suite)
1189 21bbbc9b Vangelis Koukis
            else:
1190 21bbbc9b Vangelis Koukis
                raise Exception("Cannot handle msg: %s" % msg)
1191 21bbbc9b Vangelis Koukis
1192 21bbbc9b Vangelis Koukis
1193 99d41650 John Giannelos
1194 21bbbc9b Vangelis Koukis
def _run_cases_in_parallel(cases, fanout=1, runner=None):
1195 21bbbc9b Vangelis Koukis
    """Run instances of TestCase in parallel, in a number of distinct processes
1196 21bbbc9b Vangelis Koukis

1197 21bbbc9b Vangelis Koukis
    The cases iterable specifies the TestCases to be executed in parallel,
1198 21bbbc9b Vangelis Koukis
    by test runners running in distinct processes.
1199 21bbbc9b Vangelis Koukis
    The fanout parameter specifies the number of processes to spawn,
1200 21bbbc9b Vangelis Koukis
    and defaults to 1.
1201 21bbbc9b Vangelis Koukis
    The runner argument specifies the test runner class to use inside each
1202 21bbbc9b Vangelis Koukis
    runner process.
1203 21bbbc9b Vangelis Koukis

1204 21bbbc9b Vangelis Koukis
    """
1205 21bbbc9b Vangelis Koukis
    if runner is None:
1206 00f87624 Vangelis Koukis
        runner = unittest.TextTestRunner(verbosity=2, failfast=True)
1207 21bbbc9b Vangelis Koukis
1208 21bbbc9b Vangelis Koukis
    # testq: The master process enqueues TestCase objects into this queue,
1209 21bbbc9b Vangelis Koukis
    #        test runner processes pick them up for execution, in parallel.
1210 21bbbc9b Vangelis Koukis
    testq = Queue()
1211 21bbbc9b Vangelis Koukis
    runners = []
1212 21bbbc9b Vangelis Koukis
    for i in xrange(0, fanout):
1213 21bbbc9b Vangelis Koukis
        kwargs = dict(testq=testq, runner=runner)
1214 21bbbc9b Vangelis Koukis
        runners.append(TestRunnerProcess(kwargs=kwargs))
1215 21bbbc9b Vangelis Koukis
1216 21bbbc9b Vangelis Koukis
    log.info("Spawning %d test runner processes", len(runners))
1217 21bbbc9b Vangelis Koukis
    for p in runners:
1218 21bbbc9b Vangelis Koukis
        p.start()
1219 21bbbc9b Vangelis Koukis
    log.debug("Spawned %d test runners, PIDs are %s",
1220 21bbbc9b Vangelis Koukis
              len(runners), [p.pid for p in runners])
1221 21bbbc9b Vangelis Koukis
1222 21bbbc9b Vangelis Koukis
    # Enqueue test cases
1223 21bbbc9b Vangelis Koukis
    map(testq.put, cases)
1224 21bbbc9b Vangelis Koukis
    map(testq.put, ["TEST_RUNNER_TERMINATE"] * len(runners))
1225 21bbbc9b Vangelis Koukis
1226 21bbbc9b Vangelis Koukis
    log.debug("Joining %d processes", len(runners))
1227 21bbbc9b Vangelis Koukis
    for p in runners:
1228 21bbbc9b Vangelis Koukis
        p.join()
1229 21bbbc9b Vangelis Koukis
    log.debug("Done joining %d processes", len(runners))
1230 4fdd25ab Vangelis Koukis
1231 5a140b23 Vangelis Koukis
1232 5a140b23 Vangelis Koukis
def _spawn_server_test_case(**kwargs):
1233 5a140b23 Vangelis Koukis
    """Construct a new unit test case class from SpawnServerTestCase"""
1234 5a140b23 Vangelis Koukis
1235 c1d11f96 John Giannelos
    name = "SpawnServerTestCase_%s" % kwargs["imageid"]
1236 5a140b23 Vangelis Koukis
    cls = type(name, (SpawnServerTestCase,), kwargs)
1237 5a140b23 Vangelis Koukis
1238 5a140b23 Vangelis Koukis
    # Patch extra parameters into test names by manipulating method docstrings
1239 5a140b23 Vangelis Koukis
    for (mname, m) in \
1240 5a140b23 Vangelis Koukis
        inspect.getmembers(cls, lambda x: inspect.ismethod(x)):
1241 5a140b23 Vangelis Koukis
            if hasattr(m, __doc__):
1242 5a140b23 Vangelis Koukis
                m.__func__.__doc__ = "[%s] %s" % (imagename, m.__doc__)
1243 e72bcf60 Vangelis Koukis
1244 e72bcf60 Vangelis Koukis
    # Make sure the class can be pickled, by listing it among
1245 e72bcf60 Vangelis Koukis
    # the attributes of __main__. A PicklingError is raised otherwise.
1246 e72bcf60 Vangelis Koukis
    setattr(__main__, name, cls)
1247 65462ca9 John Giannelos
    return cls 
1248 65462ca9 John Giannelos
1249 65462ca9 John Giannelos
def _spawn_network_test_case(**kwargs):
1250 65462ca9 John Giannelos
    """Construct a new unit test case class from NetworkTestCase"""
1251 65462ca9 John Giannelos
1252 65462ca9 John Giannelos
    name = "NetworkTestCase"+TEST_RUN_ID
1253 65462ca9 John Giannelos
    cls = type(name, (NetworkTestCase,), kwargs)
1254 65462ca9 John Giannelos
1255 65462ca9 John Giannelos
    # Make sure the class can be pickled, by listing it among
1256 65462ca9 John Giannelos
    # the attributes of __main__. A PicklingError is raised otherwise.
1257 65462ca9 John Giannelos
    setattr(__main__, name, cls)
1258 65462ca9 John Giannelos
    return cls 
1259 5a140b23 Vangelis Koukis
1260 5a140b23 Vangelis Koukis
1261 5a140b23 Vangelis Koukis
def cleanup_servers(delete_stale=False):
1262 74193008 John Giannelos
1263 567ffb85 John Giannelos
    c = ComputeClient(API, TOKEN)
1264 74193008 John Giannelos
1265 5a140b23 Vangelis Koukis
    servers = c.list_servers()
1266 5a140b23 Vangelis Koukis
    stale = [s for s in servers if s["name"].startswith(SNF_TEST_PREFIX)]
1267 5a140b23 Vangelis Koukis
1268 4fdd25ab Vangelis Koukis
    if len(stale) == 0:
1269 4fdd25ab Vangelis Koukis
        return
1270 4fdd25ab Vangelis Koukis
1271 5a140b23 Vangelis Koukis
    print >> sys.stderr, "Found these stale servers from previous runs:"
1272 5a140b23 Vangelis Koukis
    print "    " + \
1273 21bbbc9b Vangelis Koukis
          "\n    ".join(["%d: %s" % (s["id"], s["name"]) for s in stale])
1274 5a140b23 Vangelis Koukis
1275 5a140b23 Vangelis Koukis
    if delete_stale:
1276 5a140b23 Vangelis Koukis
        print >> sys.stderr, "Deleting %d stale servers:" % len(stale)
1277 5a140b23 Vangelis Koukis
        for server in stale:
1278 21bbbc9b Vangelis Koukis
            c.delete_server(server["id"])
1279 5a140b23 Vangelis Koukis
        print >> sys.stderr, "    ...done"
1280 5a140b23 Vangelis Koukis
    else:
1281 5a140b23 Vangelis Koukis
        print >> sys.stderr, "Use --delete-stale to delete them."
1282 5a140b23 Vangelis Koukis
1283 5a140b23 Vangelis Koukis
1284 5a140b23 Vangelis Koukis
def parse_arguments(args):
1285 5a140b23 Vangelis Koukis
    from optparse import OptionParser
1286 5a140b23 Vangelis Koukis
1287 5a140b23 Vangelis Koukis
    kw = {}
1288 5a140b23 Vangelis Koukis
    kw["usage"] = "%prog [options]"
1289 5a140b23 Vangelis Koukis
    kw["description"] = \
1290 5a140b23 Vangelis Koukis
        "%prog runs a number of test scenarios on a " \
1291 5a140b23 Vangelis Koukis
        "Synnefo deployment."
1292 5a140b23 Vangelis Koukis
1293 5a140b23 Vangelis Koukis
    parser = OptionParser(**kw)
1294 5a140b23 Vangelis Koukis
    parser.disable_interspersed_args()
1295 21bbbc9b Vangelis Koukis
    parser.add_option("--api",
1296 21bbbc9b Vangelis Koukis
                      action="store", type="string", dest="api",
1297 21bbbc9b Vangelis Koukis
                      help="The API URI to use to reach the Synnefo API",
1298 21bbbc9b Vangelis Koukis
                      default=DEFAULT_API)
1299 21bbbc9b Vangelis Koukis
    parser.add_option("--token",
1300 21bbbc9b Vangelis Koukis
                      action="store", type="string", dest="token",
1301 38d247df Kostas Papadimitriou
                      help="The token to use for authentication to the API")
1302 00f87624 Vangelis Koukis
    parser.add_option("--nofailfast",
1303 00f87624 Vangelis Koukis
                      action="store_true", dest="nofailfast",
1304 00f87624 Vangelis Koukis
                      help="Do not fail immediately if one of the tests " \
1305 00f87624 Vangelis Koukis
                           "fails (EXPERIMENTAL)",
1306 bc14ba88 Vangelis Koukis
                      default=False)
1307 5a140b23 Vangelis Koukis
    parser.add_option("--action-timeout",
1308 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="action_timeout",
1309 5a140b23 Vangelis Koukis
                      metavar="TIMEOUT",
1310 5a140b23 Vangelis Koukis
                      help="Wait SECONDS seconds for a server action to " \
1311 5a140b23 Vangelis Koukis
                           "complete, then the test is considered failed",
1312 9e4682b5 John Giannelos
                      default=100)
1313 5a140b23 Vangelis Koukis
    parser.add_option("--build-warning",
1314 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="build_warning",
1315 5a140b23 Vangelis Koukis
                      metavar="TIMEOUT",
1316 5a140b23 Vangelis Koukis
                      help="Warn if TIMEOUT seconds have passed and a " \
1317 5a140b23 Vangelis Koukis
                           "build operation is still pending",
1318 5a140b23 Vangelis Koukis
                      default=600)
1319 5a140b23 Vangelis Koukis
    parser.add_option("--build-fail",
1320 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="build_fail",
1321 5a140b23 Vangelis Koukis
                      metavar="BUILD_TIMEOUT",
1322 5a140b23 Vangelis Koukis
                      help="Fail the test if TIMEOUT seconds have passed " \
1323 5a140b23 Vangelis Koukis
                           "and a build operation is still incomplete",
1324 5a140b23 Vangelis Koukis
                      default=900)
1325 5a140b23 Vangelis Koukis
    parser.add_option("--query-interval",
1326 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="query_interval",
1327 5a140b23 Vangelis Koukis
                      metavar="INTERVAL",
1328 5a140b23 Vangelis Koukis
                      help="Query server status when requests are pending " \
1329 5a140b23 Vangelis Koukis
                           "every INTERVAL seconds",
1330 5a140b23 Vangelis Koukis
                      default=3)
1331 21bbbc9b Vangelis Koukis
    parser.add_option("--fanout",
1332 21bbbc9b Vangelis Koukis
                      action="store", type="int", dest="fanout",
1333 5a140b23 Vangelis Koukis
                      metavar="COUNT",
1334 21bbbc9b Vangelis Koukis
                      help="Spawn up to COUNT child processes to execute " \
1335 21bbbc9b Vangelis Koukis
                           "in parallel, essentially have up to COUNT " \
1336 00f87624 Vangelis Koukis
                           "server build requests outstanding (EXPERIMENTAL)",
1337 5a140b23 Vangelis Koukis
                      default=1)
1338 5a140b23 Vangelis Koukis
    parser.add_option("--force-flavor",
1339 5a140b23 Vangelis Koukis
                      action="store", type="int", dest="force_flavorid",
1340 5a140b23 Vangelis Koukis
                      metavar="FLAVOR ID",
1341 5a140b23 Vangelis Koukis
                      help="Force all server creations to use the specified "\
1342 5a140b23 Vangelis Koukis
                           "FLAVOR ID instead of a randomly chosen one, " \
1343 5a140b23 Vangelis Koukis
                           "useful if disk space is scarce",
1344 00f87624 Vangelis Koukis
                      default=None)
1345 7f62a0b5 Vangelis Koukis
    parser.add_option("--image-id",
1346 7f62a0b5 Vangelis Koukis
                      action="store", type="string", dest="force_imageid",
1347 00f87624 Vangelis Koukis
                      metavar="IMAGE ID",
1348 7f62a0b5 Vangelis Koukis
                      help="Test the specified image id, use 'all' to test " \
1349 7f62a0b5 Vangelis Koukis
                           "all available images (mandatory argument)",
1350 00f87624 Vangelis Koukis
                      default=None)
1351 5a140b23 Vangelis Koukis
    parser.add_option("--show-stale",
1352 5a140b23 Vangelis Koukis
                      action="store_true", dest="show_stale",
1353 5a140b23 Vangelis Koukis
                      help="Show stale servers from previous runs, whose "\
1354 21bbbc9b Vangelis Koukis
                           "name starts with `%s'" % SNF_TEST_PREFIX,
1355 5a140b23 Vangelis Koukis
                      default=False)
1356 5a140b23 Vangelis Koukis
    parser.add_option("--delete-stale",
1357 5a140b23 Vangelis Koukis
                      action="store_true", dest="delete_stale",
1358 5a140b23 Vangelis Koukis
                      help="Delete stale servers from previous runs, whose "\
1359 21bbbc9b Vangelis Koukis
                           "name starts with `%s'" % SNF_TEST_PREFIX,
1360 5a140b23 Vangelis Koukis
                      default=False)
1361 9659e075 John Giannelos
    parser.add_option("--force-personality",
1362 65462ca9 John Giannelos
                      action="store", type="string", dest="personality_path",
1363 9659e075 John Giannelos
                      help="Force a personality file injection. File path required. ",
1364 9659e075 John Giannelos
                      default=None)
1365 9659e075 John Giannelos
    
1366 5a140b23 Vangelis Koukis
1367 5a140b23 Vangelis Koukis
    # FIXME: Change the default for build-fanout to 10
1368 5a140b23 Vangelis Koukis
    # FIXME: Allow the user to specify a specific set of Images to test
1369 5a140b23 Vangelis Koukis
1370 5a140b23 Vangelis Koukis
    (opts, args) = parser.parse_args(args)
1371 5a140b23 Vangelis Koukis
1372 5a140b23 Vangelis Koukis
    # Verify arguments
1373 5a140b23 Vangelis Koukis
    if opts.delete_stale:
1374 5a140b23 Vangelis Koukis
        opts.show_stale = True
1375 5a140b23 Vangelis Koukis
1376 7f62a0b5 Vangelis Koukis
    if not opts.show_stale:
1377 7f62a0b5 Vangelis Koukis
        if not opts.force_imageid:
1378 7f62a0b5 Vangelis Koukis
            print >>sys.stderr, "The --image-id argument is mandatory."
1379 7f62a0b5 Vangelis Koukis
            parser.print_help()
1380 7f62a0b5 Vangelis Koukis
            sys.exit(1)
1381 7f62a0b5 Vangelis Koukis
1382 7f62a0b5 Vangelis Koukis
        if opts.force_imageid != 'all':
1383 7f62a0b5 Vangelis Koukis
            try:
1384 99d41650 John Giannelos
                opts.force_imageid = str(opts.force_imageid)
1385 7f62a0b5 Vangelis Koukis
            except ValueError:
1386 7f62a0b5 Vangelis Koukis
                print >>sys.stderr, "Invalid value specified for --image-id." \
1387 e94a9d8c John Giannelos
                                    "Use a valid id, or `all'."
1388 7f62a0b5 Vangelis Koukis
                sys.exit(1)
1389 7f62a0b5 Vangelis Koukis
1390 5a140b23 Vangelis Koukis
    return (opts, args)
1391 5a140b23 Vangelis Koukis
1392 5a140b23 Vangelis Koukis
1393 5a140b23 Vangelis Koukis
def main():
1394 5a140b23 Vangelis Koukis
    """Assemble test cases into a test suite, and run it
1395 5a140b23 Vangelis Koukis

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

1402 5a140b23 Vangelis Koukis
    """
1403 ae139e8a John Giannelos
1404 5a140b23 Vangelis Koukis
    (opts, args) = parse_arguments(sys.argv[1:])
1405 5a140b23 Vangelis Koukis
1406 21bbbc9b Vangelis Koukis
    global API, TOKEN
1407 21bbbc9b Vangelis Koukis
    API = opts.api
1408 21bbbc9b Vangelis Koukis
    TOKEN = opts.token
1409 21bbbc9b Vangelis Koukis
1410 5a140b23 Vangelis Koukis
    # Cleanup stale servers from previous runs
1411 5a140b23 Vangelis Koukis
    if opts.show_stale:
1412 5a140b23 Vangelis Koukis
        cleanup_servers(delete_stale=opts.delete_stale)
1413 5a140b23 Vangelis Koukis
        return 0
1414 5a140b23 Vangelis Koukis
1415 5a140b23 Vangelis Koukis
    # Initialize a kamaki instance, get flavors, images
1416 74193008 John Giannelos
1417 96da37c8 John Giannelos
    c = ComputeClient(API, TOKEN)
1418 74193008 John Giannelos
1419 5a140b23 Vangelis Koukis
    DIMAGES = c.list_images(detail=True)
1420 5a140b23 Vangelis Koukis
    DFLAVORS = c.list_flavors(detail=True)
1421 5a140b23 Vangelis Koukis
1422 21bbbc9b Vangelis Koukis
    # FIXME: logging, log, LOG PID, TEST_RUN_ID, arguments
1423 5a140b23 Vangelis Koukis
    # Run them: FIXME: In parallel, FAILEARLY, catchbreak?
1424 5a140b23 Vangelis Koukis
    #unittest.main(verbosity=2, catchbreak=True)
1425 5a140b23 Vangelis Koukis
1426 e94a9d8c John Giannelos
    if opts.force_imageid == 'all':
1427 e94a9d8c John Giannelos
        test_images = DIMAGES
1428 e94a9d8c John Giannelos
    else:
1429 e94a9d8c John Giannelos
        test_images = filter(lambda x: x["id"] == opts.force_imageid, DIMAGES)
1430 e94a9d8c John Giannelos
1431 00f87624 Vangelis Koukis
    for image in test_images:
1432 99d41650 John Giannelos
        imageid = str(image["id"])
1433 99d41650 John Giannelos
        flavorid = choice([f["id"] for f in DFLAVORS if f["disk"] >= 20])
1434 21bbbc9b Vangelis Koukis
        imagename = image["name"]
1435 9659e075 John Giannelos
        
1436 567ffb85 John Giannelos
        #Personality dictionary for file injection test
1437 9659e075 John Giannelos
        if opts.personality_path != None:
1438 9659e075 John Giannelos
            f = open(opts.personality_path)
1439 9659e075 John Giannelos
            content = b64encode(f.read())
1440 9659e075 John Giannelos
            personality = []
1441 9659e075 John Giannelos
            st = os.stat(opts.personality_path)
1442 9659e075 John Giannelos
            personality.append({
1443 9659e075 John Giannelos
                    'path': '/root/test_inj_file',
1444 9659e075 John Giannelos
                    'owner': 'root',
1445 9659e075 John Giannelos
                    'group': 'root',
1446 9659e075 John Giannelos
                    'mode': 0x7777 & st.st_mode,
1447 9659e075 John Giannelos
                    'contents': content
1448 9659e075 John Giannelos
                    })
1449 9659e075 John Giannelos
        else:
1450 9659e075 John Giannelos
            personality = None
1451 9659e075 John Giannelos
1452 21bbbc9b Vangelis Koukis
        servername = "%s%s for %s" % (SNF_TEST_PREFIX, TEST_RUN_ID, imagename)
1453 21bbbc9b Vangelis Koukis
        is_windows = imagename.lower().find("windows") >= 0
1454 9e4682b5 John Giannelos
        
1455 f89d0238 John Giannelos
1456 65462ca9 John Giannelos
    ServerTestCase = _spawn_server_test_case(imageid=imageid, flavorid=flavorid,
1457 65462ca9 John Giannelos
                                             imagename=imagename,
1458 65462ca9 John Giannelos
                                             personality=personality,
1459 65462ca9 John Giannelos
                                             servername=servername,
1460 65462ca9 John Giannelos
                                             is_windows=is_windows,
1461 65462ca9 John Giannelos
                                             action_timeout=opts.action_timeout,
1462 65462ca9 John Giannelos
                                             build_warning=opts.build_warning,
1463 65462ca9 John Giannelos
                                             build_fail=opts.build_fail,
1464 65462ca9 John Giannelos
                                             query_interval=opts.query_interval,
1465 65462ca9 John Giannelos
                                             )
1466 21bbbc9b Vangelis Koukis
1467 65462ca9 John Giannelos
    
1468 4d6e355c John Giannelos
    NetworkTestCase = _spawn_network_test_case(action_timeout = opts.action_timeout,
1469 ae139e8a John Giannelos
                                               imageid = imageid,
1470 ae139e8a John Giannelos
                                               flavorid = flavorid,
1471 ae139e8a John Giannelos
                                               imagename=imagename,
1472 ae139e8a John Giannelos
                                               query_interval = opts.query_interval,
1473 ae139e8a John Giannelos
                                               )
1474 ae139e8a John Giannelos
    
1475 ae139e8a John Giannelos
1476 bfce8db6 John Giannelos
    seq_cases = [UnauthorizedTestCase, ImagesTestCase, FlavorsTestCase, ServersTestCase, ServerTestCase]
1477 567ffb85 John Giannelos
1478 bfce8db6 John Giannelos
#    seq_cases = [NetworkTestCase]
1479 bfce8db6 John Giannelos
1480 bfce8db6 John Giannelos
1481 bfce8db6 John Giannelos
    os.mkdir(TEST_RUN_ID)
1482 ae139e8a John Giannelos
    
1483 99d41650 John Giannelos
    for case in seq_cases:
1484 bfce8db6 John Giannelos
        log_file = TEST_RUN_ID+'/'+'details_'+(case.__name__)+"_"+TEST_RUN_ID+'.log'
1485 bfce8db6 John Giannelos
        fail_file = TEST_RUN_ID+'/'+'failed_'+(case.__name__)+"_"+TEST_RUN_ID+'.log'
1486 bfce8db6 John Giannelos
        error_file = TEST_RUN_ID+'/'+'error_'+(case.__name__)+"_"+TEST_RUN_ID+'.log'
1487 4d6e355c John Giannelos
1488 4d6e355c John Giannelos
        f = open(log_file, "w")
1489 4d6e355c John Giannelos
        fail = open(fail_file, "w")
1490 ae139e8a John Giannelos
        error = open(error_file, "w")
1491 ae139e8a John Giannelos
1492 99d41650 John Giannelos
        suite = unittest.TestLoader().loadTestsFromTestCase(case)
1493 4d6e355c John Giannelos
        runner = unittest.TextTestRunner(f, verbosity=2)
1494 4d6e355c John Giannelos
        result = runner.run(suite)
1495 4d6e355c John Giannelos
        
1496 ae139e8a John Giannelos
        error.write("Testcases errors: \n\n")
1497 ae139e8a John Giannelos
        for res in result.errors:
1498 ae139e8a John Giannelos
            error.write(str(res[0])+'\n')
1499 ae139e8a John Giannelos
            error.write(str(res[0].__doc__) + '\n')
1500 ae139e8a John Giannelos
            error.write('\n')
1501 4d6e355c John Giannelos
1502 ae139e8a John Giannelos
            
1503 ae139e8a John Giannelos
        fail.write("Testcases failures: \n\n")
1504 4d6e355c John Giannelos
        for res in result.failures:
1505 4d6e355c John Giannelos
            fail.write(str(res[0])+'\n')
1506 6207533f John Giannelos
            fail.write(str(res[0].__doc__) + '\n')
1507 4d6e355c John Giannelos
            fail.write('\n')
1508 4d6e355c John Giannelos
        
1509 99d41650 John Giannelos
1510 5a140b23 Vangelis Koukis
1511 5a140b23 Vangelis Koukis
if __name__ == "__main__":
1512 5a140b23 Vangelis Koukis
    sys.exit(main())