From 99e31ef0db28e5e8deff8d686d575875611eb6bb Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Tue, 8 Oct 2024 20:41:31 +0200 Subject: [PATCH 1/4] bib: run "dnf" inside the container again In 17d3b56 osbuild-dnf-json was changed to run outside the container. This lead to a regression in accessing subscribed content. This commit partially reverts this commit to run dnf again inside the container so that we have access to the /run/secrets and RHEL repos. --- bib/cmd/bootc-image-builder/image.go | 4 ++-- bib/cmd/bootc-image-builder/main.go | 31 ++++++++++++++++++---------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/bib/cmd/bootc-image-builder/image.go b/bib/cmd/bootc-image-builder/image.go index e6dd282b..3a1db737 100644 --- a/bib/cmd/bootc-image-builder/image.go +++ b/bib/cmd/bootc-image-builder/image.go @@ -60,8 +60,8 @@ type ManifestConfig struct { // Extracted information about the source container image SourceInfo *source.Info - // Path to the tree that contains /etc used for osbuild-depsolve-dnf - DepsolverRootDir string + // Command to run the depsolver + DepsolverCmd []string // RootFSType specifies the filesystem type for the root partition RootFSType string diff --git a/bib/cmd/bootc-image-builder/main.go b/bib/cmd/bootc-image-builder/main.go index ac418a9e..325cc52e 100644 --- a/bib/cmd/bootc-image-builder/main.go +++ b/bib/cmd/bootc-image-builder/main.go @@ -115,7 +115,8 @@ func makeManifest(c *ManifestConfig, cacheRoot string) (manifest.OSBuildManifest c.Architecture.String(), fmt.Sprintf("%s-%s", c.SourceInfo.OSRelease.ID, c.SourceInfo.OSRelease.VersionID), cacheRoot) - solver.SetRootDir(c.DepsolverRootDir) + solver.SetDNFJSONPath(c.DepsolverCmd[0], c.DepsolverCmd[1:]...) + solver.SetRootDir("/") depsolvedSets := make(map[string][]rpmmd.PackageSpec) depsolvedRepos := make(map[string][]rpmmd.RepoConfig) for name, pkgSet := range manifest.GetPackageSetChains() { @@ -286,6 +287,14 @@ func manifestFromCobra(cmd *cobra.Command, args []string) ([]byte, *mTLSConfig, } } + if err := container.CopyInto("/usr/libexec/osbuild-depsolve-dnf", "/osbuild-depsolve-dnf"); err != nil { + return nil, nil, fmt.Errorf("cannot prepare depsolve in the container: %w", err) + } + // XXX: hardcoded python3.12 + if err := container.CopyInto("/usr/lib//python3.12/site-packages/osbuild", "/"); err != nil { + return nil, nil, fmt.Errorf("cannot prepare depsolve python-modules in the container: %w", err) + } + // This is needed just for RHEL and RHSM in most cases, but let's run it every time in case // the image has some non-standard dnf plugins. if err := container.InitDNF(); err != nil { @@ -298,16 +307,16 @@ func manifestFromCobra(cmd *cobra.Command, args []string) ([]byte, *mTLSConfig, } manifestConfig := &ManifestConfig{ - Architecture: cntArch, - Config: config, - ImageTypes: imageTypes, - Imgref: imgref, - TLSVerify: tlsVerify, - RootfsMinsize: cntSize * containerSizeToDiskSizeMultiplier, - DistroDefPaths: distroDefPaths, - SourceInfo: sourceinfo, - RootFSType: rootfsType, - DepsolverRootDir: container.Root(), + Architecture: cntArch, + Config: config, + ImageTypes: imageTypes, + Imgref: imgref, + TLSVerify: tlsVerify, + RootfsMinsize: cntSize * containerSizeToDiskSizeMultiplier, + DistroDefPaths: distroDefPaths, + SourceInfo: sourceinfo, + RootFSType: rootfsType, + DepsolverCmd: append(container.ExecArgv(), "/osbuild-depsolve-dnf"), } manifest, repos, err := makeManifest(manifestConfig, rpmCacheRoot) From c2089465ce999d089a1fc85a7b06c7d07cb0a8ca Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 9 Oct 2024 15:50:09 +0200 Subject: [PATCH 2/4] bib: add test to ensure InitDNF() works with subscribed content This commit adds a test that ensures that InitDNF() results in triggering the dnf plugin that updates the subscriptions. --- bib/internal/container/container_test.go | 55 +++++++++++++++++++++++- plans/all.fmf | 1 + 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/bib/internal/container/container_test.go b/bib/internal/container/container_test.go index 2aaf218a..3e038c7c 100644 --- a/bib/internal/container/container_test.go +++ b/bib/internal/container/container_test.go @@ -8,13 +8,17 @@ import ( "os/exec" "path" "path/filepath" + "runtime" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -const testingImage = "registry.access.redhat.com/ubi9-micro:latest" +const ( + testingImage = "registry.access.redhat.com/ubi9-micro:latest" + dnfTestingImage = "registry.access.redhat.com/ubi9:latest" +) type containerInfo struct { State string `json:"State"` @@ -171,3 +175,52 @@ echo '%s' assert.ErrorContains(t, err, "unsupported root filesystem type: ext1, supported: ") } } + +func subscribeMachine(t *testing.T) (restore func()) { + if _, err := exec.LookPath("subscription-manager"); err != nil { + t.Skip("no subscription-manager found") + return func() {} + } + + matches, err := filepath.Glob("/etc/pki/entitlement/*.pem") + if err == nil && len(matches) > 0 { + return func() {} + } + + rhsmOrg := os.Getenv("RHSM_ORG") + rhsmActivationKey := os.Getenv("RHSM_ACTIVATION_KEY") + if rhsmOrg == "" || rhsmActivationKey == "" { + t.Skip("no RHSM_{ORG,ACTIVATION_KEY} env vars found") + return func() {} + } + + err = exec.Command("subscription-manager", "register", + "--org", rhsmOrg, + "--activationkey", rhsmActivationKey).Run() + require.NoError(t, err) + + return func() { + exec.Command("subscription-manager", "unregister").Run() + } +} + +func TestDNFInitGivesAccessToSubscribedContent(t *testing.T) { + if os.Geteuid() != 0 { + t.Skip("skipping test; not running as root") + } + if runtime.GOARCH != "amd64" { + t.Skip("skipping test; only runs on x86_64") + } + + restore := subscribeMachine(t) + defer restore() + + cnt, err := New(dnfTestingImage) + require.NoError(t, err) + err = cnt.InitDNF() + require.NoError(t, err) + + content, err := cnt.ReadFile("/etc/yum.repos.d/redhat.repo") + require.NoError(t, err) + assert.Contains(t, string(content), "rhel-9-for-x86_64-baseos-rpms") +} diff --git a/plans/all.fmf b/plans/all.fmf index 2d8eb663..fc6feb9a 100644 --- a/plans/all.fmf +++ b/plans/all.fmf @@ -18,6 +18,7 @@ prepare: - python3-paramiko - python3-pip - skopeo + - subscription-manager - qemu-kvm - qemu-system-aarch64 - qemu-user-static From b3643d4db3d5290e8e85164dab9bbafbcec84c47 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 9 Oct 2024 16:16:12 +0200 Subject: [PATCH 3/4] bib: add test for DNF solver inside the container for subscribed content This commit adds a test for the DNF solver inside a subscribed RHEL container. --- bib/cmd/bootc-image-builder/main.go | 15 +++----- bib/internal/container/container.go | 11 ++++++ bib/internal/container/container_test.go | 47 ++++++++++++++++++++++++ bib/internal/source/source.go | 3 +- plans/all.fmf | 1 + 5 files changed, 67 insertions(+), 10 deletions(-) diff --git a/bib/cmd/bootc-image-builder/main.go b/bib/cmd/bootc-image-builder/main.go index 325cc52e..d9da5e6b 100644 --- a/bib/cmd/bootc-image-builder/main.go +++ b/bib/cmd/bootc-image-builder/main.go @@ -109,6 +109,7 @@ func makeManifest(c *ManifestConfig, cacheRoot string) (manifest.OSBuildManifest } // depsolve packages + // XXX: put into a dnf module solver := dnfjson.NewSolver( c.SourceInfo.OSRelease.PlatformID, c.SourceInfo.OSRelease.VersionID, @@ -287,19 +288,15 @@ func manifestFromCobra(cmd *cobra.Command, args []string) ([]byte, *mTLSConfig, } } - if err := container.CopyInto("/usr/libexec/osbuild-depsolve-dnf", "/osbuild-depsolve-dnf"); err != nil { - return nil, nil, fmt.Errorf("cannot prepare depsolve in the container: %w", err) - } - // XXX: hardcoded python3.12 - if err := container.CopyInto("/usr/lib//python3.12/site-packages/osbuild", "/"); err != nil { - return nil, nil, fmt.Errorf("cannot prepare depsolve python-modules in the container: %w", err) - } - // This is needed just for RHEL and RHSM in most cases, but let's run it every time in case // the image has some non-standard dnf plugins. if err := container.InitDNF(); err != nil { return nil, nil, err } + depSolverCmd, err := container.InitDepsolveDNF() + if err != nil { + return nil, nil, fmt.Errorf("cannot prepare depsolve in the container: %w", err) + } sourceinfo, err := source.LoadInfo(container.Root()) if err != nil { @@ -316,7 +313,7 @@ func manifestFromCobra(cmd *cobra.Command, args []string) ([]byte, *mTLSConfig, DistroDefPaths: distroDefPaths, SourceInfo: sourceinfo, RootFSType: rootfsType, - DepsolverCmd: append(container.ExecArgv(), "/osbuild-depsolve-dnf"), + DepsolverCmd: depSolverCmd, } manifest, repos, err := makeManifest(manifestConfig, rpmCacheRoot) diff --git a/bib/internal/container/container.go b/bib/internal/container/container.go index 4fa3978d..51570910 100644 --- a/bib/internal/container/container.go +++ b/bib/internal/container/container.go @@ -143,6 +143,17 @@ func (c *Container) InitDNF() error { return nil } +func (c *Container) InitDepSolveDNF() ([]string, error) { + if err := c.CopyInto("/usr/libexec/osbuild-depsolve-dnf", "/osbuild-depsolve-dnf"); err != nil { + return nil, fmt.Errorf("cannot prepare depsolve in the container: %w", err) + } + // XXX: hardcoded python3.12 + if err := c.CopyInto("/usr/lib//python3.12/site-packages/osbuild", "/"); err != nil { + return nil, fmt.Errorf("cannot prepare depsolve python-modules in the container: %w", err) + } + return append(c.ExecArgv(), "/osbuild-depsolve-dnf"), nil +} + // DefaultRootfsType returns the default rootfs type (e.g. "ext4") as // specified by the bootc container install configuration. An empty // string is valid and means the container sets no default. diff --git a/bib/internal/container/container_test.go b/bib/internal/container/container_test.go index 3e038c7c..9200dce9 100644 --- a/bib/internal/container/container_test.go +++ b/bib/internal/container/container_test.go @@ -13,6 +13,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/osbuild/images/pkg/dnfjson" + "github.com/osbuild/images/pkg/rpmmd" + + "github.com/osbuild/bootc-image-builder/bib/internal/source" ) const ( @@ -224,3 +229,45 @@ func TestDNFInitGivesAccessToSubscribedContent(t *testing.T) { require.NoError(t, err) assert.Contains(t, string(content), "rhel-9-for-x86_64-baseos-rpms") } + +// XXX: should tihs be in a different file, it's more an integration test +func TestDNFJsonWorkWithSubscribedContent(t *testing.T) { + if os.Geteuid() != 0 { + t.Skip("skipping test; not running as root") + } + if runtime.GOARCH != "amd64" { + t.Skip("skipping test; only runs on x86_64") + } + if _, err := os.Stat("/usr/libexec/osbuild-depsolve-dnf"); err != nil { + t.Skip("cannot find /usr/libexec/osbuild-depsolve-dnf") + } + cacheRoot := t.TempDir() + + restore := subscribeMachine(t) + defer restore() + + cnt, err := New(dnfTestingImage) + require.NoError(t, err) + err = cnt.InitDNF() + require.NoError(t, err) + depsolverCmd, err := cnt.InitDepSolveDNF() + require.NoError(t, err) + + sourceInfo, err := source.LoadInfo(cnt.Root()) + require.NoError(t, err) + solver := dnfjson.NewSolver( + sourceInfo.OSRelease.PlatformID, + sourceInfo.OSRelease.VersionID, + "x86_64", + fmt.Sprintf("%s-%s", sourceInfo.OSRelease.ID, sourceInfo.OSRelease.VersionID), + cacheRoot) + solver.SetDNFJSONPath(depsolverCmd[0], depsolverCmd[1:]...) + solver.SetRootDir("/") + res, err := solver.Depsolve([]rpmmd.PackageSet{ + { + Include: []string{"coreutils"}, + }, + }, 0) + require.NoError(t, err) + assert.True(t, len(res.Packages) > 0) +} diff --git a/bib/internal/source/source.go b/bib/internal/source/source.go index a4b8ee24..f2508e64 100644 --- a/bib/internal/source/source.go +++ b/bib/internal/source/source.go @@ -5,8 +5,9 @@ import ( "os" "path" - "github.com/osbuild/images/pkg/distro" "github.com/sirupsen/logrus" + + "github.com/osbuild/images/pkg/distro" ) type OSRelease struct { diff --git a/plans/all.fmf b/plans/all.fmf index fc6feb9a..688250ba 100644 --- a/plans/all.fmf +++ b/plans/all.fmf @@ -11,6 +11,7 @@ prepare: how: install package: - edk2-aarch64 + - osbuild-depsolve-dnf - podman - pytest - python3-boto3 From ca0a1e95400478111a522dae883932b3fa684931 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 9 Oct 2024 18:48:26 +0200 Subject: [PATCH 4/4] bib: add new `cntdnf` go module and move container dnf logic in there This commit moves the logic of dealing with `osbuild-json-dnf` for containers into a new container dnf `cntdnf` go module. Also move the integration test for dnfjson with subscribed/normal content there. --- bib/cmd/bootc-image-builder/image.go | 3 - bib/cmd/bootc-image-builder/main.go | 27 ++--- bib/internal/cntdnf/cntdnf.go | 48 ++++++++ bib/internal/cntdnf/cntdnf_test.go | 134 +++++++++++++++++++++++ bib/internal/container/container.go | 11 -- bib/internal/container/container_test.go | 102 +---------------- 6 files changed, 192 insertions(+), 133 deletions(-) create mode 100644 bib/internal/cntdnf/cntdnf.go create mode 100644 bib/internal/cntdnf/cntdnf_test.go diff --git a/bib/cmd/bootc-image-builder/image.go b/bib/cmd/bootc-image-builder/image.go index 3a1db737..a55e4116 100644 --- a/bib/cmd/bootc-image-builder/image.go +++ b/bib/cmd/bootc-image-builder/image.go @@ -60,9 +60,6 @@ type ManifestConfig struct { // Extracted information about the source container image SourceInfo *source.Info - // Command to run the depsolver - DepsolverCmd []string - // RootFSType specifies the filesystem type for the root partition RootFSType string } diff --git a/bib/cmd/bootc-image-builder/main.go b/bib/cmd/bootc-image-builder/main.go index d9da5e6b..2a9ce9f2 100644 --- a/bib/cmd/bootc-image-builder/main.go +++ b/bib/cmd/bootc-image-builder/main.go @@ -25,6 +25,7 @@ import ( "github.com/osbuild/images/pkg/rpmmd" "github.com/osbuild/bootc-image-builder/bib/internal/buildconfig" + "github.com/osbuild/bootc-image-builder/bib/internal/cntdnf" podman_container "github.com/osbuild/bootc-image-builder/bib/internal/container" "github.com/osbuild/bootc-image-builder/bib/internal/imagetypes" "github.com/osbuild/bootc-image-builder/bib/internal/setup" @@ -102,22 +103,13 @@ func getContainerSize(imgref string) (uint64, error) { return size, nil } -func makeManifest(c *ManifestConfig, cacheRoot string) (manifest.OSBuildManifest, map[string][]rpmmd.RepoConfig, error) { +func makeManifest(c *ManifestConfig, solver *dnfjson.Solver, cacheRoot string) (manifest.OSBuildManifest, map[string][]rpmmd.RepoConfig, error) { manifest, err := Manifest(c) if err != nil { return nil, nil, fmt.Errorf("cannot get manifest: %w", err) } // depsolve packages - // XXX: put into a dnf module - solver := dnfjson.NewSolver( - c.SourceInfo.OSRelease.PlatformID, - c.SourceInfo.OSRelease.VersionID, - c.Architecture.String(), - fmt.Sprintf("%s-%s", c.SourceInfo.OSRelease.ID, c.SourceInfo.OSRelease.VersionID), - cacheRoot) - solver.SetDNFJSONPath(c.DepsolverCmd[0], c.DepsolverCmd[1:]...) - solver.SetRootDir("/") depsolvedSets := make(map[string][]rpmmd.PackageSpec) depsolvedRepos := make(map[string][]rpmmd.RepoConfig) for name, pkgSet := range manifest.GetPackageSetChains() { @@ -287,18 +279,18 @@ func manifestFromCobra(cmd *cobra.Command, args []string) ([]byte, *mTLSConfig, rootfsType = "ext4" } } + // Gather some data from the containers distro + sourceinfo, err := source.LoadInfo(container.Root()) + if err != nil { + return nil, nil, err + } // This is needed just for RHEL and RHSM in most cases, but let's run it every time in case // the image has some non-standard dnf plugins. if err := container.InitDNF(); err != nil { return nil, nil, err } - depSolverCmd, err := container.InitDepsolveDNF() - if err != nil { - return nil, nil, fmt.Errorf("cannot prepare depsolve in the container: %w", err) - } - - sourceinfo, err := source.LoadInfo(container.Root()) + solver, err := cntdnf.NewContainerSolver(rpmCacheRoot, container, cntArch, sourceinfo) if err != nil { return nil, nil, err } @@ -313,10 +305,9 @@ func manifestFromCobra(cmd *cobra.Command, args []string) ([]byte, *mTLSConfig, DistroDefPaths: distroDefPaths, SourceInfo: sourceinfo, RootFSType: rootfsType, - DepsolverCmd: depSolverCmd, } - manifest, repos, err := makeManifest(manifestConfig, rpmCacheRoot) + manifest, repos, err := makeManifest(manifestConfig, solver, rpmCacheRoot) if err != nil { return nil, nil, err } diff --git a/bib/internal/cntdnf/cntdnf.go b/bib/internal/cntdnf/cntdnf.go new file mode 100644 index 00000000..89b9f855 --- /dev/null +++ b/bib/internal/cntdnf/cntdnf.go @@ -0,0 +1,48 @@ +package cntdnf + +import ( + "fmt" + "path/filepath" + + "github.com/osbuild/images/pkg/arch" + "github.com/osbuild/images/pkg/dnfjson" + + "github.com/osbuild/bootc-image-builder/bib/internal/container" + "github.com/osbuild/bootc-image-builder/bib/internal/source" +) + +func injectDNFJson(cnt *container.Container) ([]string, error) { + if err := cnt.CopyInto("/usr/libexec/osbuild-depsolve-dnf", "/osbuild-depsolve-dnf"); err != nil { + return nil, fmt.Errorf("cannot prepare depsolve in the container: %w", err) + } + // copy the python module too + globPath := "/usr/lib/*/site-packages/osbuild" + matches, err := filepath.Glob(globPath) + if err != nil || len(matches) == 0 { + return nil, fmt.Errorf("cannot find osbuild python module in %q: %w", globPath, err) + } + if len(matches) != 1 { + return nil, fmt.Errorf("unexpected number of osbuild python module matches: %v", matches) + } + if err := cnt.CopyInto(matches[0], "/"); err != nil { + return nil, fmt.Errorf("cannot prepare depsolve python-modules in the container: %w", err) + } + return append(cnt.ExecArgv(), "/osbuild-depsolve-dnf"), nil +} + +func NewContainerSolver(cacheRoot string, cnt *container.Container, architecture arch.Arch, sourceInfo *source.Info) (*dnfjson.Solver, error) { + depsolverCmd, err := injectDNFJson(cnt) + if err != nil { + return nil, fmt.Errorf("cannot inject depsolve into the container: %w", err) + } + + solver := dnfjson.NewSolver( + sourceInfo.OSRelease.PlatformID, + sourceInfo.OSRelease.VersionID, + architecture.String(), + fmt.Sprintf("%s-%s", sourceInfo.OSRelease.ID, sourceInfo.OSRelease.VersionID), + cacheRoot) + solver.SetDNFJSONPath(depsolverCmd[0], depsolverCmd[1:]...) + solver.SetRootDir("/") + return solver, nil +} diff --git a/bib/internal/cntdnf/cntdnf_test.go b/bib/internal/cntdnf/cntdnf_test.go new file mode 100644 index 00000000..f6a99c4f --- /dev/null +++ b/bib/internal/cntdnf/cntdnf_test.go @@ -0,0 +1,134 @@ +package cntdnf_test + +import ( + "os" + "os/exec" + "path/filepath" + "runtime" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/osbuild/images/pkg/arch" + "github.com/osbuild/images/pkg/rpmmd" + + "github.com/osbuild/bootc-image-builder/bib/internal/cntdnf" + "github.com/osbuild/bootc-image-builder/bib/internal/container" + "github.com/osbuild/bootc-image-builder/bib/internal/source" +) + +const ( + dnfTestingImageRHEL = "registry.access.redhat.com/ubi9:latest" + dnfTestingImageCentos = "quay.io/centos/centos:stream9" +) + +func TestDNFJsonWorks(t *testing.T) { + if os.Geteuid() != 0 { + t.Skip("skipping test; not running as root") + } + if _, err := os.Stat("/usr/libexec/osbuild-depsolve-dnf"); err != nil { + t.Skip("cannot find /usr/libexec/osbuild-depsolve-dnf") + } + cacheRoot := t.TempDir() + + cnt, err := container.New(dnfTestingImageCentos) + require.NoError(t, err) + err = cnt.InitDNF() + require.NoError(t, err) + + sourceInfo, err := source.LoadInfo(cnt.Root()) + require.NoError(t, err) + solver, err := cntdnf.NewContainerSolver(cacheRoot, cnt, arch.Current(), sourceInfo) + require.NoError(t, err) + res, err := solver.Depsolve([]rpmmd.PackageSet{ + { + Include: []string{"coreutils"}, + }, + }, 0) + require.NoError(t, err) + assert.True(t, len(res.Packages) > 0) +} + +func subscribeMachine(t *testing.T) (restore func()) { + if _, err := exec.LookPath("subscription-manager"); err != nil { + t.Skip("no subscription-manager found") + return func() {} + } + + matches, err := filepath.Glob("/etc/pki/entitlement/*.pem") + if err == nil && len(matches) > 0 { + return func() {} + } + + rhsmOrg := os.Getenv("RHSM_ORG") + rhsmActivationKey := os.Getenv("RHSM_ACTIVATION_KEY") + if rhsmOrg == "" || rhsmActivationKey == "" { + t.Skip("no RHSM_{ORG,ACTIVATION_KEY} env vars found") + return func() {} + } + + err = exec.Command("subscription-manager", "register", + "--org", rhsmOrg, + "--activationkey", rhsmActivationKey).Run() + require.NoError(t, err) + + return func() { + err := exec.Command("subscription-manager", "unregister").Run() + require.NoError(t, err) + } +} + +func TestDNFInitGivesAccessToSubscribedContent(t *testing.T) { + if os.Geteuid() != 0 { + t.Skip("skipping test; not running as root") + } + if runtime.GOARCH != "amd64" { + t.Skip("skipping test; only runs on x86_64") + } + + restore := subscribeMachine(t) + defer restore() + + cnt, err := container.New(dnfTestingImageRHEL) + require.NoError(t, err) + err = cnt.InitDNF() + require.NoError(t, err) + + content, err := cnt.ReadFile("/etc/yum.repos.d/redhat.repo") + require.NoError(t, err) + assert.Contains(t, string(content), "rhel-9-for-x86_64-baseos-rpms") +} + +func TestDNFJsonWorkWithSubscribedContent(t *testing.T) { + if os.Geteuid() != 0 { + t.Skip("skipping test; not running as root") + } + if runtime.GOARCH != "amd64" { + t.Skip("skipping test; only runs on x86_64") + } + if _, err := os.Stat("/usr/libexec/osbuild-depsolve-dnf"); err != nil { + t.Skip("cannot find /usr/libexec/osbuild-depsolve-dnf") + } + cacheRoot := t.TempDir() + + restore := subscribeMachine(t) + defer restore() + + cnt, err := container.New(dnfTestingImageRHEL) + require.NoError(t, err) + err = cnt.InitDNF() + require.NoError(t, err) + + sourceInfo, err := source.LoadInfo(cnt.Root()) + require.NoError(t, err) + solver, err := cntdnf.NewContainerSolver(cacheRoot, cnt, arch.ARCH_X86_64, sourceInfo) + require.NoError(t, err) + res, err := solver.Depsolve([]rpmmd.PackageSet{ + { + Include: []string{"coreutils"}, + }, + }, 0) + require.NoError(t, err) + assert.True(t, len(res.Packages) > 0) +} diff --git a/bib/internal/container/container.go b/bib/internal/container/container.go index 51570910..4fa3978d 100644 --- a/bib/internal/container/container.go +++ b/bib/internal/container/container.go @@ -143,17 +143,6 @@ func (c *Container) InitDNF() error { return nil } -func (c *Container) InitDepSolveDNF() ([]string, error) { - if err := c.CopyInto("/usr/libexec/osbuild-depsolve-dnf", "/osbuild-depsolve-dnf"); err != nil { - return nil, fmt.Errorf("cannot prepare depsolve in the container: %w", err) - } - // XXX: hardcoded python3.12 - if err := c.CopyInto("/usr/lib//python3.12/site-packages/osbuild", "/"); err != nil { - return nil, fmt.Errorf("cannot prepare depsolve python-modules in the container: %w", err) - } - return append(c.ExecArgv(), "/osbuild-depsolve-dnf"), nil -} - // DefaultRootfsType returns the default rootfs type (e.g. "ext4") as // specified by the bootc container install configuration. An empty // string is valid and means the container sets no default. diff --git a/bib/internal/container/container_test.go b/bib/internal/container/container_test.go index 9200dce9..2aaf218a 100644 --- a/bib/internal/container/container_test.go +++ b/bib/internal/container/container_test.go @@ -8,22 +8,13 @@ import ( "os/exec" "path" "path/filepath" - "runtime" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/osbuild/images/pkg/dnfjson" - "github.com/osbuild/images/pkg/rpmmd" - - "github.com/osbuild/bootc-image-builder/bib/internal/source" ) -const ( - testingImage = "registry.access.redhat.com/ubi9-micro:latest" - dnfTestingImage = "registry.access.redhat.com/ubi9:latest" -) +const testingImage = "registry.access.redhat.com/ubi9-micro:latest" type containerInfo struct { State string `json:"State"` @@ -180,94 +171,3 @@ echo '%s' assert.ErrorContains(t, err, "unsupported root filesystem type: ext1, supported: ") } } - -func subscribeMachine(t *testing.T) (restore func()) { - if _, err := exec.LookPath("subscription-manager"); err != nil { - t.Skip("no subscription-manager found") - return func() {} - } - - matches, err := filepath.Glob("/etc/pki/entitlement/*.pem") - if err == nil && len(matches) > 0 { - return func() {} - } - - rhsmOrg := os.Getenv("RHSM_ORG") - rhsmActivationKey := os.Getenv("RHSM_ACTIVATION_KEY") - if rhsmOrg == "" || rhsmActivationKey == "" { - t.Skip("no RHSM_{ORG,ACTIVATION_KEY} env vars found") - return func() {} - } - - err = exec.Command("subscription-manager", "register", - "--org", rhsmOrg, - "--activationkey", rhsmActivationKey).Run() - require.NoError(t, err) - - return func() { - exec.Command("subscription-manager", "unregister").Run() - } -} - -func TestDNFInitGivesAccessToSubscribedContent(t *testing.T) { - if os.Geteuid() != 0 { - t.Skip("skipping test; not running as root") - } - if runtime.GOARCH != "amd64" { - t.Skip("skipping test; only runs on x86_64") - } - - restore := subscribeMachine(t) - defer restore() - - cnt, err := New(dnfTestingImage) - require.NoError(t, err) - err = cnt.InitDNF() - require.NoError(t, err) - - content, err := cnt.ReadFile("/etc/yum.repos.d/redhat.repo") - require.NoError(t, err) - assert.Contains(t, string(content), "rhel-9-for-x86_64-baseos-rpms") -} - -// XXX: should tihs be in a different file, it's more an integration test -func TestDNFJsonWorkWithSubscribedContent(t *testing.T) { - if os.Geteuid() != 0 { - t.Skip("skipping test; not running as root") - } - if runtime.GOARCH != "amd64" { - t.Skip("skipping test; only runs on x86_64") - } - if _, err := os.Stat("/usr/libexec/osbuild-depsolve-dnf"); err != nil { - t.Skip("cannot find /usr/libexec/osbuild-depsolve-dnf") - } - cacheRoot := t.TempDir() - - restore := subscribeMachine(t) - defer restore() - - cnt, err := New(dnfTestingImage) - require.NoError(t, err) - err = cnt.InitDNF() - require.NoError(t, err) - depsolverCmd, err := cnt.InitDepSolveDNF() - require.NoError(t, err) - - sourceInfo, err := source.LoadInfo(cnt.Root()) - require.NoError(t, err) - solver := dnfjson.NewSolver( - sourceInfo.OSRelease.PlatformID, - sourceInfo.OSRelease.VersionID, - "x86_64", - fmt.Sprintf("%s-%s", sourceInfo.OSRelease.ID, sourceInfo.OSRelease.VersionID), - cacheRoot) - solver.SetDNFJSONPath(depsolverCmd[0], depsolverCmd[1:]...) - solver.SetRootDir("/") - res, err := solver.Depsolve([]rpmmd.PackageSet{ - { - Include: []string{"coreutils"}, - }, - }, 0) - require.NoError(t, err) - assert.True(t, len(res.Packages) > 0) -}