diff --git a/toolkit/tools/pkg/imagecustomizerlib/customizeos.go b/toolkit/tools/pkg/imagecustomizerlib/customizeos.go index f05f4695d..abc91db79 100644 --- a/toolkit/tools/pkg/imagecustomizerlib/customizeos.go +++ b/toolkit/tools/pkg/imagecustomizerlib/customizeos.go @@ -99,7 +99,7 @@ func doOsCustomizations(ctx context.Context, rc *ResolvedConfig, imageConnection return err } - verityUpdated, err := enableVerityPartition(ctx, rc.Config.Storage.Verity, imageChroot) + verityUpdated, err := enableVerityPartition(ctx, rc.Config.Storage.Verity, imageChroot, distroHandler) if err != nil { return err } @@ -116,7 +116,7 @@ func doOsCustomizations(ctx context.Context, rc *ResolvedConfig, imageConnection return err } - err = prepareUki(ctx, rc.BuildDirAbs, rc.Config.OS.Uki, imageChroot) + err = prepareUki(ctx, rc.BuildDirAbs, rc.Config.OS.Uki, imageChroot, distroHandler) if err != nil { return err } diff --git a/toolkit/tools/pkg/imagecustomizerlib/customizeuki.go b/toolkit/tools/pkg/imagecustomizerlib/customizeuki.go index 0c2fcedac..00f3d981e 100644 --- a/toolkit/tools/pkg/imagecustomizerlib/customizeuki.go +++ b/toolkit/tools/pkg/imagecustomizerlib/customizeuki.go @@ -58,7 +58,9 @@ type UkiKernelInfo struct { Initramfs string `json:"initramfs"` } -func prepareUki(ctx context.Context, buildDir string, uki *imagecustomizerapi.Uki, imageChroot *safechroot.Chroot) error { +func prepareUki(ctx context.Context, buildDir string, uki *imagecustomizerapi.Uki, imageChroot *safechroot.Chroot, + distroHandler distroHandler, +) error { var err error if uki == nil { @@ -71,7 +73,7 @@ func prepareUki(ctx context.Context, buildDir string, uki *imagecustomizerapi.Uk defer span.End() // Check UKI dependency packages. - err = validateUkiDependencies(imageChroot) + err = validateUkiDependencies(imageChroot, distroHandler) if err != nil { return fmt.Errorf("%w:\n%w", ErrUKIPackageDependencyValidation, err) } @@ -183,7 +185,7 @@ func prepareUki(ctx context.Context, buildDir string, uki *imagecustomizerapi.Uk return nil } -func validateUkiDependencies(imageChroot *safechroot.Chroot) error { +func validateUkiDependencies(imageChroot *safechroot.Chroot, distroHandler distroHandler) error { // The following packages are required for the UKI feature: // - "systemd-boot": Checked as a package dependency here to ensure installation, // but additional configuration is handled elsewhere in the UKI workflow. @@ -192,8 +194,10 @@ func validateUkiDependencies(imageChroot *safechroot.Chroot) error { // Iterate over each required package and check if it's installed. for _, pkg := range requiredRpms { logger.Log.Debugf("Checking if package (%s) is installed", pkg) - if !isPackageInstalled(imageChroot, pkg) { - return fmt.Errorf("package (%s) is not installed:\nthe following packages must be installed to use Uki: (%v)", pkg, requiredRpms) + installed := distroHandler.isPackageInstalled(imageChroot, pkg) + if !installed { + return fmt.Errorf("package (%s) is not installed:\n"+ + "the following packages must be installed to use Uki: (%v)", pkg, requiredRpms) } } diff --git a/toolkit/tools/pkg/imagecustomizerlib/customizeverity.go b/toolkit/tools/pkg/imagecustomizerlib/customizeverity.go index 2bfa05011..e42d0305d 100644 --- a/toolkit/tools/pkg/imagecustomizerlib/customizeverity.go +++ b/toolkit/tools/pkg/imagecustomizerlib/customizeverity.go @@ -65,7 +65,8 @@ const ( DracutModuleScriptFileMode = 0o755 ) -func enableVerityPartition(ctx context.Context, verity []imagecustomizerapi.Verity, imageChroot *safechroot.Chroot, +func enableVerityPartition(ctx context.Context, verity []imagecustomizerapi.Verity, + imageChroot *safechroot.Chroot, distroHandler distroHandler, ) (bool, error) { var err error @@ -78,7 +79,7 @@ func enableVerityPartition(ctx context.Context, verity []imagecustomizerapi.Veri _, span := otel.GetTracerProvider().Tracer(OtelTracerName).Start(ctx, "enable_verity_partition") defer span.End() - err = validateVerityDependencies(imageChroot) + err = validateVerityDependencies(imageChroot, distroHandler) if err != nil { return false, fmt.Errorf("%w:\n%w", ErrVerityPackageDependencyValidation, err) } @@ -435,7 +436,7 @@ func parseSystemdVerityOptions(options string) (imagecustomizerapi.CorruptionOpt return corruptionOption, hashSigPath, nil } -func validateVerityDependencies(imageChroot *safechroot.Chroot) error { +func validateVerityDependencies(imageChroot *safechroot.Chroot, distroHandler distroHandler) error { // "device-mapper" is required for dm-verity support because it provides "dmsetup", // which Dracut needs to install the "dm" module (a dependency of "systemd-veritysetup"). requiredRpms := []string{"device-mapper"} @@ -443,7 +444,8 @@ func validateVerityDependencies(imageChroot *safechroot.Chroot) error { // Iterate over each required package and check if it's installed. for _, pkg := range requiredRpms { logger.Log.Debugf("Checking if package (%s) is installed", pkg) - if !isPackageInstalled(imageChroot, pkg) { + installed := distroHandler.isPackageInstalled(imageChroot, pkg) + if !installed { return fmt.Errorf("package (%s) is not installed:\nthe following packages must be installed to use Verity: %v", pkg, requiredRpms) } } diff --git a/toolkit/tools/pkg/imagecustomizerlib/distrohandler.go b/toolkit/tools/pkg/imagecustomizerlib/distrohandler.go index 21d6a2efb..cbdac907d 100644 --- a/toolkit/tools/pkg/imagecustomizerlib/distrohandler.go +++ b/toolkit/tools/pkg/imagecustomizerlib/distrohandler.go @@ -38,6 +38,8 @@ type distroHandler interface { managePackages(ctx context.Context, buildDir string, baseConfigPath string, config *imagecustomizerapi.OS, imageChroot *safechroot.Chroot, toolsChroot *safechroot.Chroot, rpmsSources []string, useBaseImageRpmRepos bool, snapshotTime imagecustomizerapi.PackageSnapshotTime) error + + isPackageInstalled(imageChroot safechroot.ChrootInterface, packageName string) bool } // NewDistroHandlerFromTargetOs creates a distro handler directly from TargetOs diff --git a/toolkit/tools/pkg/imagecustomizerlib/distrohandler_azurelinux.go b/toolkit/tools/pkg/imagecustomizerlib/distrohandler_azurelinux.go index 5a3bc3201..6d86cd2bb 100644 --- a/toolkit/tools/pkg/imagecustomizerlib/distrohandler_azurelinux.go +++ b/toolkit/tools/pkg/imagecustomizerlib/distrohandler_azurelinux.go @@ -44,3 +44,8 @@ func (d *azureLinuxDistroHandler) managePackages(ctx context.Context, buildDir s ctx, buildDir, baseConfigPath, config, imageChroot, toolsChroot, rpmsSources, useBaseImageRpmRepos, snapshotTime, d.packageManager) } + +// isPackageInstalled implements distroHandler. +func (d *azureLinuxDistroHandler) isPackageInstalled(imageChroot safechroot.ChrootInterface, packageName string) bool { + return d.packageManager.isPackageInstalled(imageChroot, packageName) +} diff --git a/toolkit/tools/pkg/imagecustomizerlib/distrohandler_fedora.go b/toolkit/tools/pkg/imagecustomizerlib/distrohandler_fedora.go index d3013dc2e..bd5b036ed 100644 --- a/toolkit/tools/pkg/imagecustomizerlib/distrohandler_fedora.go +++ b/toolkit/tools/pkg/imagecustomizerlib/distrohandler_fedora.go @@ -43,3 +43,7 @@ func (d *fedoraDistroHandler) managePackages(ctx context.Context, buildDir strin snapshotTime, d.packageManager, ) } + +func (d *fedoraDistroHandler) isPackageInstalled(imageChroot safechroot.ChrootInterface, packageName string) bool { + return d.packageManager.isPackageInstalled(imageChroot, packageName) +} diff --git a/toolkit/tools/pkg/imagecustomizerlib/packagemanager_dnf.go b/toolkit/tools/pkg/imagecustomizerlib/packagemanager_dnf.go index 19028fae3..bf043a0ed 100644 --- a/toolkit/tools/pkg/imagecustomizerlib/packagemanager_dnf.go +++ b/toolkit/tools/pkg/imagecustomizerlib/packagemanager_dnf.go @@ -8,6 +8,8 @@ import ( "strings" "github.com/microsoft/azure-linux-image-tools/toolkit/tools/internal/logger" + "github.com/microsoft/azure-linux-image-tools/toolkit/tools/internal/safechroot" + "github.com/microsoft/azure-linux-image-tools/toolkit/tools/internal/shell" ) // DNF Package Manager Implementation @@ -176,3 +178,14 @@ func (pm *dnfPackageManager) createOutputCallback() func(string) { } } } + +func (pm *dnfPackageManager) isPackageInstalled(imageChroot safechroot.ChrootInterface, packageName string) bool { + err := imageChroot.UnsafeRun(func() error { + _, _, err := shell.Execute("dnf", "info", "--installed", packageName) + return err + }) + if err != nil { + return false + } + return true +} diff --git a/toolkit/tools/pkg/imagecustomizerlib/packagemanager_rpm.go b/toolkit/tools/pkg/imagecustomizerlib/packagemanager_rpm.go index 9e18dc3a3..37f24d077 100644 --- a/toolkit/tools/pkg/imagecustomizerlib/packagemanager_rpm.go +++ b/toolkit/tools/pkg/imagecustomizerlib/packagemanager_rpm.go @@ -3,6 +3,8 @@ package imagecustomizerlib +import "github.com/microsoft/azure-linux-image-tools/toolkit/tools/internal/safechroot" + // rpmPackageManagerHandler represents the interface for RPM-based package managers (TDNF, DNF) type rpmPackageManagerHandler interface { // Package manager configuration @@ -19,4 +21,6 @@ type rpmPackageManagerHandler interface { // Package manager specific snapshot time support supportsSnapshotTime() bool + + isPackageInstalled(imageChroot safechroot.ChrootInterface, packageName string) bool } diff --git a/toolkit/tools/pkg/imagecustomizerlib/packagemanager_tdnf.go b/toolkit/tools/pkg/imagecustomizerlib/packagemanager_tdnf.go index 93203a8a7..7835e29b2 100644 --- a/toolkit/tools/pkg/imagecustomizerlib/packagemanager_tdnf.go +++ b/toolkit/tools/pkg/imagecustomizerlib/packagemanager_tdnf.go @@ -9,6 +9,8 @@ import ( "strings" "github.com/microsoft/azure-linux-image-tools/toolkit/tools/internal/logger" + "github.com/microsoft/azure-linux-image-tools/toolkit/tools/internal/safechroot" + "github.com/microsoft/azure-linux-image-tools/toolkit/tools/internal/shell" ) // TDNF Package Manager Implementation @@ -101,3 +103,14 @@ func (pm *tdnfPackageManager) createOutputCallback() func(string) { } } } + +func (pm *tdnfPackageManager) isPackageInstalled(imageChroot safechroot.ChrootInterface, packageName string) bool { + err := imageChroot.UnsafeRun(func() error { + _, _, err := shell.Execute("tdnf", "info", packageName, "--repo", "@system") + return err + }) + if err != nil { + return false + } + return true +}