Merge lp:~canonical-platform-qa/snappy-ecosystem-tests/adding-cloud-target into lp:snappy-ecosystem-tests
- adding-cloud-target
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Heber Parrucci |
Approved revision: | 57 |
Merged at revision: | 57 |
Proposed branch: | lp:~canonical-platform-qa/snappy-ecosystem-tests/adding-cloud-target |
Merge into: | lp:snappy-ecosystem-tests |
Diff against target: |
523 lines (+374/-31) 10 files modified
README.rst (+34/-0) requirements-setup.txt (+1/-0) requirements.txt (+0/-1) run_setup (+50/-17) snappy_ecosystem_tests/environment/cloud/__init__.py (+19/-0) snappy_ecosystem_tests/environment/cloud/data/__init__.py (+19/-0) snappy_ecosystem_tests/environment/cloud/data/deployment.py (+25/-0) snappy_ecosystem_tests/environment/cloud/driver.py (+169/-0) snappy_ecosystem_tests/environment/managers.py (+17/-0) snappy_ecosystem_tests/environment/setup.py (+40/-13) |
To merge this branch: | bzr merge lp:~canonical-platform-qa/snappy-ecosystem-tests/adding-cloud-target |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
platform-qa-bot | continuous-integration | Approve | |
Sergio Cazzolato (community) | Needs Fixing | ||
Snappy ecosystem tests developer | Pending | ||
Review via email: mp+320534@code.launchpad.net |
Commit message
Adding cloud target for virtual machines provisioning using juju.
Description of the change
The change is for adding cloud as a new target.
The idea is to provision virtual machines using juju.
The new setup using cloud target will deploy a charm and by default install snapd and snapcraft in different virtual machines pointing to staging.
The corresponding driver was implemented using subprocess because python juju clients have several bugs and limitations. I tested these clients:
- jujuclient
- juju
For now it assumes that the juju controller/model is already bootstrapped in the machine where the setup is executed. But it will be also automated soon.
@run_tests: snappy_
platform-qa-bot (platform-qa-bot) wrote : | # |
- 49. By Heber Parrucci
-
Adding missing requirement: pyyaml
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:49
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
Sergio Cazzolato (sergio-j-cazzolato) wrote : | # |
Some comments inline.
Also you should check the juju version and stops execution in case it is not >v2
- 50. By Heber Parrucci
-
Addressing review comments
Heber Parrucci (heber013) wrote : | # |
Comments addressed. Added checking of juju >= 2
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:50
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
- 51. By Heber Parrucci
-
Adding cloud setup instructions on README.rst
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:51
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
- 52. By Heber Parrucci
-
merge from trunk
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:52
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
- 53. By Heber Parrucci
-
* Removing specific revision to the charm url.
* Changing back default target to lxd.
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:53
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
- 54. By Heber Parrucci
-
merge from trunk
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:54
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
- 55. By Heber Parrucci
-
merge from trunk
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:55
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
- 56. By Heber Parrucci
-
increasing retries for juju deploy
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:56
https:/
Executed test runs:
UNSTABLE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
platform-qa-bot (platform-qa-bot) wrote : | # |
FAILED: Continuous integration, rev:56
https:/
Executed test runs:
UNSTABLE: https:/
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:56
https:/
Executed test runs:
UNSTABLE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
platform-qa-bot (platform-qa-bot) wrote : | # |
FAILED: Continuous integration, rev:56
https:/
Executed test runs:
UNSTABLE: https:/
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:56
https:/
Executed test runs:
UNSTABLE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
platform-qa-bot (platform-qa-bot) wrote : | # |
FAILED: Continuous integration, rev:56
https:/
Executed test runs:
UNSTABLE: https:/
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
- 57. By Heber Parrucci
-
adding proxy variable to juju deploy
platform-qa-bot (platform-qa-bot) wrote : | # |
PASSED: Continuous integration, rev:57
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | === modified file 'README.rst' | |||
2 | --- README.rst 2017-02-24 19:27:01 +0000 | |||
3 | +++ README.rst 2017-04-10 15:34:13 +0000 | |||
4 | @@ -125,3 +125,37 @@ | |||
5 | 125 | $ bzr branch lp:snappy-ecosystem-tests | 125 | $ bzr branch lp:snappy-ecosystem-tests |
6 | 126 | $ cd snappy-ecosystem-tests/ | 126 | $ cd snappy-ecosystem-tests/ |
7 | 127 | $ python3 -m snappy_ecosystem_tests.snapd.staging_builder my_new_container_name 16.10 | 127 | $ python3 -m snappy_ecosystem_tests.snapd.staging_builder my_new_container_name 16.10 |
8 | 128 | |||
9 | 129 | |||
10 | 130 | How run the tests in openstack | ||
11 | 131 | ============================== | ||
12 | 132 | |||
13 | 133 | 1- If you do not have a cloud/controller bootstrapped in your host, you can do it with a script in qakit: | ||
14 | 134 | |||
15 | 135 | $ bzr branch lp:qakit; cd qakit | ||
16 | 136 | $ ./qakit/juju/juju_bootstrap --cloud_name ^THE_NAME_YOU_LIKE^ --nova_file ^NOVA_CREDENTIALS_FILE^ | ||
17 | 137 | For example if you have canonistack credentials in $HOME/.canonistack/novarc: | ||
18 | 138 | $ ./qakit/juju/juju_bootstrap --cloud_name canonistack --nova_file "$HOME/.canonistack/novarc" | ||
19 | 139 | Enter the sudo password if asked (Some commands are executed as root and others do not). | ||
20 | 140 | Note: You need to provide the full path for the nova file. You can use $HOME but not ~. | ||
21 | 141 | It will install the needed packages and bootstrap the cloud. | ||
22 | 142 | The controller name will be the same of the cloud. | ||
23 | 143 | |||
24 | 144 | Important note: You need to run the bootstrap only once per machine per cloud. | ||
25 | 145 | |||
26 | 146 | 2- Once the bootstrap finishes properly, you need to setup the snappy-ecosystem environment in the cloud, | ||
27 | 147 | For doing it, you should execute: | ||
28 | 148 | ./run_setup --model ^controller_name:admin/default^ --target cloud | ||
29 | 149 | Note that if you do not pass the model, the default is: canonistack:admin/default | ||
30 | 150 | It will create by default 2 machines with applications and needed dependencies: | ||
31 | 151 | - snapcraft | ||
32 | 152 | - snapd | ||
33 | 153 | Both pointing to staging by default. | ||
34 | 154 | If you would like to specify the charm when running the setup, you can do it with --charm ^CHARM-URL^. | ||
35 | 155 | If not provided, it takes the default one. | ||
36 | 156 | |||
37 | 157 | 3- After setup finished properly. You should be able to run the tests: | ||
38 | 158 | ./run_system_tests ^YOUR_TESTS^ --target cloud | ||
39 | 159 | |||
40 | 160 | Note that the step 1 (juju bootstrap) needs to be executed only once per machine per cloud. | ||
41 | 161 | Then only will need to repeat the steps 2 and 3 when needed. | ||
42 | 128 | 162 | ||
43 | === modified file 'requirements-setup.txt' | |||
44 | --- requirements-setup.txt 2017-03-06 18:06:27 +0000 | |||
45 | +++ requirements-setup.txt 2017-04-10 15:34:13 +0000 | |||
46 | @@ -1,2 +1,3 @@ | |||
47 | 1 | pylxd | 1 | pylxd |
48 | 2 | retrying | 2 | retrying |
49 | 3 | pyyaml | ||
50 | 3 | 4 | ||
51 | === modified file 'requirements.txt' | |||
52 | --- requirements.txt 2017-04-03 16:05:21 +0000 | |||
53 | +++ requirements.txt 2017-04-10 15:34:13 +0000 | |||
54 | @@ -18,4 +18,3 @@ | |||
55 | 18 | pyyaml | 18 | pyyaml |
56 | 19 | retrying | 19 | retrying |
57 | 20 | paramiko | 20 | paramiko |
58 | 21 | #chromedriver_installer | ||
59 | 22 | 21 | ||
60 | === modified file 'run_setup' | |||
61 | --- run_setup 2017-03-15 17:11:23 +0000 | |||
62 | +++ run_setup 2017-04-10 15:34:13 +0000 | |||
63 | @@ -28,41 +28,74 @@ | |||
64 | 28 | proxy="$2" | 28 | proxy="$2" |
65 | 29 | shift # past argument | 29 | shift # past argument |
66 | 30 | ;; | 30 | ;; |
69 | 31 | -m|--mode) | 31 | --target) |
70 | 32 | mode="$2" | 32 | target="$2" |
71 | 33 | shift # past argument | ||
72 | 34 | ;; | ||
73 | 35 | --charm) | ||
74 | 36 | charm="$2" | ||
75 | 37 | shift # past argument | ||
76 | 38 | ;; | ||
77 | 39 | --model) | ||
78 | 40 | model="$2" | ||
79 | 33 | shift # past argument | 41 | shift # past argument |
80 | 34 | ;; | 42 | ;; |
81 | 35 | --profile) | 43 | --profile) |
82 | 36 | profile="$2" | 44 | profile="$2" |
83 | 37 | shift # past argument | 45 | shift # past argument |
84 | 38 | ;; | 46 | ;; |
85 | 47 | --series) | ||
86 | 48 | series="$2" | ||
87 | 49 | shift # past argument | ||
88 | 50 | ;; | ||
89 | 51 | --constraints) | ||
90 | 52 | constraints="$2" | ||
91 | 53 | shift # past argument | ||
92 | 54 | ;; | ||
93 | 39 | esac | 55 | esac |
94 | 40 | shift # past argument or value | 56 | shift # past argument or value |
95 | 41 | done | 57 | done |
96 | 42 | 58 | ||
97 | 43 | . ./mk-venv -r requirements-setup.txt --proxy ${proxy} | 59 | . ./mk-venv -r requirements-setup.txt --proxy ${proxy} |
98 | 44 | 60 | ||
113 | 45 | if [ -z "$mode" ]; then | 61 | parameters='snappy_ecosystem_tests.environment.setup' |
114 | 46 | mode=lxd | 62 | |
115 | 47 | fi | 63 | if [ ! -z ${target+x} ]; then |
116 | 48 | 64 | parameters="$parameters --target $target" | |
117 | 49 | if [ -z "$profile" ]; then | 65 | fi |
118 | 50 | profile=staging | 66 | |
119 | 51 | fi | 67 | if [ ! -z ${proxy+x} ]; then |
120 | 52 | 68 | parameters="$parameters --proxy $proxy" | |
121 | 53 | if [ -z "$proxy" ]; then | 69 | fi |
122 | 54 | ve/bin/python3 -m snappy_ecosystem_tests.environment.setup --mode ${mode} --profile ${profile} | 70 | |
123 | 55 | else | 71 | if [ ! -z ${charm+x} ]; then |
124 | 56 | ve/bin/python3 -m snappy_ecosystem_tests.environment.setup --mode ${mode} --profile ${profile} --proxy ${proxy} | 72 | parameters="$parameters --charm $charm" |
125 | 57 | fi | 73 | fi |
126 | 58 | 74 | ||
127 | 75 | if [ ! -z ${model+x} ]; then | ||
128 | 76 | parameters="$parameters --model $model" | ||
129 | 77 | fi | ||
130 | 78 | |||
131 | 79 | if [ ! -z ${profile+x} ]; then | ||
132 | 80 | parameters="$parameters --profile $profile" | ||
133 | 81 | fi | ||
134 | 82 | |||
135 | 83 | if [ ! -z ${series+x} ]; then | ||
136 | 84 | parameters="$parameters --series $series" | ||
137 | 85 | fi | ||
138 | 86 | |||
139 | 87 | if [ ! -z ${constraints+x} ]; then | ||
140 | 88 | parameters="$parameters --constraints $constraints" | ||
141 | 89 | fi | ||
142 | 90 | |||
143 | 91 | ve/bin/python3 -m ${parameters} | ||
144 | 59 | 92 | ||
145 | 60 | result=$? | 93 | result=$? |
146 | 61 | deactivate | 94 | deactivate |
147 | 62 | 95 | ||
148 | 63 | if [ $result != 0 ]; then | 96 | if [ $result != 0 ]; then |
149 | 64 | echo -e -n "Environment setup FAILED.\n" | 97 | echo -e -n "Environment setup FAILED.\n" |
151 | 65 | exit 1; | 98 | exit 1 |
152 | 66 | else | 99 | else |
153 | 67 | echo -e -n "Environment setup PASSED.\n" | 100 | echo -e -n "Environment setup PASSED.\n" |
154 | 68 | fi | 101 | fi |
155 | 69 | 102 | ||
156 | === added directory 'snappy_ecosystem_tests/environment/cloud' | |||
157 | === added file 'snappy_ecosystem_tests/environment/cloud/__init__.py' | |||
158 | --- snappy_ecosystem_tests/environment/cloud/__init__.py 1970-01-01 00:00:00 +0000 | |||
159 | +++ snappy_ecosystem_tests/environment/cloud/__init__.py 2017-04-10 15:34:13 +0000 | |||
160 | @@ -0,0 +1,19 @@ | |||
161 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
162 | 2 | |||
163 | 3 | # | ||
164 | 4 | # Snappy Ecosystem Tests | ||
165 | 5 | # Copyright (C) 2017 Canonical | ||
166 | 6 | # | ||
167 | 7 | # This program is free software: you can redistribute it and/or modify | ||
168 | 8 | # it under the terms of the GNU General Public License as published by | ||
169 | 9 | # the Free Software Foundation, either version 3 of the License, or | ||
170 | 10 | # (at your option) any later version. | ||
171 | 11 | # | ||
172 | 12 | # This program is distributed in the hope that it will be useful, | ||
173 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
174 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
175 | 15 | # GNU General Public License for more details. | ||
176 | 16 | # | ||
177 | 17 | # You should have received a copy of the GNU General Public License | ||
178 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
179 | 19 | # | ||
180 | 0 | 20 | ||
181 | === added directory 'snappy_ecosystem_tests/environment/cloud/data' | |||
182 | === added file 'snappy_ecosystem_tests/environment/cloud/data/__init__.py' | |||
183 | --- snappy_ecosystem_tests/environment/cloud/data/__init__.py 1970-01-01 00:00:00 +0000 | |||
184 | +++ snappy_ecosystem_tests/environment/cloud/data/__init__.py 2017-04-10 15:34:13 +0000 | |||
185 | @@ -0,0 +1,19 @@ | |||
186 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
187 | 2 | |||
188 | 3 | # | ||
189 | 4 | # Snappy Ecosystem Tests | ||
190 | 5 | # Copyright (C) 2017 Canonical | ||
191 | 6 | # | ||
192 | 7 | # This program is free software: you can redistribute it and/or modify | ||
193 | 8 | # it under the terms of the GNU General Public License as published by | ||
194 | 9 | # the Free Software Foundation, either version 3 of the License, or | ||
195 | 10 | # (at your option) any later version. | ||
196 | 11 | # | ||
197 | 12 | # This program is distributed in the hope that it will be useful, | ||
198 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
199 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
200 | 15 | # GNU General Public License for more details. | ||
201 | 16 | # | ||
202 | 17 | # You should have received a copy of the GNU General Public License | ||
203 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
204 | 19 | # | ||
205 | 0 | 20 | ||
206 | === added file 'snappy_ecosystem_tests/environment/cloud/data/deployment.py' | |||
207 | --- snappy_ecosystem_tests/environment/cloud/data/deployment.py 1970-01-01 00:00:00 +0000 | |||
208 | +++ snappy_ecosystem_tests/environment/cloud/data/deployment.py 2017-04-10 15:34:13 +0000 | |||
209 | @@ -0,0 +1,25 @@ | |||
210 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
211 | 2 | |||
212 | 3 | # | ||
213 | 4 | # Snappy Ecosystem Tests | ||
214 | 5 | # Copyright (C) 2017 Canonical | ||
215 | 6 | # | ||
216 | 7 | # This program is free software: you can redistribute it and/or modify | ||
217 | 8 | # it under the terms of the GNU General Public License as published by | ||
218 | 9 | # the Free Software Foundation, either version 3 of the License, or | ||
219 | 10 | # (at your option) any later version. | ||
220 | 11 | # | ||
221 | 12 | # This program is distributed in the hope that it will be useful, | ||
222 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
223 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
224 | 15 | # GNU General Public License for more details. | ||
225 | 16 | # | ||
226 | 17 | # You should have received a copy of the GNU General Public License | ||
227 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
228 | 19 | # | ||
229 | 20 | """Contain information for the applications to be deployed on the cloud""" | ||
230 | 21 | |||
231 | 22 | APPLICATIONS = [ | ||
232 | 23 | {'name': 'snapcraft', 'package': 'snapcraft', 'profile': 'staging'}, | ||
233 | 24 | {'name': 'snapd', 'package': 'snapd', 'profile': 'staging'}, | ||
234 | 25 | ] | ||
235 | 0 | 26 | ||
236 | === added file 'snappy_ecosystem_tests/environment/cloud/driver.py' | |||
237 | --- snappy_ecosystem_tests/environment/cloud/driver.py 1970-01-01 00:00:00 +0000 | |||
238 | +++ snappy_ecosystem_tests/environment/cloud/driver.py 2017-04-10 15:34:13 +0000 | |||
239 | @@ -0,0 +1,169 @@ | |||
240 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
241 | 2 | |||
242 | 3 | # | ||
243 | 4 | # Snappy Ecosystem Tests | ||
244 | 5 | # Copyright (C) 2017 Canonical | ||
245 | 6 | # | ||
246 | 7 | # This program is free software: you can redistribute it and/or modify | ||
247 | 8 | # it under the terms of the GNU General Public License as published by | ||
248 | 9 | # the Free Software Foundation, either version 3 of the License, or | ||
249 | 10 | # (at your option) any later version. | ||
250 | 11 | # | ||
251 | 12 | # This program is distributed in the hope that it will be useful, | ||
252 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
253 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
254 | 15 | # GNU General Public License for more details. | ||
255 | 16 | # | ||
256 | 17 | # You should have received a copy of the GNU General Public License | ||
257 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
258 | 19 | # | ||
259 | 20 | |||
260 | 21 | """Module Drive virtual machines in the cloud using juju""" | ||
261 | 22 | |||
262 | 23 | import subprocess | ||
263 | 24 | import tempfile | ||
264 | 25 | |||
265 | 26 | import time | ||
266 | 27 | import yaml | ||
267 | 28 | from packaging import version | ||
268 | 29 | |||
269 | 30 | |||
270 | 31 | class CloudDriver: | ||
271 | 32 | |||
272 | 33 | """Class to Drive virtual machines in the cloud using juju""" | ||
273 | 34 | |||
274 | 35 | STATUSES_NOT_READY = ['maintenance', 'waiting'] | ||
275 | 36 | |||
276 | 37 | def launch(self, charm, applications, profile, model, proxy=None, **kwargs): | ||
277 | 38 | """Call to Deploy all the applications and then wait until all of them | ||
278 | 39 | are deployed | ||
279 | 40 | |||
280 | 41 | :param charm: The charm to deploy | ||
281 | 42 | :param applications: the applications to deploy | ||
282 | 43 | :param profile: the profile of the application to deploy | ||
283 | 44 | :param model: juju model in which the apps will be deployed | ||
284 | 45 | :param proxy: the proxy URL. | ||
285 | 46 | """ | ||
286 | 47 | assert self.get_version('juju') >= version.parse('2'), \ | ||
287 | 48 | 'Juju >= 2 is required.' | ||
288 | 49 | subprocess.check_call(['juju', 'switch', model]) | ||
289 | 50 | for app in applications: | ||
290 | 51 | self.deploy(charm, app, profile=profile, proxy=proxy, **kwargs) | ||
291 | 52 | self.wait_until_deployed(applications) | ||
292 | 53 | |||
293 | 54 | @staticmethod | ||
294 | 55 | def get_version(app): | ||
295 | 56 | """Return the version of the given app""" | ||
296 | 57 | app_version = subprocess.check_output( | ||
297 | 58 | [app, 'version']).decode().split('-')[0] | ||
298 | 59 | return version.parse(app_version) | ||
299 | 60 | |||
300 | 61 | def deploy(self, charm, app=None, profile=None, series=None, | ||
301 | 62 | constraints=None, proxy=None): | ||
302 | 63 | """ | ||
303 | 64 | Launch a machine deploying the given charm to the connected juju model. | ||
304 | 65 | |||
305 | 66 | :param charm: The charm to deploy | ||
306 | 67 | :param app: the application name to deploy | ||
307 | 68 | :param profile: the profile of the application to deploy | ||
308 | 69 | :param series: series of the machine in which the application | ||
309 | 70 | will be deployed. | ||
310 | 71 | :param constraints: constraints for an application are set at deploy | ||
311 | 72 | time. | ||
312 | 73 | They must be expressed as a string containing only spaces | ||
313 | 74 | and key value pairs joined by an '='. Example: mem=8G cores=4 | ||
314 | 75 | :param proxy: the proxy URL. | ||
315 | 76 | """ | ||
316 | 77 | assert charm, 'You need to specify the charm to deploy' | ||
317 | 78 | command = ['juju', 'deploy', charm] | ||
318 | 79 | if series: | ||
319 | 80 | command.extend(['--series', series]) | ||
320 | 81 | if constraints: | ||
321 | 82 | command.extend(['--constraints', ' '.join(constraints)]) | ||
322 | 83 | if app: | ||
323 | 84 | if self.get_application_status(app['name']): | ||
324 | 85 | self.remove_application(app['name']) | ||
325 | 86 | app_config = {app['name']: {'package': app['package'], | ||
326 | 87 | 'profile': profile}} | ||
327 | 88 | if proxy: | ||
328 | 89 | app_config[app['name']]['proxy'] = proxy | ||
329 | 90 | tmp_file = tempfile.NamedTemporaryFile() | ||
330 | 91 | with open(tmp_file.name, 'w+') as temp: | ||
331 | 92 | temp.write(yaml.dump(app_config)) | ||
332 | 93 | command.extend(['--config', tmp_file.name, app['name']]) | ||
333 | 94 | subprocess.check_call(command, universal_newlines=True) | ||
334 | 95 | |||
335 | 96 | def wait_until_deployed(self, apps, max_attempts=240, wait_period=5): | ||
336 | 97 | """ | ||
337 | 98 | Wait until the given application is deployed. | ||
338 | 99 | |||
339 | 100 | :param apps: The applications list to check | ||
340 | 101 | :param max_attempts: Amount of attempts to check before failing | ||
341 | 102 | :param wait_period: The period of time in second to wait between checks | ||
342 | 103 | :raise Exception: If the max attempts were reached | ||
343 | 104 | """ | ||
344 | 105 | for app in apps: | ||
345 | 106 | attempt = 0 | ||
346 | 107 | status = self.get_application_status(app['name']) | ||
347 | 108 | while status in self.STATUSES_NOT_READY and attempt < max_attempts: | ||
348 | 109 | time.sleep(wait_period) | ||
349 | 110 | attempt += 1 | ||
350 | 111 | status = self.get_application_status(app['name']) | ||
351 | 112 | if attempt == max_attempts: | ||
352 | 113 | raise Exception( | ||
353 | 114 | 'Deploy for application %s has failed' % app['name']) | ||
354 | 115 | |||
355 | 116 | @staticmethod | ||
356 | 117 | def get_juju_status(): | ||
357 | 118 | """ | ||
358 | 119 | Get the status in dict format | ||
359 | 120 | |||
360 | 121 | :return: dict containing the juju status output | ||
361 | 122 | """ | ||
362 | 123 | return yaml.load(subprocess.check_output(['juju', 'status', | ||
363 | 124 | '--format', 'yaml'], | ||
364 | 125 | universal_newlines=True)) | ||
365 | 126 | |||
366 | 127 | def get_application_status(self, app_name): | ||
367 | 128 | """Get the application status or None if it cannot be found""" | ||
368 | 129 | status = self.get_juju_status() | ||
369 | 130 | try: | ||
370 | 131 | return status['applications'][app_name]['application-status'][ | ||
371 | 132 | 'current'] | ||
372 | 133 | except (KeyError, TypeError): | ||
373 | 134 | return None | ||
374 | 135 | |||
375 | 136 | def remove_application(self, app_name, max_attempts=120, wait_period=5, | ||
376 | 137 | wait=True): | ||
377 | 138 | """Remove the given application | ||
378 | 139 | |||
379 | 140 | :param app_name: The application to remove | ||
380 | 141 | :param max_attempts: Amount of attempts to check before failing | ||
381 | 142 | :param wait_period: The period of time in second to wait between checks | ||
382 | 143 | :param wait: whether to wait until the application is actually removed | ||
383 | 144 | """ | ||
384 | 145 | try: | ||
385 | 146 | subprocess.check_output(['juju', 'remove-application', app_name], | ||
386 | 147 | universal_newlines=True, | ||
387 | 148 | stderr=subprocess.STDOUT) | ||
388 | 149 | except subprocess.CalledProcessError as _e: | ||
389 | 150 | if 'not found' in _e.output: | ||
390 | 151 | return | ||
391 | 152 | else: | ||
392 | 153 | raise | ||
393 | 154 | attempt = 0 | ||
394 | 155 | if wait: | ||
395 | 156 | status = self.get_application_status(app_name) | ||
396 | 157 | while status and attempt < max_attempts: | ||
397 | 158 | time.sleep(wait_period) | ||
398 | 159 | attempt += 1 | ||
399 | 160 | status = self.get_application_status(app_name) | ||
400 | 161 | if attempt == max_attempts: | ||
401 | 162 | raise Exception('Deploy for application %s has failed' % app_name) | ||
402 | 163 | |||
403 | 164 | def get_ip(self, app_name): | ||
404 | 165 | """Get the ip of the Machine in which the application is deployed""" | ||
405 | 166 | status = self.get_juju_status() | ||
406 | 167 | for key, value in status['applications'][app_name]['units'].items(): | ||
407 | 168 | if key.startswith(app_name): | ||
408 | 169 | return value['public-address'] | ||
409 | 0 | 170 | ||
410 | === modified file 'snappy_ecosystem_tests/environment/managers.py' | |||
411 | --- snappy_ecosystem_tests/environment/managers.py 2017-03-27 20:21:15 +0000 | |||
412 | +++ snappy_ecosystem_tests/environment/managers.py 2017-04-10 15:34:13 +0000 | |||
413 | @@ -21,9 +21,15 @@ | |||
414 | 21 | 21 | ||
415 | 22 | import logging | 22 | import logging |
416 | 23 | 23 | ||
417 | 24 | from snappy_ecosystem_tests.environment.cloud.driver import CloudDriver | ||
418 | 25 | |||
419 | 24 | from snappy_ecosystem_tests.environment.constants import ( | 26 | from snappy_ecosystem_tests.environment.constants import ( |
420 | 25 | PROFILES, DEPENDENCIES) | 27 | PROFILES, DEPENDENCIES) |
421 | 26 | from snappy_ecosystem_tests.environment.containers.lxd import LXDDriver | 28 | from snappy_ecosystem_tests.environment.containers.lxd import LXDDriver |
422 | 29 | from snappy_ecosystem_tests.environment.cloud.data.deployment import ( | ||
423 | 30 | APPLICATIONS | ||
424 | 31 | ) | ||
425 | 32 | |||
426 | 27 | 33 | ||
427 | 28 | CONTAINERS = { | 34 | CONTAINERS = { |
428 | 29 | "snapd": { | 35 | "snapd": { |
429 | @@ -65,3 +71,14 @@ | |||
430 | 65 | packages=[PROFILES[profile][cont.name]["package_name"]], | 71 | packages=[PROFILES[profile][cont.name]["package_name"]], |
431 | 66 | channel=PROFILES[profile][cont.name]["channel"]) | 72 | channel=PROFILES[profile][cont.name]["channel"]) |
432 | 67 | self.driver.enable_ssh(cont) | 73 | self.driver.enable_ssh(cont) |
433 | 74 | |||
434 | 75 | |||
435 | 76 | class CloudManager: | ||
436 | 77 | """Manage machines in the cloud""" | ||
437 | 78 | def __init__(self): | ||
438 | 79 | self.driver = CloudDriver() | ||
439 | 80 | |||
440 | 81 | def setup(self, profile, charm=None, model=None, proxy=None, **kwargs): | ||
441 | 82 | """Setup virtual machines based on the profile""" | ||
442 | 83 | self.driver.launch(charm, APPLICATIONS, profile, model, | ||
443 | 84 | proxy=proxy, **kwargs) | ||
444 | 68 | 85 | ||
445 | === modified file 'snappy_ecosystem_tests/environment/setup.py' | |||
446 | --- snappy_ecosystem_tests/environment/setup.py 2017-03-27 20:21:15 +0000 | |||
447 | +++ snappy_ecosystem_tests/environment/setup.py 2017-04-10 15:34:13 +0000 | |||
448 | @@ -22,35 +22,62 @@ | |||
449 | 22 | 22 | ||
450 | 23 | import argparse | 23 | import argparse |
451 | 24 | 24 | ||
453 | 25 | from snappy_ecosystem_tests.environment.managers import _LXDManager | 25 | from snappy_ecosystem_tests.environment.managers import ( |
454 | 26 | _LXDManager, | ||
455 | 27 | CloudManager | ||
456 | 28 | ) | ||
457 | 26 | 29 | ||
458 | 27 | 30 | ||
459 | 28 | SUPPORTED_MODULES = { | 31 | SUPPORTED_MODULES = { |
461 | 29 | "lxd": _LXDManager | 32 | "lxd": _LXDManager, |
462 | 33 | "cloud": CloudManager, | ||
463 | 30 | } | 34 | } |
464 | 31 | 35 | ||
465 | 32 | 36 | ||
467 | 33 | def get_manager(mode): | 37 | def get_manager(target): |
468 | 34 | """Get the manager for the given mode""" | 38 | """Get the manager for the given mode""" |
469 | 35 | try: | 39 | try: |
471 | 36 | return SUPPORTED_MODULES[mode]() | 40 | return SUPPORTED_MODULES[target]() |
472 | 37 | except KeyError: | 41 | except KeyError: |
477 | 38 | raise RuntimeError("Mode: {} is not supported".format(mode)) | 42 | raise RuntimeError("Target: {} is not supported".format(target)) |
478 | 39 | 43 | ||
479 | 40 | 44 | ||
480 | 41 | def main(mode, profile, proxy): | 45 | def main(target, profile, **kwargs): |
481 | 42 | """Main script""" | 46 | """Main script""" |
484 | 43 | manager = get_manager(mode) | 47 | manager = get_manager(target) |
485 | 44 | manager.setup(profile, proxy) | 48 | manager.setup(profile, **kwargs) |
486 | 45 | 49 | ||
487 | 46 | 50 | ||
488 | 47 | if __name__ == '__main__': | 51 | if __name__ == '__main__': |
489 | 48 | PARSER = argparse.ArgumentParser(description= | 52 | PARSER = argparse.ArgumentParser(description= |
490 | 49 | 'Setup a snappy ecosystem environment.') | 53 | 'Setup a snappy ecosystem environment.') |
492 | 50 | PARSER.add_argument('--mode', default="lxd", help='lxd') | 54 | PARSER.add_argument('--target', default="lxd", help='lxd') |
493 | 51 | PARSER.add_argument('--profile', default="staging", | 55 | PARSER.add_argument('--profile', default="staging", |
494 | 52 | help='Profile to configure the environment') | 56 | help='Profile to configure the environment') |
495 | 53 | PARSER.add_argument('--proxy', default=None, | 57 | PARSER.add_argument('--proxy', default=None, |
496 | 54 | help='Proxy to use in the target machine/s') | 58 | help='Proxy to use in the target machine/s') |
499 | 55 | ARGS = PARSER.parse_args() | 59 | PARSER.add_argument('--constraints', default=None, nargs='+', |
500 | 56 | main(ARGS.mode, ARGS.profile, ARGS.proxy) | 60 | help='constraints for creating machine/s') |
501 | 61 | ARGS, LEFT_OVER = PARSER.parse_known_args() | ||
502 | 62 | if ARGS.target == 'cloud': | ||
503 | 63 | CLOUD_PARSER = argparse.ArgumentParser( | ||
504 | 64 | description='Parse cloud specific arguments') | ||
505 | 65 | CLOUD_PARSER.add_argument('--charm', | ||
506 | 66 | default='cs:~heber013/snappy-ecosystem', | ||
507 | 67 | help='The juju charm to deploy') | ||
508 | 68 | CLOUD_PARSER.add_argument('--model', | ||
509 | 69 | default='canonistack:admin/default', | ||
510 | 70 | help='The juju model in which apps will' | ||
511 | 71 | ' be deployed') | ||
512 | 72 | CLOUD_PARSER.add_argument('--series', | ||
513 | 73 | help='The virtual machine series. ' | ||
514 | 74 | 'Example: xenial') | ||
515 | 75 | CLOUD_ARGS, LEFT_OVER = CLOUD_PARSER.parse_known_args() | ||
516 | 76 | main(ARGS.target, ARGS.profile, | ||
517 | 77 | charm=CLOUD_ARGS.charm, | ||
518 | 78 | model=CLOUD_ARGS.model, | ||
519 | 79 | series=CLOUD_ARGS.series, | ||
520 | 80 | constraints=ARGS.constraints, | ||
521 | 81 | proxy=ARGS.proxy) | ||
522 | 82 | else: | ||
523 | 83 | main(ARGS.target, ARGS.profile, proxy=ARGS.proxy) |
PASSED: Continuous integration, rev:48 /platform- qa-jenkins. ubuntu. com/job/ snappy- ecosystem- tests-ci/ 303/ /platform- qa-jenkins. ubuntu. com/job/ generic- update- mp/2175/ console
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild: /platform- qa-jenkins. ubuntu. com/job/ snappy- ecosystem- tests-ci/ 303/rebuild
https:/