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) |