From 95f23b7d303075e01c17931b99b29af82e6a4127 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Thu, 20 Jun 2024 17:26:50 +0200 Subject: [PATCH] Quadlet: add -list-images Add a new `-list-images` string flag Quadlet which will write a list of images mentioned in `.image` Quadlets to specified file. In order to avoid disk bloat, many bootable containers do not embed application-container images. Hence, those must be pulled in _some_ use-case dependent way. Quadlet is perfectly capable of pulling the images on boot or on demand but that does not satisfy all use cases as it slows down boot or initialization of the workloads. In those cases, we want a `bootc upgrade` to first pull down the bootable container image and then analyze its root FS to extract all referenced images in (rootful) `.image` Quadlets. This change is a first step in this direction. Signed-off-by: Valentin Rothberg --- cmd/quadlet/main.go | 39 ++++++++++++++++++++++++++++------ pkg/systemd/quadlet/quadlet.go | 15 +++++++++++++ test/system/252-quadlet.bats | 37 ++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 6 deletions(-) diff --git a/cmd/quadlet/main.go b/cmd/quadlet/main.go index c443b05f26be..5711462c4bd2 100644 --- a/cmd/quadlet/main.go +++ b/cmd/quadlet/main.go @@ -27,11 +27,12 @@ import ( // for more details. var ( - verboseFlag bool // True if -v passed - noKmsgFlag bool - isUserFlag bool // True if run as quadlet-user-generator executable - dryRunFlag bool // True if -dryrun is used - versionFlag bool // True if -version is used + verboseFlag bool // True if -v passed + noKmsgFlag bool + isUserFlag bool // True if run as quadlet-user-generator executable + dryRunFlag bool // True if -dryrun is used + versionFlag bool // True if -version is used + listImagesFlag string // Set if -list-images is used ) const ( @@ -549,7 +550,7 @@ func process() error { prevError = err } - if !dryRunFlag && flag.NArg() < 1 { + if !dryRunFlag && flag.NArg() < 1 && len(listImagesFlag) == 0 { reportError(errors.New("missing output directory argument")) return prevError } @@ -586,6 +587,31 @@ func process() error { } } + if len(listImagesFlag) > 0 { + fd, err := os.OpenFile(listImagesFlag, os.O_WRONLY, 0644) + if err != nil { + return err + } + for _, unit := range units { + if !strings.HasSuffix(unit.Filename, ".image") { + continue + } + imageName, err := quadlet.ListImage(unit) + if err != nil { + reportError(err) + } + if !isUnambiguousName(imageName) { + Logf("Warning: %s specifies the image \"%s\" which not a fully qualified image name and is hence being ignored.", unit.Filename, imageName) + continue + } + fmt.Fprintf(fd, "%s\n", imageName) + } + if err := fd.Close(); err != nil { + reportError(err) + } + return prevError + } + if !dryRunFlag { err := os.MkdirAll(outputPath, os.ModePerm) if err != nil { @@ -681,4 +707,5 @@ func init() { flag.BoolVar(&isUserFlag, "user", false, "Run as systemd user") flag.BoolVar(&dryRunFlag, "dryrun", false, "Run in dryrun mode printing debug information") flag.BoolVar(&versionFlag, "version", false, "Print version information and exit") + flag.StringVar(&listImagesFlag, "list-images", "", "Write a list of all images being references in .image Quadlets to specified file") } diff --git a/pkg/systemd/quadlet/quadlet.go b/pkg/systemd/quadlet/quadlet.go index 6cb33bb09fd2..70d05bd9ba58 100644 --- a/pkg/systemd/quadlet/quadlet.go +++ b/pkg/systemd/quadlet/quadlet.go @@ -1223,6 +1223,21 @@ func ConvertKube(kube *parser.UnitFile, names map[string]string, isUser bool) (* return service, nil } +func ListImage(image *parser.UnitFile) (string, error) { + // Even if we're only interested in the Image= of the unit, it should + // still be valid. + if err := checkForUnknownKeys(image, ImageGroup, supportedImageKeys); err != nil { + return "", err + } + + imageName, ok := image.Lookup(ImageGroup, KeyImage) + if !ok || len(imageName) == 0 { + return "", fmt.Errorf("no Image key specified") + } + + return imageName, nil +} + func ConvertImage(image *parser.UnitFile) (*parser.UnitFile, string, error) { service := image.Dup() service.Filename = replaceExtension(image.Filename, ".service", "", "-image") diff --git a/test/system/252-quadlet.bats b/test/system/252-quadlet.bats index a429454461bc..a8f8c3150783 100644 --- a/test/system/252-quadlet.bats +++ b/test/system/252-quadlet.bats @@ -1027,6 +1027,43 @@ EOF run_podman network rm podman-default-kube-network } +@test "quadlet - list images" { + local quadlet_tmpdir=$PODMAN_TMPDIR/quadlets + mkdir -p $quadlet_tmpdir + + local image_name_1=quay.io/quadlet/image:1 + local image_name_2=quay.io/quadlet/image:2 + local image_name_3=quay.io/quadlet/image:3 + + cat > $PODMAN_TMPDIR/1.image < $quadlet_tmpdir/2.image < $quadlet_tmpdir/3.image < $quadlet_tmpdir/1.container <