Merge lp:~sbaldassin/snappy-ecosystem-tests/merge_driver_and_container into lp:snappy-ecosystem-tests
- merge_driver_and_container
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Heber Parrucci |
Approved revision: | 39 |
Merged at revision: | 34 |
Proposed branch: | lp:~sbaldassin/snappy-ecosystem-tests/merge_driver_and_container |
Merge into: | lp:snappy-ecosystem-tests |
Diff against target: |
363 lines (+165/-126) 5 files modified
snappy_ecosystem_tests/environment/containers/lxd.py (+118/-0) snappy_ecosystem_tests/environment/data/snapd.py (+2/-1) snappy_ecosystem_tests/environment/managers.py (+27/-122) snappy_ecosystem_tests/environment/setup.py (+17/-2) snappy_ecosystem_tests/utils/user.py (+1/-1) |
To merge this branch: | bzr merge lp:~sbaldassin/snappy-ecosystem-tests/merge_driver_and_container |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Heber Parrucci (community) | Approve | ||
Omer Akram (community) | Approve | ||
platform-qa-bot | continuous-integration | Approve | |
Review via email:
|
Commit message
Splitting responsibilities between driver and manager
Description of the change
This mp makes a better use of the Manager and Builder and split the responsibilities between them
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
platform-qa-bot (platform-qa-bot) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Heber Parrucci (heber013) wrote : | # |
Comment inline
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Santiago Baldassin (sbaldassin) wrote : | # |
Reply inline
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Omer Akram (om26er) wrote : | # |
The approach to start multiple containers and not waiting for them is problematic and its enforcing use to use random sleeps. Added inline comment on how that is a problem.
If you really want to start multiple containers, ask pylxd to do that for you in a loop.
- 34. By Santiago Baldassin
-
Addressing comments from the reviews
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Santiago Baldassin (sbaldassin) wrote : | # |
Thanks for the feedback Omer. All comments were addressed, however, I did leave the option to create containers and not wait and I also leave a wait period for starting the containers faster. Please do take a look
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Omer Akram (om26er) wrote : | # |
Added inline comment, yesterday I started working on actually fixing the snapd staging environment but when you proposed this branch, it had a potential of conflict. So I am waiting for this branch to either land or the comment that I just made inline addressed.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
platform-qa-bot (platform-qa-bot) wrote : | # |
FAILED: Continuous integration, rev:34
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
- 35. By Santiago Baldassin
-
Fixing pylint
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Omer Akram (om26er) wrote : | # |
Added comments inline.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:35
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Santiago Baldassin (sbaldassin) wrote : | # |
Thanks Omer, I riplied inline. We'll need a phone call to get everyone on the same page
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Santiago Baldassin (sbaldassin) wrote : | # |
Replied inline
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Omer Akram (om26er) wrote : | # |
Added comments inline. Lets aim to land this sooner.
- 36. By Santiago Baldassin
-
Addressing comments from the reviews
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
platform-qa-bot (platform-qa-bot) wrote : | # |
FAILED: Continuous integration, rev:36
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
- 37. By Santiago Baldassin
-
Minor refactor
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
platform-qa-bot (platform-qa-bot) wrote : | # |
FAILED: Continuous integration, rev:37
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Omer Akram (om26er) wrote : | # |
please merge with trunk, there are conflicts.
- 38. By Santiago Baldassin
-
Merge from trunk
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
platform-qa-bot (platform-qa-bot) wrote : | # |
FAILED: Continuous integration, rev:38
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Omer Akram (om26er) wrote : | # |
Seems jenkins is again having issues. Anyways can you please add this bug report into your `launch` https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Heber Parrucci (heber013) wrote : | # |
> Seems jenkins is again having issues. Anyways can you please add this bug
> report into your `launch` https:/
Actually jenkins is not having issues. There is a pylint issue in the revision:
W: 26, 0: Unused sleep imported from time (unused-import)
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Omer Akram (om26er) wrote : | # |
hmm, I mis-interpretted the output https:/
had the impression that line: error: <urlopen error Tunnel connection failed: 403 Forbidden> was the cause. But you are right, its pylint complaint that needs fixing.
- 39. By Santiago Baldassin
-
Fixing pylint
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:39
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Heber Parrucci (heber013) wrote : | # |
Code LGTM. Let's land it.
Preview Diff
1 | === added directory 'snappy_ecosystem_tests/environment/containers' |
2 | === added file 'snappy_ecosystem_tests/environment/containers/__init__.py' |
3 | === added file 'snappy_ecosystem_tests/environment/containers/lxd.py' |
4 | --- snappy_ecosystem_tests/environment/containers/lxd.py 1970-01-01 00:00:00 +0000 |
5 | +++ snappy_ecosystem_tests/environment/containers/lxd.py 2017-03-08 15:34:35 +0000 |
6 | @@ -0,0 +1,118 @@ |
7 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
8 | + |
9 | +# |
10 | +# Snappy Ecosystem Tests |
11 | +# Copyright (C) 2017 Canonical |
12 | +# |
13 | +# This program is free software: you can redistribute it and/or modify |
14 | +# it under the terms of the GNU General Public License as published by |
15 | +# the Free Software Foundation, either version 3 of the License, or |
16 | +# (at your option) any later version. |
17 | +# |
18 | +# This program is distributed in the hope that it will be useful, |
19 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | +# GNU General Public License for more details. |
22 | +# |
23 | +# You should have received a copy of the GNU General Public License |
24 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
25 | +# |
26 | +"""Module top interact with lxd containers""" |
27 | + |
28 | +import os |
29 | +import shlex |
30 | + |
31 | +import logging |
32 | + |
33 | +from pylxd import Client |
34 | +from pylxd.exceptions import LXDAPIException, NotFound |
35 | +from retrying import retry |
36 | + |
37 | +from snappy_ecosystem_tests.environment.data.snapd import ( |
38 | + DEFAULT_CONTAINER_CONFIG) |
39 | + |
40 | +COMMAND_ALLOW_ENV_VARS = 'sed -i \'/^AcceptEnv/ s/$/ {}/\' ' \ |
41 | + '/etc/ssh/sshd_config' |
42 | + |
43 | +LOGGER = logging.getLogger(__name__) |
44 | +DOMAIN_PING = 'ubuntu.com' |
45 | + |
46 | +class LxdDriver: |
47 | + """Manage lxd containers""" |
48 | + |
49 | + def __init__(self): |
50 | + self.client = Client() |
51 | + |
52 | + def launch(self, containers): |
53 | + """Launch a container""" |
54 | + created_containers = [] |
55 | + for cont in containers: |
56 | + |
57 | + if self.client.containers.exists(cont): |
58 | + container = self.client.containers.get(cont) |
59 | + try: |
60 | + if container.status == "Running": |
61 | + container.stop(wait=True) |
62 | + container.delete(wait=True) |
63 | + except NotFound: |
64 | + # If using ephemeral stop will delete the container and try |
65 | + # to sync which will fail because the container does not |
66 | + # exist. container.delete will be only execute if stop did |
67 | + # not raise an exception: |
68 | + # https://github.com/lxc/pylxd/issues/221 |
69 | + pass |
70 | + |
71 | + container_config = DEFAULT_CONTAINER_CONFIG.copy() |
72 | + container_config['source']['alias'] = containers[cont]['release'] |
73 | + container_config['name'] = cont |
74 | + created_containers.append(self.client.containers.create( |
75 | + container_config, wait=True)) |
76 | + self.start(created_containers) |
77 | + return created_containers |
78 | + |
79 | + @staticmethod |
80 | + def start(containers): |
81 | + """start all containers received as parameter""" |
82 | + for cont in containers: |
83 | + if not cont.state().status == 'Running': |
84 | + cont.start(wait=True) |
85 | + |
86 | + @staticmethod |
87 | + def install(container, packages, channel=None): |
88 | + """Install packages""" |
89 | + container.execute(shlex.split('apt-get update')) |
90 | + install_command = 'apt-get install {} -y'.format( |
91 | + ' '.join(packages)) |
92 | + if channel: |
93 | + install_command += ' -t {}'.format(channel) |
94 | + container.execute(shlex.split(install_command)) |
95 | + |
96 | + @staticmethod |
97 | + @retry(stop_max_attempt_number=5, wait_fixed=3000, |
98 | + retry_on_exception=lambda exception: isinstance( |
99 | + exception, LXDAPIException)) |
100 | + def enable_ssh(container): |
101 | + """Enable the ssh connection on the container""" |
102 | + pub_key = open( |
103 | + os.path.expanduser('~') + '/.ssh/id_rsa.pub').read().strip('\n') |
104 | + container.files.put('/home/ubuntu/.ssh/authorized_keys', pub_key) |
105 | + |
106 | + @staticmethod |
107 | + def get_ip(container): |
108 | + """Gets the ip address for a given container""" |
109 | + networks = container.state().network['eth0']['addresses'] |
110 | + |
111 | + for network in networks: |
112 | + if network['address']: |
113 | + return network['address'] |
114 | + raise RuntimeError( |
115 | + "The container {} does not have an IPV4 connection".format( |
116 | + container.name)) |
117 | + |
118 | + @staticmethod |
119 | + def export_environment_variables(container, |
120 | + environment_variables): |
121 | + """Allow export of environment variables over ssh.""" |
122 | + container.execute(shlex.split(COMMAND_ALLOW_ENV_VARS.format( |
123 | + ' '.join(environment_variables)))) |
124 | + container.execute(shlex.split('service ssh restart')) |
125 | |
126 | === modified file 'snappy_ecosystem_tests/environment/data/snapd.py' |
127 | --- snappy_ecosystem_tests/environment/data/snapd.py 2017-03-02 10:51:37 +0000 |
128 | +++ snappy_ecosystem_tests/environment/data/snapd.py 2017-03-08 15:34:35 +0000 |
129 | @@ -93,5 +93,6 @@ |
130 | "server": "https://cloud-images.ubuntu.com/releases", |
131 | "protocol": "simplestreams", |
132 | "fingerprint": "16.04" |
133 | - } |
134 | + }, |
135 | + "ephemeral": True |
136 | } |
137 | |
138 | === modified file 'snappy_ecosystem_tests/environment/managers.py' |
139 | --- snappy_ecosystem_tests/environment/managers.py 2017-03-07 17:41:31 +0000 |
140 | +++ snappy_ecosystem_tests/environment/managers.py 2017-03-08 15:34:35 +0000 |
141 | @@ -1,7 +1,7 @@ |
142 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
143 | |
144 | # |
145 | -# Ubuntu System Tests |
146 | +# Snappy Ecosystem Tests |
147 | # Copyright (C) 2017 Canonical |
148 | # |
149 | # This program is free software: you can redistribute it and/or modify |
150 | @@ -17,134 +17,39 @@ |
151 | # You should have received a copy of the GNU General Public License |
152 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
153 | # |
154 | - |
155 | """Managers to setup the environment""" |
156 | |
157 | -import os |
158 | -import shlex |
159 | -from pylxd import Client |
160 | -from pylxd.exceptions import NotFound, LXDAPIException |
161 | -from retrying import retry |
162 | - |
163 | -from snappy_ecosystem_tests.environment import constants |
164 | from snappy_ecosystem_tests.environment.constants import ( |
165 | PROFILES, DEPENDENCIES) |
166 | -from snappy_ecosystem_tests.environment.data.snapcraft import ( |
167 | - SNAPCRAFT_CONTAINER_NAME) |
168 | -from snappy_ecosystem_tests.environment.data.snapd import ( |
169 | - DEFAULT_CONTAINER_CONFIG, SNAPD_CONTAINER_NAME) |
170 | - |
171 | -COMMAND_ALLOW_ENV_VARS = 'sed -i \'/^AcceptEnv/ s/$/ {}/\' ' \ |
172 | - '/etc/ssh/sshd_config' |
173 | - |
174 | - |
175 | -def get_manager(mode): |
176 | - """Get the manager for the given mode""" |
177 | - supported_modules = { |
178 | - "lxd": LxdManager |
179 | +from snappy_ecosystem_tests.environment.containers.lxd import LxdDriver |
180 | + |
181 | +CONTAINERS = { |
182 | + "snapd":{ |
183 | + "release": "16.04" |
184 | + }, |
185 | + "snapcraft":{ |
186 | + "release": "16.04" |
187 | } |
188 | - try: |
189 | - manager = supported_modules[mode] |
190 | - return manager() |
191 | - except KeyError: |
192 | - raise RuntimeError("Mode: {} is not supported".format(mode)) |
193 | - |
194 | - |
195 | -class LxdManager: |
196 | - """Manage lxd containers""" |
197 | +} |
198 | + |
199 | +class _LxdManager: |
200 | + """Manager for lxd containers""" |
201 | |
202 | def __init__(self): |
203 | - self.client = Client() |
204 | - |
205 | - def launch(self, container_name, release='16.04'): |
206 | - """Launch a container""" |
207 | - try: |
208 | - container = self.client.containers.get(container_name) |
209 | - if container.status == "Running": |
210 | - container.stop(wait=True) |
211 | - container.delete(wait=True) |
212 | - except NotFound: |
213 | - pass |
214 | - container_config = DEFAULT_CONTAINER_CONFIG.copy() |
215 | - container_config['source']['alias'] = release |
216 | - container_config['name'] = container_name |
217 | - container = self.client.containers.create(container_config, wait=True) |
218 | - container.start(wait=True) |
219 | - |
220 | - def execute_command(self, container_name, command): |
221 | - """execute command""" |
222 | - container = self.client.containers.get(container_name) |
223 | - container.execute(command) |
224 | - |
225 | - def install(self, container_name, packages, channel=None): |
226 | - """Install a packages""" |
227 | - container = self.client.containers.get(container_name) |
228 | - container.execute(shlex.split('apt-get update')) |
229 | - install_command = 'apt-get install {} -y'.format( |
230 | - ' '.join(packages)) |
231 | - if channel: |
232 | - install_command += ' -t {}'.format(channel) |
233 | - container.execute(shlex.split(install_command)) |
234 | - |
235 | - def install_dependencies(self, container_name, container_type): |
236 | - """Install a dependencies""" |
237 | - self.install( |
238 | - container_name, |
239 | - DEPENDENCIES[container_type] + DEPENDENCIES['shared']) |
240 | - |
241 | - def configure(self, container_name, container_type, profile): |
242 | - """Configure a given container""" |
243 | - container = self.client.containers.get(container_name) |
244 | - for key, value in \ |
245 | - PROFILES[profile][container_type]['environment_variables'].\ |
246 | - items(): |
247 | - container.config.update({'environment.{}'.format( |
248 | - key): value}) |
249 | - container.save(wait=True) |
250 | - |
251 | - @retry(stop_max_attempt_number=5, wait_fixed=3000, |
252 | - retry_on_exception=lambda exception: isinstance( |
253 | - exception, LXDAPIException)) |
254 | - def enable_ssh(self, container_name, container_type, profile): |
255 | - """Enable the ssh connection on the container""" |
256 | - container = self.client.containers.get(container_name) |
257 | - pub_key = open( |
258 | - os.path.expanduser('~') + '/.ssh/id_rsa.pub').read().strip('\n') |
259 | - container.files.put('/home/ubuntu/.ssh/authorized_keys', pub_key) |
260 | - # Allow export of environment variables over ssh. |
261 | - container.execute(shlex.split(COMMAND_ALLOW_ENV_VARS.format( |
262 | - ' '.join(PROFILES[profile][container_type] |
263 | - ['environment_variables'].keys())))) |
264 | - container.execute(shlex.split('service ssh restart')) |
265 | + self.driver = LxdDriver() |
266 | |
267 | def setup(self, profile): |
268 | """setup the container based on the profile""" |
269 | - self._setup(SNAPD_CONTAINER_NAME, constants.SNAPD, profile) |
270 | - self._setup( |
271 | - SNAPCRAFT_CONTAINER_NAME, constants.SNAPCRAFT, profile) |
272 | - |
273 | - def _setup(self, container_name, container_type, profile): |
274 | - """ |
275 | - Launch a container, enable ssh, install dependencies |
276 | - and setup the needed environment variables |
277 | - """ |
278 | - self.launch(container_name) |
279 | - self.enable_ssh(container_name, container_type, profile) |
280 | - self.install( |
281 | - container_name, |
282 | - packages=[PROFILES[profile][container_type]["package_name"]], |
283 | - channel=PROFILES[profile][container_type]["channel"]) |
284 | - self.install_dependencies(container_name, container_type) |
285 | - self.configure(container_name, container_type, profile) |
286 | - |
287 | - def get_ip(self, container_name): |
288 | - """Gets the ip address for a given container""" |
289 | - networks = self.client.containers.get( |
290 | - container_name).state().network['eth0']['addresses'] |
291 | - |
292 | - for network in networks: |
293 | - if network['address']: |
294 | - return network['address'] |
295 | - raise RuntimeError( |
296 | - "The container {} does not have an IPV4 connection".format( |
297 | - container_name)) |
298 | + containers = self.driver.launch(CONTAINERS) |
299 | + |
300 | + for cont in containers: |
301 | + deps = DEPENDENCIES[cont.name] + DEPENDENCIES["shared"] |
302 | + self.driver.install(cont, packages=deps) |
303 | + self.driver.install( |
304 | + cont, |
305 | + packages=[PROFILES[profile][cont.name]["package_name"]], |
306 | + channel=PROFILES[profile][cont.name]["channel"]) |
307 | + self.driver.enable_ssh(cont) |
308 | + self.driver.export_environment_variables( |
309 | + cont, |
310 | + PROFILES[profile][cont.name]["environment_variables"].keys()) |
311 | |
312 | === modified file 'snappy_ecosystem_tests/environment/setup.py' |
313 | --- snappy_ecosystem_tests/environment/setup.py 2017-03-03 18:58:19 +0000 |
314 | +++ snappy_ecosystem_tests/environment/setup.py 2017-03-08 15:34:35 +0000 |
315 | @@ -1,7 +1,7 @@ |
316 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
317 | |
318 | # |
319 | -# Ubuntu System Tests |
320 | +# Snappy Ecosystem Tests |
321 | # Copyright (C) 2017 Canonical |
322 | # |
323 | # This program is free software: you can redistribute it and/or modify |
324 | @@ -24,11 +24,26 @@ |
325 | |
326 | import logging |
327 | |
328 | -from snappy_ecosystem_tests.environment.managers import get_manager |
329 | +from snappy_ecosystem_tests.environment.managers import _LxdManager |
330 | |
331 | logging.basicConfig(level=logging.DEBUG) |
332 | |
333 | |
334 | +SUPPORTED_MODULES = { |
335 | + "lxd": _LxdManager |
336 | +} |
337 | + |
338 | + |
339 | +def get_manager(mode): |
340 | + """Get the manager for the given mode""" |
341 | + |
342 | + try: |
343 | + manager = SUPPORTED_MODULES[mode] |
344 | + return manager() |
345 | + except KeyError: |
346 | + raise RuntimeError("Mode: {} is not supported".format(mode)) |
347 | + |
348 | + |
349 | def main(mode, profile): |
350 | """Main script""" |
351 | manager = get_manager(mode) |
352 | |
353 | === modified file 'snappy_ecosystem_tests/utils/user.py' |
354 | --- snappy_ecosystem_tests/utils/user.py 2017-03-01 21:51:29 +0000 |
355 | +++ snappy_ecosystem_tests/utils/user.py 2017-03-08 15:34:35 +0000 |
356 | @@ -23,7 +23,7 @@ |
357 | import os |
358 | |
359 | from snappy_ecosystem_tests.commons.config import USER_CONFIG_STACK |
360 | -from snappy_ecosystem_tests.environment.managers import get_manager |
361 | +from snappy_ecosystem_tests.environment.setup import get_manager |
362 | |
363 | MANAGER = get_manager(os.environ['target']) |
364 |
PASSED: Continuous integration, rev:33 /platform- qa-jenkins. ubuntu. com/job/ snappy- ecosystem- tests-ci/ 250/ /platform- qa-jenkins. ubuntu. com/job/ generic- update- mp/2059/ console
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild: /platform- qa-jenkins. ubuntu. com/job/ snappy- ecosystem- tests-ci/ 250/rebuild
https:/