Statistics
| Branch: | Tag: | Revision:

root / ci / utils.py @ 2eda9c61

History | View | Annotate | Download (40.4 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 4daf507c Christos Stavrakakis
        self.logger.debug("Setup apt")
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 4daf507c Christos Stavrakakis
        apt-get install -q=2 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 4daf507c Christos Stavrakakis
        """.format(self.config.get('Global', 'apt_repo'))
354 4daf507c Christos Stavrakakis
        _run(cmd, False)
355 8ddb541b Ilias Tsitsimpis
356 4daf507c Christos Stavrakakis
        cmd = """
357 6c3cc77e Ilias Tsitsimpis
        # X2GO Key
358 6c3cc77e Ilias Tsitsimpis
        apt-key adv --recv-keys --keyserver keys.gnupg.net E1F958385BFE2B6E
359 71f2649f Ilias Tsitsimpis
        apt-get install x2go-keyring --yes --force-yes
360 6c3cc77e Ilias Tsitsimpis
        apt-get update
361 71f2649f Ilias Tsitsimpis
        apt-get install x2goserver x2goserver-xsession \
362 71f2649f Ilias Tsitsimpis
                iceweasel --yes --force-yes
363 8ddb541b Ilias Tsitsimpis

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

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

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

773 99d39120 Ilias Tsitsimpis
        Currently clonning from code.grnet.gr can fail unexpectedly.
774 99d39120 Ilias Tsitsimpis
        So retry!!
775 99d39120 Ilias Tsitsimpis

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

810 1c230fd8 Ilias Tsitsimpis
        # Build synnefo packages
811 99d39120 Ilias Tsitsimpis
        self.build_synnefo()
812 99d39120 Ilias Tsitsimpis
        # Build pithos-web-client packages
813 1185ff2e Christos Stavrakakis
        if self.config.get("Global", "build_pithos_webclient") == "True":
814 1185ff2e Christos Stavrakakis
            self.build_pithos_webclient()
815 99d39120 Ilias Tsitsimpis

816 99d39120 Ilias Tsitsimpis
    @_check_fabric
817 99d39120 Ilias Tsitsimpis
    def build_synnefo(self):
818 99d39120 Ilias Tsitsimpis
        """Build Synnefo packages"""
819 99d39120 Ilias Tsitsimpis
        self.logger.info("Build Synnefo packages..")
820 99d39120 Ilias Tsitsimpis

821 c29ac11d Ilias Tsitsimpis
        cmd = """
822 1c230fd8 Ilias Tsitsimpis
        devflow-autopkg snapshot -b ~/synnefo_build-area --no-sign
823 c29ac11d Ilias Tsitsimpis
        """
824 1c230fd8 Ilias Tsitsimpis
        with fabric.cd("synnefo"):
825 c29ac11d Ilias Tsitsimpis
            _run(cmd, True)
826 c29ac11d Ilias Tsitsimpis

827 1c230fd8 Ilias Tsitsimpis
        # Install snf-deploy package
828 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Install snf-deploy package")
829 c29ac11d Ilias Tsitsimpis
        cmd = """
830 c29ac11d Ilias Tsitsimpis
        dpkg -i snf-deploy*.deb
831 71f2649f Ilias Tsitsimpis
        apt-get -f install --yes --force-yes
832 c29ac11d Ilias Tsitsimpis
        """
833 1c230fd8 Ilias Tsitsimpis
        with fabric.cd("synnefo_build-area"):
834 c29ac11d Ilias Tsitsimpis
            with fabric.settings(warn_only=True):
835 c29ac11d Ilias Tsitsimpis
                _run(cmd, True)
836 c29ac11d Ilias Tsitsimpis

837 1c230fd8 Ilias Tsitsimpis
        # Setup synnefo packages for snf-deploy
838 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Copy synnefo debs to snf-deploy packages dir")
839 c29ac11d Ilias Tsitsimpis
        cmd = """
840 c29ac11d Ilias Tsitsimpis
        cp ~/synnefo_build-area/*.deb /var/lib/snf-deploy/packages/
841 c29ac11d Ilias Tsitsimpis
        """
842 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
843 c29ac11d Ilias Tsitsimpis

844 88e6558b Christos Stavrakakis
    @_check_fabric
845 99d39120 Ilias Tsitsimpis
    def build_pithos_webclient(self):
846 99d39120 Ilias Tsitsimpis
        """Build pithos-web-client packages"""
847 99d39120 Ilias Tsitsimpis
        self.logger.info("Build pithos-web-client packages..")
848 99d39120 Ilias Tsitsimpis

849 99d39120 Ilias Tsitsimpis
        cmd = """
850 99d39120 Ilias Tsitsimpis
        devflow-autopkg snapshot -b ~/webclient_build-area --no-sign
851 99d39120 Ilias Tsitsimpis
        """
852 99d39120 Ilias Tsitsimpis
        with fabric.cd("pithos-web-client"):
853 99d39120 Ilias Tsitsimpis
            _run(cmd, True)
854 99d39120 Ilias Tsitsimpis

855 99d39120 Ilias Tsitsimpis
        # Setup pithos-web-client packages for snf-deploy
856 99d39120 Ilias Tsitsimpis
        self.logger.debug("Copy webclient debs to snf-deploy packages dir")
857 99d39120 Ilias Tsitsimpis
        cmd = """
858 99d39120 Ilias Tsitsimpis
        cp ~/webclient_build-area/*.deb /var/lib/snf-deploy/packages/
859 99d39120 Ilias Tsitsimpis
        """
860 99d39120 Ilias Tsitsimpis
        _run(cmd, False)
861 99d39120 Ilias Tsitsimpis

862 99d39120 Ilias Tsitsimpis
    @_check_fabric
863 88e6558b Christos Stavrakakis
    def build_documentation(self):
864 e2a0abb8 Ilias Tsitsimpis
        """Build Synnefo documentation"""
865 88e6558b Christos Stavrakakis
        self.logger.info("Build Synnefo documentation..")
866 88e6558b Christos Stavrakakis
        _run("pip install -U Sphinx", False)
867 88e6558b Christos Stavrakakis
        with fabric.cd("synnefo"):
868 e2a0abb8 Ilias Tsitsimpis
            _run("devflow-update-version; "
869 e2a0abb8 Ilias Tsitsimpis
                 "./ci/make_docs.sh synnefo_documentation", False)
870 88e6558b Christos Stavrakakis

871 88e6558b Christos Stavrakakis
    def fetch_documentation(self, dest=None):
872 e2a0abb8 Ilias Tsitsimpis
        """Fetch Synnefo documentation"""
873 e2a0abb8 Ilias Tsitsimpis
        self.logger.info("Fetch Synnefo documentation..")
874 88e6558b Christos Stavrakakis
        if dest is None:
875 88e6558b Christos Stavrakakis
            dest = "synnefo_documentation"
876 88e6558b Christos Stavrakakis
        dest = os.path.abspath(dest)
877 88e6558b Christos Stavrakakis
        if not os.path.exists(dest):
878 88e6558b Christos Stavrakakis
            os.makedirs(dest)
879 88e6558b Christos Stavrakakis
        self.fetch_compressed("synnefo/synnefo_documentation", dest)
880 88e6558b Christos Stavrakakis
        self.logger.info("Downloaded documentation to %s" %
881 88e6558b Christos Stavrakakis
                         _green(dest))
882 88e6558b Christos Stavrakakis

883 c29ac11d Ilias Tsitsimpis
    @_check_fabric
884 ec8bc030 Christos Stavrakakis
    def deploy_synnefo(self, schema=None):
885 c29ac11d Ilias Tsitsimpis
        """Deploy Synnefo using snf-deploy"""
886 c29ac11d Ilias Tsitsimpis
        self.logger.info("Deploy Synnefo..")
887 ec8bc030 Christos Stavrakakis
        if schema is None:
888 ec8bc030 Christos Stavrakakis
            schema = self.config.get('Global', 'schema')
889 106659f1 Ilias Tsitsimpis
        self.logger.debug("Will use \"%s\" schema" % _green(schema))
890 c29ac11d Ilias Tsitsimpis

891 ec8bc030 Christos Stavrakakis
        schema_dir = os.path.join(self.ci_dir, "schemas/%s" % schema)
892 ec8bc030 Christos Stavrakakis
        if not (os.path.exists(schema_dir) and os.path.isdir(schema_dir)):
893 ec8bc030 Christos Stavrakakis
            raise ValueError("Unknown schema: %s" % schema)
894 ec8bc030 Christos Stavrakakis

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

898 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Change password in nodes.conf file")
899 c29ac11d Ilias Tsitsimpis
        cmd = """
900 c29ac11d Ilias Tsitsimpis
        sed -i 's/^password =.*/password = {0}/' /etc/snf-deploy/nodes.conf
901 3c3bccab Dimitris Aragiorgis
        sed -i 's/12345/{0}/' /etc/snf-deploy/nodes.conf
902 c29ac11d Ilias Tsitsimpis
        """.format(fabric.env.password)
903 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
904 c29ac11d Ilias Tsitsimpis

905 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Run snf-deploy")
906 c29ac11d Ilias Tsitsimpis
        cmd = """
907 985442f5 Ilias Tsitsimpis
        snf-deploy keygen --force
908 f82ce32a Christos Stavrakakis
        snf-deploy --disable-colors --autoconf all
909 c29ac11d Ilias Tsitsimpis
        """
910 c29ac11d Ilias Tsitsimpis
        _run(cmd, True)
911 c29ac11d Ilias Tsitsimpis

912 c29ac11d Ilias Tsitsimpis
    @_check_fabric
913 c29ac11d Ilias Tsitsimpis
    def unit_test(self):
914 c29ac11d Ilias Tsitsimpis
        """Run Synnefo unit test suite"""
915 c29ac11d Ilias Tsitsimpis
        self.logger.info("Run Synnefo unit test suite")
916 c29ac11d Ilias Tsitsimpis
        component = self.config.get('Unit Tests', 'component')
917 c29ac11d Ilias Tsitsimpis

918 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Install needed packages")
919 c29ac11d Ilias Tsitsimpis
        cmd = """
920 8d2c08e4 Christos Stavrakakis
        pip install -U mock
921 8d2c08e4 Christos Stavrakakis
        pip install -U factory_boy
922 cb1060f2 Ilias Tsitsimpis
        pip install -U nose
923 c29ac11d Ilias Tsitsimpis
        """
924 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
925 c29ac11d Ilias Tsitsimpis

926 861b437e Ilias Tsitsimpis
        self.logger.debug("Upload tests.sh file")
927 861b437e Ilias Tsitsimpis
        unit_tests_file = os.path.join(self.ci_dir, "tests.sh")
928 6868804a Ilias Tsitsimpis
        _put(unit_tests_file, ".")
929 c29ac11d Ilias Tsitsimpis

930 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Run unit tests")
931 c29ac11d Ilias Tsitsimpis
        cmd = """
932 861b437e Ilias Tsitsimpis
        bash tests.sh {0}
933 c29ac11d Ilias Tsitsimpis
        """.format(component)
934 c29ac11d Ilias Tsitsimpis
        _run(cmd, True)
935 c29ac11d Ilias Tsitsimpis

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

951 c29ac11d Ilias Tsitsimpis
    @_check_fabric
952 88e6558b Christos Stavrakakis
    def fetch_compressed(self, src, dest=None):
953 e2a0abb8 Ilias Tsitsimpis
        """Create a tarball and fetch it locally"""
954 88e6558b Christos Stavrakakis
        self.logger.debug("Creating tarball of %s" % src)
955 88e6558b Christos Stavrakakis
        basename = os.path.basename(src)
956 88e6558b Christos Stavrakakis
        tar_file = basename + ".tgz"
957 88e6558b Christos Stavrakakis
        cmd = "tar czf %s %s" % (tar_file, src)
958 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
959 88e6558b Christos Stavrakakis
        if not os.path.exists(dest):
960 88e6558b Christos Stavrakakis
            os.makedirs(dest)
961 c29ac11d Ilias Tsitsimpis

962 88e6558b Christos Stavrakakis
        tmp_dir = tempfile.mkdtemp()
963 88e6558b Christos Stavrakakis
        fabric.get(tar_file, tmp_dir)
964 c29ac11d Ilias Tsitsimpis

965 88e6558b Christos Stavrakakis
        dest_file = os.path.join(tmp_dir, tar_file)
966 88e6558b Christos Stavrakakis
        self._check_hash_sum(dest_file, tar_file)
967 88e6558b Christos Stavrakakis
        self.logger.debug("Untar packages file %s" % dest_file)
968 e2dc37b2 Christos Stavrakakis
        cmd = """
969 e2dc37b2 Christos Stavrakakis
        cd %s
970 88e6558b Christos Stavrakakis
        tar xzf %s
971 88e6558b Christos Stavrakakis
        cp -r %s/* %s
972 88e6558b Christos Stavrakakis
        rm -r %s
973 88e6558b Christos Stavrakakis
        """ % (tmp_dir, tar_file, src, dest, tmp_dir)
974 e2dc37b2 Christos Stavrakakis
        os.system(cmd)
975 88e6558b Christos Stavrakakis
        self.logger.info("Downloaded %s to %s" %
976 88e6558b Christos Stavrakakis
                         (src, _green(dest)))
977 88e6558b Christos Stavrakakis

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

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

1033 cf99ca80 Ilias Tsitsimpis
        self.logger.info("Writting x2go plugin html file to %s" % dest)
1034 cf99ca80 Ilias Tsitsimpis
        fid = open(dest, 'w')
1035 cf99ca80 Ilias Tsitsimpis
        fid.write(output_str)
1036 cf99ca80 Ilias Tsitsimpis
        fid.close()
1037 cf99ca80 Ilias Tsitsimpis

1038 6958ffc6 Christos Stavrakakis

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

1050 ee6eff28 Ilias Tsitsimpis

1051 ee6eff28 Ilias Tsitsimpis
def get_endpoint_url(endpoints, endpoint_type):
1052 ee6eff28 Ilias Tsitsimpis
    """Get the publicURL for the specified endpoint"""
1053 ee6eff28 Ilias Tsitsimpis

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