Statistics
| Branch: | Tag: | Revision:

root / ci / utils.py @ 0082c787

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

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

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

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

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

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

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

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

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

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

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

446 525f2979 Ilias Tsitsimpis
        self.logger.debug("Run snf-deploy")
447 525f2979 Ilias Tsitsimpis
        cmd = """
448 525f2979 Ilias Tsitsimpis
        snf-deploy all --autoconf
449 525f2979 Ilias Tsitsimpis
        """
450 525f2979 Ilias Tsitsimpis
        _run(cmd, True)
451 525f2979 Ilias Tsitsimpis

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

458 525f2979 Ilias Tsitsimpis
        self.logger.debug("Install needed packages")
459 525f2979 Ilias Tsitsimpis
        cmd = """
460 525f2979 Ilias Tsitsimpis
        pip install mock
461 525f2979 Ilias Tsitsimpis
        pip install factory_boy
462 525f2979 Ilias Tsitsimpis
        """
463 525f2979 Ilias Tsitsimpis
        _run(cmd, False)
464 525f2979 Ilias Tsitsimpis

465 2255812d Ilias Tsitsimpis
        self.logger.debug("Upload tests.sh file")
466 2255812d Ilias Tsitsimpis
        unit_tests_file = os.path.join(self.ci_dir, "tests.sh")
467 525f2979 Ilias Tsitsimpis
        with fabric.quiet():
468 525f2979 Ilias Tsitsimpis
            fabric.put(unit_tests_file, ".")
469 525f2979 Ilias Tsitsimpis

470 525f2979 Ilias Tsitsimpis
        self.logger.debug("Run unit tests")
471 525f2979 Ilias Tsitsimpis
        cmd = """
472 2255812d Ilias Tsitsimpis
        bash tests.sh {0}
473 525f2979 Ilias Tsitsimpis
        """.format(component)
474 525f2979 Ilias Tsitsimpis
        _run(cmd, True)
475 525f2979 Ilias Tsitsimpis

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

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

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

514 525f2979 Ilias Tsitsimpis
        pkgs_file = os.path.join(pkgs_dir, "synnefo_build-area.tgz")
515 525f2979 Ilias Tsitsimpis
        self._check_hash_sum(pkgs_file, "synnefo_build-area.tgz")
516 525f2979 Ilias Tsitsimpis

517 525f2979 Ilias Tsitsimpis
        self.logger.debug("Untar packages file %s" % pkgs_file)
518 525f2979 Ilias Tsitsimpis
        os.system("cd %s; tar xzf synnefo_build-area.tgz" % pkgs_dir)