Merge ~wesley-wiedenmeier/cloud-init:integration-testing-invocation-cleanup into cloud-init:master
- Git
- lp:~wesley-wiedenmeier/cloud-init
- integration-testing-invocation-cleanup
- Merge into master
Status: | Merged |
---|---|
Merged at revision: | 76d58265e34851b78e952a7f275340863c90a9f5 |
Proposed branch: | ~wesley-wiedenmeier/cloud-init:integration-testing-invocation-cleanup |
Merge into: | cloud-init:master |
Diff against target: |
600 lines (+349/-36) 8 files modified
doc/rtd/topics/tests.rst (+67/-8) tests/cloud_tests/__init__.py (+1/-0) tests/cloud_tests/__main__.py (+5/-26) tests/cloud_tests/args.py (+53/-1) tests/cloud_tests/bddeb.py (+124/-0) tests/cloud_tests/instances/base.py (+1/-1) tests/cloud_tests/run_funcs.py (+65/-0) tests/cloud_tests/util.py (+33/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Server Team CI bot | continuous-integration | Approve | |
Joshua Powers (community) | Approve | ||
cloud-init Commiters | Pending | ||
Review via email: mp+314496@code.launchpad.net |
Commit message
Description of the change
Integration Testing: provide commands to run tests from current tree
- Add 'bddeb' command to build a deb from the current working tree
cleanly in a container, so deps don't have to be installed on host
- Add 'tree_collect' and 'tree_run' commands, to build deb from
current working tree and call collect or run with deb
- Fix bug in instance.
Wesley Wiedenmeier (wesley-wiedenmeier) wrote : | # |
Thanks for reviewing
> 1) Had to increase the timeout as 120 seconds was not enough. I bumped to 600.
I'll go ahead and increase the timout a bit, or possibly add the option for the call to snapshot.launch() in bddeb to specify a longer timeout that normal, since the bddeb instance should be expected to take longer to boot than other instances. It would also work to not use cloud-init to install devscripts, and just apt-get it during the build process, that may be cleaner, and would allow finer grained logging messages.
> 2) the tox target "cittest_run" actually does a "tree_run" In order to not be
> confused between run versus tree_run I think this should really be
> "cittest_tree_run"
Good point, citest_run = tree_run may be confusing, I'll get the name switched over.
> lxc list was clean afterwards as expected. I believe I only missed a ppa test.
I think that is plenty of testing as the changes shouldn't have affected anything other than bddeb and adding the new commands. I'll run through with --ppa once to be sure though.
> The only warning message I got other than those for pylxd's 2.2 deprecation
> was:
> /home/powersj/
> DeprecationWarning: The 'warn' method is deprecated, use 'warning' instead
I always forget whether its LOG.warn or LOG.warning that is depricated, got it wrong here, good catch. I'll fix here and grep through to check if its wrong anywhere else.
I should have all of that done at some point tonight, should be ready for merge tomorrow
Wesley Wiedenmeier (wesley-wiedenmeier) wrote : | # |
Timeouts will no longer be an issue for bddeb as dep installation is now handled after boot. I think this should be ready to merge, I've tested again with tree_collect, tree_run, and just with a normal 'run --ppa'
Joshua Powers (powersj) wrote : | # |
LGTM
Thanks for the changes! Ran the following successfully with no changes to timeouts:
$ tox
$ tox -e citest_tree_run
$ tox -e citest -- tree_run -n zesty -t tests/cloud_
$ python3 -m tests.cloud_tests tree_run -v -n zesty -t tests/cloud_
Wesley Wiedenmeier (wesley-wiedenmeier) wrote : | # |
This merge proposal is no longer required, as everything here is included in the main one at:
https:/
Wesley Wiedenmeier (wesley-wiedenmeier) wrote : | # |
Since there is additional work that can be done to improve the build system, this branch and this merge proposal will be used for development. Below is some of the discussion on bddeb for reference.
> >> * creating the tarball..
> >> I think what we want to do here is:
> >> a.) make-tarball on "this side"
> >> b.) modify bddeb to be able to just create a debian/ dir
> >> either
> >> i.) have it create the orig tarball and a debian.tar.gz
> >> into a provided (empty) output dir.
> >> ii.) have it just create the debian.tar.gz and we create
> >> the tarball example of doing that
> >> http://
> >> c.) move the tarball and debian dir over, extract tarball,
> >> extract debian/
> >> d.) mk-build-deps --install .... debian/control
> >> e.) dpkg-buildpackage
> >>
> >> doing this should mean we do not have to 'install additional
> >> build deps' but rather just have mk-build-deps do the right
> >> thing.
>
> >I had been trying to avoid modifying anything outside cloud_tests,
> >but adding the --debian-tar-only option in bddeb definitely does
> >simplify this. This may be a useful feature in general for debugging
> >cloud-init builds that do not work or doing custom deb builds, as
> >going through the template system can be inconvenient.
>
> >This also avoids having to go through a source repo in case the
> >current version of cloud-init in tree has different deps from the
> >one in the source repo.
>
> > Using dpkg-buildpackage instead of debuild may be quicker too.
>
> Yeah, it makes the build much simpler in the container. I'm tempted
> to further improve bddeb to list what packages need installing even,
> then we could drop the mk-build-deps and equivs ... but that is not
> necessary now. The complexity in that comes really from the obnoxious
> 'python3-pyflakes | pyflakes (<< 1.1.0-2)'
>
> in package/
Yeah, I kinda like the idea of bddeb to handle build deps entirely. That may
make things simpler for users who want to build as well since there have been
lots of questions on irc about how to build packages. We should probably add
more documentation on cloud-inits build system at some point as well.
> >> * when building with dpkg-buildpackage or debuild, good to
> >> allow setting DEB_BUILD_
> >> nosetests)
>
> >Nice, I didn't know that was an option. Lets us avoid the additional
> >build deps step easily, since that was mostly to avoid failing because
> >testing stuff wasn't there.
>
> There is info at https:/
> on what the plan here is... ultimately, package build wont run pep8, but
> would still run nosetests and useful to be able to not run them.
I do like the idea of dropping pep8 in the build, since the actual source used
for the builds whill have already been checked.
> >> * i think the above path means we do not depend on deb-src lines.
>
> >The switch back to ubuntu daily will handle that, but this also
> >avoids going through source repo at all which can be nice if a local
> >change adds a new build dep.
>
> And simply use of mk-build-deps would too..
> I know i'm kind of over-doing this, but i really lik...
Wesley Wiedenmeier (wesley-wiedenmeier) wrote : | # |
This branch should mostly be ready to merge in now. There is additonal work to be done on getting the cc_apt_configure issue resolved in debian jessie, and the hostnamectl issue resolved on centos70, but that can wait, as these are most likely not issues caused by the test suite. Support for package management on centos still needs to be switched to dnf, but since centos is blocked on the hostnamectl issue, that can wait as well.
The cleanup to system_
Wesley Wiedenmeier (wesley-wiedenmeier) wrote : | # |
This branch is not yet ready to merge. The above comment was meant for the main merge proposal at https:/
The build system and the bddeb functionality for cloud-tests can be improved further.
Wesley Wiedenmeier (wesley-wiedenmeier) wrote : | # |
This branch should be ready to merge into trunk now. There were some additional improvements to the build system that had been discussed, but it may be best to work on those later. If the build system is improved in the future, then this code can easily be updated as well.
The tree_run command that this branch provides is useful enough on its own that this is worth merging in on its own, although this is a lower priority than either the main integration-testing update or the distro feature flags branch that is being worked on right now.
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:ac847078d33
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:e63726f671a
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
- 51fa870... by Wesley Wiedenmeier
-
Integration Testing: Updated documentation
- Added documentation on the tree_run and tree_collect commands.
- Also made minor documentation updates for additional useful
features in the test suite.
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:51fa870b721
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Scott Moser (smoser) wrote : | # |
I'm going to mark this 'work in progress'. Josh has integrated this branch and others into his merge proposal at https:/
Thanks for your work, Wesley!
Scott Moser (smoser) wrote : | # |
Hi.
I've marked this 'merged' as I think it is now in trunk under 76d58265e34851b
If you disagree, please feel free to re-open.
Preview Diff
1 | diff --git a/doc/rtd/topics/tests.rst b/doc/rtd/topics/tests.rst |
2 | index 0663811..a088e64 100644 |
3 | --- a/doc/rtd/topics/tests.rst |
4 | +++ b/doc/rtd/topics/tests.rst |
5 | @@ -47,20 +47,23 @@ The test configuration is a YAML file such as *ntp_server.yaml* below: |
6 | cat /etc/ntp.conf | grep '^server' |
7 | |
8 | |
9 | -There are two keys, 1 required and 1 optional, in the YAML file: |
10 | +There are several keys, 1 required and some optional, in the YAML file: |
11 | |
12 | 1. The required key is ``cloud_config``. This should be a string of valid |
13 | YAML that is exactly what would normally be placed in a cloud-config file, |
14 | including the cloud-config header. This essentially sets up the scenario |
15 | under test. |
16 | |
17 | -2. The optional key is ``collect_scripts``. This key has one or more |
18 | +2. One optional key is ``collect_scripts``. This key has one or more |
19 | sub-keys containing strings of arbitrary commands to execute (e.g. |
20 | ```cat /var/log/cloud-config-output.log```). In the example above the |
21 | output of dpkg is captured, grep for ntp, and the number of lines |
22 | reported. The name of the sub-key is important. The sub-key is used by |
23 | the verification script to recall the output of the commands ran. |
24 | |
25 | +3. The optinal key ``enabled`` enables or disables the test case. By defaul |
26 | + the test case will be enabled. |
27 | + |
28 | Default Collect Scripts |
29 | ----------------------- |
30 | |
31 | @@ -109,15 +112,25 @@ Here is a breakdown of the unit test file: |
32 | |
33 | * The import statement allows access to the output files. |
34 | |
35 | -* The class can be named anything, but must import the ``base.CloudTestCase`` |
36 | +* The class can be named anything, but must import the ``base.CloudTestCase``, |
37 | + either directly or via another test class. |
38 | |
39 | * There can be 1 to N number of functions with any name, however only |
40 | tests starting with ``test_*`` will be executed. |
41 | |
42 | +* There can be 1 to N number of classes in a test module, however only classes |
43 | + inheriting from ``base.CloudTestCase`` will be loaded. |
44 | + |
45 | * Output from the commands can be accessed via |
46 | ``self.get_data_file('key')`` where key is the sub-key of |
47 | ``collect_scripts`` above. |
48 | |
49 | +* The cloud config that the test ran with can be accessed via |
50 | + ``self.cloud_config``, or any entry from the cloud config can be accessed via |
51 | + ``self.get_config_entry('key')``. |
52 | + |
53 | +* See the base ``CloudTestCase`` for additional helper functions. |
54 | + |
55 | Layout |
56 | ====== |
57 | |
58 | @@ -144,6 +157,23 @@ The sub-folders of bugs, examples, main, and modules help organize the |
59 | tests. View the README.md in each to understand in more detail each |
60 | directory. |
61 | |
62 | +Test Creation Helper |
63 | +==================== |
64 | + |
65 | +The integration testing suite has a built in helper to aid in test development. |
66 | +Its help can be invoked via ``python3 -m tests.cloud_tests create --help``. It |
67 | +can create a template testcase config file with user data passed in from the |
68 | +command line, as well as a template testcase verifier module. |
69 | + |
70 | +The following would create a testcase named ``example`` under the ``modules`` |
71 | +category with the given description, and cloud config data read in from |
72 | +``/tmp/user_data``. |
73 | + |
74 | +.. code-block:: bash |
75 | + |
76 | + $ python3 -m tests.cloud_tests create modules/example \ |
77 | + -d "a simple example test case" -c "$(< /tmp/user_data)" |
78 | + |
79 | |
80 | Development Checklist |
81 | ===================== |
82 | @@ -171,7 +201,7 @@ Development Checklist |
83 | Execution |
84 | ========= |
85 | |
86 | -Executing tests has three options: |
87 | +Executing tests has several options: |
88 | |
89 | * ``run`` an alias to run both ``collect`` and ``verify`` |
90 | |
91 | @@ -182,6 +212,10 @@ Executing tests has three options: |
92 | * ``verify`` given a directory of test data, run the Python unit tests on |
93 | it to generate results. |
94 | |
95 | +* ``tree_run`` and ``tree_collect`` are helpers to run ``run`` or ``collect`` |
96 | + respectively using a deb built from the copy of cloud-init in the current |
97 | + working tree. |
98 | + |
99 | Run |
100 | --- |
101 | The first example will provide a complete end-to-end run of data |
102 | @@ -238,6 +272,29 @@ without the more lengthy collect process. This can be done by running: |
103 | The above command will run the verify scripts on the data discovered in |
104 | `/tmp/collection`. |
105 | |
106 | +TreeRun and TreeCollect |
107 | +----------------------- |
108 | + |
109 | +If working on a cloud-init feature or resolving a bug, it may be useful to run |
110 | +the current copy of cloud-init in the integration testing environment. The |
111 | +integration testing suite can automatically build a deb based on the current |
112 | +working tree of cloud-init and run the test suite using this deb. |
113 | + |
114 | +The ``tree_run`` and ``tree_collect`` commands take the same arguments as the |
115 | +``run`` and ``collect`` commands. These commands will build a deb and write it |
116 | +into a tempfile, then start the test suite and pass that deb in. To build a |
117 | +deb only, and not run the test suite, the ``bddeb`` command can be used. |
118 | + |
119 | +Note that code in the cloud-init working tree that has not been committed |
120 | +when the cloud-init deb is built will still be included. To build a cloud-init |
121 | +deb from or use the ``tree_run`` command using a copy of cloud-init located in |
122 | +a different directory, use the option ``--cloud-init /path/to/cloud-init``. |
123 | + |
124 | +.. code-block:: bash |
125 | + |
126 | + $ python3 -m tests.cloud_tests tree_run -n xenial -n zesty \ |
127 | + -t modules/final_message -t modules/write_files -v -r /tmp/result.yaml |
128 | + |
129 | Run via tox |
130 | ----------- |
131 | In order to avoid the need for dependencies and ease the setup and |
132 | @@ -256,11 +313,13 @@ arguments. |
133 | Architecture |
134 | ============ |
135 | |
136 | -The following outlines the process flow during a complete end-to-end LXD-backed test. |
137 | +The following outlines the process flow during a complete end-to-end |
138 | +LXD-backed test. |
139 | |
140 | 1. Configuration |
141 | * The back end and specific OS releases are verified as supported |
142 | - * The test or tests that need to be run are determined either by directory or by individual yaml |
143 | + * The test or tests that need to be run are determined either by |
144 | + directory or by individual yaml |
145 | |
146 | 2. Image Creation |
147 | * Acquire the daily LXD image |
148 | @@ -285,5 +344,5 @@ The following outlines the process flow during a complete end-to-end LXD-backed |
149 | |
150 | 5. Results |
151 | * If any failures were detected the test suite returns a failure |
152 | - |
153 | - |
154 | + * Results can be dumped in yaml format to a specified file using the |
155 | + ``-r <result_file_name>.yaml`` option |
156 | diff --git a/tests/cloud_tests/__init__.py b/tests/cloud_tests/__init__.py |
157 | index 099c357..7959bd9 100644 |
158 | --- a/tests/cloud_tests/__init__.py |
159 | +++ b/tests/cloud_tests/__init__.py |
160 | @@ -6,6 +6,7 @@ import os |
161 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) |
162 | TESTCASES_DIR = os.path.join(BASE_DIR, 'testcases') |
163 | TEST_CONF_DIR = os.path.join(BASE_DIR, 'configs') |
164 | +TREE_BASE = os.sep.join(BASE_DIR.split(os.sep)[:-2]) |
165 | |
166 | |
167 | def _initialize_logging(): |
168 | diff --git a/tests/cloud_tests/__main__.py b/tests/cloud_tests/__main__.py |
169 | index ef7d187..74f29f6 100644 |
170 | --- a/tests/cloud_tests/__main__.py |
171 | +++ b/tests/cloud_tests/__main__.py |
172 | @@ -2,11 +2,9 @@ |
173 | |
174 | import argparse |
175 | import logging |
176 | -import shutil |
177 | import sys |
178 | -import tempfile |
179 | |
180 | -from tests.cloud_tests import (args, collect, manage, verify) |
181 | +from tests.cloud_tests import args, bddeb, collect, manage, run_funcs, verify |
182 | from tests.cloud_tests import LOG |
183 | |
184 | |
185 | @@ -22,28 +20,6 @@ def configure_log(args): |
186 | LOG.setLevel(level) |
187 | |
188 | |
189 | -def run(args): |
190 | - """ |
191 | - run full test suite |
192 | - """ |
193 | - failed = 0 |
194 | - args.data_dir = tempfile.mkdtemp(prefix='cloud_test_data_') |
195 | - LOG.debug('using tmpdir %s', args.data_dir) |
196 | - try: |
197 | - failed += collect.collect(args) |
198 | - failed += verify.verify(args) |
199 | - except Exception: |
200 | - failed += 1 |
201 | - raise |
202 | - finally: |
203 | - # TODO: make this configurable via environ or cmdline |
204 | - if failed: |
205 | - LOG.warn('some tests failed, leaving data in %s', args.data_dir) |
206 | - else: |
207 | - shutil.rmtree(args.data_dir) |
208 | - return failed |
209 | - |
210 | - |
211 | def main(): |
212 | """ |
213 | entry point for cloud test suite |
214 | @@ -80,9 +56,12 @@ def main(): |
215 | # run handler |
216 | LOG.debug('running with args: %s\n', parsed) |
217 | return { |
218 | + 'bddeb': bddeb.bddeb, |
219 | 'collect': collect.collect, |
220 | 'create': manage.create, |
221 | - 'run': run, |
222 | + 'run': run_funcs.run, |
223 | + 'tree_collect': run_funcs.tree_collect, |
224 | + 'tree_run': run_funcs.tree_run, |
225 | 'verify': verify.verify, |
226 | }[parsed.subcmd](parsed) |
227 | |
228 | diff --git a/tests/cloud_tests/args.py b/tests/cloud_tests/args.py |
229 | index b68cc98..d051737 100644 |
230 | --- a/tests/cloud_tests/args.py |
231 | +++ b/tests/cloud_tests/args.py |
232 | @@ -3,9 +3,24 @@ |
233 | import os |
234 | |
235 | from tests.cloud_tests import config, util |
236 | -from tests.cloud_tests import LOG |
237 | +from tests.cloud_tests import LOG, TREE_BASE |
238 | |
239 | ARG_SETS = { |
240 | + 'BDDEB': ( |
241 | + (('--bddeb-args',), |
242 | + {'help': 'args to pass through to bddeb', |
243 | + 'action': 'store', 'default': None, 'required': False}), |
244 | + (('--build-os',), |
245 | + {'help': 'OS to use as build system (default is xenial)', |
246 | + 'action': 'store', 'choices': config.list_enabled_distros(), |
247 | + 'default': 'xenial', 'required': False}), |
248 | + (('--build-platform',), |
249 | + {'help': 'platform to use for build system (default is lxd)', |
250 | + 'action': 'store', 'choices': config.list_enabled_platforms(), |
251 | + 'default': 'lxd', 'required': False}), |
252 | + (('--cloud-init',), |
253 | + {'help': 'path to base of cloud-init tree', 'metavar': 'DIR', |
254 | + 'action': 'store', 'required': False, 'default': TREE_BASE}),), |
255 | 'COLLECT': ( |
256 | (('-p', '--platform'), |
257 | {'help': 'platform(s) to run tests on', 'metavar': 'PLATFORM', |
258 | @@ -42,6 +57,10 @@ ARG_SETS = { |
259 | (('-d', '--data-dir'), |
260 | {'help': 'directory to store test data in', |
261 | 'action': 'store', 'metavar': 'DIR', 'required': True}),), |
262 | + 'OUTPUT_DEB': ( |
263 | + (('--deb',), |
264 | + {'help': 'path to write output deb to', 'metavar': 'FILE', |
265 | + 'action': 'store', 'required': True}),), |
266 | 'RESULT': ( |
267 | (('-r', '--result'), |
268 | {'help': 'file to write results to', |
269 | @@ -66,10 +85,16 @@ ARG_SETS = { |
270 | } |
271 | |
272 | SUBCMDS = { |
273 | + 'bddeb': ('build cloud-init deb from tree', |
274 | + ('BDDEB', 'OUTPUT_DEB', 'INTERFACE')), |
275 | 'collect': ('collect test data', |
276 | ('COLLECT', 'INTERFACE', 'OUTPUT', 'RESULT', 'SETUP')), |
277 | 'create': ('create new test case', ('CREATE', 'INTERFACE')), |
278 | 'run': ('run test suite', ('COLLECT', 'INTERFACE', 'RESULT', 'SETUP')), |
279 | + 'tree_collect': ('collect using current working tree', |
280 | + ('BDDEB', 'COLLECT', 'INTERFACE', 'OUTPUT', 'RESULT')), |
281 | + 'tree_run': ('run using current working tree', |
282 | + ('BDDEB', 'COLLECT', 'INTERFACE', 'RESULT')), |
283 | 'verify': ('verify test data', ('INTERFACE', 'OUTPUT', 'RESULT')), |
284 | } |
285 | |
286 | @@ -81,6 +106,20 @@ def _empty_normalizer(args): |
287 | return args |
288 | |
289 | |
290 | +def normalize_bddeb_args(args): |
291 | + """ |
292 | + normalize BDDEB arguments |
293 | + args: parsed args |
294 | + return_value: updated args, or None if errors encountered |
295 | + """ |
296 | + # make sure cloud-init dir is accessible |
297 | + if not (args.cloud_init and os.path.isdir(args.cloud_init)): |
298 | + LOG.error('invalid cloud-init tree path') |
299 | + return None |
300 | + |
301 | + return args |
302 | + |
303 | + |
304 | def normalize_create_args(args): |
305 | """ |
306 | normalize CREATE arguments |
307 | @@ -185,6 +224,17 @@ def normalize_output_args(args): |
308 | return args |
309 | |
310 | |
311 | +def normalize_output_deb_args(args): |
312 | + """ |
313 | + normalize OUTPUT_DEB arguments |
314 | + args: parsed args |
315 | + return_value: updated args, or None if erros occurred |
316 | + """ |
317 | + # make sure to use abspath for deb |
318 | + args.deb = os.path.abspath(args.deb) |
319 | + return args |
320 | + |
321 | + |
322 | def normalize_setup_args(args): |
323 | """ |
324 | normalize SETUP arguments |
325 | @@ -210,10 +260,12 @@ def normalize_setup_args(args): |
326 | |
327 | |
328 | NORMALIZERS = { |
329 | + 'BDDEB': normalize_bddeb_args, |
330 | 'COLLECT': normalize_collect_args, |
331 | 'CREATE': normalize_create_args, |
332 | 'INTERFACE': _empty_normalizer, |
333 | 'OUTPUT': normalize_output_args, |
334 | + 'OUTPUT_DEB': normalize_output_deb_args, |
335 | 'RESULT': _empty_normalizer, |
336 | 'SETUP': normalize_setup_args, |
337 | } |
338 | diff --git a/tests/cloud_tests/bddeb.py b/tests/cloud_tests/bddeb.py |
339 | new file mode 100644 |
340 | index 0000000..3b79cd2 |
341 | --- /dev/null |
342 | +++ b/tests/cloud_tests/bddeb.py |
343 | @@ -0,0 +1,124 @@ |
344 | +# This file is part of cloud-init. See LICENSE file for license information. |
345 | + |
346 | +from tests.cloud_tests import (config, LOG) |
347 | +from tests.cloud_tests import (platforms, images, snapshots, instances) |
348 | +from tests.cloud_tests.stage import (PlatformComponent, run_stage, run_single) |
349 | + |
350 | +from cloudinit import util as c_util |
351 | + |
352 | +from functools import partial |
353 | +import os |
354 | + |
355 | +build_deps = ['devscripts', 'equivs', 'git', 'tar'] |
356 | + |
357 | + |
358 | +def _out(cmd_res): |
359 | + """ |
360 | + get clean output from cmd result |
361 | + """ |
362 | + return cmd_res[0].strip() |
363 | + |
364 | + |
365 | +def build_deb(args, instance): |
366 | + """ |
367 | + build deb on system and copy out to location at args.deb |
368 | + args: cmdline arguments |
369 | + return_value: tuple of results and fail count |
370 | + """ |
371 | + # update remote system package list and install build deps |
372 | + LOG.debug('installing build deps') |
373 | + pkgs = ' '.join(build_deps) |
374 | + cmd = 'apt-get update && apt-get install --yes {}'.format(pkgs) |
375 | + instance.execute(['/bin/sh', '-c', cmd]) |
376 | + instance.execute(['mk-build-deps', '--install', '-t', |
377 | + 'apt-get --no-install-recommends --yes', 'cloud-init']) |
378 | + |
379 | + # local tmpfile that must be deleted |
380 | + local_tarball = _out(c_util.subp(['mktemp'], capture=True)) |
381 | + |
382 | + try: |
383 | + # paths to use in remote system |
384 | + remote_tarball = _out(instance.execute(['mktemp'])) |
385 | + extract_dir = _out(instance.execute(['mktemp', '--directory'])) |
386 | + bddeb_path = os.path.join(extract_dir, 'packages', 'bddeb') |
387 | + output_link = '/cloud-init_all.deb' |
388 | + git_env = {'GIT_DIR': os.path.join(extract_dir, '.git'), |
389 | + 'GIT_WORK_TREE': extract_dir} |
390 | + |
391 | + # create a tarball of cloud init tree and copy to remote system |
392 | + LOG.debug('creating tarball of cloud-init at: %s', local_tarball) |
393 | + c_util.subp(['tar', 'cf', local_tarball, '--owner', 'root', |
394 | + '--group', 'root', '-C', args.cloud_init, '.']) |
395 | + LOG.debug('copying to remote system at: %s', remote_tarball) |
396 | + instance.push_file(local_tarball, remote_tarball) |
397 | + |
398 | + # extract tarball in remote system and commit anything uncommitted |
399 | + LOG.debug('extracting tarball in remote system at: %s', extract_dir) |
400 | + instance.execute(['tar', 'xf', remote_tarball, '-C', extract_dir]) |
401 | + instance.execute(['git', 'commit', '-a', '-m', 'tmp', '--allow-empty'], |
402 | + env=git_env) |
403 | + |
404 | + # build the deb, ignoring missing deps (flake8) |
405 | + LOG.debug('building deb in remote system at: %s', output_link) |
406 | + bddeb_args = args.bddeb_args.split() if args.bddeb_args else [] |
407 | + instance.execute([bddeb_path, '-d'] + bddeb_args, env=git_env) |
408 | + |
409 | + # copy the deb back to the host system |
410 | + LOG.debug('copying built deb to host at: %s', args.deb) |
411 | + instance.pull_file(output_link, args.deb) |
412 | + |
413 | + finally: |
414 | + os.remove(local_tarball) |
415 | + |
416 | + |
417 | +def setup_build(args): |
418 | + """ |
419 | + set build system up then run build |
420 | + args: cmdline arguments |
421 | + return_value: tuple of results and fail count |
422 | + """ |
423 | + res = ({}, 1) |
424 | + |
425 | + # set up platform |
426 | + LOG.info('setting up platform: %s', args.build_platform) |
427 | + platform_config = config.load_platform_config(args.build_platform) |
428 | + platform_call = partial(platforms.get_platform, args.build_platform, |
429 | + platform_config) |
430 | + with PlatformComponent(platform_call) as platform: |
431 | + |
432 | + # set up image |
433 | + LOG.info('acquiring image for os: %s', args.build_os) |
434 | + img_conf = config.load_os_config(args.build_os) |
435 | + image_call = partial(images.get_image, platform, img_conf) |
436 | + with PlatformComponent(image_call) as image: |
437 | + |
438 | + # set up snapshot |
439 | + snapshot_call = partial(snapshots.get_snapshot, image) |
440 | + with PlatformComponent(snapshot_call) as snapshot: |
441 | + |
442 | + # create instance with cloud-config to set it up |
443 | + LOG.info('creating instance to build deb in') |
444 | + empty_cloud_config = "#cloud-config\n{}" |
445 | + instance_call = partial( |
446 | + instances.get_instance, snapshot, empty_cloud_config, |
447 | + use_desc='build cloud-init deb') |
448 | + with PlatformComponent(instance_call) as instance: |
449 | + |
450 | + # build the deb |
451 | + res = run_single('build deb on system', |
452 | + partial(build_deb, args, instance)) |
453 | + |
454 | + return res |
455 | + |
456 | + |
457 | +def bddeb(args): |
458 | + """ |
459 | + entry point for build deb |
460 | + args: cmdline arguments |
461 | + return_value: fail count |
462 | + """ |
463 | + LOG.info('preparing to build cloud-init deb') |
464 | + (res, failed) = run_stage('build deb', [partial(setup_build, args)]) |
465 | + return failed |
466 | + |
467 | +# vi: ts=4 expandtab |
468 | diff --git a/tests/cloud_tests/instances/base.py b/tests/cloud_tests/instances/base.py |
469 | index 9559d28..1782c1d 100644 |
470 | --- a/tests/cloud_tests/instances/base.py |
471 | +++ b/tests/cloud_tests/instances/base.py |
472 | @@ -51,7 +51,7 @@ class Instance(object): |
473 | copy file at 'remote_path', from instance to 'local_path' |
474 | """ |
475 | with open(local_path, 'wb') as fp: |
476 | - fp.write(self.read_data(remote_path), encode=True) |
477 | + fp.write(self.read_data(remote_path)) |
478 | |
479 | def push_file(self, local_path, remote_path): |
480 | """ |
481 | diff --git a/tests/cloud_tests/run_funcs.py b/tests/cloud_tests/run_funcs.py |
482 | new file mode 100644 |
483 | index 0000000..683a3f6 |
484 | --- /dev/null |
485 | +++ b/tests/cloud_tests/run_funcs.py |
486 | @@ -0,0 +1,65 @@ |
487 | +# This file is part of cloud-init. See LICENSE file for license information. |
488 | + |
489 | +from tests.cloud_tests import bddeb, collect, util, verify |
490 | + |
491 | +import os |
492 | + |
493 | + |
494 | +def tree_collect(args): |
495 | + """ |
496 | + collect data using deb build from current tree |
497 | + args: cmdline args |
498 | + return_value: fail count |
499 | + """ |
500 | + failed = 0 |
501 | + |
502 | + with util.TempDir(args) as tmpdir: |
503 | + args.deb = os.path.join(tmpdir, 'cloud-init.deb') |
504 | + try: |
505 | + failed += bddeb.bddeb(args) |
506 | + failed += collect.collect(args) |
507 | + except Exception: |
508 | + failed += 1 |
509 | + raise |
510 | + |
511 | + return failed |
512 | + |
513 | + |
514 | +def tree_run(args): |
515 | + """ |
516 | + run test suite using deb build from current tree |
517 | + args: cmdline args |
518 | + return_value: fail count |
519 | + """ |
520 | + failed = 0 |
521 | + |
522 | + with util.TempDir(args) as tmpdir: |
523 | + args.deb = os.path.join(tmpdir, 'cloud-init.deb') |
524 | + try: |
525 | + failed += bddeb.bddeb(args) |
526 | + failed += run(args) |
527 | + except Exception: |
528 | + failed += 1 |
529 | + raise |
530 | + |
531 | + return failed |
532 | + |
533 | + |
534 | +def run(args): |
535 | + """ |
536 | + run test suite |
537 | + """ |
538 | + failed = 0 |
539 | + |
540 | + with util.TempDir(args) as tmpdir: |
541 | + args.data_dir = tmpdir |
542 | + try: |
543 | + failed += collect.collect(args) |
544 | + failed += verify.verify(args) |
545 | + except Exception: |
546 | + failed += 1 |
547 | + raise |
548 | + |
549 | + return failed |
550 | + |
551 | +# vi: ts=4 expandtab |
552 | diff --git a/tests/cloud_tests/util.py b/tests/cloud_tests/util.py |
553 | index 64a8667..18f54b4 100644 |
554 | --- a/tests/cloud_tests/util.py |
555 | +++ b/tests/cloud_tests/util.py |
556 | @@ -3,6 +3,7 @@ |
557 | import glob |
558 | import os |
559 | import random |
560 | +import shutil |
561 | import string |
562 | import tempfile |
563 | import yaml |
564 | @@ -160,4 +161,36 @@ def write_file(*args, **kwargs): |
565 | """ |
566 | c_util.write_file(*args, **kwargs) |
567 | |
568 | + |
569 | +class TempDir(object): |
570 | + """ |
571 | + temporary directory like tempfile.TemporaryDirectory, but configurable |
572 | + """ |
573 | + |
574 | + def __init__(self, args): |
575 | + """ |
576 | + setup and store args |
577 | + args: cmdline arguments |
578 | + """ |
579 | + self.args = args |
580 | + self.tmpdir = None |
581 | + |
582 | + def __enter__(self): |
583 | + """ |
584 | + create tempdir |
585 | + return_value: tempdir path |
586 | + """ |
587 | + self.tmpdir = tempfile.mkdtemp(prefix='cloud_test_') |
588 | + LOG.debug('using tmpdir: %s', self.tmpdir) |
589 | + return self.tmpdir |
590 | + |
591 | + def __exit__(self, etype, value, trace): |
592 | + """ |
593 | + destroy tempdir if no errors occurred |
594 | + """ |
595 | + if etype: |
596 | + LOG.warn('erros occurred, leaving data in %s', self.tmpdir) |
597 | + else: |
598 | + shutil.rmtree(self.tmpdir) |
599 | + |
600 | # vi: ts=4 expandtab |
LGTM with two comments:
1) Had to increase the timeout as 120 seconds was not enough. I bumped to 600.
2) the tox target "cittest_run" actually does a "tree_run" In order to not be confused between run versus tree_run I think this should really be "cittest_tree_run"
Tested by running the following on my local system with pylxd 2.1.3:
# lint archive. ubuntu. com/ubuntu/ yakkety main' 0.7.9-0ubuntu1_ all.deb tests/configs/ modules/ write_files. yaml tests/configs/ modules/ timezone. yaml
$ tox
# runs with options
$ python3 -m tests.cloud_tests run -v -n trusty
$ python3 -m tests.cloud_tests run -v -n xenial
$ python3 -m tests.cloud_tests run -v -n yakkety --repo 'deb http://
$ python3 -m tests.cloud_tests run -v -n xenial --deb cloud-init_
# new tox based runs + tree_run
$ tox -e citest_run
$ tox -e citest -- tree_run -n zesty -t tests/cloud_
$ python3 -m tests.cloud_tests tree_run -v -n zesty -t tests/cloud_
lxc list was clean afterwards as expected. I believe I only missed a ppa test.
The only warning message I got other than those for pylxd's 2.2 deprecation was: Work/repos/ cloud-init- wesley/ tests/cloud_ tests/collect. py:48: DeprecationWarning: The 'warn' method is deprecated, use 'warning' instead
/home/powersj/