Statistics
| Branch: | Tag: | Revision:

root / ci / utils.py @ 31bc4729

History | View | Annotate | Download (33.4 kB)

1 c29ac11d 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 c29ac11d Ilias Tsitsimpis
from kamaki.clients.cyclades import CycladesClient
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 c29ac11d Ilias Tsitsimpis
            self._fmt = "  %(msg)s"
96 c29ac11d Ilias Tsitsimpis
        elif record.levelno == logging.INFO:
97 c29ac11d Ilias Tsitsimpis
            self._fmt = "%(msg)s"
98 c29ac11d Ilias Tsitsimpis
        elif record.levelno == logging.WARNING:
99 c29ac11d Ilias Tsitsimpis
            self._fmt = _yellow("[W] %(msg)s")
100 c29ac11d Ilias Tsitsimpis
        elif record.levelno == logging.ERROR:
101 c29ac11d Ilias Tsitsimpis
            self._fmt = _red("[E] %(msg)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 b7496c88 Ilias Tsitsimpis
        self.logger.info("Will use \"%s\" as build id" % _green(self.build_id))
159 c29ac11d Ilias Tsitsimpis
160 c1b1d444 Christos Stavrakakis
        # Set kamaki cloud
161 c1b1d444 Christos Stavrakakis
        if cloud is not None:
162 c1b1d444 Christos Stavrakakis
            self.kamaki_cloud = cloud
163 c1b1d444 Christos Stavrakakis
        elif self.config.has_option("Deployment", "kamaki_cloud"):
164 c1b1d444 Christos Stavrakakis
            kamaki_cloud = self.config.get("Deployment", "kamaki_cloud")
165 c1b1d444 Christos Stavrakakis
            if kamaki_cloud == "":
166 c1b1d444 Christos Stavrakakis
                self.kamaki_cloud = None
167 c1b1d444 Christos Stavrakakis
        else:
168 c1b1d444 Christos Stavrakakis
            self.kamaki_cloud = None
169 c1b1d444 Christos Stavrakakis
170 c29ac11d Ilias Tsitsimpis
        # Initialize variables
171 c29ac11d Ilias Tsitsimpis
        self.fabric_installed = False
172 c29ac11d Ilias Tsitsimpis
        self.kamaki_installed = False
173 c29ac11d Ilias Tsitsimpis
        self.cyclades_client = None
174 ad21ffa9 Ilias Tsitsimpis
        self.compute_client = None
175 c29ac11d Ilias Tsitsimpis
        self.image_client = None
176 694c79bb Ilias Tsitsimpis
        self.astakos_client = None
177 c29ac11d Ilias Tsitsimpis
178 c29ac11d Ilias Tsitsimpis
    def setup_kamaki(self):
179 c29ac11d Ilias Tsitsimpis
        """Initialize kamaki
180 c29ac11d Ilias Tsitsimpis

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

306 6c3cc77e Ilias Tsitsimpis
        # X2GO Key
307 6c3cc77e Ilias Tsitsimpis
        apt-key adv --recv-keys --keyserver keys.gnupg.net E1F958385BFE2B6E
308 71f2649f Ilias Tsitsimpis
        apt-get install x2go-keyring --yes --force-yes
309 6c3cc77e Ilias Tsitsimpis
        apt-get update
310 71f2649f Ilias Tsitsimpis
        apt-get install x2goserver x2goserver-xsession \
311 71f2649f Ilias Tsitsimpis
                iceweasel --yes --force-yes
312 8ddb541b Ilias Tsitsimpis

313 8ddb541b Ilias Tsitsimpis
        # xterm published application
314 8ddb541b Ilias Tsitsimpis
        echo '[Desktop Entry]' > /usr/share/applications/xterm.desktop
315 8ddb541b Ilias Tsitsimpis
        echo 'Name=XTerm' >> /usr/share/applications/xterm.desktop
316 8ddb541b Ilias Tsitsimpis
        echo 'Comment=standard terminal emulator for the X window system' >> \
317 8ddb541b Ilias Tsitsimpis
            /usr/share/applications/xterm.desktop
318 8ddb541b Ilias Tsitsimpis
        echo 'Exec=xterm' >> /usr/share/applications/xterm.desktop
319 8ddb541b Ilias Tsitsimpis
        echo 'Terminal=false' >> /usr/share/applications/xterm.desktop
320 8ddb541b Ilias Tsitsimpis
        echo 'Type=Application' >> /usr/share/applications/xterm.desktop
321 8ddb541b Ilias Tsitsimpis
        echo 'Encoding=UTF-8' >> /usr/share/applications/xterm.desktop
322 8ddb541b Ilias Tsitsimpis
        echo 'Icon=xterm-color_48x48' >> /usr/share/applications/xterm.desktop
323 8ddb541b Ilias Tsitsimpis
        echo 'Categories=System;TerminalEmulator;' >> \
324 8ddb541b Ilias Tsitsimpis
                /usr/share/applications/xterm.desktop
325 6c3cc77e Ilias Tsitsimpis
        """.format(self.config.get('Global', 'apt_repo'))
326 6c3cc77e Ilias Tsitsimpis
        _run(cmd, False)
327 6c3cc77e Ilias Tsitsimpis
328 358a19bc Ilias Tsitsimpis
    def _find_flavor(self, flavor=None):
329 358a19bc Ilias Tsitsimpis
        """Find a suitable flavor to use
330 358a19bc Ilias Tsitsimpis

331 358a19bc Ilias Tsitsimpis
        Search by name (reg expression) or by id
332 358a19bc Ilias Tsitsimpis
        """
333 358a19bc Ilias Tsitsimpis
        # Get a list of flavors from config file
334 358a19bc Ilias Tsitsimpis
        flavors = self.config.get('Deployment', 'flavors').split(",")
335 358a19bc Ilias Tsitsimpis
        if flavor is not None:
336 a8bfeffc Ilias Tsitsimpis
            # If we have a flavor_name to use, add it to our list
337 358a19bc Ilias Tsitsimpis
            flavors.insert(0, flavor)
338 358a19bc Ilias Tsitsimpis
339 358a19bc Ilias Tsitsimpis
        list_flavors = self.compute_client.list_flavors()
340 358a19bc Ilias Tsitsimpis
        for flv in flavors:
341 905bb10b Christos Stavrakakis
            flv_type, flv_value = parse_typed_option(option="flavor",
342 905bb10b Christos Stavrakakis
                                                     value=flv)
343 358a19bc Ilias Tsitsimpis
            if flv_type == "name":
344 358a19bc Ilias Tsitsimpis
                # Filter flavors by name
345 358a19bc Ilias Tsitsimpis
                self.logger.debug(
346 358a19bc Ilias Tsitsimpis
                    "Trying to find a flavor with name \"%s\"" % flv_value)
347 358a19bc Ilias Tsitsimpis
                list_flvs = \
348 358a19bc Ilias Tsitsimpis
                    [f for f in list_flavors
349 905bb10b Christos Stavrakakis
                     if re.search(flv_value, f['name'], flags=re.I)
350 905bb10b Christos Stavrakakis
                     is not None]
351 358a19bc Ilias Tsitsimpis
            elif flv_type == "id":
352 358a19bc Ilias Tsitsimpis
                # Filter flavors by id
353 358a19bc Ilias Tsitsimpis
                self.logger.debug(
354 358a19bc Ilias Tsitsimpis
                    "Trying to find a flavor with id \"%s\"" % flv_value)
355 358a19bc Ilias Tsitsimpis
                list_flvs = \
356 358a19bc Ilias Tsitsimpis
                    [f for f in list_flavors
357 694c79bb Ilias Tsitsimpis
                     if str(f['id']) == flv_value]
358 358a19bc Ilias Tsitsimpis
            else:
359 358a19bc Ilias Tsitsimpis
                self.logger.error("Unrecognized flavor type %s" % flv_type)
360 358a19bc Ilias Tsitsimpis
361 358a19bc Ilias Tsitsimpis
            # Check if we found one
362 358a19bc Ilias Tsitsimpis
            if list_flvs:
363 358a19bc Ilias Tsitsimpis
                self.logger.debug("Will use \"%s\" with id \"%s\""
364 106659f1 Ilias Tsitsimpis
                                  % (_green(list_flvs[0]['name']),
365 106659f1 Ilias Tsitsimpis
                                     _green(list_flvs[0]['id'])))
366 358a19bc Ilias Tsitsimpis
                return list_flvs[0]['id']
367 a8bfeffc Ilias Tsitsimpis
368 a8bfeffc Ilias Tsitsimpis
        self.logger.error("No matching flavor found.. aborting")
369 a8bfeffc Ilias Tsitsimpis
        sys.exit(1)
370 ad21ffa9 Ilias Tsitsimpis
371 358a19bc Ilias Tsitsimpis
    def _find_image(self, image=None):
372 c29ac11d Ilias Tsitsimpis
        """Find a suitable image to use
373 c29ac11d Ilias Tsitsimpis

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

670 1c230fd8 Ilias Tsitsimpis
        # Build synnefo packages
671 1c230fd8 Ilias Tsitsimpis
        self.logger.debug("Build synnefo packages")
672 c29ac11d Ilias Tsitsimpis
        cmd = """
673 1c230fd8 Ilias Tsitsimpis
        devflow-autopkg snapshot -b ~/synnefo_build-area --no-sign
674 c29ac11d Ilias Tsitsimpis
        """
675 1c230fd8 Ilias Tsitsimpis
        with fabric.cd("synnefo"):
676 c29ac11d Ilias Tsitsimpis
            _run(cmd, True)
677 c29ac11d Ilias Tsitsimpis

678 1c230fd8 Ilias Tsitsimpis
        # Install snf-deploy package
679 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Install snf-deploy package")
680 c29ac11d Ilias Tsitsimpis
        cmd = """
681 c29ac11d Ilias Tsitsimpis
        dpkg -i snf-deploy*.deb
682 71f2649f Ilias Tsitsimpis
        apt-get -f install --yes --force-yes
683 c29ac11d Ilias Tsitsimpis
        """
684 1c230fd8 Ilias Tsitsimpis
        with fabric.cd("synnefo_build-area"):
685 c29ac11d Ilias Tsitsimpis
            with fabric.settings(warn_only=True):
686 c29ac11d Ilias Tsitsimpis
                _run(cmd, True)
687 c29ac11d Ilias Tsitsimpis

688 1c230fd8 Ilias Tsitsimpis
        # Setup synnefo packages for snf-deploy
689 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Copy synnefo debs to snf-deploy packages dir")
690 c29ac11d Ilias Tsitsimpis
        cmd = """
691 c29ac11d Ilias Tsitsimpis
        cp ~/synnefo_build-area/*.deb /var/lib/snf-deploy/packages/
692 c29ac11d Ilias Tsitsimpis
        """
693 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
694 c29ac11d Ilias Tsitsimpis

695 88e6558b Christos Stavrakakis
    @_check_fabric
696 88e6558b Christos Stavrakakis
    def build_documentation(self):
697 e2a0abb8 Ilias Tsitsimpis
        """Build Synnefo documentation"""
698 88e6558b Christos Stavrakakis
        self.logger.info("Build Synnefo documentation..")
699 88e6558b Christos Stavrakakis
        _run("pip install -U Sphinx", False)
700 88e6558b Christos Stavrakakis
        with fabric.cd("synnefo"):
701 e2a0abb8 Ilias Tsitsimpis
            _run("devflow-update-version; "
702 e2a0abb8 Ilias Tsitsimpis
                 "./ci/make_docs.sh synnefo_documentation", False)
703 88e6558b Christos Stavrakakis

704 88e6558b Christos Stavrakakis
    def fetch_documentation(self, dest=None):
705 e2a0abb8 Ilias Tsitsimpis
        """Fetch Synnefo documentation"""
706 e2a0abb8 Ilias Tsitsimpis
        self.logger.info("Fetch Synnefo documentation..")
707 88e6558b Christos Stavrakakis
        if dest is None:
708 88e6558b Christos Stavrakakis
            dest = "synnefo_documentation"
709 88e6558b Christos Stavrakakis
        dest = os.path.abspath(dest)
710 88e6558b Christos Stavrakakis
        if not os.path.exists(dest):
711 88e6558b Christos Stavrakakis
            os.makedirs(dest)
712 88e6558b Christos Stavrakakis
        self.fetch_compressed("synnefo/synnefo_documentation", dest)
713 88e6558b Christos Stavrakakis
        self.logger.info("Downloaded documentation to %s" %
714 88e6558b Christos Stavrakakis
                         _green(dest))
715 88e6558b Christos Stavrakakis

716 c29ac11d Ilias Tsitsimpis
    @_check_fabric
717 ec8bc030 Christos Stavrakakis
    def deploy_synnefo(self, schema=None):
718 c29ac11d Ilias Tsitsimpis
        """Deploy Synnefo using snf-deploy"""
719 c29ac11d Ilias Tsitsimpis
        self.logger.info("Deploy Synnefo..")
720 ec8bc030 Christos Stavrakakis
        if schema is None:
721 ec8bc030 Christos Stavrakakis
            schema = self.config.get('Global', 'schema')
722 106659f1 Ilias Tsitsimpis
        self.logger.debug("Will use \"%s\" schema" % _green(schema))
723 c29ac11d Ilias Tsitsimpis

724 ec8bc030 Christos Stavrakakis
        schema_dir = os.path.join(self.ci_dir, "schemas/%s" % schema)
725 ec8bc030 Christos Stavrakakis
        if not (os.path.exists(schema_dir) and os.path.isdir(schema_dir)):
726 ec8bc030 Christos Stavrakakis
            raise ValueError("Unknown schema: %s" % schema)
727 ec8bc030 Christos Stavrakakis

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

731 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Change password in nodes.conf file")
732 c29ac11d Ilias Tsitsimpis
        cmd = """
733 c29ac11d Ilias Tsitsimpis
        sed -i 's/^password =.*/password = {0}/' /etc/snf-deploy/nodes.conf
734 c29ac11d Ilias Tsitsimpis
        """.format(fabric.env.password)
735 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
736 c29ac11d Ilias Tsitsimpis

737 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Run snf-deploy")
738 c29ac11d Ilias Tsitsimpis
        cmd = """
739 985442f5 Ilias Tsitsimpis
        snf-deploy keygen --force
740 f82ce32a Christos Stavrakakis
        snf-deploy --disable-colors --autoconf all
741 c29ac11d Ilias Tsitsimpis
        """
742 c29ac11d Ilias Tsitsimpis
        _run(cmd, True)
743 c29ac11d Ilias Tsitsimpis

744 c29ac11d Ilias Tsitsimpis
    @_check_fabric
745 c29ac11d Ilias Tsitsimpis
    def unit_test(self):
746 c29ac11d Ilias Tsitsimpis
        """Run Synnefo unit test suite"""
747 c29ac11d Ilias Tsitsimpis
        self.logger.info("Run Synnefo unit test suite")
748 c29ac11d Ilias Tsitsimpis
        component = self.config.get('Unit Tests', 'component')
749 c29ac11d Ilias Tsitsimpis

750 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Install needed packages")
751 c29ac11d Ilias Tsitsimpis
        cmd = """
752 8d2c08e4 Christos Stavrakakis
        pip install -U mock
753 8d2c08e4 Christos Stavrakakis
        pip install -U factory_boy
754 c29ac11d Ilias Tsitsimpis
        """
755 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
756 c29ac11d Ilias Tsitsimpis

757 861b437e Ilias Tsitsimpis
        self.logger.debug("Upload tests.sh file")
758 861b437e Ilias Tsitsimpis
        unit_tests_file = os.path.join(self.ci_dir, "tests.sh")
759 6868804a Ilias Tsitsimpis
        _put(unit_tests_file, ".")
760 c29ac11d Ilias Tsitsimpis

761 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Run unit tests")
762 c29ac11d Ilias Tsitsimpis
        cmd = """
763 861b437e Ilias Tsitsimpis
        bash tests.sh {0}
764 c29ac11d Ilias Tsitsimpis
        """.format(component)
765 c29ac11d Ilias Tsitsimpis
        _run(cmd, True)
766 c29ac11d Ilias Tsitsimpis

767 c29ac11d Ilias Tsitsimpis
    @_check_fabric
768 c29ac11d Ilias Tsitsimpis
    def run_burnin(self):
769 c29ac11d Ilias Tsitsimpis
        """Run burnin functional test suite"""
770 c29ac11d Ilias Tsitsimpis
        self.logger.info("Run Burnin functional test suite")
771 c29ac11d Ilias Tsitsimpis
        cmd = """
772 c29ac11d Ilias Tsitsimpis
        auth_url=$(grep -e '^url =' .kamakirc | cut -d' ' -f3)
773 c29ac11d Ilias Tsitsimpis
        token=$(grep -e '^token =' .kamakirc | cut -d' ' -f3)
774 c29ac11d Ilias Tsitsimpis
        images_user=$(kamaki image list -l | grep owner | \
775 c29ac11d Ilias Tsitsimpis
                      cut -d':' -f2 | tr -d ' ')
776 c29ac11d Ilias Tsitsimpis
        snf-burnin --auth-url=$auth_url --token=$token \
777 c29ac11d Ilias Tsitsimpis
            --force-flavor=2 --image-id=all \
778 c29ac11d Ilias Tsitsimpis
            --system-images-user=$images_user \
779 c29ac11d Ilias Tsitsimpis
            {0}
780 281c7634 Ilias Tsitsimpis
        BurninExitStatus=$?
781 c29ac11d Ilias Tsitsimpis
        log_folder=$(ls -1d /var/log/burnin/* | tail -n1)
782 c29ac11d Ilias Tsitsimpis
        for i in $(ls $log_folder/*/details*); do
783 c29ac11d Ilias Tsitsimpis
            echo -e "\\n\\n"
784 c29ac11d Ilias Tsitsimpis
            echo -e "***** $i\\n"
785 c29ac11d Ilias Tsitsimpis
            cat $i
786 c29ac11d Ilias Tsitsimpis
        done
787 281c7634 Ilias Tsitsimpis
        exit $BurninExitStatus
788 c29ac11d Ilias Tsitsimpis
        """.format(self.config.get('Burnin', 'cmd_options'))
789 c29ac11d Ilias Tsitsimpis
        _run(cmd, True)
790 c29ac11d Ilias Tsitsimpis

791 c29ac11d Ilias Tsitsimpis
    @_check_fabric
792 88e6558b Christos Stavrakakis
    def fetch_compressed(self, src, dest=None):
793 e2a0abb8 Ilias Tsitsimpis
        """Create a tarball and fetch it locally"""
794 88e6558b Christos Stavrakakis
        self.logger.debug("Creating tarball of %s" % src)
795 88e6558b Christos Stavrakakis
        basename = os.path.basename(src)
796 88e6558b Christos Stavrakakis
        tar_file = basename + ".tgz"
797 88e6558b Christos Stavrakakis
        cmd = "tar czf %s %s" % (tar_file, src)
798 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
799 88e6558b Christos Stavrakakis
        if not os.path.exists(dest):
800 88e6558b Christos Stavrakakis
            os.makedirs(dest)
801 c29ac11d Ilias Tsitsimpis

802 88e6558b Christos Stavrakakis
        tmp_dir = tempfile.mkdtemp()
803 88e6558b Christos Stavrakakis
        fabric.get(tar_file, tmp_dir)
804 c29ac11d Ilias Tsitsimpis

805 88e6558b Christos Stavrakakis
        dest_file = os.path.join(tmp_dir, tar_file)
806 88e6558b Christos Stavrakakis
        self._check_hash_sum(dest_file, tar_file)
807 88e6558b Christos Stavrakakis
        self.logger.debug("Untar packages file %s" % dest_file)
808 e2dc37b2 Christos Stavrakakis
        cmd = """
809 e2dc37b2 Christos Stavrakakis
        cd %s
810 88e6558b Christos Stavrakakis
        tar xzf %s
811 88e6558b Christos Stavrakakis
        cp -r %s/* %s
812 88e6558b Christos Stavrakakis
        rm -r %s
813 88e6558b Christos Stavrakakis
        """ % (tmp_dir, tar_file, src, dest, tmp_dir)
814 e2dc37b2 Christos Stavrakakis
        os.system(cmd)
815 88e6558b Christos Stavrakakis
        self.logger.info("Downloaded %s to %s" %
816 88e6558b Christos Stavrakakis
                         (src, _green(dest)))
817 88e6558b Christos Stavrakakis

818 88e6558b Christos Stavrakakis
    @_check_fabric
819 88e6558b Christos Stavrakakis
    def fetch_packages(self, dest=None):
820 e2a0abb8 Ilias Tsitsimpis
        """Fetch Synnefo packages"""
821 88e6558b Christos Stavrakakis
        if dest is None:
822 88e6558b Christos Stavrakakis
            dest = self.config.get('Global', 'pkgs_dir')
823 6058ae72 Ilias Tsitsimpis
        dest = os.path.abspath(os.path.expanduser(dest))
824 88e6558b Christos Stavrakakis
        if not os.path.exists(dest):
825 88e6558b Christos Stavrakakis
            os.makedirs(dest)
826 88e6558b Christos Stavrakakis
        self.fetch_compressed("synnefo_build-area", dest)
827 464e58e9 Christos Stavrakakis
        self.logger.info("Downloaded debian packages to %s" %
828 88e6558b Christos Stavrakakis
                         _green(dest))
829 6958ffc6 Christos Stavrakakis

830 cf99ca80 Ilias Tsitsimpis
    def x2go_plugin(self, dest=None):
831 cf99ca80 Ilias Tsitsimpis
        """Produce an html page which will use the x2goplugin
832 cf99ca80 Ilias Tsitsimpis
833 cf99ca80 Ilias Tsitsimpis
        Arguments:
834 cf99ca80 Ilias Tsitsimpis
          dest  -- The file where to save the page (String)
835 cf99ca80 Ilias Tsitsimpis
836 cf99ca80 Ilias Tsitsimpis
        """
837 cf99ca80 Ilias Tsitsimpis
        output_str = """
838 cf99ca80 Ilias Tsitsimpis
        <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
839 cf99ca80 Ilias Tsitsimpis
        <html>
840 cf99ca80 Ilias Tsitsimpis
        <head>
841 cf99ca80 Ilias Tsitsimpis
        <title>X2Go SynnefoCI Service</title>
842 cf99ca80 Ilias Tsitsimpis
        </head>
843 cf99ca80 Ilias Tsitsimpis
        <body onload="checkPlugin()">
844 cf99ca80 Ilias Tsitsimpis
        <div id="x2goplugin">
845 cf99ca80 Ilias Tsitsimpis
            <object
846 cf99ca80 Ilias Tsitsimpis
                src="location"
847 cf99ca80 Ilias Tsitsimpis
                type="application/x2go"
848 cf99ca80 Ilias Tsitsimpis
                name="x2goplugin"
849 cf99ca80 Ilias Tsitsimpis
                palette="background"
850 cf99ca80 Ilias Tsitsimpis
                height="100%"
851 cf99ca80 Ilias Tsitsimpis
                hspace="0"
852 cf99ca80 Ilias Tsitsimpis
                vspace="0"
853 cf99ca80 Ilias Tsitsimpis
                width="100%"
854 cf99ca80 Ilias Tsitsimpis
                x2goconfig="
855 cf99ca80 Ilias Tsitsimpis
                    session=X2Go-SynnefoCI-Session
856 cf99ca80 Ilias Tsitsimpis
                    server={0}
857 cf99ca80 Ilias Tsitsimpis
                    user={1}
858 cf99ca80 Ilias Tsitsimpis
                    sshport={2}
859 cf99ca80 Ilias Tsitsimpis
                    published=true
860 cf99ca80 Ilias Tsitsimpis
                    autologin=true
861 cf99ca80 Ilias Tsitsimpis
                ">
862 cf99ca80 Ilias Tsitsimpis
            </object>
863 cf99ca80 Ilias Tsitsimpis
        </div>
864 cf99ca80 Ilias Tsitsimpis
        </body>
865 cf99ca80 Ilias Tsitsimpis
        </html>
866 cf99ca80 Ilias Tsitsimpis
        """.format(self.read_temp_config('server_ip'),
867 cf99ca80 Ilias Tsitsimpis
                   self.read_temp_config('server_user'),
868 cf99ca80 Ilias Tsitsimpis
                   self.read_temp_config('server_port'))
869 cf99ca80 Ilias Tsitsimpis
        if dest is None:
870 cf99ca80 Ilias Tsitsimpis
            dest = self.config.get('Global', 'x2go_plugin_file')
871 cf99ca80 Ilias Tsitsimpis

872 cf99ca80 Ilias Tsitsimpis
        self.logger.info("Writting x2go plugin html file to %s" % dest)
873 cf99ca80 Ilias Tsitsimpis
        fid = open(dest, 'w')
874 cf99ca80 Ilias Tsitsimpis
        fid.write(output_str)
875 cf99ca80 Ilias Tsitsimpis
        fid.close()
876 cf99ca80 Ilias Tsitsimpis

877 6958ffc6 Christos Stavrakakis

878 6958ffc6 Christos Stavrakakis
def parse_typed_option(option, value):
879 694c79bb Ilias Tsitsimpis
    """Parsed typed options (flavors and images)"""
880 6958ffc6 Christos Stavrakakis
    try:
881 6958ffc6 Christos Stavrakakis
        [type_, val] = value.strip().split(':')
882 6958ffc6 Christos Stavrakakis
        if type_ not in ["id", "name"]:
883 6958ffc6 Christos Stavrakakis
            raise ValueError
884 6958ffc6 Christos Stavrakakis
        return type_, val
885 6958ffc6 Christos Stavrakakis
    except ValueError:
886 6958ffc6 Christos Stavrakakis
        msg = "Invalid %s format. Must be [id|name]:.+" % option
887 6958ffc6 Christos Stavrakakis
        raise ValueError(msg)