← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~cjwatson/launchpad-buildd/snapception into lp:launchpad-buildd

 

Colin Watson has proposed merging lp:~cjwatson/launchpad-buildd/snapception into lp:launchpad-buildd.

Commit message:
Allow optionally installing snapcraft as a snap.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #1737994 in launchpad-buildd: "build.snapcraft.io uses snapcraft from the deb archive"
  https://bugs.launchpad.net/launchpad-buildd/+bug/1737994

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad-buildd/snapception/+merge/337126

This is controlled by an optional "channels" key in the build arguments, which takes a dict mapping snap names to channel names.  At present anything other than "core" and "snapcraft" will cause a warning but otherwise be ignored, but I chose this structure so that it's reasonably easy to extend in future (e.g. for base snaps).

In the process, I noticed that snapd wasn't actually being started in LXD-based builds due to details of how the systemd services are started in snapd.postinst, which definitely wasn't intended and is probably a regression, so I fixed that as otherwise "snap install" obviously doesn't work.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad-buildd/snapception into lp:launchpad-buildd.
=== modified file 'debian/changelog'
--- debian/changelog	2018-01-15 10:08:55 +0000
+++ debian/changelog	2018-02-04 00:20:53 +0000
@@ -1,3 +1,13 @@
+launchpad-buildd (159) UNRELEASED; urgency=medium
+
+  * Allow all snapd services in the policy-rc.d we install in LXD
+    containers; for better or worse, snapd.postinst (via deb-systemd-invoke)
+    won't start any of them, including snapd itself, if any of them is
+    forbidden.  Mask snapd.refresh.timer so that it doesn't cause trouble.
+  * Allow optionally installing snapcraft as a snap (LP: #1737994).
+
+ -- Colin Watson <cjwatson@xxxxxxxxxx>  Fri, 02 Feb 2018 16:14:46 +0000
+
 launchpad-buildd (158) xenial; urgency=medium
 
   [ Steve Langasek ]

=== modified file 'lpbuildd/snap.py'
--- lpbuildd/snap.py	2017-08-25 16:05:49 +0000
+++ lpbuildd/snap.py	2018-02-04 00:20:53 +0000
@@ -38,6 +38,7 @@
     def initiate(self, files, chroot, extra_args):
         """Initiate a build with a given set of files and chroot."""
         self.name = extra_args["name"]
+        self.channels = extra_args.get("channels", {})
         self.branch = extra_args.get("branch")
         self.git_repository = extra_args.get("git_repository")
         self.git_path = extra_args.get("git_path")
@@ -62,6 +63,16 @@
     def doRunBuild(self):
         """Run the process to build the snap."""
         args = []
+        known_snaps = ("core", "snapcraft")
+        for snap in known_snaps:
+            if snap in self.channels:
+                args.extend(["--channel-%s" % snap, self.channels[snap]])
+        unknown_snaps = set(self.channels) - set(known_snaps)
+        if unknown_snaps:
+            print(
+                "Channels requested for unknown snaps: %s" %
+                " ".join(sorted(unknown_snaps)),
+                file=sys.stderr)
         if self.proxy_url:
             args.extend(["--proxy-url", self.proxy_url])
         if self.revocation_endpoint:

=== modified file 'lpbuildd/target/build_snap.py'
--- lpbuildd/target/build_snap.py	2017-11-24 16:08:17 +0000
+++ lpbuildd/target/build_snap.py	2018-02-04 00:20:53 +0000
@@ -48,6 +48,14 @@
     @classmethod
     def add_arguments(cls, parser):
         super(BuildSnap, cls).add_arguments(parser)
+        parser.add_argument(
+            "--channel-core", metavar="CHANNEL",
+            help="install core snap from CHANNEL")
+        parser.add_argument(
+            "--channel-snapcraft", metavar="CHANNEL",
+            help=(
+                "install snapcraft as a snap from CHANNEL rather than as a "
+                ".deb"))
         build_from_group = parser.add_mutually_exclusive_group(required=True)
         build_from_group.add_argument(
             "--branch", metavar="BRANCH", help="build from this Bazaar branch")
@@ -100,7 +108,7 @@
 
     def install(self):
         logger.info("Running install phase...")
-        deps = ["snapcraft"]
+        deps = []
         if self.args.backend == "lxd":
             # udev is installed explicitly to work around
             # https://bugs.launchpad.net/snapd/+bug/1731519.
@@ -113,7 +121,17 @@
             deps.append("git")
         if self.args.proxy_url:
             deps.extend(["python3", "socat"])
+        if not self.args.channel_snapcraft:
+            deps.append("snapcraft")
         self.backend.run(["apt-get", "-y", "install"] + deps)
+        if self.args.channel_core:
+            self.backend.run(
+                ["snap", "install",
+                 "--channel=%s" % self.args.channel_core, "core"])
+        if self.args.channel_snapcraft:
+            self.backend.run(
+                ["snap", "install", "--classic",
+                 "--channel=%s" % self.args.channel_snapcraft, "snapcraft"])
         if self.args.proxy_url:
             self.backend.copy_in(
                 os.path.join(self.slavebin, "snap-git-proxy"),

=== modified file 'lpbuildd/target/lxd.py'
--- lpbuildd/target/lxd.py	2017-11-13 15:18:07 +0000
+++ lpbuildd/target/lxd.py	2018-02-04 00:20:53 +0000
@@ -51,7 +51,7 @@
             -*) shift ;;
             systemd-udevd|systemd-udevd.service|udev|udev.service)
                 exit 0 ;;
-            snapd|snapd.socket|snapd.service)
+            snapd|snapd.*)
                 exit 0 ;;
             *)
                 echo "Not running services in chroot."
@@ -419,6 +419,14 @@
                 no_cdn_file.name,
                 "/etc/systemd/system/snapd.service.d/no-cdn.conf")
 
+        # Refreshing snaps from a timer unit during a build isn't
+        # appropriate.  Mask this, but manually so that we don't depend on
+        # systemctl existing.  This relies on /etc/systemd/system/ having
+        # been created above.
+        self.run(
+            ["ln", "-s", "/dev/null",
+             "/etc/systemd/system/snapd.refresh.timer"])
+
     def run(self, args, cwd=None, env=None, input_text=None, get_output=False,
             echo=False, **kwargs):
         """See `Backend`."""

=== modified file 'lpbuildd/target/tests/test_build_snap.py'
--- lpbuildd/target/tests/test_build_snap.py	2017-11-24 16:08:17 +0000
+++ lpbuildd/target/tests/test_build_snap.py	2018-02-04 00:20:53 +0000
@@ -54,6 +54,12 @@
         super(RanAptGet, self).__init__(["apt-get", "-y"] + list(args))
 
 
+class RanSnap(RanCommand):
+
+    def __init__(self, *args):
+        super(RanSnap, self).__init__(["snap"] + list(args))
+
+
 class RanBuildCommand(RanCommand):
 
     def __init__(self, args, cwd="/build", **kwargs):
@@ -111,7 +117,7 @@
         build_snap = parse_args(args=args).operation
         build_snap.install()
         self.assertThat(build_snap.backend.run.calls, MatchesListwise([
-            RanAptGet("install", "snapcraft", "bzr"),
+            RanAptGet("install", "bzr", "snapcraft"),
             ]))
 
     def test_install_git(self):
@@ -123,7 +129,7 @@
         build_snap = parse_args(args=args).operation
         build_snap.install()
         self.assertThat(build_snap.backend.run.calls, MatchesListwise([
-            RanAptGet("install", "snapcraft", "git"),
+            RanAptGet("install", "git", "snapcraft"),
             ]))
 
     def test_install_proxy(self):
@@ -143,12 +149,27 @@
             os.fchmod(proxy_script.fileno(), 0o755)
         build_snap.install()
         self.assertThat(build_snap.backend.run.calls, MatchesListwise([
-            RanAptGet("install", "snapcraft", "git", "python3", "socat"),
+            RanAptGet("install", "git", "python3", "socat", "snapcraft"),
             ]))
         self.assertEqual(
             (b"proxy script\n", stat.S_IFREG | 0o755),
             build_snap.backend.backend_fs["/usr/local/bin/snap-git-proxy"])
 
+    def test_install_channels(self):
+        args = [
+            "buildsnap",
+            "--backend=fake", "--series=xenial", "--arch=amd64", "1",
+            "--channel-core=candidate", "--channel-snapcraft=edge",
+            "--branch", "lp:foo", "test-snap",
+            ]
+        build_snap = parse_args(args=args).operation
+        build_snap.install()
+        self.assertThat(build_snap.backend.run.calls, MatchesListwise([
+            RanAptGet("install", "bzr"),
+            RanSnap("install", "--channel=candidate", "core"),
+            RanSnap("install", "--classic", "--channel=edge", "snapcraft"),
+            ]))
+
     def test_repo_bzr(self):
         args = [
             "buildsnap",
@@ -332,7 +353,7 @@
         build_snap.backend.run = FakeRevisionID("42")
         self.assertEqual(0, build_snap.run())
         self.assertThat(build_snap.backend.run.calls, MatchesAll(
-            AnyMatch(RanAptGet("install", "snapcraft", "bzr")),
+            AnyMatch(RanAptGet("install", "bzr", "snapcraft")),
             AnyMatch(RanBuildCommand(
                 ["bzr", "branch", "lp:foo", "test-snap"])),
             AnyMatch(RanBuildCommand(

=== modified file 'lpbuildd/target/tests/test_lxd.py'
--- lpbuildd/target/tests/test_lxd.py	2017-11-13 15:18:07 +0000
+++ lpbuildd/target/tests/test_lxd.py	2018-02-04 00:20:53 +0000
@@ -254,9 +254,14 @@
                     lxc +
                     ["mknod", "-m", "0660", "/dev/loop%d" % minor,
                      "b", "7", str(minor)]))
-        expected_args.append(
-            Equals(
-                lxc + ["mkdir", "-p", "/etc/systemd/system/snapd.service.d"]))
+        expected_args.extend([
+            Equals(
+                lxc + ["mkdir", "-p", "/etc/systemd/system/snapd.service.d"]),
+            Equals(
+                lxc +
+                ["ln", "-s", "/dev/null",
+                 "/etc/systemd/system/snapd.refresh.timer"]),
+            ])
         self.assertThat(
             [proc._args["args"] for proc in processes_fixture.procs],
             MatchesListwise(expected_args))