Statistics
| Branch: | Tag: | Revision:

root / ci / utils.py @ 0a83201b

History | View | Annotate | Download (40.1 kB)

1 09f7ad00 Ilias Tsitsimpis
#!/usr/bin/env python
2 c29ac11d Ilias Tsitsimpis
3 c29ac11d Ilias Tsitsimpis
"""
4 c29ac11d Ilias Tsitsimpis
Synnefo ci utils module
5 c29ac11d Ilias Tsitsimpis
"""
6 c29ac11d Ilias Tsitsimpis
7 c29ac11d Ilias Tsitsimpis
import os
8 ad21ffa9 Ilias Tsitsimpis
import re
9 c29ac11d Ilias Tsitsimpis
import sys
10 c29ac11d Ilias Tsitsimpis
import time
11 c29ac11d Ilias Tsitsimpis
import logging
12 c29ac11d Ilias Tsitsimpis
import fabric.api as fabric
13 b69b55ca Christos Stavrakakis
import subprocess
14 88e6558b Christos Stavrakakis
import tempfile
15 329705c8 Ilias Tsitsimpis
from ConfigParser import ConfigParser, DuplicateSectionError
16 c29ac11d Ilias Tsitsimpis
17 c1b1d444 Christos Stavrakakis
from kamaki.cli import config as kamaki_config
18 ee6eff28 Ilias Tsitsimpis
from kamaki.clients.astakos import AstakosClient, parse_endpoints
19 94c89c0e Ilias Tsitsimpis
from kamaki.clients.cyclades import CycladesClient, CycladesNetworkClient
20 c29ac11d Ilias Tsitsimpis
from kamaki.clients.image import ImageClient
21 ad21ffa9 Ilias Tsitsimpis
from kamaki.clients.compute import ComputeClient
22 62fcf0e5 Ilias Tsitsimpis
import filelocker
23 c29ac11d Ilias Tsitsimpis
24 7585f464 Ilias Tsitsimpis
DEFAULT_CONFIG_FILE = "ci_wheezy.conf"
25 106659f1 Ilias Tsitsimpis
# Is our terminal a colorful one?
26 106659f1 Ilias Tsitsimpis
USE_COLORS = True
27 62f3f54f Ilias Tsitsimpis
# UUID of owner of system images
28 62f3f54f Ilias Tsitsimpis
DEFAULT_SYSTEM_IMAGES_UUID = [
29 62f3f54f Ilias Tsitsimpis
    "25ecced9-bf53-4145-91ee-cf47377e9fb2",  # production (okeanos.grnet.gr)
30 62f3f54f Ilias Tsitsimpis
    "04cbe33f-29b7-4ef1-94fb-015929e5fc06",  # testing (okeanos.io)
31 905bb10b Christos Stavrakakis
]
32 6ca8f81a Christos Stavrakakis
33 c29ac11d Ilias Tsitsimpis
34 c29ac11d Ilias Tsitsimpis
def _run(cmd, verbose):
35 c29ac11d Ilias Tsitsimpis
    """Run fabric with verbose level"""
36 c29ac11d Ilias Tsitsimpis
    if verbose:
37 c29ac11d Ilias Tsitsimpis
        args = ('running',)
38 c29ac11d Ilias Tsitsimpis
    else:
39 c29ac11d Ilias Tsitsimpis
        args = ('running', 'stdout',)
40 e2a0abb8 Ilias Tsitsimpis
    with fabric.hide(*args):  # Used * or ** magic. pylint: disable-msg=W0142
41 c29ac11d Ilias Tsitsimpis
        return fabric.run(cmd)
42 c29ac11d Ilias Tsitsimpis
43 c29ac11d Ilias Tsitsimpis
44 6868804a Ilias Tsitsimpis
def _put(local, remote):
45 6868804a Ilias Tsitsimpis
    """Run fabric put command without output"""
46 6868804a Ilias Tsitsimpis
    with fabric.quiet():
47 6868804a Ilias Tsitsimpis
        fabric.put(local, remote)
48 6868804a Ilias Tsitsimpis
49 6868804a Ilias Tsitsimpis
50 c29ac11d Ilias Tsitsimpis
def _red(msg):
51 c29ac11d Ilias Tsitsimpis
    """Red color"""
52 106659f1 Ilias Tsitsimpis
    ret = "\x1b[31m" + str(msg) + "\x1b[0m" if USE_COLORS else str(msg)
53 106659f1 Ilias Tsitsimpis
    return ret
54 c29ac11d Ilias Tsitsimpis
55 c29ac11d Ilias Tsitsimpis
56 c29ac11d Ilias Tsitsimpis
def _yellow(msg):
57 c29ac11d Ilias Tsitsimpis
    """Yellow color"""
58 106659f1 Ilias Tsitsimpis
    ret = "\x1b[33m" + str(msg) + "\x1b[0m" if USE_COLORS else str(msg)
59 106659f1 Ilias Tsitsimpis
    return ret
60 c29ac11d Ilias Tsitsimpis
61 c29ac11d Ilias Tsitsimpis
62 c29ac11d Ilias Tsitsimpis
def _green(msg):
63 c29ac11d Ilias Tsitsimpis
    """Green color"""
64 106659f1 Ilias Tsitsimpis
    ret = "\x1b[32m" + str(msg) + "\x1b[0m" if USE_COLORS else str(msg)
65 106659f1 Ilias Tsitsimpis
    return ret
66 c29ac11d Ilias Tsitsimpis
67 c29ac11d Ilias Tsitsimpis
68 c29ac11d Ilias Tsitsimpis
def _check_fabric(fun):
69 c29ac11d Ilias Tsitsimpis
    """Check if fabric env has been set"""
70 43a22402 Christos Stavrakakis
    def wrapper(self, *args, **kwargs):
71 c29ac11d Ilias Tsitsimpis
        """wrapper function"""
72 c29ac11d Ilias Tsitsimpis
        if not self.fabric_installed:
73 c29ac11d Ilias Tsitsimpis
            self.setup_fabric()
74 6c3cc77e Ilias Tsitsimpis
            self.fabric_installed = True
75 43a22402 Christos Stavrakakis
        return fun(self, *args, **kwargs)
76 c29ac11d Ilias Tsitsimpis
    return wrapper
77 c29ac11d Ilias Tsitsimpis
78 c29ac11d Ilias Tsitsimpis
79 c29ac11d Ilias Tsitsimpis
def _check_kamaki(fun):
80 c29ac11d Ilias Tsitsimpis
    """Check if kamaki has been initialized"""
81 43a22402 Christos Stavrakakis
    def wrapper(self, *args, **kwargs):
82 c29ac11d Ilias Tsitsimpis
        """wrapper function"""
83 c29ac11d Ilias Tsitsimpis
        if not self.kamaki_installed:
84 c29ac11d Ilias Tsitsimpis
            self.setup_kamaki()
85 6c3cc77e Ilias Tsitsimpis
            self.kamaki_installed = True
86 43a22402 Christos Stavrakakis
        return fun(self, *args, **kwargs)
87 c29ac11d Ilias Tsitsimpis
    return wrapper
88 c29ac11d Ilias Tsitsimpis
89 c29ac11d Ilias Tsitsimpis
90 c29ac11d Ilias Tsitsimpis
class _MyFormatter(logging.Formatter):
91 c29ac11d Ilias Tsitsimpis
    """Logging Formatter"""
92 c29ac11d Ilias Tsitsimpis
    def format(self, record):
93 c29ac11d Ilias Tsitsimpis
        format_orig = self._fmt
94 c29ac11d Ilias Tsitsimpis
        if record.levelno == logging.DEBUG:
95 94c89c0e Ilias Tsitsimpis
            self._fmt = "  %(message)s"
96 c29ac11d Ilias Tsitsimpis
        elif record.levelno == logging.INFO:
97 94c89c0e Ilias Tsitsimpis
            self._fmt = "%(message)s"
98 c29ac11d Ilias Tsitsimpis
        elif record.levelno == logging.WARNING:
99 94c89c0e Ilias Tsitsimpis
            self._fmt = _yellow("[W] %(message)s")
100 c29ac11d Ilias Tsitsimpis
        elif record.levelno == logging.ERROR:
101 94c89c0e Ilias Tsitsimpis
            self._fmt = _red("[E] %(message)s")
102 c29ac11d Ilias Tsitsimpis
        result = logging.Formatter.format(self, record)
103 c29ac11d Ilias Tsitsimpis
        self._fmt = format_orig
104 c29ac11d Ilias Tsitsimpis
        return result
105 c29ac11d Ilias Tsitsimpis
106 c29ac11d Ilias Tsitsimpis
107 56ee1bbc Ilias Tsitsimpis
# Too few public methods. pylint: disable-msg=R0903
108 56ee1bbc Ilias Tsitsimpis
class _InfoFilter(logging.Filter):
109 56ee1bbc Ilias Tsitsimpis
    """Logging Filter that allows DEBUG and INFO messages only"""
110 56ee1bbc Ilias Tsitsimpis
    def filter(self, rec):
111 56ee1bbc Ilias Tsitsimpis
        """The filter"""
112 56ee1bbc Ilias Tsitsimpis
        return rec.levelno in (logging.DEBUG, logging.INFO)
113 56ee1bbc Ilias Tsitsimpis
114 56ee1bbc Ilias Tsitsimpis
115 56ee1bbc Ilias Tsitsimpis
# Too many instance attributes. pylint: disable-msg=R0902
116 c29ac11d Ilias Tsitsimpis
class SynnefoCI(object):
117 c29ac11d Ilias Tsitsimpis
    """SynnefoCI python class"""
118 c29ac11d Ilias Tsitsimpis
119 79144a72 Ilias Tsitsimpis
    def __init__(self, config_file=None, build_id=None, cloud=None):
120 c29ac11d Ilias Tsitsimpis
        """ Initialize SynnefoCI python class
121 c29ac11d Ilias Tsitsimpis

122 c29ac11d Ilias Tsitsimpis
        Setup logger, local_dir, config and kamaki
123 c29ac11d Ilias Tsitsimpis
        """
124 c29ac11d Ilias Tsitsimpis
        # Setup logger
125 c29ac11d Ilias Tsitsimpis
        self.logger = logging.getLogger('synnefo-ci')
126 c29ac11d Ilias Tsitsimpis
        self.logger.setLevel(logging.DEBUG)
127 56ee1bbc Ilias Tsitsimpis
128 56ee1bbc Ilias Tsitsimpis
        handler1 = logging.StreamHandler(sys.stdout)
129 56ee1bbc Ilias Tsitsimpis
        handler1.setLevel(logging.DEBUG)
130 56ee1bbc Ilias Tsitsimpis
        handler1.addFilter(_InfoFilter())
131 56ee1bbc Ilias Tsitsimpis
        handler1.setFormatter(_MyFormatter())
132 56ee1bbc Ilias Tsitsimpis
        handler2 = logging.StreamHandler(sys.stderr)
133 56ee1bbc Ilias Tsitsimpis
        handler2.setLevel(logging.WARNING)
134 56ee1bbc Ilias Tsitsimpis
        handler2.setFormatter(_MyFormatter())
135 56ee1bbc Ilias Tsitsimpis
136 56ee1bbc Ilias Tsitsimpis
        self.logger.addHandler(handler1)
137 56ee1bbc Ilias Tsitsimpis
        self.logger.addHandler(handler2)
138 c29ac11d Ilias Tsitsimpis
139 c29ac11d Ilias Tsitsimpis
        # Get our local dir
140 c29ac11d Ilias Tsitsimpis
        self.ci_dir = os.path.dirname(os.path.abspath(__file__))
141 c29ac11d Ilias Tsitsimpis
        self.repo_dir = os.path.dirname(self.ci_dir)
142 c29ac11d Ilias Tsitsimpis
143 c29ac11d Ilias Tsitsimpis
        # Read config file
144 6ca8f81a Christos Stavrakakis
        if config_file is None:
145 2c4a641b Ilias Tsitsimpis
            config_file = os.path.join(self.ci_dir, DEFAULT_CONFIG_FILE)
146 2c4a641b Ilias Tsitsimpis
        config_file = os.path.abspath(config_file)
147 c29ac11d Ilias Tsitsimpis
        self.config = ConfigParser()
148 c29ac11d Ilias Tsitsimpis
        self.config.optionxform = str
149 6ca8f81a Christos Stavrakakis
        self.config.read(config_file)
150 79144a72 Ilias Tsitsimpis
151 79144a72 Ilias Tsitsimpis
        # Read temporary_config file
152 62fcf0e5 Ilias Tsitsimpis
        self.temp_config_file = \
153 62fcf0e5 Ilias Tsitsimpis
            os.path.expanduser(self.config.get('Global', 'temporary_config'))
154 79144a72 Ilias Tsitsimpis
        self.temp_config = ConfigParser()
155 79144a72 Ilias Tsitsimpis
        self.temp_config.optionxform = str
156 62fcf0e5 Ilias Tsitsimpis
        self.temp_config.read(self.temp_config_file)
157 b7496c88 Ilias Tsitsimpis
        self.build_id = build_id
158 99d39120 Ilias Tsitsimpis
        if build_id is not None:
159 99d39120 Ilias Tsitsimpis
            self.logger.info("Will use \"%s\" as build id" %
160 99d39120 Ilias Tsitsimpis
                             _green(self.build_id))
161 c29ac11d Ilias Tsitsimpis
162 c1b1d444 Christos Stavrakakis
        # Set kamaki cloud
163 c1b1d444 Christos Stavrakakis
        if cloud is not None:
164 c1b1d444 Christos Stavrakakis
            self.kamaki_cloud = cloud
165 c1b1d444 Christos Stavrakakis
        elif self.config.has_option("Deployment", "kamaki_cloud"):
166 c1b1d444 Christos Stavrakakis
            kamaki_cloud = self.config.get("Deployment", "kamaki_cloud")
167 c1b1d444 Christos Stavrakakis
            if kamaki_cloud == "":
168 c1b1d444 Christos Stavrakakis
                self.kamaki_cloud = None
169 c1b1d444 Christos Stavrakakis
        else:
170 c1b1d444 Christos Stavrakakis
            self.kamaki_cloud = None
171 c1b1d444 Christos Stavrakakis
172 c29ac11d Ilias Tsitsimpis
        # Initialize variables
173 c29ac11d Ilias Tsitsimpis
        self.fabric_installed = False
174 c29ac11d Ilias Tsitsimpis
        self.kamaki_installed = False
175 c29ac11d Ilias Tsitsimpis
        self.cyclades_client = None
176 94c89c0e Ilias Tsitsimpis
        self.network_client = None
177 ad21ffa9 Ilias Tsitsimpis
        self.compute_client = None
178 c29ac11d Ilias Tsitsimpis
        self.image_client = None
179 694c79bb Ilias Tsitsimpis
        self.astakos_client = None
180 c29ac11d Ilias Tsitsimpis
181 c29ac11d Ilias Tsitsimpis
    def setup_kamaki(self):
182 c29ac11d Ilias Tsitsimpis
        """Initialize kamaki
183 c29ac11d Ilias Tsitsimpis

184 ad21ffa9 Ilias Tsitsimpis
        Setup cyclades_client, image_client and compute_client
185 c29ac11d Ilias Tsitsimpis
        """
186 c1b1d444 Christos Stavrakakis
187 c1b1d444 Christos Stavrakakis
        config = kamaki_config.Config()
188 c1b1d444 Christos Stavrakakis
        if self.kamaki_cloud is None:
189 84d2db4f Ilias Tsitsimpis
            try:
190 84d2db4f Ilias Tsitsimpis
                self.kamaki_cloud = config.get("global", "default_cloud")
191 84d2db4f Ilias Tsitsimpis
            except AttributeError:
192 84d2db4f Ilias Tsitsimpis
                # Compatibility with kamaki version <=0.10
193 94c89c0e Ilias Tsitsimpis
                self.kamaki_cloud = config.get("global", "default_cloud")
194 c1b1d444 Christos Stavrakakis
195 c1b1d444 Christos Stavrakakis
        self.logger.info("Setup kamaki client, using cloud '%s'.." %
196 c1b1d444 Christos Stavrakakis
                         self.kamaki_cloud)
197 c1b1d444 Christos Stavrakakis
        auth_url = config.get_cloud(self.kamaki_cloud, "url")
198 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Authentication URL is %s" % _green(auth_url))
199 c1b1d444 Christos Stavrakakis
        token = config.get_cloud(self.kamaki_cloud, "token")
200 c29ac11d Ilias Tsitsimpis
        #self.logger.debug("Token is %s" % _green(token))
201 c29ac11d Ilias Tsitsimpis
202 ee6eff28 Ilias Tsitsimpis
        self.astakos_client = AstakosClient(auth_url, token)
203 ee6eff28 Ilias Tsitsimpis
        endpoints = self.astakos_client.authenticate()
204 c29ac11d Ilias Tsitsimpis
205 ee6eff28 Ilias Tsitsimpis
        cyclades_url = get_endpoint_url(endpoints, "compute")
206 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Cyclades API url is %s" % _green(cyclades_url))
207 c29ac11d Ilias Tsitsimpis
        self.cyclades_client = CycladesClient(cyclades_url, token)
208 c29ac11d Ilias Tsitsimpis
        self.cyclades_client.CONNECTION_RETRY_LIMIT = 2
209 c29ac11d Ilias Tsitsimpis
210 ee6eff28 Ilias Tsitsimpis
        network_url = get_endpoint_url(endpoints, "network")
211 94c89c0e Ilias Tsitsimpis
        self.logger.debug("Network API url is %s" % _green(network_url))
212 94c89c0e Ilias Tsitsimpis
        self.network_client = CycladesNetworkClient(network_url, token)
213 94c89c0e Ilias Tsitsimpis
        self.network_client.CONNECTION_RETRY_LIMIT = 2
214 94c89c0e Ilias Tsitsimpis
215 ee6eff28 Ilias Tsitsimpis
        image_url = get_endpoint_url(endpoints, "image")
216 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Images API url is %s" % _green(image_url))
217 c29ac11d Ilias Tsitsimpis
        self.image_client = ImageClient(cyclades_url, token)
218 c29ac11d Ilias Tsitsimpis
        self.image_client.CONNECTION_RETRY_LIMIT = 2
219 c29ac11d Ilias Tsitsimpis
220 ee6eff28 Ilias Tsitsimpis
        compute_url = get_endpoint_url(endpoints, "compute")
221 ad21ffa9 Ilias Tsitsimpis
        self.logger.debug("Compute API url is %s" % _green(compute_url))
222 ad21ffa9 Ilias Tsitsimpis
        self.compute_client = ComputeClient(compute_url, token)
223 ad21ffa9 Ilias Tsitsimpis
        self.compute_client.CONNECTION_RETRY_LIMIT = 2
224 ad21ffa9 Ilias Tsitsimpis
225 c29ac11d Ilias Tsitsimpis
    def _wait_transition(self, server_id, current_status, new_status):
226 c29ac11d Ilias Tsitsimpis
        """Wait for server to go from current_status to new_status"""
227 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Waiting for server to become %s" % new_status)
228 c29ac11d Ilias Tsitsimpis
        timeout = self.config.getint('Global', 'build_timeout')
229 c29ac11d Ilias Tsitsimpis
        sleep_time = 5
230 c29ac11d Ilias Tsitsimpis
        while True:
231 c29ac11d Ilias Tsitsimpis
            server = self.cyclades_client.get_server_details(server_id)
232 c29ac11d Ilias Tsitsimpis
            if server['status'] == new_status:
233 c29ac11d Ilias Tsitsimpis
                return server
234 c29ac11d Ilias Tsitsimpis
            elif timeout < 0:
235 c29ac11d Ilias Tsitsimpis
                self.logger.error(
236 c29ac11d Ilias Tsitsimpis
                    "Waiting for server to become %s timed out" % new_status)
237 c29ac11d Ilias Tsitsimpis
                self.destroy_server(False)
238 99d39120 Ilias Tsitsimpis
                sys.exit(1)
239 c29ac11d Ilias Tsitsimpis
            elif server['status'] == current_status:
240 c29ac11d Ilias Tsitsimpis
                # Sleep for #n secs and continue
241 c29ac11d Ilias Tsitsimpis
                timeout = timeout - sleep_time
242 c29ac11d Ilias Tsitsimpis
                time.sleep(sleep_time)
243 c29ac11d Ilias Tsitsimpis
            else:
244 c29ac11d Ilias Tsitsimpis
                self.logger.error(
245 c29ac11d Ilias Tsitsimpis
                    "Server failed with status %s" % server['status'])
246 c29ac11d Ilias Tsitsimpis
                self.destroy_server(False)
247 99d39120 Ilias Tsitsimpis
                sys.exit(1)
248 c29ac11d Ilias Tsitsimpis
249 c29ac11d Ilias Tsitsimpis
    @_check_kamaki
250 c29ac11d Ilias Tsitsimpis
    def destroy_server(self, wait=True):
251 c29ac11d Ilias Tsitsimpis
        """Destroy slave server"""
252 b7496c88 Ilias Tsitsimpis
        server_id = int(self.read_temp_config('server_id'))
253 9dc74d37 Ilias Tsitsimpis
        fips = [f for f in self.network_client.list_floatingips()
254 9dc74d37 Ilias Tsitsimpis
                if str(f['instance_id']) == str(server_id)]
255 c29ac11d Ilias Tsitsimpis
        self.logger.info("Destoying server with id %s " % server_id)
256 c29ac11d Ilias Tsitsimpis
        self.cyclades_client.delete_server(server_id)
257 c29ac11d Ilias Tsitsimpis
        if wait:
258 c29ac11d Ilias Tsitsimpis
            self._wait_transition(server_id, "ACTIVE", "DELETED")
259 9dc74d37 Ilias Tsitsimpis
        for fip in fips:
260 9dc74d37 Ilias Tsitsimpis
            self.logger.info("Destroying floating ip %s",
261 9dc74d37 Ilias Tsitsimpis
                             fip['floating_ip_address'])
262 9dc74d37 Ilias Tsitsimpis
            self.network_client.delete_floatingip(fip['id'])
263 c29ac11d Ilias Tsitsimpis
264 94c89c0e Ilias Tsitsimpis
    def _create_floating_ip(self):
265 94c89c0e Ilias Tsitsimpis
        """Create a new floating ip"""
266 94c89c0e Ilias Tsitsimpis
        networks = self.network_client.list_networks(detail=True)
267 94c89c0e Ilias Tsitsimpis
        pub_net = [n for n in networks
268 94c89c0e Ilias Tsitsimpis
                   if n['SNF:floating_ip_pool'] and n['public']]
269 94c89c0e Ilias Tsitsimpis
        pub_net = pub_net[0]
270 94c89c0e Ilias Tsitsimpis
        fip = self.network_client.create_floatingip(pub_net['id'])
271 94c89c0e Ilias Tsitsimpis
        self.logger.debug("Floating IP %s with id %s created",
272 94c89c0e Ilias Tsitsimpis
                          fip['floating_ip_address'], fip['id'])
273 94c89c0e Ilias Tsitsimpis
        return fip
274 94c89c0e Ilias Tsitsimpis
275 94c89c0e Ilias Tsitsimpis
    def _create_port(self, floating_ip):
276 94c89c0e Ilias Tsitsimpis
        """Create a new port for our floating IP"""
277 94c89c0e Ilias Tsitsimpis
        net_id = floating_ip['floating_network_id']
278 94c89c0e Ilias Tsitsimpis
        self.logger.debug("Creating a new port to network with id %s", net_id)
279 94c89c0e Ilias Tsitsimpis
        fixed_ips = [{'ip_address': floating_ip['floating_ip_address']}]
280 94c89c0e Ilias Tsitsimpis
        port = self.network_client.create_port(
281 94c89c0e Ilias Tsitsimpis
            net_id, device_id=None, fixed_ips=fixed_ips)
282 94c89c0e Ilias Tsitsimpis
        return port
283 94c89c0e Ilias Tsitsimpis
284 c29ac11d Ilias Tsitsimpis
    @_check_kamaki
285 ee6eff28 Ilias Tsitsimpis
    # Too many local variables. pylint: disable-msg=R0914
286 2945e7ed Christos Stavrakakis
    def create_server(self, image=None, flavor=None, ssh_keys=None,
287 2945e7ed Christos Stavrakakis
                      server_name=None):
288 c29ac11d Ilias Tsitsimpis
        """Create slave server"""
289 c29ac11d Ilias Tsitsimpis
        self.logger.info("Create a new server..")
290 b7496c88 Ilias Tsitsimpis
291 b7496c88 Ilias Tsitsimpis
        # Find a build_id to use
292 c7828946 Ilias Tsitsimpis
        self._create_new_build_id()
293 b7496c88 Ilias Tsitsimpis
294 b7496c88 Ilias Tsitsimpis
        # Find an image to use
295 358a19bc Ilias Tsitsimpis
        image_id = self._find_image(image)
296 b7496c88 Ilias Tsitsimpis
        # Find a flavor to use
297 358a19bc Ilias Tsitsimpis
        flavor_id = self._find_flavor(flavor)
298 358a19bc Ilias Tsitsimpis
299 358a19bc Ilias Tsitsimpis
        # Create Server
300 0368716b Christos Stavrakakis
        networks = []
301 0368716b Christos Stavrakakis
        if self.config.get("Deployment", "allocate_floating_ip") == "True":
302 0368716b Christos Stavrakakis
            fip = self._create_floating_ip()
303 0368716b Christos Stavrakakis
            port = self._create_port(fip)
304 0368716b Christos Stavrakakis
            networks.append({'port': port['id']})
305 0368716b Christos Stavrakakis
        private_networks = self.config.get('Deployment', 'private_networks')
306 0368716b Christos Stavrakakis
        if private_networks:
307 bbc826ca Ilias Tsitsimpis
            private_networks = [p.strip() for p in private_networks.split(",")]
308 bbc826ca Ilias Tsitsimpis
            networks.extend([{"uuid": uuid} for uuid in private_networks])
309 2945e7ed Christos Stavrakakis
        if server_name is None:
310 2945e7ed Christos Stavrakakis
            server_name = self.config.get("Deployment", "server_name")
311 2945e7ed Christos Stavrakakis
            server_name = "%s(BID: %s)" % (server_name, self.build_id)
312 94c89c0e Ilias Tsitsimpis
        server = self.cyclades_client.create_server(
313 94c89c0e Ilias Tsitsimpis
            server_name, flavor_id, image_id, networks=networks)
314 c29ac11d Ilias Tsitsimpis
        server_id = server['id']
315 b7496c88 Ilias Tsitsimpis
        self.write_temp_config('server_id', server_id)
316 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Server got id %s" % _green(server_id))
317 c29ac11d Ilias Tsitsimpis
        server_user = server['metadata']['users']
318 b7496c88 Ilias Tsitsimpis
        self.write_temp_config('server_user', server_user)
319 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Server's admin user is %s" % _green(server_user))
320 c29ac11d Ilias Tsitsimpis
        server_passwd = server['adminPass']
321 b7496c88 Ilias Tsitsimpis
        self.write_temp_config('server_passwd', server_passwd)
322 c29ac11d Ilias Tsitsimpis
323 c29ac11d Ilias Tsitsimpis
        server = self._wait_transition(server_id, "BUILD", "ACTIVE")
324 bbc826ca Ilias Tsitsimpis
        self._get_server_ip_and_port(server, private_networks)
325 6868804a Ilias Tsitsimpis
        self._copy_ssh_keys(ssh_keys)
326 c29ac11d Ilias Tsitsimpis
327 6c3cc77e Ilias Tsitsimpis
        # Setup Firewall
328 c29ac11d Ilias Tsitsimpis
        self.setup_fabric()
329 c29ac11d Ilias Tsitsimpis
        self.logger.info("Setup firewall")
330 6868804a Ilias Tsitsimpis
        accept_ssh_from = self.config.get('Global', 'accept_ssh_from')
331 1c75c4dd Christos Stavrakakis
        if accept_ssh_from != "":
332 1c75c4dd Christos Stavrakakis
            self.logger.debug("Block ssh except from %s" % accept_ssh_from)
333 1c75c4dd Christos Stavrakakis
            cmd = """
334 1c75c4dd Christos Stavrakakis
            local_ip=$(/sbin/ifconfig eth0 | grep 'inet addr:' | \
335 1c75c4dd Christos Stavrakakis
                cut -d':' -f2 | cut -d' ' -f1)
336 1c75c4dd Christos Stavrakakis
            iptables -A INPUT -s localhost -j ACCEPT
337 1c75c4dd Christos Stavrakakis
            iptables -A INPUT -s $local_ip -j ACCEPT
338 1c75c4dd Christos Stavrakakis
            iptables -A INPUT -s {0} -p tcp --dport 22 -j ACCEPT
339 1c75c4dd Christos Stavrakakis
            iptables -A INPUT -p tcp --dport 22 -j DROP
340 1c75c4dd Christos Stavrakakis
            """.format(accept_ssh_from)
341 1c75c4dd Christos Stavrakakis
            _run(cmd, False)
342 c29ac11d Ilias Tsitsimpis
343 6c3cc77e Ilias Tsitsimpis
        # Setup apt, download packages
344 6c3cc77e Ilias Tsitsimpis
        self.logger.debug("Setup apt. Install x2goserver and firefox")
345 6c3cc77e Ilias Tsitsimpis
        cmd = """
346 6c3cc77e Ilias Tsitsimpis
        echo 'APT::Install-Suggests "false";' >> /etc/apt/apt.conf
347 a7d32e21 Ilias Tsitsimpis
        echo 'precedence ::ffff:0:0/96  100' >> /etc/gai.conf
348 6c3cc77e Ilias Tsitsimpis
        apt-get update
349 71f2649f Ilias Tsitsimpis
        apt-get install curl --yes --force-yes
350 6c3cc77e Ilias Tsitsimpis
        echo -e "\n\n{0}" >> /etc/apt/sources.list
351 6c3cc77e Ilias Tsitsimpis
        # Synnefo repo's key
352 6c3cc77e Ilias Tsitsimpis
        curl https://dev.grnet.gr/files/apt-grnetdev.pub | apt-key add -
353 8ddb541b Ilias Tsitsimpis

354 6c3cc77e Ilias Tsitsimpis
        # X2GO Key
355 6c3cc77e Ilias Tsitsimpis
        apt-key adv --recv-keys --keyserver keys.gnupg.net E1F958385BFE2B6E
356 71f2649f Ilias Tsitsimpis
        apt-get install x2go-keyring --yes --force-yes
357 6c3cc77e Ilias Tsitsimpis
        apt-get update
358 71f2649f Ilias Tsitsimpis
        apt-get install x2goserver x2goserver-xsession \
359 71f2649f Ilias Tsitsimpis
                iceweasel --yes --force-yes
360 8ddb541b Ilias Tsitsimpis

361 8ddb541b Ilias Tsitsimpis
        # xterm published application
362 8ddb541b Ilias Tsitsimpis
        echo '[Desktop Entry]' > /usr/share/applications/xterm.desktop
363 8ddb541b Ilias Tsitsimpis
        echo 'Name=XTerm' >> /usr/share/applications/xterm.desktop
364 8ddb541b Ilias Tsitsimpis
        echo 'Comment=standard terminal emulator for the X window system' >> \
365 8ddb541b Ilias Tsitsimpis
            /usr/share/applications/xterm.desktop
366 8ddb541b Ilias Tsitsimpis
        echo 'Exec=xterm' >> /usr/share/applications/xterm.desktop
367 8ddb541b Ilias Tsitsimpis
        echo 'Terminal=false' >> /usr/share/applications/xterm.desktop
368 8ddb541b Ilias Tsitsimpis
        echo 'Type=Application' >> /usr/share/applications/xterm.desktop
369 8ddb541b Ilias Tsitsimpis
        echo 'Encoding=UTF-8' >> /usr/share/applications/xterm.desktop
370 8ddb541b Ilias Tsitsimpis
        echo 'Icon=xterm-color_48x48' >> /usr/share/applications/xterm.desktop
371 8ddb541b Ilias Tsitsimpis
        echo 'Categories=System;TerminalEmulator;' >> \
372 8ddb541b Ilias Tsitsimpis
                /usr/share/applications/xterm.desktop
373 6c3cc77e Ilias Tsitsimpis
        """.format(self.config.get('Global', 'apt_repo'))
374 6c3cc77e Ilias Tsitsimpis
        _run(cmd, False)
375 6c3cc77e Ilias Tsitsimpis
376 358a19bc Ilias Tsitsimpis
    def _find_flavor(self, flavor=None):
377 358a19bc Ilias Tsitsimpis
        """Find a suitable flavor to use
378 358a19bc Ilias Tsitsimpis

379 358a19bc Ilias Tsitsimpis
        Search by name (reg expression) or by id
380 358a19bc Ilias Tsitsimpis
        """
381 358a19bc Ilias Tsitsimpis
        # Get a list of flavors from config file
382 358a19bc Ilias Tsitsimpis
        flavors = self.config.get('Deployment', 'flavors').split(",")
383 358a19bc Ilias Tsitsimpis
        if flavor is not None:
384 a8bfeffc Ilias Tsitsimpis
            # If we have a flavor_name to use, add it to our list
385 358a19bc Ilias Tsitsimpis
            flavors.insert(0, flavor)
386 358a19bc Ilias Tsitsimpis
387 358a19bc Ilias Tsitsimpis
        list_flavors = self.compute_client.list_flavors()
388 358a19bc Ilias Tsitsimpis
        for flv in flavors:
389 905bb10b Christos Stavrakakis
            flv_type, flv_value = parse_typed_option(option="flavor",
390 905bb10b Christos Stavrakakis
                                                     value=flv)
391 358a19bc Ilias Tsitsimpis
            if flv_type == "name":
392 358a19bc Ilias Tsitsimpis
                # Filter flavors by name
393 358a19bc Ilias Tsitsimpis
                self.logger.debug(
394 358a19bc Ilias Tsitsimpis
                    "Trying to find a flavor with name \"%s\"" % flv_value)
395 358a19bc Ilias Tsitsimpis
                list_flvs = \
396 358a19bc Ilias Tsitsimpis
                    [f for f in list_flavors
397 905bb10b Christos Stavrakakis
                     if re.search(flv_value, f['name'], flags=re.I)
398 905bb10b Christos Stavrakakis
                     is not None]
399 358a19bc Ilias Tsitsimpis
            elif flv_type == "id":
400 358a19bc Ilias Tsitsimpis
                # Filter flavors by id
401 358a19bc Ilias Tsitsimpis
                self.logger.debug(
402 358a19bc Ilias Tsitsimpis
                    "Trying to find a flavor with id \"%s\"" % flv_value)
403 358a19bc Ilias Tsitsimpis
                list_flvs = \
404 358a19bc Ilias Tsitsimpis
                    [f for f in list_flavors
405 694c79bb Ilias Tsitsimpis
                     if str(f['id']) == flv_value]
406 358a19bc Ilias Tsitsimpis
            else:
407 358a19bc Ilias Tsitsimpis
                self.logger.error("Unrecognized flavor type %s" % flv_type)
408 358a19bc Ilias Tsitsimpis
409 358a19bc Ilias Tsitsimpis
            # Check if we found one
410 358a19bc Ilias Tsitsimpis
            if list_flvs:
411 358a19bc Ilias Tsitsimpis
                self.logger.debug("Will use \"%s\" with id \"%s\""
412 106659f1 Ilias Tsitsimpis
                                  % (_green(list_flvs[0]['name']),
413 106659f1 Ilias Tsitsimpis
                                     _green(list_flvs[0]['id'])))
414 358a19bc Ilias Tsitsimpis
                return list_flvs[0]['id']
415 a8bfeffc Ilias Tsitsimpis
416 a8bfeffc Ilias Tsitsimpis
        self.logger.error("No matching flavor found.. aborting")
417 a8bfeffc Ilias Tsitsimpis
        sys.exit(1)
418 ad21ffa9 Ilias Tsitsimpis
419 358a19bc Ilias Tsitsimpis
    def _find_image(self, image=None):
420 c29ac11d Ilias Tsitsimpis
        """Find a suitable image to use
421 c29ac11d Ilias Tsitsimpis

422 358a19bc Ilias Tsitsimpis
        In case of search by name, the image has to belong to one
423 358a19bc Ilias Tsitsimpis
        of the `DEFAULT_SYSTEM_IMAGES_UUID' users.
424 358a19bc Ilias Tsitsimpis
        In case of search by id it only has to exist.
425 c29ac11d Ilias Tsitsimpis
        """
426 358a19bc Ilias Tsitsimpis
        # Get a list of images from config file
427 358a19bc Ilias Tsitsimpis
        images = self.config.get('Deployment', 'images').split(",")
428 358a19bc Ilias Tsitsimpis
        if image is not None:
429 358a19bc Ilias Tsitsimpis
            # If we have an image from command line, add it to our list
430 358a19bc Ilias Tsitsimpis
            images.insert(0, image)
431 358a19bc Ilias Tsitsimpis
432 905bb10b Christos Stavrakakis
        auth = self.astakos_client.authenticate()
433 905bb10b Christos Stavrakakis
        user_uuid = auth["access"]["token"]["tenant"]["id"]
434 358a19bc Ilias Tsitsimpis
        list_images = self.image_client.list_public(detail=True)['images']
435 358a19bc Ilias Tsitsimpis
        for img in images:
436 6958ffc6 Christos Stavrakakis
            img_type, img_value = parse_typed_option(option="image", value=img)
437 358a19bc Ilias Tsitsimpis
            if img_type == "name":
438 358a19bc Ilias Tsitsimpis
                # Filter images by name
439 358a19bc Ilias Tsitsimpis
                self.logger.debug(
440 358a19bc Ilias Tsitsimpis
                    "Trying to find an image with name \"%s\"" % img_value)
441 905bb10b Christos Stavrakakis
                accepted_uuids = DEFAULT_SYSTEM_IMAGES_UUID + [user_uuid]
442 358a19bc Ilias Tsitsimpis
                list_imgs = \
443 905bb10b Christos Stavrakakis
                    [i for i in list_images if i['user_id'] in accepted_uuids
444 905bb10b Christos Stavrakakis
                     and
445 905bb10b Christos Stavrakakis
                     re.search(img_value, i['name'], flags=re.I) is not None]
446 358a19bc Ilias Tsitsimpis
            elif img_type == "id":
447 358a19bc Ilias Tsitsimpis
                # Filter images by id
448 358a19bc Ilias Tsitsimpis
                self.logger.debug(
449 358a19bc Ilias Tsitsimpis
                    "Trying to find an image with id \"%s\"" % img_value)
450 358a19bc Ilias Tsitsimpis
                list_imgs = \
451 358a19bc Ilias Tsitsimpis
                    [i for i in list_images
452 358a19bc Ilias Tsitsimpis
                     if i['id'].lower() == img_value.lower()]
453 358a19bc Ilias Tsitsimpis
            else:
454 358a19bc Ilias Tsitsimpis
                self.logger.error("Unrecognized image type %s" % img_type)
455 358a19bc Ilias Tsitsimpis
                sys.exit(1)
456 358a19bc Ilias Tsitsimpis
457 358a19bc Ilias Tsitsimpis
            # Check if we found one
458 358a19bc Ilias Tsitsimpis
            if list_imgs:
459 358a19bc Ilias Tsitsimpis
                self.logger.debug("Will use \"%s\" with id \"%s\""
460 106659f1 Ilias Tsitsimpis
                                  % (_green(list_imgs[0]['name']),
461 106659f1 Ilias Tsitsimpis
                                     _green(list_imgs[0]['id'])))
462 358a19bc Ilias Tsitsimpis
                return list_imgs[0]['id']
463 358a19bc Ilias Tsitsimpis
464 358a19bc Ilias Tsitsimpis
        # We didn't found one
465 358a19bc Ilias Tsitsimpis
        self.logger.error("No matching image found.. aborting")
466 358a19bc Ilias Tsitsimpis
        sys.exit(1)
467 c29ac11d Ilias Tsitsimpis
468 bbc826ca Ilias Tsitsimpis
    def _get_server_ip_and_port(self, server, private_networks):
469 c29ac11d Ilias Tsitsimpis
        """Compute server's IPv4 and ssh port number"""
470 c29ac11d Ilias Tsitsimpis
        self.logger.info("Get server connection details..")
471 bbc826ca Ilias Tsitsimpis
        if private_networks:
472 bbc826ca Ilias Tsitsimpis
            # Choose the networks that belong to private_networks
473 bbc826ca Ilias Tsitsimpis
            networks = [n for n in server['attachments']
474 bbc826ca Ilias Tsitsimpis
                        if n['network_id'] in private_networks]
475 bbc826ca Ilias Tsitsimpis
        else:
476 bbc826ca Ilias Tsitsimpis
            # Choose the networks that are public
477 6be99b24 Ilias Tsitsimpis
            networks = [n for n in server['attachments']
478 6be99b24 Ilias Tsitsimpis
                        if self.network_client.
479 6be99b24 Ilias Tsitsimpis
                        get_network_details(n['network_id'])['public']]
480 bbc826ca Ilias Tsitsimpis
        # Choose the networks with IPv4
481 bbc826ca Ilias Tsitsimpis
        networks = [n for n in networks if n['ipv4']]
482 bbc826ca Ilias Tsitsimpis
        # Use the first network as IPv4
483 bbc826ca Ilias Tsitsimpis
        server_ip = networks[0]['ipv4']
484 bbc826ca Ilias Tsitsimpis
485 705f70a9 Christos Stavrakakis
        if (".okeanos.io" in self.cyclades_client.base_url or
486 705f70a9 Christos Stavrakakis
           ".demo.synnefo.org" in self.cyclades_client.base_url):
487 c29ac11d Ilias Tsitsimpis
            tmp1 = int(server_ip.split(".")[2])
488 c29ac11d Ilias Tsitsimpis
            tmp2 = int(server_ip.split(".")[3])
489 c29ac11d Ilias Tsitsimpis
            server_ip = "gate.okeanos.io"
490 c29ac11d Ilias Tsitsimpis
            server_port = 10000 + tmp1 * 256 + tmp2
491 c29ac11d Ilias Tsitsimpis
        else:
492 c29ac11d Ilias Tsitsimpis
            server_port = 22
493 b7496c88 Ilias Tsitsimpis
        self.write_temp_config('server_ip', server_ip)
494 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Server's IPv4 is %s" % _green(server_ip))
495 b7496c88 Ilias Tsitsimpis
        self.write_temp_config('server_port', server_port)
496 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Server's ssh port is %s" % _green(server_port))
497 106659f1 Ilias Tsitsimpis
        ssh_command = "ssh -p %s %s@%s" \
498 106659f1 Ilias Tsitsimpis
            % (server_port, server['metadata']['users'], server_ip)
499 106659f1 Ilias Tsitsimpis
        self.logger.debug("Access server using \"%s\"" %
500 106659f1 Ilias Tsitsimpis
                          (_green(ssh_command)))
501 c29ac11d Ilias Tsitsimpis
502 e480f0ce Christos Stavrakakis
    @_check_fabric
503 6868804a Ilias Tsitsimpis
    def _copy_ssh_keys(self, ssh_keys):
504 e2a0abb8 Ilias Tsitsimpis
        """Upload/Install ssh keys to server"""
505 4b743650 Ilias Tsitsimpis
        self.logger.debug("Check for authentication keys to use")
506 6868804a Ilias Tsitsimpis
        if ssh_keys is None:
507 6868804a Ilias Tsitsimpis
            ssh_keys = self.config.get("Deployment", "ssh_keys")
508 6868804a Ilias Tsitsimpis
509 4b743650 Ilias Tsitsimpis
        if ssh_keys != "":
510 6058ae72 Ilias Tsitsimpis
            ssh_keys = os.path.expanduser(ssh_keys)
511 106659f1 Ilias Tsitsimpis
            self.logger.debug("Will use \"%s\" authentication keys file" %
512 106659f1 Ilias Tsitsimpis
                              _green(ssh_keys))
513 e480f0ce Christos Stavrakakis
            keyfile = '/tmp/%s.pub' % fabric.env.user
514 e480f0ce Christos Stavrakakis
            _run('mkdir -p ~/.ssh && chmod 700 ~/.ssh', False)
515 4b743650 Ilias Tsitsimpis
            if ssh_keys.startswith("http://") or \
516 4b743650 Ilias Tsitsimpis
                    ssh_keys.startswith("https://") or \
517 4b743650 Ilias Tsitsimpis
                    ssh_keys.startswith("ftp://"):
518 4b743650 Ilias Tsitsimpis
                cmd = """
519 4b743650 Ilias Tsitsimpis
                apt-get update
520 71f2649f Ilias Tsitsimpis
                apt-get install wget --yes --force-yes
521 4b743650 Ilias Tsitsimpis
                wget {0} -O {1} --no-check-certificate
522 4b743650 Ilias Tsitsimpis
                """.format(ssh_keys, keyfile)
523 4b743650 Ilias Tsitsimpis
                _run(cmd, False)
524 4b743650 Ilias Tsitsimpis
            elif os.path.exists(ssh_keys):
525 4b743650 Ilias Tsitsimpis
                _put(ssh_keys, keyfile)
526 4b743650 Ilias Tsitsimpis
            else:
527 4b743650 Ilias Tsitsimpis
                self.logger.debug("No ssh keys found")
528 6058ae72 Ilias Tsitsimpis
                return
529 e480f0ce Christos Stavrakakis
            _run('cat %s >> ~/.ssh/authorized_keys' % keyfile, False)
530 e480f0ce Christos Stavrakakis
            _run('rm %s' % keyfile, False)
531 e480f0ce Christos Stavrakakis
            self.logger.debug("Uploaded ssh authorized keys")
532 e480f0ce Christos Stavrakakis
        else:
533 e480f0ce Christos Stavrakakis
            self.logger.debug("No ssh keys found")
534 e480f0ce Christos Stavrakakis
535 2cbdb63f Ilias Tsitsimpis
    def _create_new_build_id(self):
536 2cbdb63f Ilias Tsitsimpis
        """Find a uniq build_id to use"""
537 2cbdb63f Ilias Tsitsimpis
        with filelocker.lock("%s.lock" % self.temp_config_file,
538 2cbdb63f Ilias Tsitsimpis
                             filelocker.LOCK_EX):
539 2cbdb63f Ilias Tsitsimpis
            # Read temp_config again to get any new entries
540 2cbdb63f Ilias Tsitsimpis
            self.temp_config.read(self.temp_config_file)
541 2cbdb63f Ilias Tsitsimpis
542 2cbdb63f Ilias Tsitsimpis
            # Find a uniq build_id to use
543 c7828946 Ilias Tsitsimpis
            if self.build_id is None:
544 c7828946 Ilias Tsitsimpis
                ids = self.temp_config.sections()
545 c7828946 Ilias Tsitsimpis
                if ids:
546 c7828946 Ilias Tsitsimpis
                    max_id = int(max(self.temp_config.sections(), key=int))
547 c7828946 Ilias Tsitsimpis
                    self.build_id = max_id + 1
548 c7828946 Ilias Tsitsimpis
                else:
549 c7828946 Ilias Tsitsimpis
                    self.build_id = 1
550 c7828946 Ilias Tsitsimpis
            self.logger.debug("Will use \"%s\" as build id"
551 2cbdb63f Ilias Tsitsimpis
                              % _green(self.build_id))
552 2cbdb63f Ilias Tsitsimpis
553 2cbdb63f Ilias Tsitsimpis
            # Create a new section
554 329705c8 Ilias Tsitsimpis
            try:
555 329705c8 Ilias Tsitsimpis
                self.temp_config.add_section(str(self.build_id))
556 329705c8 Ilias Tsitsimpis
            except DuplicateSectionError:
557 329705c8 Ilias Tsitsimpis
                msg = ("Build id \"%s\" already in use. " +
558 329705c8 Ilias Tsitsimpis
                       "Please use a uniq one or cleanup \"%s\" file.\n") \
559 329705c8 Ilias Tsitsimpis
                    % (self.build_id, self.temp_config_file)
560 329705c8 Ilias Tsitsimpis
                self.logger.error(msg)
561 329705c8 Ilias Tsitsimpis
                sys.exit(1)
562 2cbdb63f Ilias Tsitsimpis
            creation_time = \
563 2cbdb63f Ilias Tsitsimpis
                time.strftime("%a, %d %b %Y %X", time.localtime())
564 2cbdb63f Ilias Tsitsimpis
            self.temp_config.set(str(self.build_id),
565 2cbdb63f Ilias Tsitsimpis
                                 "created", str(creation_time))
566 2cbdb63f Ilias Tsitsimpis
567 2cbdb63f Ilias Tsitsimpis
            # Write changes back to temp config file
568 2cbdb63f Ilias Tsitsimpis
            with open(self.temp_config_file, 'wb') as tcf:
569 2cbdb63f Ilias Tsitsimpis
                self.temp_config.write(tcf)
570 2cbdb63f Ilias Tsitsimpis
571 b7496c88 Ilias Tsitsimpis
    def write_temp_config(self, option, value):
572 c29ac11d Ilias Tsitsimpis
        """Write changes back to config file"""
573 62fcf0e5 Ilias Tsitsimpis
        # Acquire the lock to write to temp_config_file
574 62fcf0e5 Ilias Tsitsimpis
        with filelocker.lock("%s.lock" % self.temp_config_file,
575 62fcf0e5 Ilias Tsitsimpis
                             filelocker.LOCK_EX):
576 62fcf0e5 Ilias Tsitsimpis
577 62fcf0e5 Ilias Tsitsimpis
            # Read temp_config again to get any new entries
578 62fcf0e5 Ilias Tsitsimpis
            self.temp_config.read(self.temp_config_file)
579 62fcf0e5 Ilias Tsitsimpis
580 62fcf0e5 Ilias Tsitsimpis
            self.temp_config.set(str(self.build_id), option, str(value))
581 62fcf0e5 Ilias Tsitsimpis
            curr_time = time.strftime("%a, %d %b %Y %X", time.localtime())
582 62fcf0e5 Ilias Tsitsimpis
            self.temp_config.set(str(self.build_id), "modified", curr_time)
583 2cbdb63f Ilias Tsitsimpis
584 2cbdb63f Ilias Tsitsimpis
            # Write changes back to temp config file
585 62fcf0e5 Ilias Tsitsimpis
            with open(self.temp_config_file, 'wb') as tcf:
586 62fcf0e5 Ilias Tsitsimpis
                self.temp_config.write(tcf)
587 c29ac11d Ilias Tsitsimpis
588 b7496c88 Ilias Tsitsimpis
    def read_temp_config(self, option):
589 b7496c88 Ilias Tsitsimpis
        """Read from temporary_config file"""
590 b7496c88 Ilias Tsitsimpis
        # If build_id is None use the latest one
591 b7496c88 Ilias Tsitsimpis
        if self.build_id is None:
592 b7496c88 Ilias Tsitsimpis
            ids = self.temp_config.sections()
593 b7496c88 Ilias Tsitsimpis
            if ids:
594 b7496c88 Ilias Tsitsimpis
                self.build_id = int(ids[-1])
595 b7496c88 Ilias Tsitsimpis
            else:
596 b7496c88 Ilias Tsitsimpis
                self.logger.error("No sections in temporary config file")
597 b7496c88 Ilias Tsitsimpis
                sys.exit(1)
598 b7496c88 Ilias Tsitsimpis
            self.logger.debug("Will use \"%s\" as build id"
599 b7496c88 Ilias Tsitsimpis
                              % _green(self.build_id))
600 b7496c88 Ilias Tsitsimpis
        # Read specified option
601 b7496c88 Ilias Tsitsimpis
        return self.temp_config.get(str(self.build_id), option)
602 b7496c88 Ilias Tsitsimpis
603 c29ac11d Ilias Tsitsimpis
    def setup_fabric(self):
604 c29ac11d Ilias Tsitsimpis
        """Setup fabric environment"""
605 c29ac11d Ilias Tsitsimpis
        self.logger.info("Setup fabric parameters..")
606 b7496c88 Ilias Tsitsimpis
        fabric.env.user = self.read_temp_config('server_user')
607 b7496c88 Ilias Tsitsimpis
        fabric.env.host_string = self.read_temp_config('server_ip')
608 b7496c88 Ilias Tsitsimpis
        fabric.env.port = int(self.read_temp_config('server_port'))
609 b7496c88 Ilias Tsitsimpis
        fabric.env.password = self.read_temp_config('server_passwd')
610 c29ac11d Ilias Tsitsimpis
        fabric.env.connection_attempts = 10
611 c29ac11d Ilias Tsitsimpis
        fabric.env.shell = "/bin/bash -c"
612 c29ac11d Ilias Tsitsimpis
        fabric.env.disable_known_hosts = True
613 c29ac11d Ilias Tsitsimpis
        fabric.env.output_prefix = None
614 c29ac11d Ilias Tsitsimpis
615 c29ac11d Ilias Tsitsimpis
    def _check_hash_sum(self, localfile, remotefile):
616 c29ac11d Ilias Tsitsimpis
        """Check hash sums of two files"""
617 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Check hash sum for local file %s" % localfile)
618 c29ac11d Ilias Tsitsimpis
        hash1 = os.popen("sha256sum %s" % localfile).read().split(' ')[0]
619 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Local file has sha256 hash %s" % hash1)
620 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Check hash sum for remote file %s" % remotefile)
621 c29ac11d Ilias Tsitsimpis
        hash2 = _run("sha256sum %s" % remotefile, False)
622 c29ac11d Ilias Tsitsimpis
        hash2 = hash2.split(' ')[0]
623 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Remote file has sha256 hash %s" % hash2)
624 c29ac11d Ilias Tsitsimpis
        if hash1 != hash2:
625 c29ac11d Ilias Tsitsimpis
            self.logger.error("Hashes differ.. aborting")
626 99d39120 Ilias Tsitsimpis
            sys.exit(1)
627 c29ac11d Ilias Tsitsimpis
628 c29ac11d Ilias Tsitsimpis
    @_check_fabric
629 5323404f Ilias Tsitsimpis
    def clone_repo(self, local_repo=False):
630 c29ac11d Ilias Tsitsimpis
        """Clone Synnefo repo from slave server"""
631 c29ac11d Ilias Tsitsimpis
        self.logger.info("Configure repositories on remote server..")
632 6c3cc77e Ilias Tsitsimpis
        self.logger.debug("Install/Setup git")
633 c29ac11d Ilias Tsitsimpis
        cmd = """
634 71f2649f Ilias Tsitsimpis
        apt-get install git --yes --force-yes
635 6c3cc77e Ilias Tsitsimpis
        git config --global user.name {0}
636 6c3cc77e Ilias Tsitsimpis
        git config --global user.email {1}
637 6c3cc77e Ilias Tsitsimpis
        """.format(self.config.get('Global', 'git_config_name'),
638 c29ac11d Ilias Tsitsimpis
                   self.config.get('Global', 'git_config_mail'))
639 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
640 c29ac11d Ilias Tsitsimpis
641 99d39120 Ilias Tsitsimpis
        # Clone synnefo_repo
642 99d39120 Ilias Tsitsimpis
        synnefo_branch = self.clone_synnefo_repo(local_repo=local_repo)
643 99d39120 Ilias Tsitsimpis
        # Clone pithos-web-client
644 99d39120 Ilias Tsitsimpis
        self.clone_pithos_webclient_repo(synnefo_branch)
645 99d39120 Ilias Tsitsimpis
646 99d39120 Ilias Tsitsimpis
    @_check_fabric
647 99d39120 Ilias Tsitsimpis
    def clone_synnefo_repo(self, local_repo=False):
648 99d39120 Ilias Tsitsimpis
        """Clone Synnefo repo to remote server"""
649 5323404f Ilias Tsitsimpis
        # Find synnefo_repo and synnefo_branch to use
650 c29ac11d Ilias Tsitsimpis
        synnefo_repo = self.config.get('Global', 'synnefo_repo')
651 b69b55ca Christos Stavrakakis
        synnefo_branch = self.config.get("Global", "synnefo_branch")
652 b69b55ca Christos Stavrakakis
        if synnefo_branch == "":
653 e2a0abb8 Ilias Tsitsimpis
            synnefo_branch = \
654 e2a0abb8 Ilias Tsitsimpis
                subprocess.Popen(
655 e2a0abb8 Ilias Tsitsimpis
                    ["git", "rev-parse", "--abbrev-ref", "HEAD"],
656 b69b55ca Christos Stavrakakis
                    stdout=subprocess.PIPE).communicate()[0].strip()
657 b69b55ca Christos Stavrakakis
            if synnefo_branch == "HEAD":
658 b69b55ca Christos Stavrakakis
                synnefo_branch = \
659 e2a0abb8 Ilias Tsitsimpis
                    subprocess.Popen(
660 e2a0abb8 Ilias Tsitsimpis
                        ["git", "rev-parse", "--short", "HEAD"],
661 b69b55ca Christos Stavrakakis
                        stdout=subprocess.PIPE).communicate()[0].strip()
662 99d39120 Ilias Tsitsimpis
        self.logger.debug("Will use branch \"%s\"" % _green(synnefo_branch))
663 5323404f Ilias Tsitsimpis
664 99d39120 Ilias Tsitsimpis
        if local_repo or synnefo_repo == "":
665 5323404f Ilias Tsitsimpis
            # Use local_repo
666 5323404f Ilias Tsitsimpis
            self.logger.debug("Push local repo to server")
667 5323404f Ilias Tsitsimpis
            # Firstly create the remote repo
668 5323404f Ilias Tsitsimpis
            _run("git init synnefo", False)
669 5323404f Ilias Tsitsimpis
            # Then push our local repo over ssh
670 5323404f Ilias Tsitsimpis
            # We have to pass some arguments to ssh command
671 5323404f Ilias Tsitsimpis
            # namely to disable host checking.
672 5323404f Ilias Tsitsimpis
            (temp_ssh_file_handle, temp_ssh_file) = tempfile.mkstemp()
673 5323404f Ilias Tsitsimpis
            os.close(temp_ssh_file_handle)
674 62fcf0e5 Ilias Tsitsimpis
            # XXX: git push doesn't read the password
675 5323404f Ilias Tsitsimpis
            cmd = """
676 5323404f Ilias Tsitsimpis
            echo 'exec ssh -o "StrictHostKeyChecking no" \
677 5323404f Ilias Tsitsimpis
                           -o "UserKnownHostsFile /dev/null" \
678 5323404f Ilias Tsitsimpis
                           -q "$@"' > {4}
679 5323404f Ilias Tsitsimpis
            chmod u+x {4}
680 5323404f Ilias Tsitsimpis
            export GIT_SSH="{4}"
681 99d39120 Ilias Tsitsimpis
            echo "{0}" | git push --quiet --mirror ssh://{1}@{2}:{3}/~/synnefo
682 5323404f Ilias Tsitsimpis
            rm -f {4}
683 5323404f Ilias Tsitsimpis
            """.format(fabric.env.password,
684 5323404f Ilias Tsitsimpis
                       fabric.env.user,
685 5323404f Ilias Tsitsimpis
                       fabric.env.host_string,
686 5323404f Ilias Tsitsimpis
                       fabric.env.port,
687 5323404f Ilias Tsitsimpis
                       temp_ssh_file)
688 5323404f Ilias Tsitsimpis
            os.system(cmd)
689 5323404f Ilias Tsitsimpis
        else:
690 5323404f Ilias Tsitsimpis
            # Clone Synnefo from remote repo
691 99d39120 Ilias Tsitsimpis
            self.logger.debug("Clone synnefo from %s" % synnefo_repo)
692 99d39120 Ilias Tsitsimpis
            self._git_clone(synnefo_repo)
693 5323404f Ilias Tsitsimpis
694 5323404f Ilias Tsitsimpis
        # Checkout the desired synnefo_branch
695 07710fc3 Ilias Tsitsimpis
        self.logger.debug("Checkout \"%s\" branch/commit" % synnefo_branch)
696 e2a0abb8 Ilias Tsitsimpis
        cmd = """
697 b69b55ca Christos Stavrakakis
        cd synnefo
698 99d39120 Ilias Tsitsimpis
        for branch in `git branch -a | grep remotes | grep -v HEAD`; do
699 b69b55ca Christos Stavrakakis
            git branch --track ${branch##*/} $branch
700 b69b55ca Christos Stavrakakis
        done
701 b69b55ca Christos Stavrakakis
        git checkout %s
702 b69b55ca Christos Stavrakakis
        """ % (synnefo_branch)
703 b69b55ca Christos Stavrakakis
        _run(cmd, False)
704 b69b55ca Christos Stavrakakis
705 99d39120 Ilias Tsitsimpis
        return synnefo_branch
706 99d39120 Ilias Tsitsimpis
707 c29ac11d Ilias Tsitsimpis
    @_check_fabric
708 99d39120 Ilias Tsitsimpis
    def clone_pithos_webclient_repo(self, synnefo_branch):
709 99d39120 Ilias Tsitsimpis
        """Clone Pithos WebClient repo to remote server"""
710 99d39120 Ilias Tsitsimpis
        # Find pithos_webclient_repo and pithos_webclient_branch to use
711 99d39120 Ilias Tsitsimpis
        pithos_webclient_repo = \
712 99d39120 Ilias Tsitsimpis
            self.config.get('Global', 'pithos_webclient_repo')
713 99d39120 Ilias Tsitsimpis
        pithos_webclient_branch = \
714 99d39120 Ilias Tsitsimpis
            self.config.get('Global', 'pithos_webclient_branch')
715 99d39120 Ilias Tsitsimpis
716 99d39120 Ilias Tsitsimpis
        # Clone pithos-webclient from remote repo
717 99d39120 Ilias Tsitsimpis
        self.logger.debug("Clone pithos-webclient from %s" %
718 99d39120 Ilias Tsitsimpis
                          pithos_webclient_repo)
719 99d39120 Ilias Tsitsimpis
        self._git_clone(pithos_webclient_repo)
720 99d39120 Ilias Tsitsimpis
721 99d39120 Ilias Tsitsimpis
        # Track all pithos-webclient branches
722 99d39120 Ilias Tsitsimpis
        cmd = """
723 99d39120 Ilias Tsitsimpis
        cd pithos-web-client
724 99d39120 Ilias Tsitsimpis
        for branch in `git branch -a | grep remotes | grep -v HEAD`; do
725 99d39120 Ilias Tsitsimpis
            git branch --track ${branch##*/} $branch > /dev/null 2>&1
726 99d39120 Ilias Tsitsimpis
        done
727 99d39120 Ilias Tsitsimpis
        git branch
728 99d39120 Ilias Tsitsimpis
        """
729 99d39120 Ilias Tsitsimpis
        webclient_branches = _run(cmd, False)
730 99d39120 Ilias Tsitsimpis
        webclient_branches = webclient_branches.split()
731 99d39120 Ilias Tsitsimpis
732 99d39120 Ilias Tsitsimpis
        # If we have pithos_webclient_branch in config file use this one
733 99d39120 Ilias Tsitsimpis
        # else try to use the same branch as synnefo_branch
734 99d39120 Ilias Tsitsimpis
        # else use an appropriate one.
735 99d39120 Ilias Tsitsimpis
        if pithos_webclient_branch == "":
736 99d39120 Ilias Tsitsimpis
            if synnefo_branch in webclient_branches:
737 99d39120 Ilias Tsitsimpis
                pithos_webclient_branch = synnefo_branch
738 99d39120 Ilias Tsitsimpis
            else:
739 99d39120 Ilias Tsitsimpis
                # If synnefo_branch starts with one of
740 99d39120 Ilias Tsitsimpis
                # 'master', 'hotfix'; use the master branch
741 99d39120 Ilias Tsitsimpis
                if synnefo_branch.startswith('master') or \
742 99d39120 Ilias Tsitsimpis
                        synnefo_branch.startswith('hotfix'):
743 99d39120 Ilias Tsitsimpis
                    pithos_webclient_branch = "master"
744 99d39120 Ilias Tsitsimpis
                # If synnefo_branch starts with one of
745 99d39120 Ilias Tsitsimpis
                # 'develop', 'feature'; use the develop branch
746 99d39120 Ilias Tsitsimpis
                elif synnefo_branch.startswith('develop') or \
747 99d39120 Ilias Tsitsimpis
                        synnefo_branch.startswith('feature'):
748 99d39120 Ilias Tsitsimpis
                    pithos_webclient_branch = "develop"
749 99d39120 Ilias Tsitsimpis
                else:
750 7a8e156f Ilias Tsitsimpis
                    self.logger.warning(
751 99d39120 Ilias Tsitsimpis
                        "Cannot determine which pithos-web-client branch to "
752 99d39120 Ilias Tsitsimpis
                        "use based on \"%s\" synnefo branch. "
753 99d39120 Ilias Tsitsimpis
                        "Will use develop." % synnefo_branch)
754 99d39120 Ilias Tsitsimpis
                    pithos_webclient_branch = "develop"
755 99d39120 Ilias Tsitsimpis
        # Checkout branch
756 99d39120 Ilias Tsitsimpis
        self.logger.debug("Checkout \"%s\" branch" %
757 99d39120 Ilias Tsitsimpis
                          _green(pithos_webclient_branch))
758 99d39120 Ilias Tsitsimpis
        cmd = """
759 99d39120 Ilias Tsitsimpis
        cd pithos-web-client
760 99d39120 Ilias Tsitsimpis
        git checkout {0}
761 99d39120 Ilias Tsitsimpis
        """.format(pithos_webclient_branch)
762 99d39120 Ilias Tsitsimpis
        _run(cmd, False)
763 99d39120 Ilias Tsitsimpis
764 99d39120 Ilias Tsitsimpis
    def _git_clone(self, repo):
765 99d39120 Ilias Tsitsimpis
        """Clone repo to remote server
766 99d39120 Ilias Tsitsimpis

767 99d39120 Ilias Tsitsimpis
        Currently clonning from code.grnet.gr can fail unexpectedly.
768 99d39120 Ilias Tsitsimpis
        So retry!!
769 99d39120 Ilias Tsitsimpis

770 99d39120 Ilias Tsitsimpis
        """
771 99d39120 Ilias Tsitsimpis
        cloned = False
772 99d39120 Ilias Tsitsimpis
        for i in range(1, 11):
773 99d39120 Ilias Tsitsimpis
            try:
774 99d39120 Ilias Tsitsimpis
                _run("git clone %s" % repo, False)
775 99d39120 Ilias Tsitsimpis
                cloned = True
776 99d39120 Ilias Tsitsimpis
                break
777 99d39120 Ilias Tsitsimpis
            except BaseException:
778 99d39120 Ilias Tsitsimpis
                self.logger.warning("Clonning failed.. retrying %s/10" % i)
779 99d39120 Ilias Tsitsimpis
        if not cloned:
780 99d39120 Ilias Tsitsimpis
            self.logger.error("Can not clone repo.")
781 99d39120 Ilias Tsitsimpis
            sys.exit(1)
782 99d39120 Ilias Tsitsimpis
783 99d39120 Ilias Tsitsimpis
    @_check_fabric
784 99d39120 Ilias Tsitsimpis
    def build_packages(self):
785 99d39120 Ilias Tsitsimpis
        """Build packages needed by Synnefo software"""
786 99d39120 Ilias Tsitsimpis
        self.logger.info("Install development packages")
787 c29ac11d Ilias Tsitsimpis
        cmd = """
788 c29ac11d Ilias Tsitsimpis
        apt-get update
789 c29ac11d Ilias Tsitsimpis
        apt-get install zlib1g-dev dpkg-dev debhelper git-buildpackage \
790 99d39120 Ilias Tsitsimpis
                python-dev python-all python-pip ant --yes --force-yes
791 6a99aca3 Ilias Tsitsimpis
        pip install -U devflow
792 6a99aca3 Ilias Tsitsimpis
        """
793 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
794 c29ac11d Ilias Tsitsimpis
795 99d39120 Ilias Tsitsimpis
        # Patch pydist bug
796 e908a902 Christos Stavrakakis
        if self.config.get('Global', 'patch_pydist') == "True":
797 c29ac11d Ilias Tsitsimpis
            self.logger.debug("Patch pydist.py module")
798 c29ac11d Ilias Tsitsimpis
            cmd = r"""
799 c29ac11d Ilias Tsitsimpis
            sed -r -i 's/(\(\?P<name>\[A-Za-z\]\[A-Za-z0-9_\.)/\1\\\-/' \
800 c29ac11d Ilias Tsitsimpis
                /usr/share/python/debpython/pydist.py
801 c29ac11d Ilias Tsitsimpis
            """
802 c29ac11d Ilias Tsitsimpis
            _run(cmd, False)
803 c29ac11d Ilias Tsitsimpis

804 1c230fd8 Ilias Tsitsimpis
        # Build synnefo packages
805 99d39120 Ilias Tsitsimpis
        self.build_synnefo()
806 99d39120 Ilias Tsitsimpis
        # Build pithos-web-client packages
807 99d39120 Ilias Tsitsimpis
        self.build_pithos_webclient()
808 99d39120 Ilias Tsitsimpis

809 99d39120 Ilias Tsitsimpis
    @_check_fabric
810 99d39120 Ilias Tsitsimpis
    def build_synnefo(self):
811 99d39120 Ilias Tsitsimpis
        """Build Synnefo packages"""
812 99d39120 Ilias Tsitsimpis
        self.logger.info("Build Synnefo packages..")
813 99d39120 Ilias Tsitsimpis

814 c29ac11d Ilias Tsitsimpis
        cmd = """
815 1c230fd8 Ilias Tsitsimpis
        devflow-autopkg snapshot -b ~/synnefo_build-area --no-sign
816 c29ac11d Ilias Tsitsimpis
        """
817 1c230fd8 Ilias Tsitsimpis
        with fabric.cd("synnefo"):
818 c29ac11d Ilias Tsitsimpis
            _run(cmd, True)
819 c29ac11d Ilias Tsitsimpis

820 1c230fd8 Ilias Tsitsimpis
        # Install snf-deploy package
821 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Install snf-deploy package")
822 c29ac11d Ilias Tsitsimpis
        cmd = """
823 c29ac11d Ilias Tsitsimpis
        dpkg -i snf-deploy*.deb
824 71f2649f Ilias Tsitsimpis
        apt-get -f install --yes --force-yes
825 c29ac11d Ilias Tsitsimpis
        """
826 1c230fd8 Ilias Tsitsimpis
        with fabric.cd("synnefo_build-area"):
827 c29ac11d Ilias Tsitsimpis
            with fabric.settings(warn_only=True):
828 c29ac11d Ilias Tsitsimpis
                _run(cmd, True)
829 c29ac11d Ilias Tsitsimpis

830 1c230fd8 Ilias Tsitsimpis
        # Setup synnefo packages for snf-deploy
831 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Copy synnefo debs to snf-deploy packages dir")
832 c29ac11d Ilias Tsitsimpis
        cmd = """
833 c29ac11d Ilias Tsitsimpis
        cp ~/synnefo_build-area/*.deb /var/lib/snf-deploy/packages/
834 c29ac11d Ilias Tsitsimpis
        """
835 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
836 c29ac11d Ilias Tsitsimpis

837 88e6558b Christos Stavrakakis
    @_check_fabric
838 99d39120 Ilias Tsitsimpis
    def build_pithos_webclient(self):
839 99d39120 Ilias Tsitsimpis
        """Build pithos-web-client packages"""
840 99d39120 Ilias Tsitsimpis
        self.logger.info("Build pithos-web-client packages..")
841 99d39120 Ilias Tsitsimpis

842 99d39120 Ilias Tsitsimpis
        cmd = """
843 99d39120 Ilias Tsitsimpis
        devflow-autopkg snapshot -b ~/webclient_build-area --no-sign
844 99d39120 Ilias Tsitsimpis
        """
845 99d39120 Ilias Tsitsimpis
        with fabric.cd("pithos-web-client"):
846 99d39120 Ilias Tsitsimpis
            _run(cmd, True)
847 99d39120 Ilias Tsitsimpis

848 99d39120 Ilias Tsitsimpis
        # Setup pithos-web-client packages for snf-deploy
849 99d39120 Ilias Tsitsimpis
        self.logger.debug("Copy webclient debs to snf-deploy packages dir")
850 99d39120 Ilias Tsitsimpis
        cmd = """
851 99d39120 Ilias Tsitsimpis
        cp ~/webclient_build-area/*.deb /var/lib/snf-deploy/packages/
852 99d39120 Ilias Tsitsimpis
        """
853 99d39120 Ilias Tsitsimpis
        _run(cmd, False)
854 99d39120 Ilias Tsitsimpis

855 99d39120 Ilias Tsitsimpis
    @_check_fabric
856 88e6558b Christos Stavrakakis
    def build_documentation(self):
857 e2a0abb8 Ilias Tsitsimpis
        """Build Synnefo documentation"""
858 88e6558b Christos Stavrakakis
        self.logger.info("Build Synnefo documentation..")
859 88e6558b Christos Stavrakakis
        _run("pip install -U Sphinx", False)
860 88e6558b Christos Stavrakakis
        with fabric.cd("synnefo"):
861 e2a0abb8 Ilias Tsitsimpis
            _run("devflow-update-version; "
862 e2a0abb8 Ilias Tsitsimpis
                 "./ci/make_docs.sh synnefo_documentation", False)
863 88e6558b Christos Stavrakakis

864 88e6558b Christos Stavrakakis
    def fetch_documentation(self, dest=None):
865 e2a0abb8 Ilias Tsitsimpis
        """Fetch Synnefo documentation"""
866 e2a0abb8 Ilias Tsitsimpis
        self.logger.info("Fetch Synnefo documentation..")
867 88e6558b Christos Stavrakakis
        if dest is None:
868 88e6558b Christos Stavrakakis
            dest = "synnefo_documentation"
869 88e6558b Christos Stavrakakis
        dest = os.path.abspath(dest)
870 88e6558b Christos Stavrakakis
        if not os.path.exists(dest):
871 88e6558b Christos Stavrakakis
            os.makedirs(dest)
872 88e6558b Christos Stavrakakis
        self.fetch_compressed("synnefo/synnefo_documentation", dest)
873 88e6558b Christos Stavrakakis
        self.logger.info("Downloaded documentation to %s" %
874 88e6558b Christos Stavrakakis
                         _green(dest))
875 88e6558b Christos Stavrakakis

876 c29ac11d Ilias Tsitsimpis
    @_check_fabric
877 ec8bc030 Christos Stavrakakis
    def deploy_synnefo(self, schema=None):
878 c29ac11d Ilias Tsitsimpis
        """Deploy Synnefo using snf-deploy"""
879 c29ac11d Ilias Tsitsimpis
        self.logger.info("Deploy Synnefo..")
880 ec8bc030 Christos Stavrakakis
        if schema is None:
881 ec8bc030 Christos Stavrakakis
            schema = self.config.get('Global', 'schema')
882 106659f1 Ilias Tsitsimpis
        self.logger.debug("Will use \"%s\" schema" % _green(schema))
883 c29ac11d Ilias Tsitsimpis

884 ec8bc030 Christos Stavrakakis
        schema_dir = os.path.join(self.ci_dir, "schemas/%s" % schema)
885 ec8bc030 Christos Stavrakakis
        if not (os.path.exists(schema_dir) and os.path.isdir(schema_dir)):
886 ec8bc030 Christos Stavrakakis
            raise ValueError("Unknown schema: %s" % schema)
887 ec8bc030 Christos Stavrakakis

888 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Upload schema files to server")
889 6868804a Ilias Tsitsimpis
        _put(os.path.join(schema_dir, "*"), "/etc/snf-deploy/")
890 c29ac11d Ilias Tsitsimpis

891 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Change password in nodes.conf file")
892 c29ac11d Ilias Tsitsimpis
        cmd = """
893 c29ac11d Ilias Tsitsimpis
        sed -i 's/^password =.*/password = {0}/' /etc/snf-deploy/nodes.conf
894 3c3bccab Dimitris Aragiorgis
        sed -i 's/12345/{0}/' /etc/snf-deploy/nodes.conf
895 c29ac11d Ilias Tsitsimpis
        """.format(fabric.env.password)
896 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
897 c29ac11d Ilias Tsitsimpis

898 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Run snf-deploy")
899 c29ac11d Ilias Tsitsimpis
        cmd = """
900 985442f5 Ilias Tsitsimpis
        snf-deploy keygen --force
901 f82ce32a Christos Stavrakakis
        snf-deploy --disable-colors --autoconf all
902 c29ac11d Ilias Tsitsimpis
        """
903 c29ac11d Ilias Tsitsimpis
        _run(cmd, True)
904 c29ac11d Ilias Tsitsimpis

905 c29ac11d Ilias Tsitsimpis
    @_check_fabric
906 c29ac11d Ilias Tsitsimpis
    def unit_test(self):
907 c29ac11d Ilias Tsitsimpis
        """Run Synnefo unit test suite"""
908 c29ac11d Ilias Tsitsimpis
        self.logger.info("Run Synnefo unit test suite")
909 c29ac11d Ilias Tsitsimpis
        component = self.config.get('Unit Tests', 'component')
910 c29ac11d Ilias Tsitsimpis

911 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Install needed packages")
912 c29ac11d Ilias Tsitsimpis
        cmd = """
913 8d2c08e4 Christos Stavrakakis
        pip install -U mock
914 8d2c08e4 Christos Stavrakakis
        pip install -U factory_boy
915 cb1060f2 Ilias Tsitsimpis
        pip install -U nose
916 c29ac11d Ilias Tsitsimpis
        """
917 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
918 c29ac11d Ilias Tsitsimpis

919 861b437e Ilias Tsitsimpis
        self.logger.debug("Upload tests.sh file")
920 861b437e Ilias Tsitsimpis
        unit_tests_file = os.path.join(self.ci_dir, "tests.sh")
921 6868804a Ilias Tsitsimpis
        _put(unit_tests_file, ".")
922 c29ac11d Ilias Tsitsimpis

923 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Run unit tests")
924 c29ac11d Ilias Tsitsimpis
        cmd = """
925 861b437e Ilias Tsitsimpis
        bash tests.sh {0}
926 c29ac11d Ilias Tsitsimpis
        """.format(component)
927 c29ac11d Ilias Tsitsimpis
        _run(cmd, True)
928 c29ac11d Ilias Tsitsimpis

929 c29ac11d Ilias Tsitsimpis
    @_check_fabric
930 c29ac11d Ilias Tsitsimpis
    def run_burnin(self):
931 c29ac11d Ilias Tsitsimpis
        """Run burnin functional test suite"""
932 c29ac11d Ilias Tsitsimpis
        self.logger.info("Run Burnin functional test suite")
933 c29ac11d Ilias Tsitsimpis
        cmd = """
934 c29ac11d Ilias Tsitsimpis
        auth_url=$(grep -e '^url =' .kamakirc | cut -d' ' -f3)
935 c29ac11d Ilias Tsitsimpis
        token=$(grep -e '^token =' .kamakirc | cut -d' ' -f3)
936 c29ac11d Ilias Tsitsimpis
        images_user=$(kamaki image list -l | grep owner | \
937 c29ac11d Ilias Tsitsimpis
                      cut -d':' -f2 | tr -d ' ')
938 2afd10bf Ilias Tsitsimpis
        snf-burnin --auth-url=$auth_url --token=$token {0}
939 281c7634 Ilias Tsitsimpis
        BurninExitStatus=$?
940 281c7634 Ilias Tsitsimpis
        exit $BurninExitStatus
941 c29ac11d Ilias Tsitsimpis
        """.format(self.config.get('Burnin', 'cmd_options'))
942 c29ac11d Ilias Tsitsimpis
        _run(cmd, True)
943 c29ac11d Ilias Tsitsimpis

944 c29ac11d Ilias Tsitsimpis
    @_check_fabric
945 88e6558b Christos Stavrakakis
    def fetch_compressed(self, src, dest=None):
946 e2a0abb8 Ilias Tsitsimpis
        """Create a tarball and fetch it locally"""
947 88e6558b Christos Stavrakakis
        self.logger.debug("Creating tarball of %s" % src)
948 88e6558b Christos Stavrakakis
        basename = os.path.basename(src)
949 88e6558b Christos Stavrakakis
        tar_file = basename + ".tgz"
950 88e6558b Christos Stavrakakis
        cmd = "tar czf %s %s" % (tar_file, src)
951 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
952 88e6558b Christos Stavrakakis
        if not os.path.exists(dest):
953 88e6558b Christos Stavrakakis
            os.makedirs(dest)
954 c29ac11d Ilias Tsitsimpis

955 88e6558b Christos Stavrakakis
        tmp_dir = tempfile.mkdtemp()
956 88e6558b Christos Stavrakakis
        fabric.get(tar_file, tmp_dir)
957 c29ac11d Ilias Tsitsimpis

958 88e6558b Christos Stavrakakis
        dest_file = os.path.join(tmp_dir, tar_file)
959 88e6558b Christos Stavrakakis
        self._check_hash_sum(dest_file, tar_file)
960 88e6558b Christos Stavrakakis
        self.logger.debug("Untar packages file %s" % dest_file)
961 e2dc37b2 Christos Stavrakakis
        cmd = """
962 e2dc37b2 Christos Stavrakakis
        cd %s
963 88e6558b Christos Stavrakakis
        tar xzf %s
964 88e6558b Christos Stavrakakis
        cp -r %s/* %s
965 88e6558b Christos Stavrakakis
        rm -r %s
966 88e6558b Christos Stavrakakis
        """ % (tmp_dir, tar_file, src, dest, tmp_dir)
967 e2dc37b2 Christos Stavrakakis
        os.system(cmd)
968 88e6558b Christos Stavrakakis
        self.logger.info("Downloaded %s to %s" %
969 88e6558b Christos Stavrakakis
                         (src, _green(dest)))
970 88e6558b Christos Stavrakakis

971 88e6558b Christos Stavrakakis
    @_check_fabric
972 88e6558b Christos Stavrakakis
    def fetch_packages(self, dest=None):
973 e2a0abb8 Ilias Tsitsimpis
        """Fetch Synnefo packages"""
974 88e6558b Christos Stavrakakis
        if dest is None:
975 88e6558b Christos Stavrakakis
            dest = self.config.get('Global', 'pkgs_dir')
976 6058ae72 Ilias Tsitsimpis
        dest = os.path.abspath(os.path.expanduser(dest))
977 88e6558b Christos Stavrakakis
        if not os.path.exists(dest):
978 88e6558b Christos Stavrakakis
            os.makedirs(dest)
979 88e6558b Christos Stavrakakis
        self.fetch_compressed("synnefo_build-area", dest)
980 99d39120 Ilias Tsitsimpis
        self.fetch_compressed("webclient_build-area", dest)
981 464e58e9 Christos Stavrakakis
        self.logger.info("Downloaded debian packages to %s" %
982 88e6558b Christos Stavrakakis
                         _green(dest))
983 6958ffc6 Christos Stavrakakis

984 cf99ca80 Ilias Tsitsimpis
    def x2go_plugin(self, dest=None):
985 cf99ca80 Ilias Tsitsimpis
        """Produce an html page which will use the x2goplugin
986 cf99ca80 Ilias Tsitsimpis
987 cf99ca80 Ilias Tsitsimpis
        Arguments:
988 cf99ca80 Ilias Tsitsimpis
          dest  -- The file where to save the page (String)
989 cf99ca80 Ilias Tsitsimpis
990 cf99ca80 Ilias Tsitsimpis
        """
991 cf99ca80 Ilias Tsitsimpis
        output_str = """
992 cf99ca80 Ilias Tsitsimpis
        <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
993 cf99ca80 Ilias Tsitsimpis
        <html>
994 cf99ca80 Ilias Tsitsimpis
        <head>
995 cf99ca80 Ilias Tsitsimpis
        <title>X2Go SynnefoCI Service</title>
996 cf99ca80 Ilias Tsitsimpis
        </head>
997 cf99ca80 Ilias Tsitsimpis
        <body onload="checkPlugin()">
998 cf99ca80 Ilias Tsitsimpis
        <div id="x2goplugin">
999 cf99ca80 Ilias Tsitsimpis
            <object
1000 cf99ca80 Ilias Tsitsimpis
                src="location"
1001 cf99ca80 Ilias Tsitsimpis
                type="application/x2go"
1002 cf99ca80 Ilias Tsitsimpis
                name="x2goplugin"
1003 cf99ca80 Ilias Tsitsimpis
                palette="background"
1004 cf99ca80 Ilias Tsitsimpis
                height="100%"
1005 cf99ca80 Ilias Tsitsimpis
                hspace="0"
1006 cf99ca80 Ilias Tsitsimpis
                vspace="0"
1007 cf99ca80 Ilias Tsitsimpis
                width="100%"
1008 cf99ca80 Ilias Tsitsimpis
                x2goconfig="
1009 cf99ca80 Ilias Tsitsimpis
                    session=X2Go-SynnefoCI-Session
1010 cf99ca80 Ilias Tsitsimpis
                    server={0}
1011 cf99ca80 Ilias Tsitsimpis
                    user={1}
1012 cf99ca80 Ilias Tsitsimpis
                    sshport={2}
1013 cf99ca80 Ilias Tsitsimpis
                    published=true
1014 cf99ca80 Ilias Tsitsimpis
                    autologin=true
1015 cf99ca80 Ilias Tsitsimpis
                ">
1016 cf99ca80 Ilias Tsitsimpis
            </object>
1017 cf99ca80 Ilias Tsitsimpis
        </div>
1018 cf99ca80 Ilias Tsitsimpis
        </body>
1019 cf99ca80 Ilias Tsitsimpis
        </html>
1020 cf99ca80 Ilias Tsitsimpis
        """.format(self.read_temp_config('server_ip'),
1021 cf99ca80 Ilias Tsitsimpis
                   self.read_temp_config('server_user'),
1022 cf99ca80 Ilias Tsitsimpis
                   self.read_temp_config('server_port'))
1023 cf99ca80 Ilias Tsitsimpis
        if dest is None:
1024 cf99ca80 Ilias Tsitsimpis
            dest = self.config.get('Global', 'x2go_plugin_file')
1025 cf99ca80 Ilias Tsitsimpis

1026 cf99ca80 Ilias Tsitsimpis
        self.logger.info("Writting x2go plugin html file to %s" % dest)
1027 cf99ca80 Ilias Tsitsimpis
        fid = open(dest, 'w')
1028 cf99ca80 Ilias Tsitsimpis
        fid.write(output_str)
1029 cf99ca80 Ilias Tsitsimpis
        fid.close()
1030 cf99ca80 Ilias Tsitsimpis

1031 6958ffc6 Christos Stavrakakis

1032 6958ffc6 Christos Stavrakakis
def parse_typed_option(option, value):
1033 694c79bb Ilias Tsitsimpis
    """Parsed typed options (flavors and images)"""
1034 6958ffc6 Christos Stavrakakis
    try:
1035 6958ffc6 Christos Stavrakakis
        [type_, val] = value.strip().split(':')
1036 6958ffc6 Christos Stavrakakis
        if type_ not in ["id", "name"]:
1037 6958ffc6 Christos Stavrakakis
            raise ValueError
1038 6958ffc6 Christos Stavrakakis
        return type_, val
1039 6958ffc6 Christos Stavrakakis
    except ValueError:
1040 6958ffc6 Christos Stavrakakis
        msg = "Invalid %s format. Must be [id|name]:.+" % option
1041 6958ffc6 Christos Stavrakakis
        raise ValueError(msg)
1042 ee6eff28 Ilias Tsitsimpis

1043 ee6eff28 Ilias Tsitsimpis

1044 ee6eff28 Ilias Tsitsimpis
def get_endpoint_url(endpoints, endpoint_type):
1045 ee6eff28 Ilias Tsitsimpis
    """Get the publicURL for the specified endpoint"""
1046 ee6eff28 Ilias Tsitsimpis

1047 ee6eff28 Ilias Tsitsimpis
    service_catalog = parse_endpoints(endpoints, ep_type=endpoint_type)
1048 ee6eff28 Ilias Tsitsimpis
    return service_catalog[0]['endpoints'][0]['publicURL']