Skip to content

Commit

Permalink
Extract list of images built from u-i state JSON file
Browse files Browse the repository at this point in the history
Signed-off-by: Paul Mars <[email protected]>
  • Loading branch information
upils committed Aug 5, 2024
1 parent 6c8eda8 commit 6da0706
Show file tree
Hide file tree
Showing 7 changed files with 399 additions and 7 deletions.
12 changes: 9 additions & 3 deletions imagecraft/services/pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
"""Imagecraft Package service."""

import pathlib
import shutil
import typing

from craft_application import AppMetadata, PackageService, models
from overrides import override # type: ignore[reportUnknownVariableType]

from imagecraft.ubuntu_image import ubuntu_image_pack
from imagecraft.ubuntu_image import list_image_paths, ubuntu_image_pack

if typing.TYPE_CHECKING:
from imagecraft.services import ImagecraftServiceFactory
Expand Down Expand Up @@ -52,14 +53,19 @@ def pack(self, prime_dir: pathlib.Path, dest: pathlib.Path) -> list[pathlib.Path
"""
gadget_path = f"{prime_dir}/gadget/"
rootfs_path = f"{prime_dir}/rootfs/"
workdir_path = f"{prime_dir}/workdir/"

# Create per-platform output directories
platform_output = pathlib.Path(dest, self._platform if self._platform else "")
platform_output.mkdir(parents=True, exist_ok=True)

ubuntu_image_pack(rootfs_path, gadget_path, str(dest))
ubuntu_image_pack(rootfs_path, gadget_path, str(dest), workdir_path)

return []
img_paths = list_image_paths(workdir_path)

shutil.rmtree(workdir_path)

return [pathlib.Path(dest) / img for img in img_paths]

@property
def metadata(self) -> models.BaseMetadata:
Expand Down
16 changes: 15 additions & 1 deletion imagecraft/ubuntu_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

"""Ubuntu-image related helpers."""

import json
import pathlib
import subprocess

from craft_cli import emit
Expand Down Expand Up @@ -81,6 +83,7 @@ def ubuntu_image_pack(
rootfs_path: str,
gadget_path: str,
output_path: str,
workdir_path: str,
image_type: str | None = None,
*,
debug: bool = False,
Expand All @@ -89,6 +92,8 @@ def ubuntu_image_pack(
cmd: list[str] = [
"ubuntu-image",
"pack",
"--workdir",
workdir_path,
"--gadget-dir",
gadget_path,
"--rootfs-dir",
Expand All @@ -106,7 +111,7 @@ def ubuntu_image_pack(
try:
subprocess.check_call(cmd, universal_newlines=True)
except subprocess.CalledProcessError as err:
message = f"Cannot make (pack) image: {err!s}"
message = f"Cannot pack image: {err!s}"
details = f"Error output: {err.stderr.strip()!s}"
resolution = "Please check the error output for resolution guidance."

Expand All @@ -115,3 +120,12 @@ def ubuntu_image_pack(
details=details,
resolution=resolution,
) from err


def list_image_paths(workdir_path: str) -> list[str]:
"""Extract the list of images from a ubuntu-image.json file."""
p = pathlib.Path(workdir_path) / "ubuntu-image.json"
f = p.open("r")
ui_state = json.load(f)

return list(ui_state["VolumeNames"].values())
19 changes: 17 additions & 2 deletions tests/unit/services/test_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,42 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from pathlib import Path

from imagecraft.services import pack
from imagecraft.services.pack import pathlib
from imagecraft.services.pack import pathlib, shutil


def test_pack(pack_service, default_factory, mocker):
mock_inner_ubuntu_image_pack = mocker.patch.object(pack, "ubuntu_image_pack")
mock_inner_list_image_paths = mocker.patch.object(
pack,
"list_image_paths",
return_value=True,
)
mock_inner_list_image_paths.return_value = [
pathlib.Path("pc.img"),
pathlib.Path("pc2.img"),
]

mocker.patch.object(pathlib.Path, "mkdir", return_value=True)
mocker.patch.object(shutil, "rmtree")

prime = "prime"
prime_dir = Path(prime)
dest_path = Path()

pack_service.pack(prime_dir, dest=dest_path)
assert pack_service.pack(prime_dir, dest=dest_path) == [
pathlib.Path("pc.img"),
pathlib.Path("pc2.img"),
]

# Check that ubuntu_image_pack() was called with the correct
# parameters.
mock_inner_ubuntu_image_pack.assert_called_once_with(
"prime/rootfs/",
"prime/gadget/",
str(dest_path),
"prime/workdir/",
)
32 changes: 31 additions & 1 deletion tests/unit/test_ubuntu_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from imagecraft.image_definition import ImageDefinition
from imagecraft.models.package_repository import PackageRepositoryPPA
from imagecraft.ubuntu_image import (
list_image_paths,
ubuntu_image_cmds_build_rootfs,
ubuntu_image_pack,
)
Expand Down Expand Up @@ -229,13 +230,16 @@ def test_ubuntu_image_pack(mocker):
rootfs_path="rootfs/path/test",
gadget_path="gadget/test",
output_path="output/path/test",
workdir_path="workdir/path/test",
image_type="",
)

subprocess_patcher.assert_called_with(
[
"ubuntu-image",
"pack",
"--workdir",
"workdir/path/test",
"--gadget-dir",
"gadget/test",
"--rootfs-dir",
Expand All @@ -250,13 +254,16 @@ def test_ubuntu_image_pack(mocker):
rootfs_path="rootfs/path/test",
gadget_path="gadget/test",
output_path="output/path/test",
workdir_path="workdir/path/test",
image_type="raw",
)

subprocess_patcher.assert_called_with(
[
"ubuntu-image",
"pack",
"--workdir",
"workdir/path/test",
"--gadget-dir",
"gadget/test",
"--rootfs-dir",
Expand All @@ -280,10 +287,33 @@ def test_ubuntu_image_pack(mocker):
rootfs_path="rootfs/path/test",
gadget_path="gadget/test",
output_path="output/path/test",
workdir_path="workdir/path/test",
image_type="raw",
)

assert (
str(raised.value)
== "Cannot make (pack) image: Command 'some command' returned non-zero exit status 1."
== "Cannot pack image: Command 'some command' returned non-zero exit status 1."
)


@pytest.mark.parametrize(
("workdir_path", "img_paths"),
[
(
"testsdata/valid",
["pc.img"],
),
(
"testsdata/multiple_volumes",
["pc.img", "pc2.img"],
),
(
"testsdata/no_volume",
[],
),
],
)
def test_list_image_paths(workdir_path, img_paths):
paths = list_image_paths(workdir_path)
assert paths == img_paths
103 changes: 103 additions & 0 deletions tests/unit/testsdata/multiple_volumes/ubuntu-image.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"CurrentStep": "update_bootloader",
"StepsTaken": 9,
"ConfDefPath": "",
"YamlFilePath": "/home/ubuntu/prime/gadget/meta/gadget.yaml",
"IsSeeded": false,
"RootfsVolName": "pc",
"RootfsPartNum": 3,
"SectorSize": 512,
"RootfsSize": 3024625664,
"GadgetInfo": {
"Volumes": {
"pc": {
"schema": "gpt",
"bootloader": "grub",
"id": "",
"structure": [
{
"name": "mbr",
"filesystem-label": "",
"offset": 0,
"offset-write": null,
"min-size": 440,
"size": 440,
"type": "mbr",
"role": "mbr",
"id": "",
"filesystem": "",
"content": [
{
"source": "",
"target": "",
"image": "pc-boot.img",
"offset": null,
"size": 0,
"unpack": false
}
],
"update": {
"edition": 0,
"preserve": null
}
}
]
},
"pc2": {
"schema": "gpt",
"bootloader": "grub",
"id": "",
"structure": [
{
"name": "mbr",
"filesystem-label": "",
"offset": 0,
"offset-write": null,
"min-size": 440,
"size": 440,
"type": "mbr",
"role": "mbr",
"id": "",
"filesystem": "",
"content": [
{
"source": "",
"target": "",
"image": "pc-boot.img",
"offset": null,
"size": 0,
"unpack": false
}
],
"update": {
"edition": 0,
"preserve": null
}
}
]
}
},
"Defaults": null,
"Connections": null,
"KernelCmdline": {
"Allow": null,
"Append": null,
"Remove": null
}
},
"ImageSizes": {
"pc": 288358400
},
"VolumeOrder": [
"pc",
"pc2"
],
"VolumeNames": {
"pc": "pc.img",
"pc2": "pc2.img"
},
"MainVolumeName": "",
"Packages": null,
"Snaps": null
}

28 changes: 28 additions & 0 deletions tests/unit/testsdata/no_volume/ubuntu-image.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"CurrentStep": "update_bootloader",
"StepsTaken": 9,
"ConfDefPath": "",
"YamlFilePath": "/home/ubuntu/prime/gadget/meta/gadget.yaml",
"IsSeeded": false,
"RootfsVolName": "pc",
"RootfsPartNum": 3,
"SectorSize": 512,
"RootfsSize": 3024625664,
"GadgetInfo": {
"Volumes": {},
"Defaults": null,
"Connections": null,
"KernelCmdline": {
"Allow": null,
"Append": null,
"Remove": null
}
},
"ImageSizes": {},
"VolumeOrder": [],
"VolumeNames": {},
"MainVolumeName": "",
"Packages": null,
"Snaps": null
}

Loading

0 comments on commit 6da0706

Please sign in to comment.