Merge ~mwhudson/ubuntu-cdimage:deb822-sources into ubuntu-cdimage:main
- Git
- lp:~mwhudson/ubuntu-cdimage
- deb822-sources
- Merge into main
Status: | Merged |
---|---|
Approved by: | Łukasz Zemczak |
Approved revision: | d0db6ef81c6e272bef70e8849665c7c0d192c14b |
Merged at revision: | 25a5d7e1c7677d279ca413b006dd856cb2ad03d6 |
Proposed branch: | ~mwhudson/ubuntu-cdimage:deb822-sources |
Merge into: | ubuntu-cdimage:main |
Diff against target: |
605 lines (+381/-18) 9 files modified
.launchpad.yaml (+11/-1) lib/cdimage/build.py (+14/-4) lib/cdimage/config.py (+1/-0) lib/cdimage/germinate.py (+12/-4) lib/cdimage/mirror.py (+127/-0) lib/cdimage/tests/helpers.py (+5/-0) lib/cdimage/tests/test_build.py (+15/-6) lib/cdimage/tests/test_germinate.py (+38/-3) lib/cdimage/tests/test_mirror.py (+158/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Łukasz Zemczak | Approve | ||
Review via email: mp+457014@code.launchpad.net |
Commit message
Description of the change
This changes ubuntu-cdimage to set up a chdist-like apt environment for each architecture, adds code to use that for germination (although that cannot be used until https:/
As such this should be harmless if a little wasteful to merge and deploy at this point. But it would be still interesting to have a review of it!
Steve Langasek (vorlon) wrote : | # |
Michael Hudson-Doyle (mwhudson) wrote : | # |
I fixed that a while ago now...
Michael Hudson-Doyle (mwhudson) wrote : | # |
I think this is ready for review. I think it will be slightly wasteful (basically it will download the package lists an extra time) but not change behaviour at all in its current form.
Michael Hudson-Doyle (mwhudson) wrote : | # |
So to expand:
1) This can be landed now safely (I think!)
2) Then we can land https:/
3) The final step is to use the apt configs this branch makes for germination too. The relevant germinate branch has landed now but I don't know if the checkout on the ftpmaster machine has been updated yet.
Michael Hudson-Doyle (mwhudson) wrote : | # |
One thing I am not 100% sure I've got right is handling a build with non-trivial subarch. I should try one of those locally at some point.
Łukasz Zemczak (sil2100) wrote : | # |
I think this is good enough. Conceptually, of course, I am not entirely sure if cdimage is the right place for generation of such configuration. Conceptually cdimage should only care about triggering builds, packing them up, publishing, cleaning up... Conceptually... But in reality right now it doesn't.
So I'm fine with merging this as-is, since I assume it's better to do it here in cdimage than debian-cd as we're running germinate here. That being said, actually I'm curious why we're calling germinate here, since I think the only consumer so far is debian-cd? So many questions, so little answers.
I think subarch handling should work fine, since if it does not then it means cpuarches was broken (which I don't know if we actually use that much anyway).
Michael Hudson-Doyle (mwhudson) wrote : | # |
I think eventually the bulk of this should move into livecd-rootfs or ubuntu-image or imagecraft or whatever. But one step at a time!
Michael Hudson-Doyle (mwhudson) wrote : | # |
Thanks for the review btw!
Preview Diff
1 | diff --git a/.launchpad.yaml b/.launchpad.yaml |
2 | index bef522b..bb396c1 100644 |
3 | --- a/.launchpad.yaml |
4 | +++ b/.launchpad.yaml |
5 | @@ -5,7 +5,17 @@ jobs: |
6 | run-tests: |
7 | series: jammy |
8 | architectures: amd64 |
9 | - packages: [dctrl-tools, python3, python3, python3-mock, python3-simplestreams, procmail, squashfs-tools, file, pycodestyle, pyflakes3] |
10 | + packages: |
11 | + - dctrl-tools |
12 | + - file |
13 | + - procmail |
14 | + - pycodestyle |
15 | + - pyflakes3 |
16 | + - python3 |
17 | + - python3-apt |
18 | + - python3-mock |
19 | + - python3-simplestreams |
20 | + - squashfs-tools |
21 | run: ./run-tests >output |
22 | output: |
23 | paths: [output] |
24 | diff --git a/lib/cdimage/build.py b/lib/cdimage/build.py |
25 | index b3b296e..02e59ee 100644 |
26 | --- a/lib/cdimage/build.py |
27 | +++ b/lib/cdimage/build.py |
28 | @@ -40,7 +40,7 @@ from cdimage.livefs import ( |
29 | ) |
30 | from cdimage.log import logger, reset_logging |
31 | from cdimage.mail import get_notify_addresses, send_mail |
32 | -from cdimage.mirror import trigger_mirrors |
33 | +from cdimage.mirror import AptStateManager, trigger_mirrors |
34 | from cdimage.tracker import tracker_set_rebuild_status |
35 | from cdimage.tree import Publisher, Tree |
36 | |
37 | @@ -532,10 +532,13 @@ def configure_splash(config): |
38 | config[key] = generic_image |
39 | |
40 | |
41 | -def run_debian_cd(config): |
42 | +def run_debian_cd(config, apt_state_mgr): |
43 | log_marker("Building %s daily CDs" % config.capproject) |
44 | debian_cd_dir = os.path.join(config.root, "debian-cd") |
45 | - subprocess.call(["./build_all.sh"], cwd=debian_cd_dir, env=config.export()) |
46 | + env = config.export() |
47 | + for cpuarch in config.cpuarches: |
48 | + env["APT_CONFIG_" + cpuarch] = apt_state_mgr.apt_conf_for_arch(cpuarch) |
49 | + subprocess.call(["./build_all.sh"], cwd=debian_cd_dir, env=env) |
50 | |
51 | |
52 | def fix_permissions(config): |
53 | @@ -652,7 +655,14 @@ def build_image_set_locked(config, options): |
54 | else: |
55 | assert not config["CDIMAGE_PREINSTALLED"] |
56 | |
57 | + apt_state_mgr = AptStateManager(config) |
58 | + apt_state_mgr.setup() |
59 | + |
60 | log_marker("Germinating") |
61 | + # Cannot use apt_state_mgr for germination until |
62 | + # https://code.launchpad.net/~mwhudson/germinate/+git/ |
63 | + # germinate-1/+merge/456723 |
64 | + # is merged. |
65 | germination = Germination(config) |
66 | germination.run() |
67 | |
68 | @@ -669,7 +679,7 @@ def build_image_set_locked(config, options): |
69 | |
70 | configure_splash(config) |
71 | |
72 | - run_debian_cd(config) |
73 | + run_debian_cd(config, apt_state_mgr) |
74 | copy_netboot_tarballs(config) |
75 | fix_permissions(config) |
76 | |
77 | diff --git a/lib/cdimage/config.py b/lib/cdimage/config.py |
78 | index 3de5c65..1c263cc 100644 |
79 | --- a/lib/cdimage/config.py |
80 | +++ b/lib/cdimage/config.py |
81 | @@ -288,6 +288,7 @@ _allowed_keys = ( |
82 | "EXTRA_PPAS", |
83 | "CHANNEL", |
84 | "SIMPLESTREAMS", |
85 | + "APT_PROXY", |
86 | ) |
87 | |
88 | |
89 | diff --git a/lib/cdimage/germinate.py b/lib/cdimage/germinate.py |
90 | index f33ef6a..dcc5e88 100644 |
91 | --- a/lib/cdimage/germinate.py |
92 | +++ b/lib/cdimage/germinate.py |
93 | @@ -39,10 +39,11 @@ class GerminateNotInstalled(Exception): |
94 | |
95 | |
96 | class Germination: |
97 | - def __init__(self, config, prefer_vcs=True): |
98 | + def __init__(self, config, prefer_vcs=True, apt_state_mgr=None): |
99 | self.config = config |
100 | # Set to False to use old-style seed checkouts. |
101 | self.prefer_vcs = prefer_vcs |
102 | + self.apt_state_mgr = apt_state_mgr |
103 | |
104 | @property |
105 | def germinate_path(self): |
106 | @@ -152,13 +153,20 @@ class Germination: |
107 | command = [ |
108 | self.germinate_path, |
109 | "--seed-source", ",".join(self.seed_sources()), |
110 | - "--mirror", find_mirror(self.config.project, arch), |
111 | "--seed-dist", self.seed_dist(), |
112 | - "--dist", ",".join(self.germinate_dists), |
113 | "--arch", cpuarch, |
114 | - "--components", ",".join(self.components), |
115 | "--no-rdepends", |
116 | ] |
117 | + if self.apt_state_mgr is not None: |
118 | + command.extend([ |
119 | + "--apt-config", self.apt_state_mgr.apt_conf_for_arch(cpuarch), |
120 | + ]) |
121 | + else: |
122 | + command.extend([ |
123 | + "--mirror", find_mirror(self.config.project, arch), |
124 | + "--components", ",".join(self.components), |
125 | + "--dist", ",".join(self.germinate_dists), |
126 | + ]) |
127 | if self.use_vcs: |
128 | command.append("--vcs=git") |
129 | proxy_check_call( |
130 | diff --git a/lib/cdimage/mirror.py b/lib/cdimage/mirror.py |
131 | index c02bda6..3d0d2b5 100644 |
132 | --- a/lib/cdimage/mirror.py |
133 | +++ b/lib/cdimage/mirror.py |
134 | @@ -22,6 +22,7 @@ import os |
135 | import subprocess |
136 | |
137 | from cdimage.log import logger |
138 | +from cdimage import osextras |
139 | |
140 | __metaclass__ = type |
141 | |
142 | @@ -124,3 +125,129 @@ def trigger_mirrors(config): |
143 | |
144 | for host in _get_mirrors_async(config): |
145 | _trigger_mirror(config, key, "archvsync", host, background=True) |
146 | + |
147 | + |
148 | +APT_CONF_TMPL = """\ |
149 | +Apt {{ |
150 | + Architecture "{ARCH}"; |
151 | + Architectures "{OTHERARCH}"; |
152 | +}}; |
153 | + |
154 | +Dir "{DIR}"; |
155 | +Dir::state::status "/dev/null"; |
156 | +""" |
157 | + |
158 | +SOURCES_TMPL = """\ |
159 | +Types: deb deb-src |
160 | +URIs: {MIRROR} |
161 | +Suites: {SUITES} |
162 | +Components: {COMPONENTS} |
163 | +Signed-By: {KEYRING} |
164 | +""" |
165 | + |
166 | + |
167 | +class AptStateManager: |
168 | + def __init__(self, config): |
169 | + self.config = config |
170 | + self._apt_conf_per_arch = {} |
171 | + |
172 | + def _output_dir(self, arch): |
173 | + return os.path.join( |
174 | + self.config.root, "scratch", self.config.subtree, |
175 | + self.config.project, self.config.full_series, |
176 | + self.config.image_type, "apt-state", arch) |
177 | + |
178 | + def _otherarch(self, arch): |
179 | + # XXX should probably move this knowledge into ubuntu-cdimage |
180 | + # once debian-cd no longer cares. |
181 | + debian_cd_dir = os.path.join(self.config.root, "debian-cd") |
182 | + archlist_file = os.path.join( |
183 | + debian_cd_dir, "data", self.config.series, "multiarch", arch) |
184 | + if os.path.exists(archlist_file): |
185 | + with open(archlist_file) as f: |
186 | + return f.read().strip() |
187 | + return arch |
188 | + |
189 | + def _components(self): |
190 | + components = ["main"] |
191 | + if not self.config["CDIMAGE_ONLYFREE"]: |
192 | + components.append("restricted") |
193 | + if self.config["CDIMAGE_UNSUPPORTED"]: |
194 | + components.append("universe") |
195 | + if not self.config["CDIMAGE_ONLYFREE"]: |
196 | + components.append("multiverse") |
197 | + return " ".join(components) |
198 | + |
199 | + def _suites(self): |
200 | + suite_patterns = ["%s", "%s-security", "%s-updates"] |
201 | + if self.config.get("PROPOSED", "0") not in ("", "0"): |
202 | + suite_patterns.append("%s-proposed") |
203 | + return " ".join( |
204 | + [pattern % self.config.series for pattern in suite_patterns]) |
205 | + |
206 | + def _get_sources_text(self, arch): |
207 | + if self.config["CDIMAGE_POOL_SOURCES"]: |
208 | + with open(self.config["CDIMAGE_POOL_SOURCES"]) as fp: |
209 | + return fp.read() |
210 | + |
211 | + keyring = "/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg" |
212 | + |
213 | + return SOURCES_TMPL.format( |
214 | + MIRROR=find_mirror(self.config, arch), |
215 | + SUITES=self._suites(), |
216 | + COMPONENTS=self._components(), |
217 | + KEYRING=keyring) |
218 | + |
219 | + def _setup_arch(self, arch): |
220 | + state_dir = self._output_dir(arch) |
221 | + osextras.mkemptydir(state_dir) |
222 | + |
223 | + conf_path = os.path.join(state_dir, 'base.conf') |
224 | + with open(conf_path, 'w') as conf: |
225 | + conf.write(APT_CONF_TMPL.format( |
226 | + ARCH=arch, |
227 | + OTHERARCH=self._otherarch(arch), |
228 | + DIR=state_dir)) |
229 | + |
230 | + needed_dirs = [ |
231 | + 'etc/apt/sources.list.d', |
232 | + 'etc/apt/apt.conf.d', |
233 | + 'etc/apt/preferences.d', |
234 | + 'var/lib/apt/lists/partial', |
235 | + ] |
236 | + |
237 | + for path in needed_dirs: |
238 | + osextras.mkemptydir(os.path.join(state_dir, path)) |
239 | + |
240 | + sources_path = os.path.join( |
241 | + state_dir, 'etc/apt/sources.list.d/default.sources') |
242 | + |
243 | + with open(sources_path, 'w') as sources: |
244 | + sources.write(self._get_sources_text(arch)) |
245 | + |
246 | + if self.config["APT_PROXY"]: |
247 | + proxy_conf_path = os.path.join( |
248 | + state_dir, "etc/apt/apt.conf.d/proxy.conf") |
249 | + with open(proxy_conf_path, "w") as proxy_conf: |
250 | + proxy_conf.write( |
251 | + 'Acquire::http::Proxy "{PROXY}";\n'.format( |
252 | + PROXY=self.config["APT_PROXY"])) |
253 | + proxy_conf.write( |
254 | + 'Acquire::https::Proxy "{PROXY}";\n'.format( |
255 | + PROXY=self.config["APT_PROXY"])) |
256 | + |
257 | + subprocess.check_call( |
258 | + ['apt-get', 'update'], |
259 | + env=dict(os.environ, APT_CONFIG=conf_path)) |
260 | + |
261 | + return conf_path |
262 | + |
263 | + def setup(self): |
264 | + for arch in self.config.cpuarches: |
265 | + logger.info( |
266 | + "Setting up apt state for %s/%s ...", |
267 | + self.config.series, arch) |
268 | + self._apt_conf_per_arch[arch] = self._setup_arch(arch) |
269 | + |
270 | + def apt_conf_for_arch(self, arch): |
271 | + return self._apt_conf_per_arch[arch] |
272 | diff --git a/lib/cdimage/tests/helpers.py b/lib/cdimage/tests/helpers.py |
273 | index 5e107ce..d1d9db5 100644 |
274 | --- a/lib/cdimage/tests/helpers.py |
275 | +++ b/lib/cdimage/tests/helpers.py |
276 | @@ -145,3 +145,8 @@ def touch(path): |
277 | def date_to_time(date): |
278 | """Return UTC seconds-since-epoch for a string in the form "20130321".""" |
279 | return calendar.timegm(time.strptime(date, "%Y%m%d")) |
280 | + |
281 | + |
282 | +class StubAptStateManager: |
283 | + def apt_conf_for_arch(self, arch): |
284 | + return arch + "/apt.conf" |
285 | diff --git a/lib/cdimage/tests/test_build.py b/lib/cdimage/tests/test_build.py |
286 | index c893613..d38a91c 100644 |
287 | --- a/lib/cdimage/tests/test_build.py |
288 | +++ b/lib/cdimage/tests/test_build.py |
289 | @@ -59,7 +59,7 @@ from cdimage.build import ( |
290 | from cdimage.config import Config |
291 | from cdimage.log import logger |
292 | from cdimage.mail import text_file_type |
293 | -from cdimage.tests.helpers import TestCase, mkfile, touch |
294 | +from cdimage.tests.helpers import TestCase, mkfile, touch, StubAptStateManager |
295 | |
296 | __metaclass__ = type |
297 | |
298 | @@ -687,8 +687,10 @@ class TestBuildImageSet(TestCase): |
299 | @mock.patch("subprocess.call", return_value=0) |
300 | def test_run_debian_cd(self, mock_call): |
301 | self.config["CAPPROJECT"] = "Ubuntu" |
302 | + self.config["ARCHES"] = "amd64 arm64" |
303 | + self.config.set_default_cpuarches() |
304 | self.capture_logging() |
305 | - run_debian_cd(self.config) |
306 | + run_debian_cd(self.config, StubAptStateManager()) |
307 | self.assertLogEqual([ |
308 | "===== Building Ubuntu daily CDs =====", |
309 | self.epoch_date, |
310 | @@ -696,6 +698,9 @@ class TestBuildImageSet(TestCase): |
311 | expected_cwd = os.path.join(self.temp_dir, "debian-cd") |
312 | mock_call.assert_called_once_with( |
313 | ["./build_all.sh"], cwd=expected_cwd, env=mock.ANY) |
314 | + env = mock_call.call_args.kwargs["env"] |
315 | + self.assertEqual("amd64/apt.conf", env["APT_CONFIG_amd64"]) |
316 | + self.assertEqual("arm64/apt.conf", env["APT_CONFIG_arm64"]) |
317 | |
318 | @mock.patch("subprocess.call", return_value=0) |
319 | def test_run_debian_cd_reexports_config(self, mock_call): |
320 | @@ -712,7 +717,7 @@ class TestBuildImageSet(TestCase): |
321 | os.environ["CDIMAGE_ROOT"] = self.temp_dir |
322 | config = Config() |
323 | self.capture_logging() |
324 | - run_debian_cd(config) |
325 | + run_debian_cd(config, StubAptStateManager()) |
326 | self.assertLogEqual([ |
327 | "===== Building Ubuntu daily CDs =====", |
328 | self.epoch_date, |
329 | @@ -914,18 +919,20 @@ class TestBuildImageSet(TestCase): |
330 | return mock.call([ |
331 | germinate_path, |
332 | "--seed-source", mock.ANY, |
333 | - "--mirror", "http://ftpmaster.internal/ubuntu/", |
334 | "--seed-dist", "ubuntu.bionic", |
335 | - "--dist", "bionic,bionic-security,bionic-updates", |
336 | "--arch", arch, |
337 | - "--components", "main,restricted", |
338 | "--no-rdepends", |
339 | + "--mirror", "http://ftpmaster.internal/ubuntu/", |
340 | + "--components", "main,restricted", |
341 | + "--dist", "bionic,bionic-security,bionic-updates", |
342 | "--vcs=git", |
343 | ], cwd=os.path.join(germinate_output, arch), env=mock.ANY) |
344 | |
345 | mock_call.assert_has_calls([ |
346 | mock.call([ |
347 | "make", "-C", os.path.dirname(britney_makefile)]), |
348 | + mock.call(["apt-get", "update"], env=mock.ANY), |
349 | + mock.call(["apt-get", "update"], env=mock.ANY), |
350 | germinate_command("amd64"), |
351 | germinate_command("i386"), |
352 | mock.call( |
353 | @@ -964,6 +971,8 @@ class TestBuildImageSet(TestCase): |
354 | DATE |
355 | ===== Building britney ===== |
356 | DATE |
357 | + Setting up apt state for bionic/amd64 ... |
358 | + Setting up apt state for bionic/i386 ... |
359 | ===== Germinating ===== |
360 | DATE |
361 | Germinating for bionic/amd64 ... |
362 | diff --git a/lib/cdimage/tests/test_germinate.py b/lib/cdimage/tests/test_germinate.py |
363 | index dd409e1..f567eae 100644 |
364 | --- a/lib/cdimage/tests/test_germinate.py |
365 | +++ b/lib/cdimage/tests/test_germinate.py |
366 | @@ -37,7 +37,7 @@ from cdimage.germinate import ( |
367 | NoMasterSeeds, |
368 | ) |
369 | from cdimage.mail import text_file_type |
370 | -from cdimage.tests.helpers import TestCase, mkfile, touch |
371 | +from cdimage.tests.helpers import TestCase, mkfile, touch, StubAptStateManager |
372 | |
373 | __metaclass__ = type |
374 | |
375 | @@ -190,12 +190,47 @@ class TestGermination(TestCase): |
376 | germinate_path, |
377 | "--seed-source", |
378 | "https://git.launchpad.net/~ubuntu-core-dev/ubuntu-seeds/+git/", |
379 | - "--mirror", "http://ftpmaster.internal/ubuntu/", |
380 | "--seed-dist", "ubuntu.bionic", |
381 | - "--dist", "bionic,bionic-security,bionic-updates", |
382 | "--arch", "amd64", |
383 | + "--no-rdepends", |
384 | + "--mirror", "http://ftpmaster.internal/ubuntu/", |
385 | "--components", "main,restricted", |
386 | + "--dist", "bionic,bionic-security,bionic-updates", |
387 | + "--vcs=git", |
388 | + ] |
389 | + self.assertEqual(1, mock_check_call.call_count) |
390 | + self.assertEqual(expected_command, mock_check_call.call_args[0][0]) |
391 | + self.assertEqual( |
392 | + "%s/amd64" % output_dir, mock_check_call.call_args[1]["cwd"]) |
393 | + |
394 | + @mock.patch("subprocess.check_call") |
395 | + def test_germinate_arch_with_apt_state_manager(self, mock_check_call): |
396 | + self.config.root = self.use_temp_dir() |
397 | + germinate_path = os.path.join( |
398 | + self.temp_dir, "germinate", "bin", "germinate") |
399 | + touch(germinate_path) |
400 | + os.chmod(germinate_path, 0o755) |
401 | + self.config["DIST"] = "bionic" |
402 | + self.config["IMAGE_TYPE"] = "daily" |
403 | + self.config["PROJECT"] = "ubuntu" |
404 | + |
405 | + output_dir = "%s/scratch/ubuntu/bionic/daily/germinate" % self.temp_dir |
406 | + |
407 | + def check_call_side_effect(*args, **kwargs): |
408 | + touch(os.path.join(output_dir, "amd64", "structure")) |
409 | + |
410 | + mock_check_call.side_effect = check_call_side_effect |
411 | + |
412 | + self.germination.apt_state_mgr = StubAptStateManager() |
413 | + self.germination.germinate_arch("amd64") |
414 | + expected_command = [ |
415 | + germinate_path, |
416 | + "--seed-source", |
417 | + "https://git.launchpad.net/~ubuntu-core-dev/ubuntu-seeds/+git/", |
418 | + "--seed-dist", "ubuntu.bionic", |
419 | + "--arch", "amd64", |
420 | "--no-rdepends", |
421 | + "--apt-config", "amd64/apt.conf", |
422 | "--vcs=git", |
423 | ] |
424 | self.assertEqual(1, mock_check_call.call_count) |
425 | diff --git a/lib/cdimage/tests/test_mirror.py b/lib/cdimage/tests/test_mirror.py |
426 | index b3b913d..56b00fe 100644 |
427 | --- a/lib/cdimage/tests/test_mirror.py |
428 | +++ b/lib/cdimage/tests/test_mirror.py |
429 | @@ -19,7 +19,10 @@ |
430 | |
431 | from __future__ import print_function, with_statement |
432 | |
433 | +import glob |
434 | import os |
435 | +import subprocess |
436 | +import sys |
437 | |
438 | try: |
439 | from unittest import mock |
440 | @@ -28,6 +31,7 @@ except ImportError: |
441 | |
442 | from cdimage.config import Config, all_series |
443 | from cdimage.mirror import ( |
444 | + AptStateManager, |
445 | UnknownManifestFile, |
446 | _get_mirror_key, |
447 | _get_mirrors, |
448 | @@ -220,3 +224,157 @@ class TestTriggerMirrors(TestCase): |
449 | "w"): |
450 | trigger_mirrors(self.config) |
451 | mock_trigger_mirror.assert_not_called() |
452 | + |
453 | + |
454 | +class TestAptStateManager(TestCase): |
455 | + def test_output_dir(self): |
456 | + config = Config(read=False) |
457 | + config.root = "/cdimage" |
458 | + config["PROJECT"] = "ubuntu" |
459 | + config["DIST"] = "noble" |
460 | + config["IMAGE_TYPE"] = "daily" |
461 | + mgr = AptStateManager(config) |
462 | + self.assertEqual( |
463 | + "/cdimage/scratch/ubuntu/noble/daily/apt-state/amd64", |
464 | + mgr._output_dir("amd64")) |
465 | + |
466 | + def test_otherarch_no_foreign_arch(self): |
467 | + config = Config(read=False) |
468 | + config.root = self.use_temp_dir() |
469 | + mgr = AptStateManager(config) |
470 | + self.assertEqual("arm64", mgr._otherarch("arm64")) |
471 | + |
472 | + def test_otherarch_with_foreign_arch(self): |
473 | + config = Config(read=False) |
474 | + config.root = self.use_temp_dir() |
475 | + config["DIST"] = "noble" |
476 | + # This is duplicating the implementation a bit too much to be |
477 | + # a truly useful tests. But really this information should be |
478 | + # moved into ubuntu-cdimage somewhere. |
479 | + archlist_path = os.path.join( |
480 | + config.root, "debian-cd", "data", config.series, |
481 | + "multiarch", "arm64") |
482 | + os.makedirs(os.path.dirname(archlist_path)) |
483 | + with open(archlist_path, 'w') as fp: |
484 | + fp.write("armhf\n") |
485 | + mgr = AptStateManager(config) |
486 | + self.assertEqual("armhf", mgr._otherarch("arm64")) |
487 | + |
488 | + def test_components(self): |
489 | + config = Config(read=False) |
490 | + mgr = AptStateManager(config) |
491 | + self.assertEqual("main restricted", mgr._components()) |
492 | + config["CDIMAGE_ONLYFREE"] = "1" |
493 | + self.assertEqual("main", mgr._components()) |
494 | + config["CDIMAGE_UNSUPPORTED"] = "1" |
495 | + self.assertEqual("main universe", mgr._components()) |
496 | + del config["CDIMAGE_ONLYFREE"] |
497 | + self.assertEqual( |
498 | + "main restricted universe multiverse", mgr._components()) |
499 | + |
500 | + def test_suites(self): |
501 | + config = Config(read=False) |
502 | + config["DIST"] = "noble" |
503 | + mgr = AptStateManager(config) |
504 | + self.assertEqual("noble noble-security noble-updates", mgr._suites()) |
505 | + config["PROPOSED"] = "1" |
506 | + self.assertEqual( |
507 | + "noble noble-security noble-updates noble-proposed", mgr._suites()) |
508 | + |
509 | + @mock.patch("cdimage.mirror.find_mirror") |
510 | + @mock.patch("cdimage.mirror.AptStateManager._components") |
511 | + @mock.patch("cdimage.mirror.AptStateManager._suites") |
512 | + def test_get_sources_text(self, m_suites, m_components, m_find_mirror): |
513 | + m_find_mirror.return_value = "MIRROR" |
514 | + m_components.return_value = "COMPONENTS" |
515 | + m_suites.return_value = "SUITES" |
516 | + config = Config(read=False) |
517 | + config["DIST"] = "noble" |
518 | + mgr = AptStateManager(config) |
519 | + expected = """\ |
520 | +Types: deb deb-src |
521 | +URIs: MIRROR |
522 | +Suites: SUITES |
523 | +Components: COMPONENTS |
524 | +Signed-By: /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg |
525 | +""" |
526 | + self.assertEqual(expected, mgr._get_sources_text("s390x")) |
527 | + |
528 | + def test_get_sources_text_override(self): |
529 | + config = Config(read=False) |
530 | + sources_path = os.path.join(self.use_temp_dir(), "my.sources") |
531 | + content = "# content\n" |
532 | + with open(sources_path, 'w') as fp: |
533 | + fp.write(content) |
534 | + config["CDIMAGE_POOL_SOURCES"] = sources_path |
535 | + mgr = AptStateManager(config) |
536 | + self.assertEqual(content, mgr._get_sources_text("s390x")) |
537 | + |
538 | + def _get_apt_config(self, apt_config, var, meth='find'): |
539 | + env = dict(os.environ, APT_CONFIG=apt_config) |
540 | + cmd = [ |
541 | + sys.executable, |
542 | + "-c", |
543 | + "import apt_pkg, sys; apt_pkg.init_config()\n" |
544 | + "print(apt_pkg.config.{}(sys.argv[1]))".format(meth), |
545 | + var |
546 | + ] |
547 | + cp = subprocess.run( |
548 | + cmd, env=env, encoding='utf-8', stdout=subprocess.PIPE, check=True) |
549 | + return cp.stdout.strip() |
550 | + |
551 | + @mock.patch("cdimage.mirror.AptStateManager._output_dir") |
552 | + @mock.patch("cdimage.mirror.AptStateManager._get_sources_text") |
553 | + @mock.patch("cdimage.mirror.AptStateManager._otherarch") |
554 | + def test_setup_arch(self, m_otherarch, m_get_sources_text, m_output_dir): |
555 | + m_otherarch.return_value = "OTHERARCH" |
556 | + # We *could* create a local apt repo with apt-ftparchive and |
557 | + # arrange to point the apt update call _setup_arch does to it |
558 | + # but that seems like a lot of effort. |
559 | + m_get_sources_text.return_value = "# Our content\n" |
560 | + m_output_dir.return_value = self.use_temp_dir() |
561 | + config = Config(read=False) |
562 | + config["DIST"] = "noble" |
563 | + mgr = AptStateManager(config) |
564 | + apt_conf = mgr._setup_arch("ARCH") |
565 | + self.assertEqual( |
566 | + "ARCH", |
567 | + self._get_apt_config(apt_conf, "Apt::Architecture")) |
568 | + self.assertEqual( |
569 | + "OTHERARCH", |
570 | + self._get_apt_config(apt_conf, "Apt::Architectures")) |
571 | + sources_list_d = self._get_apt_config( |
572 | + apt_conf, "Dir::Etc::sourceparts", meth='find_dir') |
573 | + sources_files = glob.glob(os.path.join(sources_list_d, "*.sources")) |
574 | + self.assertEqual(1, len(sources_files)) |
575 | + with open(sources_files[0]) as fp: |
576 | + self.assertEqual("# Our content\n", fp.read()) |
577 | + |
578 | + @mock.patch("subprocess.check_call") |
579 | + def test_setup_arch_proxy(self, m_check_call): |
580 | + config = Config(read=False) |
581 | + config["DIST"] = "noble" |
582 | + config["APT_PROXY"] = "http://localhost:3128" |
583 | + mgr = AptStateManager(config) |
584 | + apt_conf = mgr._setup_arch("ARCH") |
585 | + self.assertEqual( |
586 | + "http://localhost:3128", |
587 | + self._get_apt_config(apt_conf, "Acquire::http::Proxy")) |
588 | + self.assertEqual( |
589 | + "http://localhost:3128", |
590 | + self._get_apt_config(apt_conf, "Acquire::https::Proxy")) |
591 | + |
592 | + @mock.patch("cdimage.mirror.AptStateManager._setup_arch") |
593 | + def test_setup(self, m_setup_arch): |
594 | + self.capture_logging() |
595 | + m_setup_arch.side_effect = lambda arch: arch + 'dir' |
596 | + config = Config(read=False) |
597 | + config["ARCHES"] = ( |
598 | + "arch1 arch1+subarch arch2+subarch1 arch2+subarch2 arch3") |
599 | + config.set_default_cpuarches() |
600 | + mgr = AptStateManager(config) |
601 | + mgr.setup() |
602 | + self.assertCountEqual( |
603 | + [mock.call("arch1"), mock.call("arch2"), mock.call("arch3")], |
604 | + m_setup_arch.mock_calls) |
605 | + self.assertEqual('arch1dir', mgr.apt_conf_for_arch('arch1')) |
appears that this currently fails CI, holding review until resolved https:/ /code.launchpad .net/~mwhudson/ ubuntu- cdimage/ +git/ubuntu- cdimage- 1/+build/ 67241