Statistics
| Branch: | Tag: | Revision:

root / ci / utils.py @ 43a22402

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

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

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

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

393 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Build snf-deploy package")
394 c29ac11d Ilias Tsitsimpis
        cmd = """
395 c29ac11d Ilias Tsitsimpis
        git checkout -t origin/debian
396 c29ac11d Ilias Tsitsimpis
        git-buildpackage --git-upstream-branch=master \
397 c29ac11d Ilias Tsitsimpis
                --git-debian-branch=debian \
398 c29ac11d Ilias Tsitsimpis
                --git-export-dir=../snf-deploy_build-area \
399 c29ac11d Ilias Tsitsimpis
                -uc -us
400 c29ac11d Ilias Tsitsimpis
        """
401 c29ac11d Ilias Tsitsimpis
        with fabric.cd("snf-deploy"):
402 c29ac11d Ilias Tsitsimpis
            _run(cmd, True)
403 c29ac11d Ilias Tsitsimpis

404 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Install snf-deploy package")
405 c29ac11d Ilias Tsitsimpis
        cmd = """
406 c29ac11d Ilias Tsitsimpis
        dpkg -i snf-deploy*.deb
407 c29ac11d Ilias Tsitsimpis
        apt-get -f install --yes
408 c29ac11d Ilias Tsitsimpis
        """
409 c29ac11d Ilias Tsitsimpis
        with fabric.cd("snf-deploy_build-area"):
410 c29ac11d Ilias Tsitsimpis
            with fabric.settings(warn_only=True):
411 c29ac11d Ilias Tsitsimpis
                _run(cmd, True)
412 c29ac11d Ilias Tsitsimpis

413 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Build synnefo packages")
414 c29ac11d Ilias Tsitsimpis
        cmd = """
415 c29ac11d Ilias Tsitsimpis
        devflow-autopkg snapshot -b ~/synnefo_build-area --no-sign
416 c29ac11d Ilias Tsitsimpis
        """
417 c29ac11d Ilias Tsitsimpis
        with fabric.cd("synnefo"):
418 c29ac11d Ilias Tsitsimpis
            _run(cmd, True)
419 c29ac11d Ilias Tsitsimpis

420 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Copy synnefo debs to snf-deploy packages dir")
421 c29ac11d Ilias Tsitsimpis
        cmd = """
422 c29ac11d Ilias Tsitsimpis
        cp ~/synnefo_build-area/*.deb /var/lib/snf-deploy/packages/
423 c29ac11d Ilias Tsitsimpis
        """
424 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
425 c29ac11d Ilias Tsitsimpis

426 c29ac11d Ilias Tsitsimpis
    @_check_fabric
427 c29ac11d Ilias Tsitsimpis
    def deploy_synnefo(self):
428 c29ac11d Ilias Tsitsimpis
        """Deploy Synnefo using snf-deploy"""
429 c29ac11d Ilias Tsitsimpis
        self.logger.info("Deploy Synnefo..")
430 c29ac11d Ilias Tsitsimpis
        schema = self.config.get('Global', 'schema')
431 c29ac11d Ilias Tsitsimpis
        schema_files = os.path.join(self.ci_dir, "schemas/%s/*" % schema)
432 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Will use %s schema" % schema)
433 c29ac11d Ilias Tsitsimpis

434 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Upload schema files to server")
435 c29ac11d Ilias Tsitsimpis
        with fabric.quiet():
436 c29ac11d Ilias Tsitsimpis
            fabric.put(schema_files, "/etc/snf-deploy/")
437 c29ac11d Ilias Tsitsimpis

438 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Change password in nodes.conf file")
439 c29ac11d Ilias Tsitsimpis
        cmd = """
440 c29ac11d Ilias Tsitsimpis
        sed -i 's/^password =.*/password = {0}/' /etc/snf-deploy/nodes.conf
441 c29ac11d Ilias Tsitsimpis
        """.format(fabric.env.password)
442 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
443 c29ac11d Ilias Tsitsimpis

444 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Run snf-deploy")
445 c29ac11d Ilias Tsitsimpis
        cmd = """
446 c29ac11d Ilias Tsitsimpis
        snf-deploy all --autoconf
447 c29ac11d Ilias Tsitsimpis
        """
448 c29ac11d Ilias Tsitsimpis
        _run(cmd, True)
449 c29ac11d Ilias Tsitsimpis

450 c29ac11d Ilias Tsitsimpis
    @_check_fabric
451 c29ac11d Ilias Tsitsimpis
    def unit_test(self):
452 c29ac11d Ilias Tsitsimpis
        """Run Synnefo unit test suite"""
453 c29ac11d Ilias Tsitsimpis
        self.logger.info("Run Synnefo unit test suite")
454 c29ac11d Ilias Tsitsimpis
        component = self.config.get('Unit Tests', 'component')
455 c29ac11d Ilias Tsitsimpis

456 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Install needed packages")
457 c29ac11d Ilias Tsitsimpis
        cmd = """
458 c29ac11d Ilias Tsitsimpis
        pip install mock
459 c29ac11d Ilias Tsitsimpis
        pip install factory_boy
460 c29ac11d Ilias Tsitsimpis
        """
461 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
462 c29ac11d Ilias Tsitsimpis

463 861b437e Ilias Tsitsimpis
        self.logger.debug("Upload tests.sh file")
464 861b437e Ilias Tsitsimpis
        unit_tests_file = os.path.join(self.ci_dir, "tests.sh")
465 c29ac11d Ilias Tsitsimpis
        with fabric.quiet():
466 c29ac11d Ilias Tsitsimpis
            fabric.put(unit_tests_file, ".")
467 c29ac11d Ilias Tsitsimpis

468 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Run unit tests")
469 c29ac11d Ilias Tsitsimpis
        cmd = """
470 861b437e Ilias Tsitsimpis
        bash tests.sh {0}
471 c29ac11d Ilias Tsitsimpis
        """.format(component)
472 c29ac11d Ilias Tsitsimpis
        _run(cmd, True)
473 c29ac11d Ilias Tsitsimpis

474 c29ac11d Ilias Tsitsimpis
    @_check_fabric
475 c29ac11d Ilias Tsitsimpis
    def run_burnin(self):
476 c29ac11d Ilias Tsitsimpis
        """Run burnin functional test suite"""
477 c29ac11d Ilias Tsitsimpis
        self.logger.info("Run Burnin functional test suite")
478 c29ac11d Ilias Tsitsimpis
        cmd = """
479 c29ac11d Ilias Tsitsimpis
        auth_url=$(grep -e '^url =' .kamakirc | cut -d' ' -f3)
480 c29ac11d Ilias Tsitsimpis
        token=$(grep -e '^token =' .kamakirc | cut -d' ' -f3)
481 c29ac11d Ilias Tsitsimpis
        images_user=$(kamaki image list -l | grep owner | \
482 c29ac11d Ilias Tsitsimpis
                      cut -d':' -f2 | tr -d ' ')
483 c29ac11d Ilias Tsitsimpis
        snf-burnin --auth-url=$auth_url --token=$token \
484 c29ac11d Ilias Tsitsimpis
            --force-flavor=2 --image-id=all \
485 c29ac11d Ilias Tsitsimpis
            --system-images-user=$images_user \
486 c29ac11d Ilias Tsitsimpis
            {0}
487 c29ac11d Ilias Tsitsimpis
        log_folder=$(ls -1d /var/log/burnin/* | tail -n1)
488 c29ac11d Ilias Tsitsimpis
        for i in $(ls $log_folder/*/details*); do
489 c29ac11d Ilias Tsitsimpis
            echo -e "\\n\\n"
490 c29ac11d Ilias Tsitsimpis
            echo -e "***** $i\\n"
491 c29ac11d Ilias Tsitsimpis
            cat $i
492 c29ac11d Ilias Tsitsimpis
        done
493 c29ac11d Ilias Tsitsimpis
        """.format(self.config.get('Burnin', 'cmd_options'))
494 c29ac11d Ilias Tsitsimpis
        _run(cmd, True)
495 c29ac11d Ilias Tsitsimpis

496 c29ac11d Ilias Tsitsimpis
    @_check_fabric
497 c29ac11d Ilias Tsitsimpis
    def fetch_packages(self):
498 c29ac11d Ilias Tsitsimpis
        """Download Synnefo packages"""
499 c29ac11d Ilias Tsitsimpis
        self.logger.info("Download Synnefo packages")
500 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Create tarball with packages")
501 c29ac11d Ilias Tsitsimpis
        cmd = """
502 c29ac11d Ilias Tsitsimpis
        tar czf synnefo_build-area.tgz synnefo_build-area
503 c29ac11d Ilias Tsitsimpis
        """
504 c29ac11d Ilias Tsitsimpis
        _run(cmd, False)
505 c29ac11d Ilias Tsitsimpis

506 c29ac11d Ilias Tsitsimpis
        pkgs_dir = self.config.get('Global', 'pkgs_dir')
507 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Fetch packages to local dir %s" % pkgs_dir)
508 c29ac11d Ilias Tsitsimpis
        os.makedirs(pkgs_dir)
509 c29ac11d Ilias Tsitsimpis
        with fabric.quiet():
510 c29ac11d Ilias Tsitsimpis
            fabric.get("synnefo_build-area.tgz", pkgs_dir)
511 c29ac11d Ilias Tsitsimpis

512 c29ac11d Ilias Tsitsimpis
        pkgs_file = os.path.join(pkgs_dir, "synnefo_build-area.tgz")
513 c29ac11d Ilias Tsitsimpis
        self._check_hash_sum(pkgs_file, "synnefo_build-area.tgz")
514 c29ac11d Ilias Tsitsimpis

515 c29ac11d Ilias Tsitsimpis
        self.logger.debug("Untar packages file %s" % pkgs_file)
516 c29ac11d Ilias Tsitsimpis
        os.system("cd %s; tar xzf synnefo_build-area.tgz" % pkgs_dir)