Merge ~andrey-fedoseev/launchpad-buildd:backend-open into launchpad-buildd:master
- Git
- lp:~andrey-fedoseev/launchpad-buildd
- backend-open
- Merge into master
Proposed by
Andrey Fedoseev
Status: | Merged |
---|---|
Approved by: | Andrey Fedoseev |
Approved revision: | 37ae20af627f8b0056b988972b42845888510e5a |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~andrey-fedoseev/launchpad-buildd:backend-open |
Merge into: | launchpad-buildd:master |
Diff against target: |
540 lines (+146/-105) 11 files modified
debian/changelog (+5/-0) lpbuildd/binarypackage.py (+3/-3) lpbuildd/ci.py (+3/-8) lpbuildd/target/apt.py (+18/-24) lpbuildd/target/backend.py (+25/-0) lpbuildd/target/build_oci.py (+1/-4) lpbuildd/target/build_snap.py (+4/-6) lpbuildd/target/lxd.py (+20/-37) lpbuildd/target/run_ci.py (+5/-10) lpbuildd/target/tests/test_backend.py (+39/-0) lpbuildd/target/tests/test_lxd.py (+23/-13) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Colin Watson (community) | Approve | ||
Review via email: mp+432731@code.launchpad.net |
Commit message
Use `Backend.open` to modify files in target environments
instead of using a local temporary file and `copy_out` / `copy_in` methods
Description of the change
A new method `open` is added to the base `Backend` class
The method access to the files in the target environment via a file-like object.
Under the hood it uses a temporary file on the host system and `copy_in` / `copy_out` methods to transfer the file to / from the target environment.
To post a comment you must log in.
Revision history for this message
Andrey Fedoseev (andrey-fedoseev) wrote : | # |
Colin,
Please see my comments below
Revision history for this message
Colin Watson (cjwatson) wrote : | # |
All your replies make sense. Go ahead (except for adding the copyright/licensing comment to `lpbuildd/
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/debian/changelog b/debian/changelog |
2 | index 0ce11f2..fba13f2 100644 |
3 | --- a/debian/changelog |
4 | +++ b/debian/changelog |
5 | @@ -1,9 +1,14 @@ |
6 | launchpad-buildd (224) UNRELEASED; urgency=medium |
7 | |
8 | + [ Colin Watson ] |
9 | * Allow configuring builders to use a different ClamAV database URL. |
10 | * Require the LXD snap to be installed, rather than depending on the lxd |
11 | package (which no longer exists in jammy). |
12 | |
13 | + [ Andrey Fedoseev ] |
14 | + * `open` method is added to the backends providing access to the files |
15 | + in target environments via a file-like object. |
16 | + |
17 | -- Colin Watson <cjwatson@ubuntu.com> Wed, 26 Oct 2022 08:55:39 +0200 |
18 | |
19 | launchpad-buildd (223) focal; urgency=medium |
20 | diff --git a/lpbuildd/binarypackage.py b/lpbuildd/binarypackage.py |
21 | index c3fef09..3498e58 100644 |
22 | --- a/lpbuildd/binarypackage.py |
23 | +++ b/lpbuildd/binarypackage.py |
24 | @@ -156,11 +156,11 @@ class BinaryPackageBuildManager(DebianBuildManager): |
25 | self.archive_purpose)) |
26 | if self.build_debug_symbols: |
27 | currently_building_contents += 'Build-Debug-Symbols: yes\n' |
28 | - with tempfile.NamedTemporaryFile(mode='w+') as currently_building: |
29 | + with self.backend.open( |
30 | + '/CurrentlyBuilding', mode='w+' |
31 | + ) as currently_building: |
32 | currently_building.write(currently_building_contents) |
33 | - currently_building.flush() |
34 | os.fchmod(currently_building.fileno(), 0o644) |
35 | - self.backend.copy_in(currently_building.name, '/CurrentlyBuilding') |
36 | |
37 | args = ["sbuild-package", self._buildid, self.arch_tag] |
38 | args.append(self.suite) |
39 | diff --git a/lpbuildd/ci.py b/lpbuildd/ci.py |
40 | index 04aa5f8..601d8b4 100644 |
41 | --- a/lpbuildd/ci.py |
42 | +++ b/lpbuildd/ci.py |
43 | @@ -6,7 +6,6 @@ from configparser import ( |
44 | NoSectionError, |
45 | ) |
46 | import os |
47 | -import tempfile |
48 | import yaml |
49 | |
50 | from twisted.internet import defer |
51 | @@ -168,14 +167,10 @@ class CIBuildManager(BuildManagerProxyMixin, DebianBuildManager): |
52 | ["--plugin-setting", f"{key}={value}"]) |
53 | if self.secrets is not None: |
54 | text = yaml.dump(self.secrets) |
55 | - with tempfile.NamedTemporaryFile(mode="w") as f: |
56 | + with self.backend.open( |
57 | + "/build/.launchpad-secrets.yaml", mode="w" |
58 | + ) as f: |
59 | f.write(text) |
60 | - f.flush() |
61 | - path_to_secrets = f.name |
62 | - self.backend.copy_in( |
63 | - source_path=path_to_secrets, |
64 | - target_path="/build/.launchpad-secrets.yaml" |
65 | - ) |
66 | args.extend( |
67 | ["--secrets", "/build/.launchpad-secrets.yaml"]) |
68 | if self.scan_malware: |
69 | diff --git a/lpbuildd/target/apt.py b/lpbuildd/target/apt.py |
70 | index ebd4683..a411806 100644 |
71 | --- a/lpbuildd/target/apt.py |
72 | +++ b/lpbuildd/target/apt.py |
73 | @@ -5,7 +5,6 @@ import logging |
74 | import os |
75 | import subprocess |
76 | import sys |
77 | -import tempfile |
78 | from textwrap import dedent |
79 | import time |
80 | |
81 | @@ -30,49 +29,44 @@ class OverrideSourcesList(Operation): |
82 | |
83 | def run(self): |
84 | logger.info("Overriding sources.list in build-%s", self.args.build_id) |
85 | - with tempfile.NamedTemporaryFile(mode="w+") as sources_list: |
86 | + with self.backend.open( |
87 | + "/etc/apt/sources.list", mode="w+" |
88 | + ) as sources_list: |
89 | for archive in self.args.archives: |
90 | print(archive, file=sources_list) |
91 | - sources_list.flush() |
92 | os.fchmod(sources_list.fileno(), 0o644) |
93 | - self.backend.copy_in(sources_list.name, "/etc/apt/sources.list") |
94 | - with tempfile.NamedTemporaryFile(mode="w+") as apt_retries_conf: |
95 | + with self.backend.open( |
96 | + "/etc/apt/apt.conf.d/99retries", mode="w+" |
97 | + ) as apt_retries_conf: |
98 | print('Acquire::Retries "3";', file=apt_retries_conf) |
99 | - apt_retries_conf.flush() |
100 | os.fchmod(apt_retries_conf.fileno(), 0o644) |
101 | - self.backend.copy_in( |
102 | - apt_retries_conf.name, "/etc/apt/apt.conf.d/99retries") |
103 | # Versions of APT that support phased updates do this automatically |
104 | # if running in a chroot, but builds may be running in a LXD |
105 | # container instead. |
106 | - with tempfile.NamedTemporaryFile(mode="w+") as apt_phasing_conf: |
107 | + with self.backend.open( |
108 | + "/etc/apt/apt.conf.d/99phasing", mode="w+" |
109 | + ) as apt_phasing_conf: |
110 | print('APT::Get::Always-Include-Phased-Updates "true";', |
111 | file=apt_phasing_conf) |
112 | - apt_phasing_conf.flush() |
113 | os.fchmod(apt_phasing_conf.fileno(), 0o644) |
114 | - self.backend.copy_in( |
115 | - apt_phasing_conf.name, "/etc/apt/apt.conf.d/99phasing") |
116 | if self.args.apt_proxy_url is not None: |
117 | - with tempfile.NamedTemporaryFile(mode="w+") as apt_proxy_conf: |
118 | + with self.backend.open( |
119 | + "/etc/apt/apt.conf.d/99proxy", mode="w+" |
120 | + ) as apt_proxy_conf: |
121 | print( |
122 | f'Acquire::http::Proxy "{self.args.apt_proxy_url}";', |
123 | file=apt_proxy_conf) |
124 | - apt_proxy_conf.flush() |
125 | os.fchmod(apt_proxy_conf.fileno(), 0o644) |
126 | - self.backend.copy_in( |
127 | - apt_proxy_conf.name, "/etc/apt/apt.conf.d/99proxy") |
128 | for pocket in ("proposed", "backports"): |
129 | - with tempfile.NamedTemporaryFile(mode="w+") as preferences: |
130 | + with self.backend.open( |
131 | + f"/etc/apt/preferences.d/{pocket}.pref", mode="w+" |
132 | + ) as preferences: |
133 | print(dedent(f"""\ |
134 | Package: * |
135 | Pin: release a=*-{pocket} |
136 | Pin-Priority: 500 |
137 | """), file=preferences, end="") |
138 | - preferences.flush() |
139 | os.fchmod(preferences.fileno(), 0o644) |
140 | - self.backend.copy_in( |
141 | - preferences.name, |
142 | - f"/etc/apt/preferences.d/{pocket}.pref") |
143 | return 0 |
144 | |
145 | |
146 | @@ -91,7 +85,9 @@ class AddTrustedKeys(Operation): |
147 | gpg_cmd = [ |
148 | "gpg", "--ignore-time-conflict", "--no-options", "--no-keyring", |
149 | ] |
150 | - with tempfile.NamedTemporaryFile(mode="wb+") as keyring: |
151 | + with self.backend.open( |
152 | + "/etc/apt/trusted.gpg.d/launchpad-buildd.gpg", mode="wb+" |
153 | + ) as keyring: |
154 | subprocess.check_call( |
155 | gpg_cmd + ["--dearmor"], stdin=self.input_file, stdout=keyring) |
156 | keyring.seek(0) |
157 | @@ -100,8 +96,6 @@ class AddTrustedKeys(Operation): |
158 | ["--show-keys", "--keyid-format", "long", "--fingerprint"], |
159 | stdin=keyring, stdout=self.show_keys_file) |
160 | os.fchmod(keyring.fileno(), 0o644) |
161 | - self.backend.copy_in( |
162 | - keyring.name, "/etc/apt/trusted.gpg.d/launchpad-buildd.gpg") |
163 | return 0 |
164 | |
165 | |
166 | diff --git a/lpbuildd/target/backend.py b/lpbuildd/target/backend.py |
167 | index 69746bb..a920cf1 100644 |
168 | --- a/lpbuildd/target/backend.py |
169 | +++ b/lpbuildd/target/backend.py |
170 | @@ -3,6 +3,10 @@ |
171 | |
172 | import os.path |
173 | import subprocess |
174 | +import tempfile |
175 | +from contextlib import contextmanager |
176 | +from pathlib import Path |
177 | +from shutil import rmtree |
178 | |
179 | |
180 | class BackendException(Exception): |
181 | @@ -189,6 +193,27 @@ class Backend: |
182 | """Remove the backend.""" |
183 | subprocess.check_call(["sudo", "rm", "-rf", self.build_path]) |
184 | |
185 | + @contextmanager |
186 | + def open(self, path: str, mode="r", **kwargs): |
187 | + """ |
188 | + Provides access to the files in the target environment via a |
189 | + file-like object. |
190 | + |
191 | + The arguments are the same as those of the built-in `open` function. |
192 | + """ |
193 | + tmp_dir = tempfile.mkdtemp() |
194 | + tmp_path = os.path.join(tmp_dir, Path(path).name) |
195 | + if self.path_exists(path): |
196 | + self.copy_out(path, tmp_path) |
197 | + tmp_file = open(tmp_path, mode=mode, **kwargs) |
198 | + try: |
199 | + yield tmp_file |
200 | + finally: |
201 | + tmp_file.close() |
202 | + if mode not in ("r", "rb", "rt"): |
203 | + self.copy_in(tmp_path, path) |
204 | + rmtree(tmp_dir) |
205 | + |
206 | |
207 | def make_backend(name, build_id, series=None, arch=None): |
208 | if name == "chroot": |
209 | diff --git a/lpbuildd/target/build_oci.py b/lpbuildd/target/build_oci.py |
210 | index 5241f9f..ecbda0d 100644 |
211 | --- a/lpbuildd/target/build_oci.py |
212 | +++ b/lpbuildd/target/build_oci.py |
213 | @@ -3,7 +3,6 @@ |
214 | |
215 | import logging |
216 | import os.path |
217 | -import tempfile |
218 | from textwrap import dedent |
219 | |
220 | from lpbuildd.target.backend import check_path_escape |
221 | @@ -56,10 +55,8 @@ class BuildOCI(BuilderProxyOperationMixin, VCSOperationMixin, |
222 | Environment="{setting.upper()}={self.args.proxy_url}" |
223 | """) |
224 | file_path = f"/etc/systemd/system/docker.service.d/{setting}.conf" |
225 | - with tempfile.NamedTemporaryFile(mode="w+") as systemd_file: |
226 | + with self.backend.open(file_path, mode="w+") as systemd_file: |
227 | systemd_file.write(contents) |
228 | - systemd_file.flush() |
229 | - self.backend.copy_in(systemd_file.name, file_path) |
230 | |
231 | def install(self): |
232 | logger.info("Running install phase...") |
233 | diff --git a/lpbuildd/target/build_snap.py b/lpbuildd/target/build_snap.py |
234 | index 30c5ecc..615c2d9 100644 |
235 | --- a/lpbuildd/target/build_snap.py |
236 | +++ b/lpbuildd/target/build_snap.py |
237 | @@ -5,7 +5,6 @@ import argparse |
238 | import json |
239 | import logging |
240 | import os.path |
241 | -import tempfile |
242 | from textwrap import dedent |
243 | from urllib.parse import urlparse |
244 | |
245 | @@ -92,13 +91,12 @@ class BuildSnap(BuilderProxyOperationMixin, VCSOperationMixin, |
246 | svn_servers += f"http-proxy-username = {proxy.username}\n" |
247 | if proxy.password: |
248 | svn_servers += f"http-proxy-password = {proxy.password}\n" |
249 | - with tempfile.NamedTemporaryFile(mode="w+") as svn_servers_file: |
250 | + self.backend.run(["mkdir", "-p", "/root/.subversion"]) |
251 | + with self.backend.open( |
252 | + "/root/.subversion/servers", mode="w+" |
253 | + ) as svn_servers_file: |
254 | svn_servers_file.write(svn_servers) |
255 | - svn_servers_file.flush() |
256 | os.fchmod(svn_servers_file.fileno(), 0o644) |
257 | - self.backend.run(["mkdir", "-p", "/root/.subversion"]) |
258 | - self.backend.copy_in( |
259 | - svn_servers_file.name, "/root/.subversion/servers") |
260 | |
261 | def install(self): |
262 | logger.info("Running install phase...") |
263 | diff --git a/lpbuildd/target/lxd.py b/lpbuildd/target/lxd.py |
264 | index d58d9ab..63f36d5 100644 |
265 | --- a/lpbuildd/target/lxd.py |
266 | +++ b/lpbuildd/target/lxd.py |
267 | @@ -9,7 +9,6 @@ import re |
268 | import stat |
269 | import subprocess |
270 | import tarfile |
271 | -import tempfile |
272 | from textwrap import dedent |
273 | import time |
274 | |
275 | @@ -376,22 +375,16 @@ class LXD(Backend): |
276 | ["hostname"], universal_newlines=True).rstrip("\n") |
277 | fqdn = subprocess.check_output( |
278 | ["hostname", "--fqdn"], universal_newlines=True).rstrip("\n") |
279 | - with tempfile.NamedTemporaryFile(mode="w+") as hosts_file: |
280 | - try: |
281 | - self.copy_out("/etc/hosts", hosts_file.name) |
282 | - except LXDException: |
283 | - hosts_file.seek(0, os.SEEK_SET) |
284 | - hosts_file.write(fallback_hosts) |
285 | + with self.open("/etc/hosts", mode="a") as hosts_file: |
286 | hosts_file.seek(0, os.SEEK_END) |
287 | + if not hosts_file.tell(): |
288 | + # /etc/hosts is missing or empty |
289 | + hosts_file.write(fallback_hosts) |
290 | print(f"\n127.0.1.1\t{fqdn} {hostname}", file=hosts_file) |
291 | - hosts_file.flush() |
292 | os.fchmod(hosts_file.fileno(), 0o644) |
293 | - self.copy_in(hosts_file.name, "/etc/hosts") |
294 | - with tempfile.NamedTemporaryFile(mode="w+") as hostname_file: |
295 | + with self.open("/etc/hostname", mode="w+") as hostname_file: |
296 | print(hostname, file=hostname_file) |
297 | - hostname_file.flush() |
298 | os.fchmod(hostname_file.fileno(), 0o644) |
299 | - self.copy_in(hostname_file.name, "/etc/hostname") |
300 | |
301 | resolv_conf = "/etc/resolv.conf" |
302 | |
303 | @@ -403,23 +396,17 @@ class LXD(Backend): |
304 | |
305 | self.copy_in(resolv_conf, "/etc/resolv.conf") |
306 | |
307 | - with tempfile.NamedTemporaryFile(mode="w+") as policy_rc_d_file: |
308 | + with self.open( |
309 | + "/usr/local/sbin/policy-rc.d", mode="w+" |
310 | + ) as policy_rc_d_file: |
311 | policy_rc_d_file.write(policy_rc_d) |
312 | - policy_rc_d_file.flush() |
313 | os.fchmod(policy_rc_d_file.fileno(), 0o755) |
314 | - self.copy_in(policy_rc_d_file.name, "/usr/local/sbin/policy-rc.d") |
315 | # For targets that use Upstart, prevent the mounted-dev job from |
316 | # creating devices. Most of the devices it creates are unnecessary |
317 | # in a container, and creating loop devices will race with our own |
318 | # code to do so. |
319 | - with tempfile.NamedTemporaryFile(mode="w+") as mounted_dev_file: |
320 | - try: |
321 | - self.copy_out( |
322 | - "/etc/init/mounted-dev.conf", mounted_dev_file.name) |
323 | - except LXDException: |
324 | - pass |
325 | - else: |
326 | - mounted_dev_file.seek(0, os.SEEK_SET) |
327 | + if self.path_exists("/etc/init/mounted-dev.conf"): |
328 | + with self.open("/etc/init/mounted-dev.conf") as mounted_dev_file: |
329 | script = "" |
330 | in_script = False |
331 | for line in mounted_dev_file: |
332 | @@ -431,15 +418,13 @@ class LXD(Backend): |
333 | elif line.strip() == "script": |
334 | script += line |
335 | in_script = True |
336 | - if script: |
337 | - mounted_dev_file.seek(0, os.SEEK_SET) |
338 | - mounted_dev_file.truncate() |
339 | - mounted_dev_file.write(script) |
340 | - mounted_dev_file.flush() |
341 | - os.fchmod(mounted_dev_file.fileno(), 0o644) |
342 | - self.copy_in( |
343 | - mounted_dev_file.name, |
344 | - "/etc/init/mounted-dev.override") |
345 | + |
346 | + if script: |
347 | + with self.open( |
348 | + "/etc/init/mounted-dev.override", mode="w" |
349 | + ) as mounted_dev_override_file: |
350 | + mounted_dev_override_file.write(script) |
351 | + os.fchmod(mounted_dev_override_file.fileno(), 0o644) |
352 | |
353 | # Start the container and wait for it to start. |
354 | container.start(wait=True) |
355 | @@ -481,16 +466,14 @@ class LXD(Backend): |
356 | # directory until the container has started. We can get away with |
357 | # this for the time being because snapd isn't in the buildd chroots. |
358 | self.run(["mkdir", "-p", "/etc/systemd/system/snapd.service.d"]) |
359 | - with tempfile.NamedTemporaryFile(mode="w+") as no_cdn_file: |
360 | + with self.open( |
361 | + "/etc/systemd/system/snapd.service.d/no-cdn.conf", mode="w+" |
362 | + ) as no_cdn_file: |
363 | print(dedent("""\ |
364 | [Service] |
365 | Environment=SNAPPY_STORE_NO_CDN=1 |
366 | """), file=no_cdn_file, end="") |
367 | - no_cdn_file.flush() |
368 | os.fchmod(no_cdn_file.fileno(), 0o644) |
369 | - self.copy_in( |
370 | - no_cdn_file.name, |
371 | - "/etc/systemd/system/snapd.service.d/no-cdn.conf") |
372 | |
373 | # Refreshing snaps from a timer unit during a build isn't |
374 | # appropriate. Mask this, but manually so that we don't depend on |
375 | diff --git a/lpbuildd/target/run_ci.py b/lpbuildd/target/run_ci.py |
376 | index 4ebf765..28dc2e7 100644 |
377 | --- a/lpbuildd/target/run_ci.py |
378 | +++ b/lpbuildd/target/run_ci.py |
379 | @@ -3,7 +3,6 @@ |
380 | |
381 | import logging |
382 | import os |
383 | -import tempfile |
384 | |
385 | from lpbuildd.target.build_snap import SnapChannelsAction |
386 | from lpbuildd.target.operation import Operation |
387 | @@ -77,16 +76,12 @@ class RunCIPrepare(BuilderProxyOperationMixin, VCSOperationMixin, |
388 | # services, which is convenient since it allows us to ensure |
389 | # that ClamAV's database is up to date before proceeding. |
390 | if self.args.clamav_database_url: |
391 | - freshclam_path = "/etc/clamav/freshclam.conf" |
392 | - with tempfile.NamedTemporaryFile(mode="w+") as freshclam_file: |
393 | - self.backend.copy_out(freshclam_path, freshclam_file.name) |
394 | - freshclam_file.seek(0, os.SEEK_END) |
395 | - print( |
396 | - f"PrivateMirror {self.args.clamav_database_url}", |
397 | - file=freshclam_file, |
398 | + with self.backend.open( |
399 | + "/etc/clamav/freshclam.conf", mode="a" |
400 | + ) as freshclam_file: |
401 | + freshclam_file.write( |
402 | + f"PrivateMirror {self.args.clamav_database_url}\n" |
403 | ) |
404 | - freshclam_file.flush() |
405 | - self.backend.copy_in(freshclam_file.name, freshclam_path) |
406 | kwargs = {} |
407 | env = self.build_proxy_environment(proxy_url=self.args.proxy_url) |
408 | if env: |
409 | diff --git a/lpbuildd/target/tests/test_backend.py b/lpbuildd/target/tests/test_backend.py |
410 | new file mode 100644 |
411 | index 0000000..ff617e3 |
412 | --- /dev/null |
413 | +++ b/lpbuildd/target/tests/test_backend.py |
414 | @@ -0,0 +1,39 @@ |
415 | +# Copyright 2022 Canonical Ltd. This software is licensed under the |
416 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
417 | +from unittest.mock import patch, ANY |
418 | + |
419 | +from testtools import TestCase |
420 | +from fixtures import TempDir |
421 | + |
422 | +from lpbuildd.tests.fakebuilder import UncontainedBackend |
423 | + |
424 | + |
425 | +class TestBackend(TestCase): |
426 | + |
427 | + def test_open(self): |
428 | + backend = UncontainedBackend("1") |
429 | + backend_root = self.useFixture(TempDir()) |
430 | + target_path = backend_root.join("test.txt") |
431 | + |
432 | + with patch.object( |
433 | + backend, "copy_in", wraps=backend.copy_in |
434 | + ) as copy_in, patch.object( |
435 | + backend, "copy_out", wraps=backend.copy_out |
436 | + ) as copy_out: |
437 | + |
438 | + with backend.open(target_path, "w") as f: |
439 | + f.write("text") |
440 | + |
441 | + copy_out.assert_not_called() |
442 | + copy_in.assert_called_once_with(ANY, target_path) |
443 | + |
444 | + self.assertTrue(backend.path_exists(target_path)) |
445 | + |
446 | + copy_in.reset_mock() |
447 | + copy_out.reset_mock() |
448 | + |
449 | + with backend.open(target_path, "r") as f: |
450 | + self.assertEqual(f.read(), "text") |
451 | + |
452 | + copy_in.assert_not_called() |
453 | + copy_out.assert_called_once_with(target_path, ANY) |
454 | diff --git a/lpbuildd/target/tests/test_lxd.py b/lpbuildd/target/tests/test_lxd.py |
455 | index ecf3ddd..73f4d94 100644 |
456 | --- a/lpbuildd/target/tests/test_lxd.py |
457 | +++ b/lpbuildd/target/tests/test_lxd.py |
458 | @@ -391,9 +391,10 @@ class TestLXD(TestCase): |
459 | lambda wait=False: setattr(container, "status_code", LXD_RUNNING)) |
460 | files_api = container.api.files |
461 | files_api._api_endpoint = f"/1.0/containers/lp-xenial-{arch}/files" |
462 | - files_api.session.get.side_effect = FakeSessionGet({ |
463 | + existing_files = { |
464 | "/etc/hosts": [b"127.0.0.1\tlocalhost\n"], |
465 | - }) |
466 | + } |
467 | + files_api.session.get.side_effect = FakeSessionGet(existing_files) |
468 | processes_fixture = self.useFixture(FakeProcesses()) |
469 | |
470 | def fake_sudo(args): |
471 | @@ -414,7 +415,13 @@ class TestLXD(TestCase): |
472 | processes_fixture.add(lambda _: {}, name="lxc") |
473 | processes_fixture.add( |
474 | FakeHostname("example", "example.buildd"), name="hostname") |
475 | - LXD("1", "xenial", arch).start() |
476 | + |
477 | + with mock.patch.object( |
478 | + LXD, |
479 | + "path_exists", |
480 | + side_effect=lambda path: path in existing_files |
481 | + ): |
482 | + LXD("1", "xenial", arch).start() |
483 | |
484 | self.assert_correct_profile() |
485 | |
486 | @@ -515,9 +522,6 @@ class TestLXD(TestCase): |
487 | params={"path": "/usr/local/sbin/policy-rc.d"}, |
488 | data=policy_rc_d.encode("UTF-8"), |
489 | headers={"X-LXD-uid": "0", "X-LXD-gid": "0", "X-LXD-mode": "0755"}) |
490 | - files_api.session.get.assert_any_call( |
491 | - f"/1.0/containers/lp-xenial-{arch}/files", |
492 | - params={"path": "/etc/init/mounted-dev.conf"}, stream=True) |
493 | self.assertNotIn( |
494 | "/etc/init/mounted-dev.override", |
495 | [kwargs["params"]["path"] |
496 | @@ -551,11 +555,10 @@ class TestLXD(TestCase): |
497 | processes_fixture.add(lambda _: {}, name="lxc") |
498 | processes_fixture.add( |
499 | FakeHostname("example", "example.buildd"), name="hostname") |
500 | - LXD("1", "xenial", "amd64").start() |
501 | |
502 | - files_api.session.get.assert_any_call( |
503 | - "/1.0/containers/lp-xenial-amd64/files", |
504 | - params={"path": "/etc/hosts"}, stream=True) |
505 | + with mock.patch.object(LXD, "path_exists", return_value=False): |
506 | + LXD("1", "xenial", "amd64").start() |
507 | + |
508 | files_api.post.assert_any_call( |
509 | params={"path": "/etc/hosts"}, |
510 | data=( |
511 | @@ -576,7 +579,7 @@ class TestLXD(TestCase): |
512 | lambda wait=False: setattr(container, "status_code", LXD_RUNNING)) |
513 | files_api = container.api.files |
514 | files_api._api_endpoint = "/1.0/containers/lp-trusty-amd64/files" |
515 | - files_api.session.get.side_effect = FakeSessionGet({ |
516 | + existing_files = { |
517 | "/etc/init/mounted-dev.conf": [dedent("""\ |
518 | start on mounted MOUNTPOINT=/dev |
519 | script |
520 | @@ -584,11 +587,18 @@ class TestLXD(TestCase): |
521 | /sbin/MAKEDEV std fd ppp tun |
522 | end script |
523 | task |
524 | - """).encode("UTF-8")]}) |
525 | + """).encode("UTF-8")]} |
526 | + files_api.session.get.side_effect = FakeSessionGet(existing_files) |
527 | processes_fixture = self.useFixture(FakeProcesses()) |
528 | processes_fixture.add(lambda _: {}, name="sudo") |
529 | processes_fixture.add(lambda _: {}, name="lxc") |
530 | - LXD("1", "trusty", "amd64").start() |
531 | + |
532 | + with mock.patch.object( |
533 | + LXD, |
534 | + "path_exists", |
535 | + side_effect=lambda path: path in existing_files |
536 | + ): |
537 | + LXD("1", "trusty", "amd64").start() |
538 | |
539 | files_api.session.get.assert_any_call( |
540 | "/1.0/containers/lp-trusty-amd64/files", |
Nice simplification, thanks!