Statistics
| Branch: | Tag: | Revision:

root / ci / utils.py @ 4b61ee63

History | View | Annotate | Download (29.2 kB)

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

120 525f2979 Ilias Tsitsimpis
        Setup logger, local_dir, config and kamaki
121 525f2979 Ilias Tsitsimpis
        """
122 525f2979 Ilias Tsitsimpis
        # Setup logger
123 525f2979 Ilias Tsitsimpis
        self.logger = logging.getLogger('synnefo-ci')
124 525f2979 Ilias Tsitsimpis
        self.logger.setLevel(logging.DEBUG)
125 d8363ea2 Ilias Tsitsimpis
126 d8363ea2 Ilias Tsitsimpis
        handler1 = logging.StreamHandler(sys.stdout)
127 d8363ea2 Ilias Tsitsimpis
        handler1.setLevel(logging.DEBUG)
128 d8363ea2 Ilias Tsitsimpis
        handler1.addFilter(_InfoFilter())
129 d8363ea2 Ilias Tsitsimpis
        handler1.setFormatter(_MyFormatter())
130 d8363ea2 Ilias Tsitsimpis
        handler2 = logging.StreamHandler(sys.stderr)
131 d8363ea2 Ilias Tsitsimpis
        handler2.setLevel(logging.WARNING)
132 d8363ea2 Ilias Tsitsimpis
        handler2.setFormatter(_MyFormatter())
133 d8363ea2 Ilias Tsitsimpis
134 d8363ea2 Ilias Tsitsimpis
        self.logger.addHandler(handler1)
135 d8363ea2 Ilias Tsitsimpis
        self.logger.addHandler(handler2)
136 525f2979 Ilias Tsitsimpis
137 525f2979 Ilias Tsitsimpis
        # Get our local dir
138 525f2979 Ilias Tsitsimpis
        self.ci_dir = os.path.dirname(os.path.abspath(__file__))
139 525f2979 Ilias Tsitsimpis
        self.repo_dir = os.path.dirname(self.ci_dir)
140 525f2979 Ilias Tsitsimpis
141 525f2979 Ilias Tsitsimpis
        # Read config file
142 e2db4a57 Christos Stavrakakis
        if config_file is None:
143 e2db4a57 Christos Stavrakakis
            config_file = DEFAULT_CONFIG_FILE
144 e2db4a57 Christos Stavrakakis
        if not os.path.isabs(config_file):
145 e2db4a57 Christos Stavrakakis
            config_file = os.path.join(self.ci_dir, config_file)
146 525f2979 Ilias Tsitsimpis
        self.config = ConfigParser()
147 525f2979 Ilias Tsitsimpis
        self.config.optionxform = str
148 e2db4a57 Christos Stavrakakis
        self.config.read(config_file)
149 c441b6a7 Ilias Tsitsimpis
150 c441b6a7 Ilias Tsitsimpis
        # Read temporary_config file
151 4b61ee63 Ilias Tsitsimpis
        self.temp_config_file = \
152 4b61ee63 Ilias Tsitsimpis
            os.path.expanduser(self.config.get('Global', 'temporary_config'))
153 c441b6a7 Ilias Tsitsimpis
        self.temp_config = ConfigParser()
154 c441b6a7 Ilias Tsitsimpis
        self.temp_config.optionxform = str
155 4b61ee63 Ilias Tsitsimpis
        self.temp_config.read(self.temp_config_file)
156 ef695867 Ilias Tsitsimpis
        self.build_id = build_id
157 ef695867 Ilias Tsitsimpis
        self.logger.info("Will use \"%s\" as build id" % _green(self.build_id))
158 525f2979 Ilias Tsitsimpis
159 da593e0c Christos Stavrakakis
        # Set kamaki cloud
160 da593e0c Christos Stavrakakis
        if cloud is not None:
161 da593e0c Christos Stavrakakis
            self.kamaki_cloud = cloud
162 da593e0c Christos Stavrakakis
        elif self.config.has_option("Deployment", "kamaki_cloud"):
163 da593e0c Christos Stavrakakis
            kamaki_cloud = self.config.get("Deployment", "kamaki_cloud")
164 da593e0c Christos Stavrakakis
            if kamaki_cloud == "":
165 da593e0c Christos Stavrakakis
                self.kamaki_cloud = None
166 da593e0c Christos Stavrakakis
        else:
167 da593e0c Christos Stavrakakis
            self.kamaki_cloud = None
168 da593e0c Christos Stavrakakis
169 525f2979 Ilias Tsitsimpis
        # Initialize variables
170 525f2979 Ilias Tsitsimpis
        self.fabric_installed = False
171 525f2979 Ilias Tsitsimpis
        self.kamaki_installed = False
172 525f2979 Ilias Tsitsimpis
        self.cyclades_client = None
173 dae06cfc Ilias Tsitsimpis
        self.compute_client = None
174 525f2979 Ilias Tsitsimpis
        self.image_client = None
175 525f2979 Ilias Tsitsimpis
176 525f2979 Ilias Tsitsimpis
    def setup_kamaki(self):
177 525f2979 Ilias Tsitsimpis
        """Initialize kamaki
178 525f2979 Ilias Tsitsimpis

179 dae06cfc Ilias Tsitsimpis
        Setup cyclades_client, image_client and compute_client
180 525f2979 Ilias Tsitsimpis
        """
181 da593e0c Christos Stavrakakis
182 da593e0c Christos Stavrakakis
        config = kamaki_config.Config()
183 da593e0c Christos Stavrakakis
        if self.kamaki_cloud is None:
184 da593e0c Christos Stavrakakis
            self.kamaki_cloud = config.get_global("default_cloud")
185 da593e0c Christos Stavrakakis
186 da593e0c Christos Stavrakakis
        self.logger.info("Setup kamaki client, using cloud '%s'.." %
187 da593e0c Christos Stavrakakis
                         self.kamaki_cloud)
188 da593e0c Christos Stavrakakis
        auth_url = config.get_cloud(self.kamaki_cloud, "url")
189 525f2979 Ilias Tsitsimpis
        self.logger.debug("Authentication URL is %s" % _green(auth_url))
190 da593e0c Christos Stavrakakis
        token = config.get_cloud(self.kamaki_cloud, "token")
191 525f2979 Ilias Tsitsimpis
        #self.logger.debug("Token is %s" % _green(token))
192 525f2979 Ilias Tsitsimpis
193 525f2979 Ilias Tsitsimpis
        astakos_client = AstakosClient(auth_url, token)
194 525f2979 Ilias Tsitsimpis
195 525f2979 Ilias Tsitsimpis
        cyclades_url = \
196 525f2979 Ilias Tsitsimpis
            astakos_client.get_service_endpoints('compute')['publicURL']
197 525f2979 Ilias Tsitsimpis
        self.logger.debug("Cyclades API url is %s" % _green(cyclades_url))
198 525f2979 Ilias Tsitsimpis
        self.cyclades_client = CycladesClient(cyclades_url, token)
199 525f2979 Ilias Tsitsimpis
        self.cyclades_client.CONNECTION_RETRY_LIMIT = 2
200 525f2979 Ilias Tsitsimpis
201 525f2979 Ilias Tsitsimpis
        image_url = \
202 525f2979 Ilias Tsitsimpis
            astakos_client.get_service_endpoints('image')['publicURL']
203 525f2979 Ilias Tsitsimpis
        self.logger.debug("Images API url is %s" % _green(image_url))
204 525f2979 Ilias Tsitsimpis
        self.image_client = ImageClient(cyclades_url, token)
205 525f2979 Ilias Tsitsimpis
        self.image_client.CONNECTION_RETRY_LIMIT = 2
206 525f2979 Ilias Tsitsimpis
207 dae06cfc Ilias Tsitsimpis
        compute_url = \
208 dae06cfc Ilias Tsitsimpis
            astakos_client.get_service_endpoints('compute')['publicURL']
209 dae06cfc Ilias Tsitsimpis
        self.logger.debug("Compute API url is %s" % _green(compute_url))
210 dae06cfc Ilias Tsitsimpis
        self.compute_client = ComputeClient(compute_url, token)
211 dae06cfc Ilias Tsitsimpis
        self.compute_client.CONNECTION_RETRY_LIMIT = 2
212 dae06cfc Ilias Tsitsimpis
213 525f2979 Ilias Tsitsimpis
    def _wait_transition(self, server_id, current_status, new_status):
214 525f2979 Ilias Tsitsimpis
        """Wait for server to go from current_status to new_status"""
215 525f2979 Ilias Tsitsimpis
        self.logger.debug("Waiting for server to become %s" % new_status)
216 525f2979 Ilias Tsitsimpis
        timeout = self.config.getint('Global', 'build_timeout')
217 525f2979 Ilias Tsitsimpis
        sleep_time = 5
218 525f2979 Ilias Tsitsimpis
        while True:
219 525f2979 Ilias Tsitsimpis
            server = self.cyclades_client.get_server_details(server_id)
220 525f2979 Ilias Tsitsimpis
            if server['status'] == new_status:
221 525f2979 Ilias Tsitsimpis
                return server
222 525f2979 Ilias Tsitsimpis
            elif timeout < 0:
223 525f2979 Ilias Tsitsimpis
                self.logger.error(
224 525f2979 Ilias Tsitsimpis
                    "Waiting for server to become %s timed out" % new_status)
225 525f2979 Ilias Tsitsimpis
                self.destroy_server(False)
226 525f2979 Ilias Tsitsimpis
                sys.exit(-1)
227 525f2979 Ilias Tsitsimpis
            elif server['status'] == current_status:
228 525f2979 Ilias Tsitsimpis
                # Sleep for #n secs and continue
229 525f2979 Ilias Tsitsimpis
                timeout = timeout - sleep_time
230 525f2979 Ilias Tsitsimpis
                time.sleep(sleep_time)
231 525f2979 Ilias Tsitsimpis
            else:
232 525f2979 Ilias Tsitsimpis
                self.logger.error(
233 525f2979 Ilias Tsitsimpis
                    "Server failed with status %s" % server['status'])
234 525f2979 Ilias Tsitsimpis
                self.destroy_server(False)
235 525f2979 Ilias Tsitsimpis
                sys.exit(-1)
236 525f2979 Ilias Tsitsimpis
237 525f2979 Ilias Tsitsimpis
    @_check_kamaki
238 525f2979 Ilias Tsitsimpis
    def destroy_server(self, wait=True):
239 525f2979 Ilias Tsitsimpis
        """Destroy slave server"""
240 ef695867 Ilias Tsitsimpis
        server_id = int(self.read_temp_config('server_id'))
241 525f2979 Ilias Tsitsimpis
        self.logger.info("Destoying server with id %s " % server_id)
242 525f2979 Ilias Tsitsimpis
        self.cyclades_client.delete_server(server_id)
243 525f2979 Ilias Tsitsimpis
        if wait:
244 525f2979 Ilias Tsitsimpis
            self._wait_transition(server_id, "ACTIVE", "DELETED")
245 525f2979 Ilias Tsitsimpis
246 525f2979 Ilias Tsitsimpis
    @_check_kamaki
247 6f8b2632 Ilias Tsitsimpis
    def create_server(self, image=None, flavor=None, ssh_keys=None):
248 525f2979 Ilias Tsitsimpis
        """Create slave server"""
249 525f2979 Ilias Tsitsimpis
        self.logger.info("Create a new server..")
250 ef695867 Ilias Tsitsimpis
251 ef695867 Ilias Tsitsimpis
        # Find a build_id to use
252 ef695867 Ilias Tsitsimpis
        if self.build_id is None:
253 ef695867 Ilias Tsitsimpis
            # If build_id is given use this, else ..
254 ef695867 Ilias Tsitsimpis
            # Find a uniq build_id to use
255 ef695867 Ilias Tsitsimpis
            ids = self.temp_config.sections()
256 ef695867 Ilias Tsitsimpis
            if ids:
257 ef695867 Ilias Tsitsimpis
                max_id = int(max(self.temp_config.sections(), key=int))
258 ef695867 Ilias Tsitsimpis
                self.build_id = max_id + 1
259 ef695867 Ilias Tsitsimpis
            else:
260 ef695867 Ilias Tsitsimpis
                self.build_id = 1
261 ef695867 Ilias Tsitsimpis
        self.logger.debug("New build id \"%s\" was created"
262 ef695867 Ilias Tsitsimpis
                          % _green(self.build_id))
263 ef695867 Ilias Tsitsimpis
264 ef695867 Ilias Tsitsimpis
        # Find an image to use
265 6f8b2632 Ilias Tsitsimpis
        image_id = self._find_image(image)
266 ef695867 Ilias Tsitsimpis
        # Find a flavor to use
267 6f8b2632 Ilias Tsitsimpis
        flavor_id = self._find_flavor(flavor)
268 6f8b2632 Ilias Tsitsimpis
269 6f8b2632 Ilias Tsitsimpis
        # Create Server
270 69a64e60 Christos Stavrakakis
        server_name = self.config.get("Deployment", "server_name")
271 525f2979 Ilias Tsitsimpis
        server = self.cyclades_client.create_server(
272 69a64e60 Christos Stavrakakis
            "%s(BID: %s)" % (server_name, self.build_id),
273 947b6106 Christos Stavrakakis
            flavor_id,
274 947b6106 Christos Stavrakakis
            image_id)
275 525f2979 Ilias Tsitsimpis
        server_id = server['id']
276 ef695867 Ilias Tsitsimpis
        self.write_temp_config('server_id', server_id)
277 525f2979 Ilias Tsitsimpis
        self.logger.debug("Server got id %s" % _green(server_id))
278 525f2979 Ilias Tsitsimpis
        server_user = server['metadata']['users']
279 ef695867 Ilias Tsitsimpis
        self.write_temp_config('server_user', server_user)
280 525f2979 Ilias Tsitsimpis
        self.logger.debug("Server's admin user is %s" % _green(server_user))
281 525f2979 Ilias Tsitsimpis
        server_passwd = server['adminPass']
282 ef695867 Ilias Tsitsimpis
        self.write_temp_config('server_passwd', server_passwd)
283 525f2979 Ilias Tsitsimpis
284 525f2979 Ilias Tsitsimpis
        server = self._wait_transition(server_id, "BUILD", "ACTIVE")
285 525f2979 Ilias Tsitsimpis
        self._get_server_ip_and_port(server)
286 4c818bb2 Ilias Tsitsimpis
        self._copy_ssh_keys(ssh_keys)
287 525f2979 Ilias Tsitsimpis
288 eaf0b161 Ilias Tsitsimpis
        # Setup Firewall
289 525f2979 Ilias Tsitsimpis
        self.setup_fabric()
290 525f2979 Ilias Tsitsimpis
        self.logger.info("Setup firewall")
291 4c818bb2 Ilias Tsitsimpis
        accept_ssh_from = self.config.get('Global', 'accept_ssh_from')
292 0082c787 Christos Stavrakakis
        if accept_ssh_from != "":
293 0082c787 Christos Stavrakakis
            self.logger.debug("Block ssh except from %s" % accept_ssh_from)
294 0082c787 Christos Stavrakakis
            cmd = """
295 0082c787 Christos Stavrakakis
            local_ip=$(/sbin/ifconfig eth0 | grep 'inet addr:' | \
296 0082c787 Christos Stavrakakis
                cut -d':' -f2 | cut -d' ' -f1)
297 0082c787 Christos Stavrakakis
            iptables -A INPUT -s localhost -j ACCEPT
298 0082c787 Christos Stavrakakis
            iptables -A INPUT -s $local_ip -j ACCEPT
299 0082c787 Christos Stavrakakis
            iptables -A INPUT -s {0} -p tcp --dport 22 -j ACCEPT
300 0082c787 Christos Stavrakakis
            iptables -A INPUT -p tcp --dport 22 -j DROP
301 0082c787 Christos Stavrakakis
            """.format(accept_ssh_from)
302 0082c787 Christos Stavrakakis
            _run(cmd, False)
303 525f2979 Ilias Tsitsimpis
304 eaf0b161 Ilias Tsitsimpis
        # Setup apt, download packages
305 eaf0b161 Ilias Tsitsimpis
        self.logger.debug("Setup apt. Install x2goserver and firefox")
306 eaf0b161 Ilias Tsitsimpis
        cmd = """
307 eaf0b161 Ilias Tsitsimpis
        echo 'APT::Install-Suggests "false";' >> /etc/apt/apt.conf
308 eaf0b161 Ilias Tsitsimpis
        apt-get update
309 eaf0b161 Ilias Tsitsimpis
        apt-get install curl --yes
310 eaf0b161 Ilias Tsitsimpis
        echo -e "\n\n{0}" >> /etc/apt/sources.list
311 eaf0b161 Ilias Tsitsimpis
        # Synnefo repo's key
312 eaf0b161 Ilias Tsitsimpis
        curl https://dev.grnet.gr/files/apt-grnetdev.pub | apt-key add -
313 eaf0b161 Ilias Tsitsimpis
        # X2GO Key
314 eaf0b161 Ilias Tsitsimpis
        apt-key adv --recv-keys --keyserver keys.gnupg.net E1F958385BFE2B6E
315 fb4988ce Ilias Tsitsimpis
        apt-get install x2go-keyring --yes
316 eaf0b161 Ilias Tsitsimpis
        apt-get update
317 fb4988ce Ilias Tsitsimpis
        apt-get install x2goserver x2goserver-xsession iceweasel --yes
318 eaf0b161 Ilias Tsitsimpis
        """.format(self.config.get('Global', 'apt_repo'))
319 eaf0b161 Ilias Tsitsimpis
        _run(cmd, False)
320 eaf0b161 Ilias Tsitsimpis
321 6f8b2632 Ilias Tsitsimpis
    def _find_flavor(self, flavor=None):
322 6f8b2632 Ilias Tsitsimpis
        """Find a suitable flavor to use
323 6f8b2632 Ilias Tsitsimpis

324 6f8b2632 Ilias Tsitsimpis
        Search by name (reg expression) or by id
325 6f8b2632 Ilias Tsitsimpis
        """
326 6f8b2632 Ilias Tsitsimpis
        # Get a list of flavors from config file
327 6f8b2632 Ilias Tsitsimpis
        flavors = self.config.get('Deployment', 'flavors').split(",")
328 6f8b2632 Ilias Tsitsimpis
        if flavor is not None:
329 c314fcd2 Ilias Tsitsimpis
            # If we have a flavor_name to use, add it to our list
330 6f8b2632 Ilias Tsitsimpis
            flavors.insert(0, flavor)
331 6f8b2632 Ilias Tsitsimpis
332 6f8b2632 Ilias Tsitsimpis
        list_flavors = self.compute_client.list_flavors()
333 6f8b2632 Ilias Tsitsimpis
        for flv in flavors:
334 6f8b2632 Ilias Tsitsimpis
            [flv_type, flv_value] = flv.strip().split(':')
335 6f8b2632 Ilias Tsitsimpis
            if flv_type == "name":
336 6f8b2632 Ilias Tsitsimpis
                # Filter flavors by name
337 6f8b2632 Ilias Tsitsimpis
                self.logger.debug(
338 6f8b2632 Ilias Tsitsimpis
                    "Trying to find a flavor with name \"%s\"" % flv_value)
339 6f8b2632 Ilias Tsitsimpis
                list_flvs = \
340 6f8b2632 Ilias Tsitsimpis
                    [f for f in list_flavors
341 6f8b2632 Ilias Tsitsimpis
                     if re.search(flv_value, f['name'], flags=re.I) is not None]
342 6f8b2632 Ilias Tsitsimpis
            elif flv_type == "id":
343 6f8b2632 Ilias Tsitsimpis
                # Filter flavors by id
344 6f8b2632 Ilias Tsitsimpis
                self.logger.debug(
345 6f8b2632 Ilias Tsitsimpis
                    "Trying to find a flavor with id \"%s\"" % flv_value)
346 6f8b2632 Ilias Tsitsimpis
                list_flvs = \
347 6f8b2632 Ilias Tsitsimpis
                    [f for f in list_flavors
348 6f8b2632 Ilias Tsitsimpis
                     if f['id'].lower() == flv_value.lower()]
349 6f8b2632 Ilias Tsitsimpis
            else:
350 6f8b2632 Ilias Tsitsimpis
                self.logger.error("Unrecognized flavor type %s" % flv_type)
351 6f8b2632 Ilias Tsitsimpis
352 6f8b2632 Ilias Tsitsimpis
            # Check if we found one
353 6f8b2632 Ilias Tsitsimpis
            if list_flvs:
354 6f8b2632 Ilias Tsitsimpis
                self.logger.debug("Will use \"%s\" with id \"%s\""
355 6f8b2632 Ilias Tsitsimpis
                                  % (list_flvs[0]['name'], list_flvs[0]['id']))
356 6f8b2632 Ilias Tsitsimpis
                return list_flvs[0]['id']
357 c314fcd2 Ilias Tsitsimpis
358 c314fcd2 Ilias Tsitsimpis
        self.logger.error("No matching flavor found.. aborting")
359 c314fcd2 Ilias Tsitsimpis
        sys.exit(1)
360 dae06cfc Ilias Tsitsimpis
361 6f8b2632 Ilias Tsitsimpis
    def _find_image(self, image=None):
362 525f2979 Ilias Tsitsimpis
        """Find a suitable image to use
363 525f2979 Ilias Tsitsimpis

364 6f8b2632 Ilias Tsitsimpis
        In case of search by name, the image has to belong to one
365 6f8b2632 Ilias Tsitsimpis
        of the `DEFAULT_SYSTEM_IMAGES_UUID' users.
366 6f8b2632 Ilias Tsitsimpis
        In case of search by id it only has to exist.
367 525f2979 Ilias Tsitsimpis
        """
368 6f8b2632 Ilias Tsitsimpis
        # Get a list of images from config file
369 6f8b2632 Ilias Tsitsimpis
        images = self.config.get('Deployment', 'images').split(",")
370 6f8b2632 Ilias Tsitsimpis
        if image is not None:
371 6f8b2632 Ilias Tsitsimpis
            # If we have an image from command line, add it to our list
372 6f8b2632 Ilias Tsitsimpis
            images.insert(0, image)
373 6f8b2632 Ilias Tsitsimpis
374 6f8b2632 Ilias Tsitsimpis
        list_images = self.image_client.list_public(detail=True)['images']
375 6f8b2632 Ilias Tsitsimpis
        for img in images:
376 6f8b2632 Ilias Tsitsimpis
            [img_type, img_value] = img.strip().split(':')
377 6f8b2632 Ilias Tsitsimpis
            if img_type == "name":
378 6f8b2632 Ilias Tsitsimpis
                # Filter images by name
379 6f8b2632 Ilias Tsitsimpis
                self.logger.debug(
380 6f8b2632 Ilias Tsitsimpis
                    "Trying to find an image with name \"%s\"" % img_value)
381 6f8b2632 Ilias Tsitsimpis
                list_imgs = \
382 6f8b2632 Ilias Tsitsimpis
                    [i for i in list_images
383 6f8b2632 Ilias Tsitsimpis
                     if i['user_id'] in DEFAULT_SYSTEM_IMAGES_UUID and
384 6f8b2632 Ilias Tsitsimpis
                        re.search(img_value, i['name'], flags=re.I) is not None]
385 6f8b2632 Ilias Tsitsimpis
            elif img_type == "id":
386 6f8b2632 Ilias Tsitsimpis
                # Filter images by id
387 6f8b2632 Ilias Tsitsimpis
                self.logger.debug(
388 6f8b2632 Ilias Tsitsimpis
                    "Trying to find an image with id \"%s\"" % img_value)
389 6f8b2632 Ilias Tsitsimpis
                list_imgs = \
390 6f8b2632 Ilias Tsitsimpis
                    [i for i in list_images
391 6f8b2632 Ilias Tsitsimpis
                     if i['id'].lower() == img_value.lower()]
392 6f8b2632 Ilias Tsitsimpis
            else:
393 6f8b2632 Ilias Tsitsimpis
                self.logger.error("Unrecognized image type %s" % img_type)
394 6f8b2632 Ilias Tsitsimpis
                sys.exit(1)
395 6f8b2632 Ilias Tsitsimpis
396 6f8b2632 Ilias Tsitsimpis
            # Check if we found one
397 6f8b2632 Ilias Tsitsimpis
            if list_imgs:
398 6f8b2632 Ilias Tsitsimpis
                self.logger.debug("Will use \"%s\" with id \"%s\""
399 6f8b2632 Ilias Tsitsimpis
                                  % (list_imgs[0]['name'], list_imgs[0]['id']))
400 6f8b2632 Ilias Tsitsimpis
                return list_imgs[0]['id']
401 6f8b2632 Ilias Tsitsimpis
402 6f8b2632 Ilias Tsitsimpis
        # We didn't found one
403 6f8b2632 Ilias Tsitsimpis
        self.logger.error("No matching image found.. aborting")
404 6f8b2632 Ilias Tsitsimpis
        sys.exit(1)
405 525f2979 Ilias Tsitsimpis
406 525f2979 Ilias Tsitsimpis
    def _get_server_ip_and_port(self, server):
407 525f2979 Ilias Tsitsimpis
        """Compute server's IPv4 and ssh port number"""
408 525f2979 Ilias Tsitsimpis
        self.logger.info("Get server connection details..")
409 525f2979 Ilias Tsitsimpis
        server_ip = server['attachments'][0]['ipv4']
410 ddd240ff Christos Stavrakakis
        if ".okeanos.io" in self.cyclades_client.base_url:
411 525f2979 Ilias Tsitsimpis
            tmp1 = int(server_ip.split(".")[2])
412 525f2979 Ilias Tsitsimpis
            tmp2 = int(server_ip.split(".")[3])
413 525f2979 Ilias Tsitsimpis
            server_ip = "gate.okeanos.io"
414 525f2979 Ilias Tsitsimpis
            server_port = 10000 + tmp1 * 256 + tmp2
415 525f2979 Ilias Tsitsimpis
        else:
416 525f2979 Ilias Tsitsimpis
            server_port = 22
417 ef695867 Ilias Tsitsimpis
        self.write_temp_config('server_ip', server_ip)
418 525f2979 Ilias Tsitsimpis
        self.logger.debug("Server's IPv4 is %s" % _green(server_ip))
419 ef695867 Ilias Tsitsimpis
        self.write_temp_config('server_port', server_port)
420 525f2979 Ilias Tsitsimpis
        self.logger.debug("Server's ssh port is %s" % _green(server_port))
421 064d2f1b Ilias Tsitsimpis
        self.logger.debug("Access server using \"ssh -X -p %s %s@%s\"" %
422 2fab294e Ilias Tsitsimpis
                          (server_port, server['metadata']['users'], server_ip))
423 525f2979 Ilias Tsitsimpis
424 5c3b5c9f Christos Stavrakakis
    @_check_fabric
425 4c818bb2 Ilias Tsitsimpis
    def _copy_ssh_keys(self, ssh_keys):
426 33ad9a0d Ilias Tsitsimpis
        """Upload/Install ssh keys to server"""
427 2fab294e Ilias Tsitsimpis
        self.logger.debug("Check for authentication keys to use")
428 4c818bb2 Ilias Tsitsimpis
        if ssh_keys is None:
429 4c818bb2 Ilias Tsitsimpis
            ssh_keys = self.config.get("Deployment", "ssh_keys")
430 4c818bb2 Ilias Tsitsimpis
431 2fab294e Ilias Tsitsimpis
        if ssh_keys != "":
432 8baa4ae7 Ilias Tsitsimpis
            ssh_keys = os.path.expanduser(ssh_keys)
433 2fab294e Ilias Tsitsimpis
            self.logger.debug("Will use %s authentication keys file" % ssh_keys)
434 5c3b5c9f Christos Stavrakakis
            keyfile = '/tmp/%s.pub' % fabric.env.user
435 5c3b5c9f Christos Stavrakakis
            _run('mkdir -p ~/.ssh && chmod 700 ~/.ssh', False)
436 2fab294e Ilias Tsitsimpis
            if ssh_keys.startswith("http://") or \
437 2fab294e Ilias Tsitsimpis
                    ssh_keys.startswith("https://") or \
438 2fab294e Ilias Tsitsimpis
                    ssh_keys.startswith("ftp://"):
439 2fab294e Ilias Tsitsimpis
                cmd = """
440 2fab294e Ilias Tsitsimpis
                apt-get update
441 2fab294e Ilias Tsitsimpis
                apt-get install wget --yes
442 2fab294e Ilias Tsitsimpis
                wget {0} -O {1} --no-check-certificate
443 2fab294e Ilias Tsitsimpis
                """.format(ssh_keys, keyfile)
444 2fab294e Ilias Tsitsimpis
                _run(cmd, False)
445 2fab294e Ilias Tsitsimpis
            elif os.path.exists(ssh_keys):
446 2fab294e Ilias Tsitsimpis
                _put(ssh_keys, keyfile)
447 2fab294e Ilias Tsitsimpis
            else:
448 2fab294e Ilias Tsitsimpis
                self.logger.debug("No ssh keys found")
449 8baa4ae7 Ilias Tsitsimpis
                return
450 5c3b5c9f Christos Stavrakakis
            _run('cat %s >> ~/.ssh/authorized_keys' % keyfile, False)
451 5c3b5c9f Christos Stavrakakis
            _run('rm %s' % keyfile, False)
452 5c3b5c9f Christos Stavrakakis
            self.logger.debug("Uploaded ssh authorized keys")
453 5c3b5c9f Christos Stavrakakis
        else:
454 5c3b5c9f Christos Stavrakakis
            self.logger.debug("No ssh keys found")
455 5c3b5c9f Christos Stavrakakis
456 ef695867 Ilias Tsitsimpis
    def write_temp_config(self, option, value):
457 525f2979 Ilias Tsitsimpis
        """Write changes back to config file"""
458 4b61ee63 Ilias Tsitsimpis
        # Acquire the lock to write to temp_config_file
459 4b61ee63 Ilias Tsitsimpis
        with filelocker.lock("%s.lock" % self.temp_config_file,
460 4b61ee63 Ilias Tsitsimpis
                             filelocker.LOCK_EX):
461 4b61ee63 Ilias Tsitsimpis
462 4b61ee63 Ilias Tsitsimpis
            # Read temp_config again to get any new entries
463 4b61ee63 Ilias Tsitsimpis
            self.temp_config.read(self.temp_config_file)
464 4b61ee63 Ilias Tsitsimpis
465 4b61ee63 Ilias Tsitsimpis
            # If build_id section doesn't exist create a new one
466 4b61ee63 Ilias Tsitsimpis
            try:
467 4b61ee63 Ilias Tsitsimpis
                self.temp_config.add_section(str(self.build_id))
468 4b61ee63 Ilias Tsitsimpis
                creation_time = \
469 4b61ee63 Ilias Tsitsimpis
                    time.strftime("%a, %d %b %Y %X", time.localtime())
470 4b61ee63 Ilias Tsitsimpis
                self.temp_config.set(str(self.build_id),
471 4b61ee63 Ilias Tsitsimpis
                                     "created", str(creation_time))
472 4b61ee63 Ilias Tsitsimpis
            except DuplicateSectionError:
473 4b61ee63 Ilias Tsitsimpis
                pass
474 4b61ee63 Ilias Tsitsimpis
            self.temp_config.set(str(self.build_id), option, str(value))
475 4b61ee63 Ilias Tsitsimpis
            curr_time = time.strftime("%a, %d %b %Y %X", time.localtime())
476 4b61ee63 Ilias Tsitsimpis
            self.temp_config.set(str(self.build_id), "modified", curr_time)
477 4b61ee63 Ilias Tsitsimpis
            with open(self.temp_config_file, 'wb') as tcf:
478 4b61ee63 Ilias Tsitsimpis
                self.temp_config.write(tcf)
479 525f2979 Ilias Tsitsimpis
480 ef695867 Ilias Tsitsimpis
    def read_temp_config(self, option):
481 ef695867 Ilias Tsitsimpis
        """Read from temporary_config file"""
482 ef695867 Ilias Tsitsimpis
        # If build_id is None use the latest one
483 ef695867 Ilias Tsitsimpis
        if self.build_id is None:
484 ef695867 Ilias Tsitsimpis
            ids = self.temp_config.sections()
485 ef695867 Ilias Tsitsimpis
            if ids:
486 ef695867 Ilias Tsitsimpis
                self.build_id = int(ids[-1])
487 ef695867 Ilias Tsitsimpis
            else:
488 ef695867 Ilias Tsitsimpis
                self.logger.error("No sections in temporary config file")
489 ef695867 Ilias Tsitsimpis
                sys.exit(1)
490 ef695867 Ilias Tsitsimpis
            self.logger.debug("Will use \"%s\" as build id"
491 ef695867 Ilias Tsitsimpis
                              % _green(self.build_id))
492 ef695867 Ilias Tsitsimpis
        # Read specified option
493 ef695867 Ilias Tsitsimpis
        return self.temp_config.get(str(self.build_id), option)
494 ef695867 Ilias Tsitsimpis
495 525f2979 Ilias Tsitsimpis
    def setup_fabric(self):
496 525f2979 Ilias Tsitsimpis
        """Setup fabric environment"""
497 525f2979 Ilias Tsitsimpis
        self.logger.info("Setup fabric parameters..")
498 ef695867 Ilias Tsitsimpis
        fabric.env.user = self.read_temp_config('server_user')
499 ef695867 Ilias Tsitsimpis
        fabric.env.host_string = self.read_temp_config('server_ip')
500 ef695867 Ilias Tsitsimpis
        fabric.env.port = int(self.read_temp_config('server_port'))
501 ef695867 Ilias Tsitsimpis
        fabric.env.password = self.read_temp_config('server_passwd')
502 525f2979 Ilias Tsitsimpis
        fabric.env.connection_attempts = 10
503 525f2979 Ilias Tsitsimpis
        fabric.env.shell = "/bin/bash -c"
504 525f2979 Ilias Tsitsimpis
        fabric.env.disable_known_hosts = True
505 525f2979 Ilias Tsitsimpis
        fabric.env.output_prefix = None
506 525f2979 Ilias Tsitsimpis
507 525f2979 Ilias Tsitsimpis
    def _check_hash_sum(self, localfile, remotefile):
508 525f2979 Ilias Tsitsimpis
        """Check hash sums of two files"""
509 525f2979 Ilias Tsitsimpis
        self.logger.debug("Check hash sum for local file %s" % localfile)
510 525f2979 Ilias Tsitsimpis
        hash1 = os.popen("sha256sum %s" % localfile).read().split(' ')[0]
511 525f2979 Ilias Tsitsimpis
        self.logger.debug("Local file has sha256 hash %s" % hash1)
512 525f2979 Ilias Tsitsimpis
        self.logger.debug("Check hash sum for remote file %s" % remotefile)
513 525f2979 Ilias Tsitsimpis
        hash2 = _run("sha256sum %s" % remotefile, False)
514 525f2979 Ilias Tsitsimpis
        hash2 = hash2.split(' ')[0]
515 525f2979 Ilias Tsitsimpis
        self.logger.debug("Remote file has sha256 hash %s" % hash2)
516 525f2979 Ilias Tsitsimpis
        if hash1 != hash2:
517 525f2979 Ilias Tsitsimpis
            self.logger.error("Hashes differ.. aborting")
518 525f2979 Ilias Tsitsimpis
            sys.exit(-1)
519 525f2979 Ilias Tsitsimpis
520 525f2979 Ilias Tsitsimpis
    @_check_fabric
521 1d9f2031 Ilias Tsitsimpis
    def clone_repo(self, local_repo=False):
522 525f2979 Ilias Tsitsimpis
        """Clone Synnefo repo from slave server"""
523 525f2979 Ilias Tsitsimpis
        self.logger.info("Configure repositories on remote server..")
524 eaf0b161 Ilias Tsitsimpis
        self.logger.debug("Install/Setup git")
525 525f2979 Ilias Tsitsimpis
        cmd = """
526 eaf0b161 Ilias Tsitsimpis
        apt-get install git --yes
527 eaf0b161 Ilias Tsitsimpis
        git config --global user.name {0}
528 eaf0b161 Ilias Tsitsimpis
        git config --global user.email {1}
529 eaf0b161 Ilias Tsitsimpis
        """.format(self.config.get('Global', 'git_config_name'),
530 525f2979 Ilias Tsitsimpis
                   self.config.get('Global', 'git_config_mail'))
531 525f2979 Ilias Tsitsimpis
        _run(cmd, False)
532 525f2979 Ilias Tsitsimpis
533 1d9f2031 Ilias Tsitsimpis
        # Find synnefo_repo and synnefo_branch to use
534 525f2979 Ilias Tsitsimpis
        synnefo_repo = self.config.get('Global', 'synnefo_repo')
535 024faf05 Christos Stavrakakis
        synnefo_branch = self.config.get("Global", "synnefo_branch")
536 024faf05 Christos Stavrakakis
        if synnefo_branch == "":
537 33ad9a0d Ilias Tsitsimpis
            synnefo_branch = \
538 33ad9a0d Ilias Tsitsimpis
                subprocess.Popen(
539 33ad9a0d Ilias Tsitsimpis
                    ["git", "rev-parse", "--abbrev-ref", "HEAD"],
540 024faf05 Christos Stavrakakis
                    stdout=subprocess.PIPE).communicate()[0].strip()
541 024faf05 Christos Stavrakakis
            if synnefo_branch == "HEAD":
542 024faf05 Christos Stavrakakis
                synnefo_branch = \
543 33ad9a0d Ilias Tsitsimpis
                    subprocess.Popen(
544 33ad9a0d Ilias Tsitsimpis
                        ["git", "rev-parse", "--short", "HEAD"],
545 024faf05 Christos Stavrakakis
                        stdout=subprocess.PIPE).communicate()[0].strip()
546 024faf05 Christos Stavrakakis
        self.logger.info("Will use branch %s" % synnefo_branch)
547 1d9f2031 Ilias Tsitsimpis
548 1d9f2031 Ilias Tsitsimpis
        if local_repo or synnefo_branch == "":
549 1d9f2031 Ilias Tsitsimpis
            # Use local_repo
550 1d9f2031 Ilias Tsitsimpis
            self.logger.debug("Push local repo to server")
551 1d9f2031 Ilias Tsitsimpis
            # Firstly create the remote repo
552 1d9f2031 Ilias Tsitsimpis
            _run("git init synnefo", False)
553 1d9f2031 Ilias Tsitsimpis
            # Then push our local repo over ssh
554 1d9f2031 Ilias Tsitsimpis
            # We have to pass some arguments to ssh command
555 1d9f2031 Ilias Tsitsimpis
            # namely to disable host checking.
556 1d9f2031 Ilias Tsitsimpis
            (temp_ssh_file_handle, temp_ssh_file) = tempfile.mkstemp()
557 1d9f2031 Ilias Tsitsimpis
            os.close(temp_ssh_file_handle)
558 4b61ee63 Ilias Tsitsimpis
            # XXX: git push doesn't read the password
559 1d9f2031 Ilias Tsitsimpis
            cmd = """
560 1d9f2031 Ilias Tsitsimpis
            echo 'exec ssh -o "StrictHostKeyChecking no" \
561 1d9f2031 Ilias Tsitsimpis
                           -o "UserKnownHostsFile /dev/null" \
562 1d9f2031 Ilias Tsitsimpis
                           -q "$@"' > {4}
563 1d9f2031 Ilias Tsitsimpis
            chmod u+x {4}
564 1d9f2031 Ilias Tsitsimpis
            export GIT_SSH="{4}"
565 1d9f2031 Ilias Tsitsimpis
            echo "{0}" | git push --mirror ssh://{1}@{2}:{3}/~/synnefo
566 1d9f2031 Ilias Tsitsimpis
            rm -f {4}
567 1d9f2031 Ilias Tsitsimpis
            """.format(fabric.env.password,
568 1d9f2031 Ilias Tsitsimpis
                       fabric.env.user,
569 1d9f2031 Ilias Tsitsimpis
                       fabric.env.host_string,
570 1d9f2031 Ilias Tsitsimpis
                       fabric.env.port,
571 1d9f2031 Ilias Tsitsimpis
                       temp_ssh_file)
572 1d9f2031 Ilias Tsitsimpis
            os.system(cmd)
573 1d9f2031 Ilias Tsitsimpis
        else:
574 1d9f2031 Ilias Tsitsimpis
            # Clone Synnefo from remote repo
575 1d9f2031 Ilias Tsitsimpis
            # Currently clonning synnefo can fail unexpectedly
576 1d9f2031 Ilias Tsitsimpis
            cloned = False
577 1d9f2031 Ilias Tsitsimpis
            for i in range(10):
578 1d9f2031 Ilias Tsitsimpis
                self.logger.debug("Clone synnefo from %s" % synnefo_repo)
579 1d9f2031 Ilias Tsitsimpis
                try:
580 1d9f2031 Ilias Tsitsimpis
                    _run("git clone %s synnefo" % synnefo_repo, False)
581 1d9f2031 Ilias Tsitsimpis
                    cloned = True
582 1d9f2031 Ilias Tsitsimpis
                    break
583 1d9f2031 Ilias Tsitsimpis
                except BaseException:
584 1d9f2031 Ilias Tsitsimpis
                    self.logger.warning(
585 1d9f2031 Ilias Tsitsimpis
                        "Clonning synnefo failed.. retrying %s" % i)
586 1d9f2031 Ilias Tsitsimpis
            if not cloned:
587 1d9f2031 Ilias Tsitsimpis
                self.logger.error("Can not clone Synnefo repo.")
588 1d9f2031 Ilias Tsitsimpis
                sys.exit(-1)
589 1d9f2031 Ilias Tsitsimpis
590 1d9f2031 Ilias Tsitsimpis
        # Checkout the desired synnefo_branch
591 064d2f1b Ilias Tsitsimpis
        self.logger.debug("Checkout \"%s\" branch/commit" % synnefo_branch)
592 33ad9a0d Ilias Tsitsimpis
        cmd = """
593 024faf05 Christos Stavrakakis
        cd synnefo
594 33ad9a0d Ilias Tsitsimpis
        for branch in `git branch -a | grep remotes | \
595 33ad9a0d Ilias Tsitsimpis
                       grep -v HEAD | grep -v master`; do
596 024faf05 Christos Stavrakakis
            git branch --track ${branch##*/} $branch
597 024faf05 Christos Stavrakakis
        done
598 024faf05 Christos Stavrakakis
        git checkout %s
599 024faf05 Christos Stavrakakis
        """ % (synnefo_branch)
600 024faf05 Christos Stavrakakis
        _run(cmd, False)
601 024faf05 Christos Stavrakakis
602 525f2979 Ilias Tsitsimpis
    @_check_fabric
603 525f2979 Ilias Tsitsimpis
    def build_synnefo(self):
604 525f2979 Ilias Tsitsimpis
        """Build Synnefo packages"""
605 525f2979 Ilias Tsitsimpis
        self.logger.info("Build Synnefo packages..")
606 525f2979 Ilias Tsitsimpis
        self.logger.debug("Install development packages")
607 525f2979 Ilias Tsitsimpis
        cmd = """
608 525f2979 Ilias Tsitsimpis
        apt-get update
609 525f2979 Ilias Tsitsimpis
        apt-get install zlib1g-dev dpkg-dev debhelper git-buildpackage \
610 525f2979 Ilias Tsitsimpis
                python-dev python-all python-pip --yes
611 525f2979 Ilias Tsitsimpis
        pip install devflow
612 525f2979 Ilias Tsitsimpis
        """
613 525f2979 Ilias Tsitsimpis
        _run(cmd, False)
614 525f2979 Ilias Tsitsimpis
615 133e5a5b Christos Stavrakakis
        if self.config.get('Global', 'patch_pydist') == "True":
616 525f2979 Ilias Tsitsimpis
            self.logger.debug("Patch pydist.py module")
617 525f2979 Ilias Tsitsimpis
            cmd = r"""
618 525f2979 Ilias Tsitsimpis
            sed -r -i 's/(\(\?P<name>\[A-Za-z\]\[A-Za-z0-9_\.)/\1\\\-/' \
619 525f2979 Ilias Tsitsimpis
                /usr/share/python/debpython/pydist.py
620 525f2979 Ilias Tsitsimpis
            """
621 525f2979 Ilias Tsitsimpis
            _run(cmd, False)
622 525f2979 Ilias Tsitsimpis

623 24ccf5d3 Ilias Tsitsimpis
        # Build synnefo packages
624 24ccf5d3 Ilias Tsitsimpis
        self.logger.debug("Build synnefo packages")
625 525f2979 Ilias Tsitsimpis
        cmd = """
626 24ccf5d3 Ilias Tsitsimpis
        devflow-autopkg snapshot -b ~/synnefo_build-area --no-sign
627 525f2979 Ilias Tsitsimpis
        """
628 24ccf5d3 Ilias Tsitsimpis
        with fabric.cd("synnefo"):
629 525f2979 Ilias Tsitsimpis
            _run(cmd, True)
630 525f2979 Ilias Tsitsimpis

631 24ccf5d3 Ilias Tsitsimpis
        # Install snf-deploy package
632 525f2979 Ilias Tsitsimpis
        self.logger.debug("Install snf-deploy package")
633 525f2979 Ilias Tsitsimpis
        cmd = """
634 525f2979 Ilias Tsitsimpis
        dpkg -i snf-deploy*.deb
635 525f2979 Ilias Tsitsimpis
        apt-get -f install --yes
636 525f2979 Ilias Tsitsimpis
        """
637 24ccf5d3 Ilias Tsitsimpis
        with fabric.cd("synnefo_build-area"):
638 525f2979 Ilias Tsitsimpis
            with fabric.settings(warn_only=True):
639 525f2979 Ilias Tsitsimpis
                _run(cmd, True)
640 525f2979 Ilias Tsitsimpis

641 24ccf5d3 Ilias Tsitsimpis
        # Setup synnefo packages for snf-deploy
642 525f2979 Ilias Tsitsimpis
        self.logger.debug("Copy synnefo debs to snf-deploy packages dir")
643 525f2979 Ilias Tsitsimpis
        cmd = """
644 525f2979 Ilias Tsitsimpis
        cp ~/synnefo_build-area/*.deb /var/lib/snf-deploy/packages/
645 525f2979 Ilias Tsitsimpis
        """
646 525f2979 Ilias Tsitsimpis
        _run(cmd, False)
647 525f2979 Ilias Tsitsimpis

648 124c300e Christos Stavrakakis
    @_check_fabric
649 124c300e Christos Stavrakakis
    def build_documentation(self):
650 33ad9a0d Ilias Tsitsimpis
        """Build Synnefo documentation"""
651 124c300e Christos Stavrakakis
        self.logger.info("Build Synnefo documentation..")
652 124c300e Christos Stavrakakis
        _run("pip install -U Sphinx", False)
653 124c300e Christos Stavrakakis
        with fabric.cd("synnefo"):
654 33ad9a0d Ilias Tsitsimpis
            _run("devflow-update-version; "
655 33ad9a0d Ilias Tsitsimpis
                 "./ci/make_docs.sh synnefo_documentation", False)
656 124c300e Christos Stavrakakis

657 124c300e Christos Stavrakakis
    def fetch_documentation(self, dest=None):
658 33ad9a0d Ilias Tsitsimpis
        """Fetch Synnefo documentation"""
659 33ad9a0d Ilias Tsitsimpis
        self.logger.info("Fetch Synnefo documentation..")
660 124c300e Christos Stavrakakis
        if dest is None:
661 124c300e Christos Stavrakakis
            dest = "synnefo_documentation"
662 124c300e Christos Stavrakakis
        dest = os.path.abspath(dest)
663 124c300e Christos Stavrakakis
        if not os.path.exists(dest):
664 124c300e Christos Stavrakakis
            os.makedirs(dest)
665 124c300e Christos Stavrakakis
        self.fetch_compressed("synnefo/synnefo_documentation", dest)
666 124c300e Christos Stavrakakis
        self.logger.info("Downloaded documentation to %s" %
667 124c300e Christos Stavrakakis
                         _green(dest))
668 124c300e Christos Stavrakakis

669 525f2979 Ilias Tsitsimpis
    @_check_fabric
670 46a07468 Christos Stavrakakis
    def deploy_synnefo(self, schema=None):
671 525f2979 Ilias Tsitsimpis
        """Deploy Synnefo using snf-deploy"""
672 525f2979 Ilias Tsitsimpis
        self.logger.info("Deploy Synnefo..")
673 46a07468 Christos Stavrakakis
        if schema is None:
674 46a07468 Christos Stavrakakis
            schema = self.config.get('Global', 'schema')
675 6f8b2632 Ilias Tsitsimpis
        self.logger.debug("Will use \"%s\" schema" % schema)
676 525f2979 Ilias Tsitsimpis

677 46a07468 Christos Stavrakakis
        schema_dir = os.path.join(self.ci_dir, "schemas/%s" % schema)
678 46a07468 Christos Stavrakakis
        if not (os.path.exists(schema_dir) and os.path.isdir(schema_dir)):
679 46a07468 Christos Stavrakakis
            raise ValueError("Unknown schema: %s" % schema)
680 46a07468 Christos Stavrakakis

681 525f2979 Ilias Tsitsimpis
        self.logger.debug("Upload schema files to server")
682 4c818bb2 Ilias Tsitsimpis
        _put(os.path.join(schema_dir, "*"), "/etc/snf-deploy/")
683 525f2979 Ilias Tsitsimpis

684 525f2979 Ilias Tsitsimpis
        self.logger.debug("Change password in nodes.conf file")
685 525f2979 Ilias Tsitsimpis
        cmd = """
686 525f2979 Ilias Tsitsimpis
        sed -i 's/^password =.*/password = {0}/' /etc/snf-deploy/nodes.conf
687 525f2979 Ilias Tsitsimpis
        """.format(fabric.env.password)
688 525f2979 Ilias Tsitsimpis
        _run(cmd, False)
689 525f2979 Ilias Tsitsimpis

690 525f2979 Ilias Tsitsimpis
        self.logger.debug("Run snf-deploy")
691 525f2979 Ilias Tsitsimpis
        cmd = """
692 39dd21c2 Christos Stavrakakis
        snf-deploy --disable-colors --autoconf all
693 525f2979 Ilias Tsitsimpis
        """
694 525f2979 Ilias Tsitsimpis
        _run(cmd, True)
695 525f2979 Ilias Tsitsimpis

696 525f2979 Ilias Tsitsimpis
    @_check_fabric
697 525f2979 Ilias Tsitsimpis
    def unit_test(self):
698 525f2979 Ilias Tsitsimpis
        """Run Synnefo unit test suite"""
699 525f2979 Ilias Tsitsimpis
        self.logger.info("Run Synnefo unit test suite")
700 525f2979 Ilias Tsitsimpis
        component = self.config.get('Unit Tests', 'component')
701 525f2979 Ilias Tsitsimpis

702 525f2979 Ilias Tsitsimpis
        self.logger.debug("Install needed packages")
703 525f2979 Ilias Tsitsimpis
        cmd = """
704 525f2979 Ilias Tsitsimpis
        pip install mock
705 525f2979 Ilias Tsitsimpis
        pip install factory_boy
706 525f2979 Ilias Tsitsimpis
        """
707 525f2979 Ilias Tsitsimpis
        _run(cmd, False)
708 525f2979 Ilias Tsitsimpis

709 2255812d Ilias Tsitsimpis
        self.logger.debug("Upload tests.sh file")
710 2255812d Ilias Tsitsimpis
        unit_tests_file = os.path.join(self.ci_dir, "tests.sh")
711 4c818bb2 Ilias Tsitsimpis
        _put(unit_tests_file, ".")
712 525f2979 Ilias Tsitsimpis

713 525f2979 Ilias Tsitsimpis
        self.logger.debug("Run unit tests")
714 525f2979 Ilias Tsitsimpis
        cmd = """
715 2255812d Ilias Tsitsimpis
        bash tests.sh {0}
716 525f2979 Ilias Tsitsimpis
        """.format(component)
717 525f2979 Ilias Tsitsimpis
        _run(cmd, True)
718 525f2979 Ilias Tsitsimpis

719 525f2979 Ilias Tsitsimpis
    @_check_fabric
720 525f2979 Ilias Tsitsimpis
    def run_burnin(self):
721 525f2979 Ilias Tsitsimpis
        """Run burnin functional test suite"""
722 525f2979 Ilias Tsitsimpis
        self.logger.info("Run Burnin functional test suite")
723 525f2979 Ilias Tsitsimpis
        cmd = """
724 525f2979 Ilias Tsitsimpis
        auth_url=$(grep -e '^url =' .kamakirc | cut -d' ' -f3)
725 525f2979 Ilias Tsitsimpis
        token=$(grep -e '^token =' .kamakirc | cut -d' ' -f3)
726 525f2979 Ilias Tsitsimpis
        images_user=$(kamaki image list -l | grep owner | \
727 525f2979 Ilias Tsitsimpis
                      cut -d':' -f2 | tr -d ' ')
728 525f2979 Ilias Tsitsimpis
        snf-burnin --auth-url=$auth_url --token=$token \
729 525f2979 Ilias Tsitsimpis
            --force-flavor=2 --image-id=all \
730 525f2979 Ilias Tsitsimpis
            --system-images-user=$images_user \
731 525f2979 Ilias Tsitsimpis
            {0}
732 525f2979 Ilias Tsitsimpis
        log_folder=$(ls -1d /var/log/burnin/* | tail -n1)
733 525f2979 Ilias Tsitsimpis
        for i in $(ls $log_folder/*/details*); do
734 525f2979 Ilias Tsitsimpis
            echo -e "\\n\\n"
735 525f2979 Ilias Tsitsimpis
            echo -e "***** $i\\n"
736 525f2979 Ilias Tsitsimpis
            cat $i
737 525f2979 Ilias Tsitsimpis
        done
738 525f2979 Ilias Tsitsimpis
        """.format(self.config.get('Burnin', 'cmd_options'))
739 525f2979 Ilias Tsitsimpis
        _run(cmd, True)
740 525f2979 Ilias Tsitsimpis

741 525f2979 Ilias Tsitsimpis
    @_check_fabric
742 124c300e Christos Stavrakakis
    def fetch_compressed(self, src, dest=None):
743 33ad9a0d Ilias Tsitsimpis
        """Create a tarball and fetch it locally"""
744 124c300e Christos Stavrakakis
        self.logger.debug("Creating tarball of %s" % src)
745 124c300e Christos Stavrakakis
        basename = os.path.basename(src)
746 124c300e Christos Stavrakakis
        tar_file = basename + ".tgz"
747 124c300e Christos Stavrakakis
        cmd = "tar czf %s %s" % (tar_file, src)
748 525f2979 Ilias Tsitsimpis
        _run(cmd, False)
749 124c300e Christos Stavrakakis
        if not os.path.exists(dest):
750 124c300e Christos Stavrakakis
            os.makedirs(dest)
751 525f2979 Ilias Tsitsimpis

752 124c300e Christos Stavrakakis
        tmp_dir = tempfile.mkdtemp()
753 124c300e Christos Stavrakakis
        fabric.get(tar_file, tmp_dir)
754 525f2979 Ilias Tsitsimpis

755 124c300e Christos Stavrakakis
        dest_file = os.path.join(tmp_dir, tar_file)
756 124c300e Christos Stavrakakis
        self._check_hash_sum(dest_file, tar_file)
757 124c300e Christos Stavrakakis
        self.logger.debug("Untar packages file %s" % dest_file)
758 ee2419c5 Christos Stavrakakis
        cmd = """
759 ee2419c5 Christos Stavrakakis
        cd %s
760 124c300e Christos Stavrakakis
        tar xzf %s
761 124c300e Christos Stavrakakis
        cp -r %s/* %s
762 124c300e Christos Stavrakakis
        rm -r %s
763 124c300e Christos Stavrakakis
        """ % (tmp_dir, tar_file, src, dest, tmp_dir)
764 ee2419c5 Christos Stavrakakis
        os.system(cmd)
765 124c300e Christos Stavrakakis
        self.logger.info("Downloaded %s to %s" %
766 124c300e Christos Stavrakakis
                         (src, _green(dest)))
767 124c300e Christos Stavrakakis

768 124c300e Christos Stavrakakis
    @_check_fabric
769 124c300e Christos Stavrakakis
    def fetch_packages(self, dest=None):
770 33ad9a0d Ilias Tsitsimpis
        """Fetch Synnefo packages"""
771 124c300e Christos Stavrakakis
        if dest is None:
772 124c300e Christos Stavrakakis
            dest = self.config.get('Global', 'pkgs_dir')
773 8baa4ae7 Ilias Tsitsimpis
        dest = os.path.abspath(os.path.expanduser(dest))
774 124c300e Christos Stavrakakis
        if not os.path.exists(dest):
775 124c300e Christos Stavrakakis
            os.makedirs(dest)
776 124c300e Christos Stavrakakis
        self.fetch_compressed("synnefo_build-area", dest)
777 85bcc8da Christos Stavrakakis
        self.logger.info("Downloaded debian packages to %s" %
778 124c300e Christos Stavrakakis
                         _green(dest))