Statistics
| Branch: | Tag: | Revision:

root / ci / utils.py @ 124c300e

History | View | Annotate | Download (20.9 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 525f2979 Ilias Tsitsimpis
import sys
9 525f2979 Ilias Tsitsimpis
import time
10 525f2979 Ilias Tsitsimpis
import logging
11 525f2979 Ilias Tsitsimpis
import fabric.api as fabric
12 024faf05 Christos Stavrakakis
import subprocess
13 124c300e Christos Stavrakakis
import tempfile
14 525f2979 Ilias Tsitsimpis
from ConfigParser import ConfigParser, DuplicateSectionError
15 525f2979 Ilias Tsitsimpis
16 da593e0c Christos Stavrakakis
from kamaki.cli import config as kamaki_config
17 525f2979 Ilias Tsitsimpis
from kamaki.clients.astakos import AstakosClient
18 525f2979 Ilias Tsitsimpis
from kamaki.clients.cyclades import CycladesClient
19 525f2979 Ilias Tsitsimpis
from kamaki.clients.image import ImageClient
20 525f2979 Ilias Tsitsimpis
21 e2db4a57 Christos Stavrakakis
DEFAULT_CONFIG_FILE = "new_config"
22 e2db4a57 Christos Stavrakakis
23 525f2979 Ilias Tsitsimpis
24 525f2979 Ilias Tsitsimpis
def _run(cmd, verbose):
25 525f2979 Ilias Tsitsimpis
    """Run fabric with verbose level"""
26 525f2979 Ilias Tsitsimpis
    if verbose:
27 525f2979 Ilias Tsitsimpis
        args = ('running',)
28 525f2979 Ilias Tsitsimpis
    else:
29 525f2979 Ilias Tsitsimpis
        args = ('running', 'stdout',)
30 525f2979 Ilias Tsitsimpis
    with fabric.hide(*args):
31 525f2979 Ilias Tsitsimpis
        return fabric.run(cmd)
32 525f2979 Ilias Tsitsimpis
33 525f2979 Ilias Tsitsimpis
34 525f2979 Ilias Tsitsimpis
def _red(msg):
35 525f2979 Ilias Tsitsimpis
    """Red color"""
36 525f2979 Ilias Tsitsimpis
    #return "\x1b[31m" + str(msg) + "\x1b[0m"
37 525f2979 Ilias Tsitsimpis
    return str(msg)
38 525f2979 Ilias Tsitsimpis
39 525f2979 Ilias Tsitsimpis
40 525f2979 Ilias Tsitsimpis
def _yellow(msg):
41 525f2979 Ilias Tsitsimpis
    """Yellow color"""
42 525f2979 Ilias Tsitsimpis
    #return "\x1b[33m" + str(msg) + "\x1b[0m"
43 525f2979 Ilias Tsitsimpis
    return str(msg)
44 525f2979 Ilias Tsitsimpis
45 525f2979 Ilias Tsitsimpis
46 525f2979 Ilias Tsitsimpis
def _green(msg):
47 525f2979 Ilias Tsitsimpis
    """Green color"""
48 525f2979 Ilias Tsitsimpis
    #return "\x1b[32m" + str(msg) + "\x1b[0m"
49 525f2979 Ilias Tsitsimpis
    return str(msg)
50 525f2979 Ilias Tsitsimpis
51 525f2979 Ilias Tsitsimpis
52 525f2979 Ilias Tsitsimpis
def _check_fabric(fun):
53 525f2979 Ilias Tsitsimpis
    """Check if fabric env has been set"""
54 947b6106 Christos Stavrakakis
    def wrapper(self, *args, **kwargs):
55 525f2979 Ilias Tsitsimpis
        """wrapper function"""
56 525f2979 Ilias Tsitsimpis
        if not self.fabric_installed:
57 525f2979 Ilias Tsitsimpis
            self.setup_fabric()
58 947b6106 Christos Stavrakakis
        return fun(self, *args, **kwargs)
59 525f2979 Ilias Tsitsimpis
    return wrapper
60 525f2979 Ilias Tsitsimpis
61 525f2979 Ilias Tsitsimpis
62 525f2979 Ilias Tsitsimpis
def _check_kamaki(fun):
63 525f2979 Ilias Tsitsimpis
    """Check if kamaki has been initialized"""
64 947b6106 Christos Stavrakakis
    def wrapper(self, *args, **kwargs):
65 525f2979 Ilias Tsitsimpis
        """wrapper function"""
66 525f2979 Ilias Tsitsimpis
        if not self.kamaki_installed:
67 525f2979 Ilias Tsitsimpis
            self.setup_kamaki()
68 947b6106 Christos Stavrakakis
        return fun(self, *args, **kwargs)
69 525f2979 Ilias Tsitsimpis
    return wrapper
70 525f2979 Ilias Tsitsimpis
71 525f2979 Ilias Tsitsimpis
72 525f2979 Ilias Tsitsimpis
class _MyFormatter(logging.Formatter):
73 525f2979 Ilias Tsitsimpis
    """Logging Formatter"""
74 525f2979 Ilias Tsitsimpis
    def format(self, record):
75 525f2979 Ilias Tsitsimpis
        format_orig = self._fmt
76 525f2979 Ilias Tsitsimpis
        if record.levelno == logging.DEBUG:
77 525f2979 Ilias Tsitsimpis
            self._fmt = "  %(msg)s"
78 525f2979 Ilias Tsitsimpis
        elif record.levelno == logging.INFO:
79 525f2979 Ilias Tsitsimpis
            self._fmt = "%(msg)s"
80 525f2979 Ilias Tsitsimpis
        elif record.levelno == logging.WARNING:
81 525f2979 Ilias Tsitsimpis
            self._fmt = _yellow("[W] %(msg)s")
82 525f2979 Ilias Tsitsimpis
        elif record.levelno == logging.ERROR:
83 525f2979 Ilias Tsitsimpis
            self._fmt = _red("[E] %(msg)s")
84 525f2979 Ilias Tsitsimpis
        result = logging.Formatter.format(self, record)
85 525f2979 Ilias Tsitsimpis
        self._fmt = format_orig
86 525f2979 Ilias Tsitsimpis
        return result
87 525f2979 Ilias Tsitsimpis
88 525f2979 Ilias Tsitsimpis
89 525f2979 Ilias Tsitsimpis
class SynnefoCI(object):
90 525f2979 Ilias Tsitsimpis
    """SynnefoCI python class"""
91 525f2979 Ilias Tsitsimpis
92 e2db4a57 Christos Stavrakakis
    def __init__(self, config_file=None, cleanup_config=False, cloud=None):
93 525f2979 Ilias Tsitsimpis
        """ Initialize SynnefoCI python class
94 525f2979 Ilias Tsitsimpis

95 525f2979 Ilias Tsitsimpis
        Setup logger, local_dir, config and kamaki
96 525f2979 Ilias Tsitsimpis
        """
97 525f2979 Ilias Tsitsimpis
        # Setup logger
98 525f2979 Ilias Tsitsimpis
        self.logger = logging.getLogger('synnefo-ci')
99 525f2979 Ilias Tsitsimpis
        self.logger.setLevel(logging.DEBUG)
100 525f2979 Ilias Tsitsimpis
        handler = logging.StreamHandler()
101 525f2979 Ilias Tsitsimpis
        handler.setFormatter(_MyFormatter())
102 525f2979 Ilias Tsitsimpis
        self.logger.addHandler(handler)
103 525f2979 Ilias Tsitsimpis
104 525f2979 Ilias Tsitsimpis
        # Get our local dir
105 525f2979 Ilias Tsitsimpis
        self.ci_dir = os.path.dirname(os.path.abspath(__file__))
106 525f2979 Ilias Tsitsimpis
        self.repo_dir = os.path.dirname(self.ci_dir)
107 525f2979 Ilias Tsitsimpis
108 525f2979 Ilias Tsitsimpis
        # Read config file
109 e2db4a57 Christos Stavrakakis
        if config_file is None:
110 e2db4a57 Christos Stavrakakis
            config_file = DEFAULT_CONFIG_FILE
111 e2db4a57 Christos Stavrakakis
        if not os.path.isabs(config_file):
112 e2db4a57 Christos Stavrakakis
            config_file = os.path.join(self.ci_dir, config_file)
113 133e5a5b Christos Stavrakakis
114 525f2979 Ilias Tsitsimpis
        self.config = ConfigParser()
115 525f2979 Ilias Tsitsimpis
        self.config.optionxform = str
116 e2db4a57 Christos Stavrakakis
        self.config.read(config_file)
117 525f2979 Ilias Tsitsimpis
        temp_config = self.config.get('Global', 'temporary_config')
118 525f2979 Ilias Tsitsimpis
        if cleanup_config:
119 525f2979 Ilias Tsitsimpis
            try:
120 525f2979 Ilias Tsitsimpis
                os.remove(temp_config)
121 525f2979 Ilias Tsitsimpis
            except:
122 525f2979 Ilias Tsitsimpis
                pass
123 525f2979 Ilias Tsitsimpis
        else:
124 525f2979 Ilias Tsitsimpis
            self.config.read(self.config.get('Global', 'temporary_config'))
125 525f2979 Ilias Tsitsimpis
126 da593e0c Christos Stavrakakis
        # Set kamaki cloud
127 da593e0c Christos Stavrakakis
        if cloud is not None:
128 da593e0c Christos Stavrakakis
            self.kamaki_cloud = cloud
129 da593e0c Christos Stavrakakis
        elif self.config.has_option("Deployment", "kamaki_cloud"):
130 da593e0c Christos Stavrakakis
            kamaki_cloud = self.config.get("Deployment", "kamaki_cloud")
131 da593e0c Christos Stavrakakis
            if kamaki_cloud == "":
132 da593e0c Christos Stavrakakis
                self.kamaki_cloud = None
133 da593e0c Christos Stavrakakis
        else:
134 da593e0c Christos Stavrakakis
            self.kamaki_cloud = None
135 da593e0c Christos Stavrakakis
136 525f2979 Ilias Tsitsimpis
        # Initialize variables
137 525f2979 Ilias Tsitsimpis
        self.fabric_installed = False
138 525f2979 Ilias Tsitsimpis
        self.kamaki_installed = False
139 525f2979 Ilias Tsitsimpis
        self.cyclades_client = None
140 525f2979 Ilias Tsitsimpis
        self.image_client = None
141 525f2979 Ilias Tsitsimpis
142 525f2979 Ilias Tsitsimpis
    def setup_kamaki(self):
143 525f2979 Ilias Tsitsimpis
        """Initialize kamaki
144 525f2979 Ilias Tsitsimpis

145 525f2979 Ilias Tsitsimpis
        Setup cyclades_client and image_client
146 525f2979 Ilias Tsitsimpis
        """
147 da593e0c Christos Stavrakakis
148 da593e0c Christos Stavrakakis
        config = kamaki_config.Config()
149 da593e0c Christos Stavrakakis
        if self.kamaki_cloud is None:
150 da593e0c Christos Stavrakakis
            self.kamaki_cloud = config.get_global("default_cloud")
151 da593e0c Christos Stavrakakis
152 da593e0c Christos Stavrakakis
        self.logger.info("Setup kamaki client, using cloud '%s'.." %
153 da593e0c Christos Stavrakakis
                         self.kamaki_cloud)
154 da593e0c Christos Stavrakakis
        auth_url = config.get_cloud(self.kamaki_cloud, "url")
155 525f2979 Ilias Tsitsimpis
        self.logger.debug("Authentication URL is %s" % _green(auth_url))
156 da593e0c Christos Stavrakakis
        token = config.get_cloud(self.kamaki_cloud, "token")
157 525f2979 Ilias Tsitsimpis
        #self.logger.debug("Token is %s" % _green(token))
158 525f2979 Ilias Tsitsimpis
159 525f2979 Ilias Tsitsimpis
        astakos_client = AstakosClient(auth_url, token)
160 525f2979 Ilias Tsitsimpis
161 525f2979 Ilias Tsitsimpis
        cyclades_url = \
162 525f2979 Ilias Tsitsimpis
            astakos_client.get_service_endpoints('compute')['publicURL']
163 525f2979 Ilias Tsitsimpis
        self.logger.debug("Cyclades API url is %s" % _green(cyclades_url))
164 525f2979 Ilias Tsitsimpis
        self.cyclades_client = CycladesClient(cyclades_url, token)
165 525f2979 Ilias Tsitsimpis
        self.cyclades_client.CONNECTION_RETRY_LIMIT = 2
166 525f2979 Ilias Tsitsimpis
167 525f2979 Ilias Tsitsimpis
        image_url = \
168 525f2979 Ilias Tsitsimpis
            astakos_client.get_service_endpoints('image')['publicURL']
169 525f2979 Ilias Tsitsimpis
        self.logger.debug("Images API url is %s" % _green(image_url))
170 525f2979 Ilias Tsitsimpis
        self.image_client = ImageClient(cyclades_url, token)
171 525f2979 Ilias Tsitsimpis
        self.image_client.CONNECTION_RETRY_LIMIT = 2
172 525f2979 Ilias Tsitsimpis
173 525f2979 Ilias Tsitsimpis
    def _wait_transition(self, server_id, current_status, new_status):
174 525f2979 Ilias Tsitsimpis
        """Wait for server to go from current_status to new_status"""
175 525f2979 Ilias Tsitsimpis
        self.logger.debug("Waiting for server to become %s" % new_status)
176 525f2979 Ilias Tsitsimpis
        timeout = self.config.getint('Global', 'build_timeout')
177 525f2979 Ilias Tsitsimpis
        sleep_time = 5
178 525f2979 Ilias Tsitsimpis
        while True:
179 525f2979 Ilias Tsitsimpis
            server = self.cyclades_client.get_server_details(server_id)
180 525f2979 Ilias Tsitsimpis
            if server['status'] == new_status:
181 525f2979 Ilias Tsitsimpis
                return server
182 525f2979 Ilias Tsitsimpis
            elif timeout < 0:
183 525f2979 Ilias Tsitsimpis
                self.logger.error(
184 525f2979 Ilias Tsitsimpis
                    "Waiting for server to become %s timed out" % new_status)
185 525f2979 Ilias Tsitsimpis
                self.destroy_server(False)
186 525f2979 Ilias Tsitsimpis
                sys.exit(-1)
187 525f2979 Ilias Tsitsimpis
            elif server['status'] == current_status:
188 525f2979 Ilias Tsitsimpis
                # Sleep for #n secs and continue
189 525f2979 Ilias Tsitsimpis
                timeout = timeout - sleep_time
190 525f2979 Ilias Tsitsimpis
                time.sleep(sleep_time)
191 525f2979 Ilias Tsitsimpis
            else:
192 525f2979 Ilias Tsitsimpis
                self.logger.error(
193 525f2979 Ilias Tsitsimpis
                    "Server failed with status %s" % server['status'])
194 525f2979 Ilias Tsitsimpis
                self.destroy_server(False)
195 525f2979 Ilias Tsitsimpis
                sys.exit(-1)
196 525f2979 Ilias Tsitsimpis
197 525f2979 Ilias Tsitsimpis
    @_check_kamaki
198 525f2979 Ilias Tsitsimpis
    def destroy_server(self, wait=True):
199 525f2979 Ilias Tsitsimpis
        """Destroy slave server"""
200 525f2979 Ilias Tsitsimpis
        server_id = self.config.getint('Temporary Options', 'server_id')
201 525f2979 Ilias Tsitsimpis
        self.logger.info("Destoying server with id %s " % server_id)
202 525f2979 Ilias Tsitsimpis
        self.cyclades_client.delete_server(server_id)
203 525f2979 Ilias Tsitsimpis
        if wait:
204 525f2979 Ilias Tsitsimpis
            self._wait_transition(server_id, "ACTIVE", "DELETED")
205 525f2979 Ilias Tsitsimpis
206 525f2979 Ilias Tsitsimpis
    @_check_kamaki
207 947b6106 Christos Stavrakakis
    def create_server(self, image_id=None, flavor_id=None):
208 525f2979 Ilias Tsitsimpis
        """Create slave server"""
209 525f2979 Ilias Tsitsimpis
        self.logger.info("Create a new server..")
210 947b6106 Christos Stavrakakis
        if image_id is None:
211 947b6106 Christos Stavrakakis
            image = self._find_image()
212 947b6106 Christos Stavrakakis
            self.logger.debug("Will use image \"%s\"" % _green(image['name']))
213 947b6106 Christos Stavrakakis
            image_id = image["id"]
214 947b6106 Christos Stavrakakis
        self.logger.debug("Image has id %s" % _green(image_id))
215 947b6106 Christos Stavrakakis
        if flavor_id is None:
216 947b6106 Christos Stavrakakis
            flavor_id = self.config.getint("Deployment", "flavor_id")
217 525f2979 Ilias Tsitsimpis
        server = self.cyclades_client.create_server(
218 525f2979 Ilias Tsitsimpis
            self.config.get('Deployment', 'server_name'),
219 947b6106 Christos Stavrakakis
            flavor_id,
220 947b6106 Christos Stavrakakis
            image_id)
221 525f2979 Ilias Tsitsimpis
        server_id = server['id']
222 525f2979 Ilias Tsitsimpis
        self.write_config('server_id', server_id)
223 525f2979 Ilias Tsitsimpis
        self.logger.debug("Server got id %s" % _green(server_id))
224 525f2979 Ilias Tsitsimpis
        server_user = server['metadata']['users']
225 525f2979 Ilias Tsitsimpis
        self.write_config('server_user', server_user)
226 525f2979 Ilias Tsitsimpis
        self.logger.debug("Server's admin user is %s" % _green(server_user))
227 525f2979 Ilias Tsitsimpis
        server_passwd = server['adminPass']
228 525f2979 Ilias Tsitsimpis
        self.write_config('server_passwd', server_passwd)
229 525f2979 Ilias Tsitsimpis
230 525f2979 Ilias Tsitsimpis
        server = self._wait_transition(server_id, "BUILD", "ACTIVE")
231 525f2979 Ilias Tsitsimpis
        self._get_server_ip_and_port(server)
232 5c3b5c9f Christos Stavrakakis
        self._copy_ssh_keys()
233 525f2979 Ilias Tsitsimpis
234 525f2979 Ilias Tsitsimpis
        self.setup_fabric()
235 525f2979 Ilias Tsitsimpis
        self.logger.info("Setup firewall")
236 525f2979 Ilias Tsitsimpis
        accept_ssh_from = self.config.get('Global', 'filter_access_network')
237 0082c787 Christos Stavrakakis
        if accept_ssh_from != "":
238 0082c787 Christos Stavrakakis
            self.logger.debug("Block ssh except from %s" % accept_ssh_from)
239 0082c787 Christos Stavrakakis
            cmd = """
240 0082c787 Christos Stavrakakis
            local_ip=$(/sbin/ifconfig eth0 | grep 'inet addr:' | \
241 0082c787 Christos Stavrakakis
                cut -d':' -f2 | cut -d' ' -f1)
242 0082c787 Christos Stavrakakis
            iptables -A INPUT -s localhost -j ACCEPT
243 0082c787 Christos Stavrakakis
            iptables -A INPUT -s $local_ip -j ACCEPT
244 0082c787 Christos Stavrakakis
            iptables -A INPUT -s {0} -p tcp --dport 22 -j ACCEPT
245 0082c787 Christos Stavrakakis
            iptables -A INPUT -p tcp --dport 22 -j DROP
246 0082c787 Christos Stavrakakis
            """.format(accept_ssh_from)
247 0082c787 Christos Stavrakakis
            _run(cmd, False)
248 525f2979 Ilias Tsitsimpis
249 525f2979 Ilias Tsitsimpis
    def _find_image(self):
250 525f2979 Ilias Tsitsimpis
        """Find a suitable image to use
251 525f2979 Ilias Tsitsimpis

252 525f2979 Ilias Tsitsimpis
        It has to belong to the `system_uuid' user and
253 525f2979 Ilias Tsitsimpis
        contain the word `image_name'
254 525f2979 Ilias Tsitsimpis
        """
255 525f2979 Ilias Tsitsimpis
        system_uuid = self.config.get('Deployment', 'system_uuid')
256 525f2979 Ilias Tsitsimpis
        image_name = self.config.get('Deployment', 'image_name').lower()
257 525f2979 Ilias Tsitsimpis
        images = self.image_client.list_public(detail=True)['images']
258 525f2979 Ilias Tsitsimpis
        # Select images by `system_uuid' user
259 525f2979 Ilias Tsitsimpis
        images = [x for x in images if x['user_id'] == system_uuid]
260 525f2979 Ilias Tsitsimpis
        # Select images with `image_name' in their names
261 525f2979 Ilias Tsitsimpis
        images = \
262 525f2979 Ilias Tsitsimpis
            [x for x in images if x['name'].lower().find(image_name) != -1]
263 525f2979 Ilias Tsitsimpis
        # Let's select the first one
264 525f2979 Ilias Tsitsimpis
        return images[0]
265 525f2979 Ilias Tsitsimpis
266 525f2979 Ilias Tsitsimpis
    def _get_server_ip_and_port(self, server):
267 525f2979 Ilias Tsitsimpis
        """Compute server's IPv4 and ssh port number"""
268 525f2979 Ilias Tsitsimpis
        self.logger.info("Get server connection details..")
269 525f2979 Ilias Tsitsimpis
        server_ip = server['attachments'][0]['ipv4']
270 ddd240ff Christos Stavrakakis
        if ".okeanos.io" in self.cyclades_client.base_url:
271 525f2979 Ilias Tsitsimpis
            tmp1 = int(server_ip.split(".")[2])
272 525f2979 Ilias Tsitsimpis
            tmp2 = int(server_ip.split(".")[3])
273 525f2979 Ilias Tsitsimpis
            server_ip = "gate.okeanos.io"
274 525f2979 Ilias Tsitsimpis
            server_port = 10000 + tmp1 * 256 + tmp2
275 525f2979 Ilias Tsitsimpis
        else:
276 525f2979 Ilias Tsitsimpis
            server_port = 22
277 525f2979 Ilias Tsitsimpis
        self.write_config('server_ip', server_ip)
278 525f2979 Ilias Tsitsimpis
        self.logger.debug("Server's IPv4 is %s" % _green(server_ip))
279 525f2979 Ilias Tsitsimpis
        self.write_config('server_port', server_port)
280 525f2979 Ilias Tsitsimpis
        self.logger.debug("Server's ssh port is %s" % _green(server_port))
281 525f2979 Ilias Tsitsimpis
282 5c3b5c9f Christos Stavrakakis
    @_check_fabric
283 5c3b5c9f Christos Stavrakakis
    def _copy_ssh_keys(self):
284 0082c787 Christos Stavrakakis
        if not self.config.has_option("Deployment", "ssh_keys"):
285 0082c787 Christos Stavrakakis
            return
286 5c3b5c9f Christos Stavrakakis
        authorized_keys = self.config.get("Deployment",
287 5c3b5c9f Christos Stavrakakis
                                          "ssh_keys")
288 0082c787 Christos Stavrakakis
        if authorized_keys != "" and os.path.exists(authorized_keys):
289 5c3b5c9f Christos Stavrakakis
            keyfile = '/tmp/%s.pub' % fabric.env.user
290 5c3b5c9f Christos Stavrakakis
            _run('mkdir -p ~/.ssh && chmod 700 ~/.ssh', False)
291 5c3b5c9f Christos Stavrakakis
            fabric.put(authorized_keys, keyfile)
292 5c3b5c9f Christos Stavrakakis
            _run('cat %s >> ~/.ssh/authorized_keys' % keyfile, False)
293 5c3b5c9f Christos Stavrakakis
            _run('rm %s' % keyfile, False)
294 5c3b5c9f Christos Stavrakakis
            self.logger.debug("Uploaded ssh authorized keys")
295 5c3b5c9f Christos Stavrakakis
        else:
296 5c3b5c9f Christos Stavrakakis
            self.logger.debug("No ssh keys found")
297 5c3b5c9f Christos Stavrakakis
298 525f2979 Ilias Tsitsimpis
    def write_config(self, option, value, section="Temporary Options"):
299 525f2979 Ilias Tsitsimpis
        """Write changes back to config file"""
300 525f2979 Ilias Tsitsimpis
        try:
301 525f2979 Ilias Tsitsimpis
            self.config.add_section(section)
302 525f2979 Ilias Tsitsimpis
        except DuplicateSectionError:
303 525f2979 Ilias Tsitsimpis
            pass
304 525f2979 Ilias Tsitsimpis
        self.config.set(section, option, str(value))
305 525f2979 Ilias Tsitsimpis
        temp_conf_file = self.config.get('Global', 'temporary_config')
306 525f2979 Ilias Tsitsimpis
        with open(temp_conf_file, 'wb') as tcf:
307 525f2979 Ilias Tsitsimpis
            self.config.write(tcf)
308 525f2979 Ilias Tsitsimpis
309 525f2979 Ilias Tsitsimpis
    def setup_fabric(self):
310 525f2979 Ilias Tsitsimpis
        """Setup fabric environment"""
311 525f2979 Ilias Tsitsimpis
        self.logger.info("Setup fabric parameters..")
312 525f2979 Ilias Tsitsimpis
        fabric.env.user = self.config.get('Temporary Options', 'server_user')
313 525f2979 Ilias Tsitsimpis
        fabric.env.host_string = \
314 525f2979 Ilias Tsitsimpis
            self.config.get('Temporary Options', 'server_ip')
315 133e5a5b Christos Stavrakakis
        fabric.env.port = self.config.getint('Temporary Options',
316 133e5a5b Christos Stavrakakis
                                             'server_port')
317 133e5a5b Christos Stavrakakis
        fabric.env.password = self.config.get('Temporary Options',
318 133e5a5b Christos Stavrakakis
                                              'server_passwd')
319 525f2979 Ilias Tsitsimpis
        fabric.env.connection_attempts = 10
320 525f2979 Ilias Tsitsimpis
        fabric.env.shell = "/bin/bash -c"
321 525f2979 Ilias Tsitsimpis
        fabric.env.disable_known_hosts = True
322 525f2979 Ilias Tsitsimpis
        fabric.env.output_prefix = None
323 525f2979 Ilias Tsitsimpis
324 525f2979 Ilias Tsitsimpis
    def _check_hash_sum(self, localfile, remotefile):
325 525f2979 Ilias Tsitsimpis
        """Check hash sums of two files"""
326 525f2979 Ilias Tsitsimpis
        self.logger.debug("Check hash sum for local file %s" % localfile)
327 525f2979 Ilias Tsitsimpis
        hash1 = os.popen("sha256sum %s" % localfile).read().split(' ')[0]
328 525f2979 Ilias Tsitsimpis
        self.logger.debug("Local file has sha256 hash %s" % hash1)
329 525f2979 Ilias Tsitsimpis
        self.logger.debug("Check hash sum for remote file %s" % remotefile)
330 525f2979 Ilias Tsitsimpis
        hash2 = _run("sha256sum %s" % remotefile, False)
331 525f2979 Ilias Tsitsimpis
        hash2 = hash2.split(' ')[0]
332 525f2979 Ilias Tsitsimpis
        self.logger.debug("Remote file has sha256 hash %s" % hash2)
333 525f2979 Ilias Tsitsimpis
        if hash1 != hash2:
334 525f2979 Ilias Tsitsimpis
            self.logger.error("Hashes differ.. aborting")
335 525f2979 Ilias Tsitsimpis
            sys.exit(-1)
336 525f2979 Ilias Tsitsimpis
337 525f2979 Ilias Tsitsimpis
    @_check_fabric
338 525f2979 Ilias Tsitsimpis
    def clone_repo(self):
339 525f2979 Ilias Tsitsimpis
        """Clone Synnefo repo from slave server"""
340 525f2979 Ilias Tsitsimpis
        self.logger.info("Configure repositories on remote server..")
341 525f2979 Ilias Tsitsimpis
        self.logger.debug("Setup apt, install curl and git")
342 525f2979 Ilias Tsitsimpis
        cmd = """
343 525f2979 Ilias Tsitsimpis
        echo 'APT::Install-Suggests "false";' >> /etc/apt/apt.conf
344 525f2979 Ilias Tsitsimpis
        apt-get update
345 525f2979 Ilias Tsitsimpis
        apt-get install curl git --yes
346 525f2979 Ilias Tsitsimpis
        echo -e "\n\ndeb {0}" >> /etc/apt/sources.list
347 525f2979 Ilias Tsitsimpis
        curl https://dev.grnet.gr/files/apt-grnetdev.pub | apt-key add -
348 525f2979 Ilias Tsitsimpis
        apt-get update
349 525f2979 Ilias Tsitsimpis
        git config --global user.name {1}
350 525f2979 Ilias Tsitsimpis
        git config --global user.mail {2}
351 525f2979 Ilias Tsitsimpis
        """.format(self.config.get('Global', 'apt_repo'),
352 525f2979 Ilias Tsitsimpis
                   self.config.get('Global', 'git_config_name'),
353 525f2979 Ilias Tsitsimpis
                   self.config.get('Global', 'git_config_mail'))
354 525f2979 Ilias Tsitsimpis
        _run(cmd, False)
355 525f2979 Ilias Tsitsimpis
356 525f2979 Ilias Tsitsimpis
        synnefo_repo = self.config.get('Global', 'synnefo_repo')
357 024faf05 Christos Stavrakakis
        synnefo_branch = self.config.get("Global", "synnefo_branch")
358 024faf05 Christos Stavrakakis
        if synnefo_branch == "":
359 024faf05 Christos Stavrakakis
            synnefo_branch =\
360 024faf05 Christos Stavrakakis
                subprocess.Popen(["git", "rev-parse", "--abbrev-ref", "HEAD"],
361 024faf05 Christos Stavrakakis
                    stdout=subprocess.PIPE).communicate()[0].strip()
362 024faf05 Christos Stavrakakis
            if synnefo_branch == "HEAD":
363 024faf05 Christos Stavrakakis
                synnefo_branch = \
364 024faf05 Christos Stavrakakis
                    subprocess.Popen(["git", "rev-parse","--short", "HEAD"],
365 024faf05 Christos Stavrakakis
                        stdout=subprocess.PIPE).communicate()[0].strip()
366 024faf05 Christos Stavrakakis
        self.logger.info("Will use branch %s" % synnefo_branch)
367 525f2979 Ilias Tsitsimpis
        # Currently clonning synnefo can fail unexpectedly
368 133e5a5b Christos Stavrakakis
        cloned = False
369 024faf05 Christos Stavrakakis
        for i in range(10):
370 525f2979 Ilias Tsitsimpis
            self.logger.debug("Clone synnefo from %s" % synnefo_repo)
371 525f2979 Ilias Tsitsimpis
            try:
372 024faf05 Christos Stavrakakis
                _run("git clone %s synnefo" % synnefo_repo, False)
373 133e5a5b Christos Stavrakakis
                cloned = True
374 525f2979 Ilias Tsitsimpis
                break
375 525f2979 Ilias Tsitsimpis
            except:
376 133e5a5b Christos Stavrakakis
                self.logger.warning("Clonning synnefo failed.. retrying %s"
377 133e5a5b Christos Stavrakakis
                                    % i)
378 024faf05 Christos Stavrakakis
        cmd ="""
379 024faf05 Christos Stavrakakis
        cd synnefo
380 024faf05 Christos Stavrakakis
        for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master`; do
381 024faf05 Christos Stavrakakis
            git branch --track ${branch##*/} $branch
382 024faf05 Christos Stavrakakis
        done
383 024faf05 Christos Stavrakakis
        git checkout %s
384 024faf05 Christos Stavrakakis
        """ % (synnefo_branch)
385 024faf05 Christos Stavrakakis
        _run(cmd, False)
386 024faf05 Christos Stavrakakis
387 133e5a5b Christos Stavrakakis
        if not cloned:
388 133e5a5b Christos Stavrakakis
            self.logger.error("Can not clone Synnefo repo.")
389 133e5a5b Christos Stavrakakis
            sys.exit(-1)
390 525f2979 Ilias Tsitsimpis
391 525f2979 Ilias Tsitsimpis
        deploy_repo = self.config.get('Global', 'deploy_repo')
392 525f2979 Ilias Tsitsimpis
        self.logger.debug("Clone snf-deploy from %s" % deploy_repo)
393 133e5a5b Christos Stavrakakis
        _run("git clone --depth 1 %s" % deploy_repo, False)
394 525f2979 Ilias Tsitsimpis
395 525f2979 Ilias Tsitsimpis
    @_check_fabric
396 525f2979 Ilias Tsitsimpis
    def build_synnefo(self):
397 525f2979 Ilias Tsitsimpis
        """Build Synnefo packages"""
398 525f2979 Ilias Tsitsimpis
        self.logger.info("Build Synnefo packages..")
399 525f2979 Ilias Tsitsimpis
        self.logger.debug("Install development packages")
400 525f2979 Ilias Tsitsimpis
        cmd = """
401 525f2979 Ilias Tsitsimpis
        apt-get update
402 525f2979 Ilias Tsitsimpis
        apt-get install zlib1g-dev dpkg-dev debhelper git-buildpackage \
403 525f2979 Ilias Tsitsimpis
                python-dev python-all python-pip --yes
404 525f2979 Ilias Tsitsimpis
        pip install devflow
405 525f2979 Ilias Tsitsimpis
        """
406 525f2979 Ilias Tsitsimpis
        _run(cmd, False)
407 525f2979 Ilias Tsitsimpis
408 133e5a5b Christos Stavrakakis
        if self.config.get('Global', 'patch_pydist') == "True":
409 525f2979 Ilias Tsitsimpis
            self.logger.debug("Patch pydist.py module")
410 525f2979 Ilias Tsitsimpis
            cmd = r"""
411 525f2979 Ilias Tsitsimpis
            sed -r -i 's/(\(\?P<name>\[A-Za-z\]\[A-Za-z0-9_\.)/\1\\\-/' \
412 525f2979 Ilias Tsitsimpis
                /usr/share/python/debpython/pydist.py
413 525f2979 Ilias Tsitsimpis
            """
414 525f2979 Ilias Tsitsimpis
            _run(cmd, False)
415 525f2979 Ilias Tsitsimpis

416 525f2979 Ilias Tsitsimpis
        self.logger.debug("Build snf-deploy package")
417 525f2979 Ilias Tsitsimpis
        cmd = """
418 525f2979 Ilias Tsitsimpis
        git checkout -t origin/debian
419 525f2979 Ilias Tsitsimpis
        git-buildpackage --git-upstream-branch=master \
420 525f2979 Ilias Tsitsimpis
                --git-debian-branch=debian \
421 525f2979 Ilias Tsitsimpis
                --git-export-dir=../snf-deploy_build-area \
422 525f2979 Ilias Tsitsimpis
                -uc -us
423 525f2979 Ilias Tsitsimpis
        """
424 525f2979 Ilias Tsitsimpis
        with fabric.cd("snf-deploy"):
425 525f2979 Ilias Tsitsimpis
            _run(cmd, True)
426 525f2979 Ilias Tsitsimpis

427 525f2979 Ilias Tsitsimpis
        self.logger.debug("Install snf-deploy package")
428 525f2979 Ilias Tsitsimpis
        cmd = """
429 525f2979 Ilias Tsitsimpis
        dpkg -i snf-deploy*.deb
430 525f2979 Ilias Tsitsimpis
        apt-get -f install --yes
431 525f2979 Ilias Tsitsimpis
        """
432 525f2979 Ilias Tsitsimpis
        with fabric.cd("snf-deploy_build-area"):
433 525f2979 Ilias Tsitsimpis
            with fabric.settings(warn_only=True):
434 525f2979 Ilias Tsitsimpis
                _run(cmd, True)
435 525f2979 Ilias Tsitsimpis

436 525f2979 Ilias Tsitsimpis
        self.logger.debug("Build synnefo packages")
437 525f2979 Ilias Tsitsimpis
        cmd = """
438 525f2979 Ilias Tsitsimpis
        devflow-autopkg snapshot -b ~/synnefo_build-area --no-sign
439 525f2979 Ilias Tsitsimpis
        """
440 525f2979 Ilias Tsitsimpis
        with fabric.cd("synnefo"):
441 525f2979 Ilias Tsitsimpis
            _run(cmd, True)
442 525f2979 Ilias Tsitsimpis

443 525f2979 Ilias Tsitsimpis
        self.logger.debug("Copy synnefo debs to snf-deploy packages dir")
444 525f2979 Ilias Tsitsimpis
        cmd = """
445 525f2979 Ilias Tsitsimpis
        cp ~/synnefo_build-area/*.deb /var/lib/snf-deploy/packages/
446 525f2979 Ilias Tsitsimpis
        """
447 525f2979 Ilias Tsitsimpis
        _run(cmd, False)
448 525f2979 Ilias Tsitsimpis

449 124c300e Christos Stavrakakis

450 124c300e Christos Stavrakakis
    @_check_fabric
451 124c300e Christos Stavrakakis
    def build_documentation(self):
452 124c300e Christos Stavrakakis
        self.logger.info("Build Synnefo documentation..")
453 124c300e Christos Stavrakakis
        _run("pip install -U Sphinx", False)
454 124c300e Christos Stavrakakis
        with fabric.cd("synnefo"):
455 124c300e Christos Stavrakakis
            _run("./ci/make_docs.sh synnefo_documentation", False)
456 124c300e Christos Stavrakakis

457 124c300e Christos Stavrakakis
    def fetch_documentation(self, dest=None):
458 124c300e Christos Stavrakakis
        if dest is None:
459 124c300e Christos Stavrakakis
            dest = "synnefo_documentation"
460 124c300e Christos Stavrakakis
        dest = os.path.abspath(dest)
461 124c300e Christos Stavrakakis
        if not os.path.exists(dest):
462 124c300e Christos Stavrakakis
            os.makedirs(dest)
463 124c300e Christos Stavrakakis
        self.fetch_compressed("synnefo/synnefo_documentation", dest)
464 124c300e Christos Stavrakakis
        self.logger.info("Downloaded documentation to %s" %
465 124c300e Christos Stavrakakis
                         _green(dest))
466 124c300e Christos Stavrakakis

467 525f2979 Ilias Tsitsimpis
    @_check_fabric
468 46a07468 Christos Stavrakakis
    def deploy_synnefo(self, schema=None):
469 525f2979 Ilias Tsitsimpis
        """Deploy Synnefo using snf-deploy"""
470 525f2979 Ilias Tsitsimpis
        self.logger.info("Deploy Synnefo..")
471 46a07468 Christos Stavrakakis
        if schema is None:
472 46a07468 Christos Stavrakakis
            schema = self.config.get('Global', 'schema')
473 525f2979 Ilias Tsitsimpis
        self.logger.debug("Will use %s schema" % schema)
474 525f2979 Ilias Tsitsimpis

475 46a07468 Christos Stavrakakis
        schema_dir = os.path.join(self.ci_dir, "schemas/%s" % schema)
476 46a07468 Christos Stavrakakis
        if not (os.path.exists(schema_dir) and os.path.isdir(schema_dir)):
477 46a07468 Christos Stavrakakis
            raise ValueError("Unknown schema: %s" % schema)
478 46a07468 Christos Stavrakakis

479 525f2979 Ilias Tsitsimpis
        self.logger.debug("Upload schema files to server")
480 525f2979 Ilias Tsitsimpis
        with fabric.quiet():
481 46a07468 Christos Stavrakakis
            fabric.put(os.path.join(schema_dir, "*"), "/etc/snf-deploy/")
482 525f2979 Ilias Tsitsimpis

483 525f2979 Ilias Tsitsimpis
        self.logger.debug("Change password in nodes.conf file")
484 525f2979 Ilias Tsitsimpis
        cmd = """
485 525f2979 Ilias Tsitsimpis
        sed -i 's/^password =.*/password = {0}/' /etc/snf-deploy/nodes.conf
486 525f2979 Ilias Tsitsimpis
        """.format(fabric.env.password)
487 525f2979 Ilias Tsitsimpis
        _run(cmd, False)
488 525f2979 Ilias Tsitsimpis

489 525f2979 Ilias Tsitsimpis
        self.logger.debug("Run snf-deploy")
490 525f2979 Ilias Tsitsimpis
        cmd = """
491 525f2979 Ilias Tsitsimpis
        snf-deploy all --autoconf
492 525f2979 Ilias Tsitsimpis
        """
493 525f2979 Ilias Tsitsimpis
        _run(cmd, True)
494 525f2979 Ilias Tsitsimpis

495 525f2979 Ilias Tsitsimpis
    @_check_fabric
496 525f2979 Ilias Tsitsimpis
    def unit_test(self):
497 525f2979 Ilias Tsitsimpis
        """Run Synnefo unit test suite"""
498 525f2979 Ilias Tsitsimpis
        self.logger.info("Run Synnefo unit test suite")
499 525f2979 Ilias Tsitsimpis
        component = self.config.get('Unit Tests', 'component')
500 525f2979 Ilias Tsitsimpis

501 525f2979 Ilias Tsitsimpis
        self.logger.debug("Install needed packages")
502 525f2979 Ilias Tsitsimpis
        cmd = """
503 525f2979 Ilias Tsitsimpis
        pip install mock
504 525f2979 Ilias Tsitsimpis
        pip install factory_boy
505 525f2979 Ilias Tsitsimpis
        """
506 525f2979 Ilias Tsitsimpis
        _run(cmd, False)
507 525f2979 Ilias Tsitsimpis

508 2255812d Ilias Tsitsimpis
        self.logger.debug("Upload tests.sh file")
509 2255812d Ilias Tsitsimpis
        unit_tests_file = os.path.join(self.ci_dir, "tests.sh")
510 525f2979 Ilias Tsitsimpis
        with fabric.quiet():
511 525f2979 Ilias Tsitsimpis
            fabric.put(unit_tests_file, ".")
512 525f2979 Ilias Tsitsimpis

513 525f2979 Ilias Tsitsimpis
        self.logger.debug("Run unit tests")
514 525f2979 Ilias Tsitsimpis
        cmd = """
515 2255812d Ilias Tsitsimpis
        bash tests.sh {0}
516 525f2979 Ilias Tsitsimpis
        """.format(component)
517 525f2979 Ilias Tsitsimpis
        _run(cmd, True)
518 525f2979 Ilias Tsitsimpis

519 525f2979 Ilias Tsitsimpis
    @_check_fabric
520 525f2979 Ilias Tsitsimpis
    def run_burnin(self):
521 525f2979 Ilias Tsitsimpis
        """Run burnin functional test suite"""
522 525f2979 Ilias Tsitsimpis
        self.logger.info("Run Burnin functional test suite")
523 525f2979 Ilias Tsitsimpis
        cmd = """
524 525f2979 Ilias Tsitsimpis
        auth_url=$(grep -e '^url =' .kamakirc | cut -d' ' -f3)
525 525f2979 Ilias Tsitsimpis
        token=$(grep -e '^token =' .kamakirc | cut -d' ' -f3)
526 525f2979 Ilias Tsitsimpis
        images_user=$(kamaki image list -l | grep owner | \
527 525f2979 Ilias Tsitsimpis
                      cut -d':' -f2 | tr -d ' ')
528 525f2979 Ilias Tsitsimpis
        snf-burnin --auth-url=$auth_url --token=$token \
529 525f2979 Ilias Tsitsimpis
            --force-flavor=2 --image-id=all \
530 525f2979 Ilias Tsitsimpis
            --system-images-user=$images_user \
531 525f2979 Ilias Tsitsimpis
            {0}
532 525f2979 Ilias Tsitsimpis
        log_folder=$(ls -1d /var/log/burnin/* | tail -n1)
533 525f2979 Ilias Tsitsimpis
        for i in $(ls $log_folder/*/details*); do
534 525f2979 Ilias Tsitsimpis
            echo -e "\\n\\n"
535 525f2979 Ilias Tsitsimpis
            echo -e "***** $i\\n"
536 525f2979 Ilias Tsitsimpis
            cat $i
537 525f2979 Ilias Tsitsimpis
        done
538 525f2979 Ilias Tsitsimpis
        """.format(self.config.get('Burnin', 'cmd_options'))
539 525f2979 Ilias Tsitsimpis
        _run(cmd, True)
540 525f2979 Ilias Tsitsimpis

541 525f2979 Ilias Tsitsimpis
    @_check_fabric
542 124c300e Christos Stavrakakis
    def fetch_compressed(self, src, dest=None):
543 124c300e Christos Stavrakakis
        self.logger.debug("Creating tarball of %s" % src)
544 124c300e Christos Stavrakakis
        basename = os.path.basename(src)
545 124c300e Christos Stavrakakis
        tar_file = basename + ".tgz"
546 124c300e Christos Stavrakakis
        cmd = "tar czf %s %s" % (tar_file, src)
547 525f2979 Ilias Tsitsimpis
        _run(cmd, False)
548 124c300e Christos Stavrakakis
        if not os.path.exists(dest):
549 124c300e Christos Stavrakakis
            os.makedirs(dest)
550 525f2979 Ilias Tsitsimpis

551 124c300e Christos Stavrakakis
        tmp_dir = tempfile.mkdtemp()
552 124c300e Christos Stavrakakis
        fabric.get(tar_file, tmp_dir)
553 525f2979 Ilias Tsitsimpis

554 124c300e Christos Stavrakakis
        dest_file = os.path.join(tmp_dir, tar_file)
555 124c300e Christos Stavrakakis
        self._check_hash_sum(dest_file, tar_file)
556 124c300e Christos Stavrakakis
        self.logger.debug("Untar packages file %s" % dest_file)
557 ee2419c5 Christos Stavrakakis
        cmd = """
558 ee2419c5 Christos Stavrakakis
        cd %s
559 124c300e Christos Stavrakakis
        tar xzf %s
560 124c300e Christos Stavrakakis
        cp -r %s/* %s
561 124c300e Christos Stavrakakis
        rm -r %s
562 124c300e Christos Stavrakakis
        """ % (tmp_dir, tar_file, src, dest, tmp_dir)
563 ee2419c5 Christos Stavrakakis
        os.system(cmd)
564 124c300e Christos Stavrakakis
        self.logger.info("Downloaded %s to %s" %
565 124c300e Christos Stavrakakis
                         (src, _green(dest)))
566 124c300e Christos Stavrakakis

567 124c300e Christos Stavrakakis
    @_check_fabric
568 124c300e Christos Stavrakakis
    def fetch_packages(self, dest=None):
569 124c300e Christos Stavrakakis
        if dest is None:
570 124c300e Christos Stavrakakis
            dest = self.config.get('Global', 'pkgs_dir')
571 124c300e Christos Stavrakakis
        dest = os.path.abspath(dest)
572 124c300e Christos Stavrakakis
        if not os.path.exists(dest):
573 124c300e Christos Stavrakakis
            os.makedirs(dest)
574 124c300e Christos Stavrakakis
        self.fetch_compressed("synnefo_build-area", dest)
575 85bcc8da Christos Stavrakakis
        self.logger.info("Downloaded debian packages to %s" %
576 124c300e Christos Stavrakakis
                         _green(dest))