Merge ~cjwatson/launchpad-buildd:cpuinfo-workaround into launchpad-buildd:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 29affd0ca3e686d612711f30634280f4b878eb97
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad-buildd:cpuinfo-workaround
Merge into: launchpad-buildd:master
Diff against target: 138 lines (+35/-9)
3 files modified
debian/changelog (+7/-0)
lpbuildd/target/lxd.py (+10/-0)
lpbuildd/target/tests/test_lxd.py (+18/-9)
Reviewer Review Type Date Requested Status
Jürgen Gmach Approve
Review via email: mp+428923@code.launchpad.net

Commit message

Work around hangs in Rust-based snap builds for armhf

Description of the change

LXCFS provides `/proc/cpuinfo` as a FUSE overlay inside containers to filter visible CPUs based on cgroups. On armhf, this results in the wrong CPU features being visible to guests, because LXCFS itself is an arm64 binary. This causes Rust-based snap builds to hang on armhf, because the combination of armhf userspace and a `/proc/cpuinfo` that lacks the `neon` feature causes them to attempt to run ARMv6 code.

For now, work around this as suggested by the LXD maintainer by unmounting `/proc/cpuinfo` inside the container.

To post a comment you must log in.
Revision history for this message
Jürgen Gmach (jugmac00) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index f19778c..c9f4cc4 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,10 @@
6+launchpad-buildd (220) UNRELEASED; urgency=medium
7+
8+ * Work around https://github.com/lxc/lxcfs/issues/553 by unmounting
9+ /proc/cpuinfo in LXD-based armhf builds.
10+
11+ -- Colin Watson <cjwatson@ubuntu.com> Thu, 25 Aug 2022 17:58:34 +0100
12+
13 launchpad-buildd (219) focal; urgency=medium
14
15 * Provide additional package repositories for CI builds rather than replacing
16diff --git a/lpbuildd/target/lxd.py b/lpbuildd/target/lxd.py
17index 0307a06..fbb6f14 100644
18--- a/lpbuildd/target/lxd.py
19+++ b/lpbuildd/target/lxd.py
20@@ -501,6 +501,16 @@ class LXD(Backend):
21 ["ln", "-s", "/dev/null",
22 "/etc/systemd/system/snapd.refresh.timer"])
23
24+ if self.arch == "armhf":
25+ # Work around https://github.com/lxc/lxcfs/issues/553. In
26+ # principle that could result in over-reporting the number of
27+ # available CPU cores, but that isn't a concern in
28+ # launchpad-buildd.
29+ try:
30+ self.run(["umount", "/proc/cpuinfo"])
31+ except subprocess.CalledProcessError:
32+ pass
33+
34 def run(self, args, cwd=None, env=None, input_text=None, get_output=False,
35 echo=False, return_process=False, **kwargs):
36 """See `Backend`."""
37diff --git a/lpbuildd/target/tests/test_lxd.py b/lpbuildd/target/tests/test_lxd.py
38index 93c854d..8258d0f 100644
39--- a/lpbuildd/target/tests/test_lxd.py
40+++ b/lpbuildd/target/tests/test_lxd.py
41@@ -43,6 +43,7 @@ from lpbuildd.target.lxd import (
42 policy_rc_d,
43 )
44 from lpbuildd.target.tests.testfixtures import CarefulFakeProcessFixture
45+from lpbuildd.util import get_arch_bits
46
47
48 LXD_RUNNING = 103
49@@ -372,7 +373,9 @@ class TestLXD(TestCase):
50 print("host resolv.conf", file=f)
51 os.chmod("/etc/resolv.conf", 0o644)
52
53- def test_start(self, with_dm0=True):
54+ # XXX cjwatson 2022-08-25: Refactor this to use some more sensible kind
55+ # of test parameterization.
56+ def test_start(self, arch="amd64", with_dm0=True, unmounts_cpuinfo=False):
57 self.fakeFS()
58 DM_BLOCK_MAJOR = random.randrange(128, 255)
59 if with_dm0:
60@@ -388,7 +391,7 @@ class TestLXD(TestCase):
61 container.start.side_effect = (
62 lambda wait=False: setattr(container, "status_code", LXD_RUNNING))
63 files_api = container.api.files
64- files_api._api_endpoint = "/1.0/containers/lp-xenial-amd64/files"
65+ files_api._api_endpoint = f"/1.0/containers/lp-xenial-{arch}/files"
66 files_api.session.get.side_effect = FakeSessionGet({
67 "/etc/hosts": [b"127.0.0.1\tlocalhost\n"],
68 })
69@@ -412,7 +415,7 @@ class TestLXD(TestCase):
70 processes_fixture.add(lambda _: {}, name="lxc")
71 processes_fixture.add(
72 FakeHostname("example", "example.buildd"), name="hostname")
73- LXD("1", "xenial", "amd64").start()
74+ LXD("1", "xenial", arch).start()
75
76 self.assert_correct_profile()
77
78@@ -420,7 +423,8 @@ class TestLXD(TestCase):
79 iptables = ["sudo", "iptables", "-w"]
80 iptables_comment = [
81 "-m", "comment", "--comment", "managed by launchpad-buildd"]
82- lxc = ["lxc", "exec", "lp-xenial-amd64", "--", "linux64"]
83+ setarch_cmd = "linux64" if get_arch_bits(arch) == 64 else "linux32"
84+ lxc = ["lxc", "exec", f"lp-xenial-{arch}", "--", setarch_cmd]
85 expected_args = [
86 Equals(ip + ["link", "add", "dev", "lpbuilddbr0",
87 "type", "bridge"]),
88@@ -480,17 +484,19 @@ class TestLXD(TestCase):
89 ["ln", "-s", "/dev/null",
90 "/etc/systemd/system/snapd.refresh.timer"]),
91 ])
92+ if unmounts_cpuinfo:
93+ expected_args.append(Equals(lxc + ["umount", "/proc/cpuinfo"]))
94 self.assertThat(
95 [proc._args["args"] for proc in processes_fixture.procs],
96 MatchesListwise(expected_args))
97
98 client.containers.create.assert_called_once_with({
99- "name": "lp-xenial-amd64",
100+ "name": f"lp-xenial-{arch}",
101 "profiles": ["lpbuildd"],
102- "source": {"type": "image", "alias": "lp-xenial-amd64"},
103+ "source": {"type": "image", "alias": f"lp-xenial-{arch}"},
104 }, wait=True)
105 files_api.session.get.assert_any_call(
106- "/1.0/containers/lp-xenial-amd64/files",
107+ f"/1.0/containers/lp-xenial-{arch}/files",
108 params={"path": "/etc/hosts"}, stream=True)
109 files_api.post.assert_any_call(
110 params={"path": "/etc/hosts"},
111@@ -511,7 +517,7 @@ class TestLXD(TestCase):
112 data=policy_rc_d.encode("UTF-8"),
113 headers={"X-LXD-uid": "0", "X-LXD-gid": "0", "X-LXD-mode": "0755"})
114 files_api.session.get.assert_any_call(
115- "/1.0/containers/lp-xenial-amd64/files",
116+ f"/1.0/containers/lp-xenial-{arch}/files",
117 params={"path": "/etc/init/mounted-dev.conf"}, stream=True)
118 self.assertNotIn(
119 "/etc/init/mounted-dev.override",
120@@ -525,7 +531,7 @@ class TestLXD(TestCase):
121 self.assertEqual(LXD_RUNNING, container.status_code)
122
123 def test_start_no_dm0(self):
124- self.test_start(False)
125+ self.test_start(with_dm0=False)
126
127 def test_start_missing_etc_hosts(self):
128 self.fakeFS()
129@@ -598,6 +604,9 @@ class TestLXD(TestCase):
130 """).encode("UTF-8"),
131 headers={"X-LXD-uid": "0", "X-LXD-gid": "0", "X-LXD-mode": "0644"})
132
133+ def test_start_armhf_unmounts_cpuinfo(self):
134+ self.test_start(arch="armhf", unmounts_cpuinfo=True)
135+
136 def test_run(self):
137 processes_fixture = self.useFixture(FakeProcesses())
138 processes_fixture.add(lambda _: {}, name="lxc")

Subscribers

People subscribed via source and target branches