Statistics
| Branch: | Tag: | Revision:

root / ci / utils.py @ 6be99b24

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1032 6958ffc6 Christos Stavrakakis

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