← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~artemstreltsov/launchpad-buildd:add_docker26_support into launchpad-buildd:master

 

Artem Streltsov has proposed merging ~artemstreltsov/launchpad-buildd:add_docker26_support into launchpad-buildd:master.

Commit message:
Add docker v26 support

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~artemstreltsov/launchpad-buildd/+git/launchpad-buildd/+merge/492535

Fixes build failures on Docker 26.x where docker saves images as an OCI image layout. Also, unpins the ppa with an older docker version, which was a temporary fix.

Converts the new layout into (which is what the publisher expects):
- manifest.json
- config.json
- <layer-digest>.tar.gz
- digests.json

How to verify:
- do a local oci build
- check artifacts

The previous MP created digests.json incorrectly. Now I adapt docker26 manifest.json and reuse the rest of the logic.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~artemstreltsov/launchpad-buildd:add_docker26_support into launchpad-buildd:master.
diff --git a/lpbuildd/oci.py b/lpbuildd/oci.py
index 5ce2cd8..3d58af7 100644
--- a/lpbuildd/oci.py
+++ b/lpbuildd/oci.py
@@ -163,6 +163,7 @@ class OCIBuildManager(BuildManagerProxyMixin, DebianBuildManager):
         current_dir = ""
         gzip_layer = None
         symlinks = []
+        fileobj = None
         try:
             # The tarfile is a stream and must be processed in order
             for file in tar:
@@ -185,6 +186,8 @@ class OCIBuildManager(BuildManagerProxyMixin, DebianBuildManager):
                     )
                     symlinks.append(file)
                     continue
+                if file.name.startswith("blobs/"):
+                    tar.extract(file, extract_path)
                 if current_dir and file.name.endswith("layer.tar"):
                     # This is the actual layer data.
                     # Instead of adding the layer.tar to a gzip directory
@@ -215,7 +218,8 @@ class OCIBuildManager(BuildManagerProxyMixin, DebianBuildManager):
         finally:
             if gzip_layer is not None:
                 gzip_layer.close()
-            fileobj.close()
+            if fileobj is not None:
+                fileobj.close()
 
         # deal with any symlinks we had
         for symlink in symlinks:
@@ -234,6 +238,10 @@ class OCIBuildManager(BuildManagerProxyMixin, DebianBuildManager):
             )
             shutil.copy(source_name, target_name)
 
+        oci_layout_path = os.path.join(extract_path, "oci-layout")
+        if os.path.exists(oci_layout_path):
+            self._normalizeImageLayout(extract_path)
+
         # We need these mapping files
         sha_directory = tempfile.mkdtemp()
         # This can change depending on the kernel options / docker package
@@ -281,3 +289,40 @@ class OCIBuildManager(BuildManagerProxyMixin, DebianBuildManager):
         except Exception as e:
             self._builder.log(f"Failed to parse manifest: {e}")
             raise
+
+    def _normalizeImageLayout(self, extract_path):
+        manifest_path = os.path.join(extract_path, "manifest.json")
+        with open(manifest_path) as fp:
+            manifest = json.load(fp)
+
+        config_rel_path = manifest[0]["Config"]
+        config_path = os.path.join(extract_path, config_rel_path)
+        config_hex = os.path.basename(config_rel_path)
+        config_out_path = os.path.join(extract_path, f"{config_hex}.json")
+        shutil.copy(config_path, config_out_path)
+
+        repo_tags = manifest[0]["RepoTags"]
+
+        layers = manifest[0]["Layers"]
+        layer_hexes = []
+
+        for layer_path in layers:
+            # layer_path is e.g. "blobs/sha256/<hex>"
+            hex_id = os.path.basename(layer_path)
+            src = os.path.join(extract_path, layer_path)
+            out_path = os.path.join(extract_path, f"{hex_id}.tar.gz")
+
+            with open(src, "rb") as inf, gzip.open(out_path, "wb") as outf:
+                shutil.copyfileobj(inf, outf)
+
+            layer_hexes.append(hex_id)
+
+        manifest = [
+            {
+                "Config": f"{config_hex}.json",
+                "RepoTags": repo_tags,
+                "Layers": [f"{hex_id}/layer.tar" for hex_id in layer_hexes],
+            }
+        ]
+        with open(manifest_path, "w") as fp:
+            json.dump(manifest, fp)
diff --git a/lpbuildd/target/build_oci.py b/lpbuildd/target/build_oci.py
index 22d30df..28c4869 100644
--- a/lpbuildd/target/build_oci.py
+++ b/lpbuildd/target/build_oci.py
@@ -79,25 +79,7 @@ class BuildOCI(
             self._add_docker_engine_proxy_settings()
         deps.extend(self.vcs_deps)
         self.backend.run(["apt-get", "-y", "install"] + deps)
-        # XXX jchittum: pin docker.io to last known working version
-        # provided by the Ubuntu Server team via a PPA
-        # the PPA version contains an epoch, and will sort higher in version
-        # to the archive. To revert, simply delete the addition of the PPA
-        # The PPA only contains docker.io.
-        # For more info: https://bugs.launchpad.net/launchpad/+bug/2098106
-        # software-properties-common required for add-apt-repository
-        # we do not want to handle the entire process ourselves
-        # and assuming a buildd base for the lxd container, it will not 
-        # have software-properties-common installed by default
-        self.backend.run(
-            ["apt-get", "-y", "install", "software-properties-common"]
-        )
-        self.backend.run(
-            ["add-apt-repository", "-y", "ppa:canonical-server/lp2098106-docker-rollback"]
-        )
-        self.backend.run(
-            ["apt-get", "-y", "install", "docker.io"]
-        )
+        self.backend.run(["apt-get", "-y", "install", "docker.io"])
         if self.backend.supports_snapd:
             self.snap_store_set_proxy()
         self.backend.run(["systemctl", "restart", "docker"])
@@ -120,7 +102,12 @@ class BuildOCI(
         logger.info("Running build phase...")
         args = ["docker", "build", "--no-cache"]
         if self.args.proxy_url:
-            for var in ("http_proxy", "HTTP_PROXY", "https_proxy", "HTTPS_PROXY"):
+            for var in (
+                "http_proxy",
+                "HTTP_PROXY",
+                "https_proxy",
+                "HTTPS_PROXY",
+            ):
                 args.extend(["--build-arg", f"{var}={self.args.proxy_url}"])
         args.extend(["--tag", self.args.name])
         if self.args.build_file is not None:
diff --git a/lpbuildd/target/tests/test_build_oci.py b/lpbuildd/target/tests/test_build_oci.py
index 1b47c2d..46a3343 100644
--- a/lpbuildd/target/tests/test_build_oci.py
+++ b/lpbuildd/target/tests/test_build_oci.py
@@ -100,11 +100,6 @@ class TestBuildOCI(TestCase):
             MatchesListwise(
                 [
                     RanAptGet("install", "bzr"),
-                    RanAptGet("install", "software-properties-common"),
-                    RanCommand(
-                        ["add-apt-repository",
-                         "-y",
-                         "ppa:canonical-server/lp2098106-docker-rollback"]),
                     RanAptGet("install", "docker.io"),
                     RanCommand(["systemctl", "restart", "docker"]),
                     RanCommand(["mkdir", "-p", "/home/buildd"]),
@@ -131,11 +126,6 @@ class TestBuildOCI(TestCase):
             MatchesListwise(
                 [
                     RanAptGet("install", "git"),
-                    RanAptGet("install", "software-properties-common"),
-                    RanCommand(
-                        ["add-apt-repository",
-                         "-y",
-                         "ppa:canonical-server/lp2098106-docker-rollback"]),
                     RanAptGet("install", "docker.io"),
                     RanCommand(["systemctl", "restart", "docker"]),
                     RanCommand(["mkdir", "-p", "/home/buildd"]),
@@ -224,11 +214,6 @@ class TestBuildOCI(TestCase):
                         ["mkdir", "-p", "/etc/systemd/system/docker.service.d"]
                     ),
                     RanAptGet("install", "python3", "socat", "git"),
-                    RanAptGet("install", "software-properties-common"),
-                    RanCommand(
-                        ["add-apt-repository",
-                         "-y",
-                         "ppa:canonical-server/lp2098106-docker-rollback"]),
                     RanAptGet("install", "docker.io"),
                     RanCommand(["systemctl", "restart", "docker"]),
                     RanCommand(["mkdir", "-p", "/home/buildd"]),
@@ -753,11 +738,6 @@ class TestBuildOCI(TestCase):
             build_oci.backend.run.calls,
             MatchesAll(
                 AnyMatch(RanAptGet("install", "bzr")),
-                AnyMatch(RanAptGet("install", "software-properties-common")),
-                AnyMatch(RanCommand(
-                        ["add-apt-repository",
-                         "-y",
-                         "ppa:canonical-server/lp2098106-docker-rollback"])),
                 AnyMatch(RanAptGet("install", "docker.io")),
                 AnyMatch(
                     RanBuildCommand(