Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: skip install tools cmd #741

Merged
merged 12 commits into from
Aug 30, 2024
14 changes: 14 additions & 0 deletions pkg/patch/patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,20 @@
return err
}

if solveOpt.SourcePolicy != nil {
switch {
case strings.Contains(solveOpt.SourcePolicy.Rules[0].Updates.Identifier, "redhat"):
err = errors.New("RedHat is not supported via source policies due to BusyBox not being in the RHEL repos\n" +
"Please use a different RPM-based image")
return err

Check warning on line 171 in pkg/patch/patch.go

View check run for this annotation

Codecov / codecov/patch

pkg/patch/patch.go#L166-L171

Added lines #L166 - L171 were not covered by tests

case strings.Contains(solveOpt.SourcePolicy.Rules[0].Updates.Identifier, "rockylinux"):
err = errors.New("RockyLinux is not supported via source policies due to BusyBox not being in the RockyLinux repos\n" +
"Please use a different RPM-based image")
return err

Check warning on line 176 in pkg/patch/patch.go

View check run for this annotation

Codecov / codecov/patch

pkg/patch/patch.go#L173-L176

Added lines #L173 - L176 were not covered by tests
}
}

buildChannel := make(chan *client.SolveStatus)
eg, ctx := errgroup.WithContext(ctx)
eg.Go(func() error {
Expand Down
60 changes: 56 additions & 4 deletions pkg/pkgmgr/rpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
rpmManifest2 = "container-manifest-2"
rpmManifestWildcard = "container-manifest-*"

installToolsCmd = "tdnf install busybox cpio dnf-utils -y"
resultQueryFormat = "%{NAME}\t%{VERSION}-%{RELEASE}\t%{ARCH}\n"
)

Expand Down Expand Up @@ -255,14 +254,21 @@
llb.ResolveModeDefault,
)

// List all packages installed in the tooling image
toolsListed := toolingBase.Run(llb.Shlex(`sh -c 'ls /usr/bin > applications.txt'`)).Root()
installToolsCmd, err := rm.generateToolInstallCmd(ctx, &toolsListed)
if err != nil {
return err

Check warning on line 261 in pkg/pkgmgr/rpm.go

View check run for this annotation

Codecov / codecov/patch

pkg/pkgmgr/rpm.go#L258-L261

Added lines #L258 - L261 were not covered by tests
}

packageManagers := []string{"tdnf", "dnf", "microdnf", "yum", "rpm"}

Check warning on line 264 in pkg/pkgmgr/rpm.go

View check run for this annotation

Codecov / codecov/patch

pkg/pkgmgr/rpm.go#L264

Added line #L264 was not covered by tests

toolsInstalled := toolingBase.Run(llb.Shlex(installToolsCmd), llb.WithProxy(utils.GetProxy())).Root()
toolsApplied := rm.config.ImageState.File(llb.Copy(toolsInstalled, "/usr/sbin/busybox", "/usr/sbin/busybox"))
mkFolders := toolsApplied.
File(llb.Mkdir(resultsPath, 0o744, llb.WithParents(true))).
File(llb.Mkdir(inputPath, 0o744, llb.WithParents(true)))

toolList := []string{"dnf", "microdnf", "rpm", "yum"}

rpmDBList := []string{
filepath.Join(rpmLibPath, rpmBDB),
filepath.Join(rpmLibPath, rpmNDB),
Expand All @@ -274,7 +280,7 @@
toolListPath := filepath.Join(inputPath, "tool_list")
dbListPath := filepath.Join(inputPath, "rpm_db_list")

probed := buildkit.WithArrayFile(&mkFolders, toolListPath, toolList)
probed := buildkit.WithArrayFile(&mkFolders, toolListPath, packageManagers)

Check warning on line 283 in pkg/pkgmgr/rpm.go

View check run for this annotation

Codecov / codecov/patch

pkg/pkgmgr/rpm.go#L283

Added line #L283 was not covered by tests
probed = buildkit.WithArrayFile(&probed, dbListPath, rpmDBList)
outState := probed.Run(
llb.AddEnv("TOOL_LIST_PATH", toolListPath),
Expand Down Expand Up @@ -361,6 +367,45 @@
return nil
}

func (rm *rpmManager) generateToolInstallCmd(ctx context.Context, toolsListed *llb.State) (string, error) {
applicationsList, err := buildkit.ExtractFileFromState(ctx, rm.config.Client, toolsListed, "/applications.txt")
if err != nil {
return "", err

Check warning on line 373 in pkg/pkgmgr/rpm.go

View check run for this annotation

Codecov / codecov/patch

pkg/pkgmgr/rpm.go#L373

Added line #L373 was not covered by tests
}

// packageManagersInstalled is the package manager(s) available within the tooling image
// RPM must be excluded from this list as it cannot connect to RPM repos
var packageManagersInstalled []string
packageManagerList := []string{"tdnf", "dnf", "microdnf", "yum"}

for _, packageManager := range packageManagerList {
if strings.Contains(string(applicationsList), packageManager) {
packageManagersInstalled = append(packageManagersInstalled, packageManager)
}
}

// missingTools indicates which tools, if any, need to be installed within the tooling image
var missingTools []string
requiredToolingList := []string{"busybox", "dnf-utils", "cpio"}

for _, tool := range requiredToolingList {
isMissingTool := !strings.Contains(string(applicationsList), tool)
if isMissingTool {
missingTools = append(missingTools, tool)
}

if tool == "cpio" && !isMissingTool && strings.Contains(string(applicationsList), "rpm2cpio") {
missingTools = append(missingTools, "cpio")

Check warning on line 398 in pkg/pkgmgr/rpm.go

View check run for this annotation

Codecov / codecov/patch

pkg/pkgmgr/rpm.go#L398

Added line #L398 was not covered by tests
}
}

// A tooling image could contain multiple package managers
// Choose the first one detected to use in the installation command
installCmd := fmt.Sprintf("%s install %s -y", packageManagersInstalled[0], strings.Join(missingTools, " "))

return installCmd, nil
}

func parseManifestFile(file string) (map[string]string, error) {
// split into lines
file = strings.TrimSuffix(file, "\n")
Expand Down Expand Up @@ -496,6 +541,13 @@
llb.ResolveModeDefault,
)

// List all packages installed in the tooling image
toolsListed := toolingBase.Run(llb.Shlex(`sh -c 'ls /usr/bin > applications.txt'`)).Root()
installToolsCmd, err := rm.generateToolInstallCmd(ctx, &toolsListed)
if err != nil {
return nil, nil, err

Check warning on line 548 in pkg/pkgmgr/rpm.go

View check run for this annotation

Codecov / codecov/patch

pkg/pkgmgr/rpm.go#L548

Added line #L548 was not covered by tests
}

// Install busybox. This should reuse the layer cached from probeRPMStatus.
toolsInstalled := toolingBase.Run(llb.Shlex(installToolsCmd), llb.WithProxy(utils.GetProxy())).Root()
busyboxCopied := toolsInstalled.Dir(downloadPath).Run(llb.Shlex("cp /usr/sbin/busybox .")).Root()
Expand Down
14 changes: 8 additions & 6 deletions pkg/pkgmgr/rpm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,8 @@ func Test_installUpdates_RPM(t *testing.T) {
}

func Test_unpackAndMergeUpdates_RPM(t *testing.T) {
// Due to the generateToolInstallCmd function, we need to pass in a package manager as well
// Without a package manager passed in, these tests all fail
tests := []struct {
name string
updates unversioned.UpdatePackages
Expand All @@ -602,7 +604,7 @@ func Test_unpackAndMergeUpdates_RPM(t *testing.T) {
{
name: "Successful update with specific packages",
mockSetup: func(mr *mocks.MockReference) {
mr.On("ReadFile", mock.Anything, mock.Anything).Return([]byte("package1\t1.2.3\tx86_64\npackage2\t2.3.4\tx86_64"), nil)
mr.On("ReadFile", mock.Anything, mock.Anything).Return([]byte("package1\t1.2.3\tx86_64\npackage2\t2.3.4\tx86_64\ntdnf"), nil)
},
updates: unversioned.UpdatePackages{
{Name: "package1", FixedVersion: "1.2.3"},
Expand All @@ -611,31 +613,31 @@ func Test_unpackAndMergeUpdates_RPM(t *testing.T) {
toolImage: "test-tool-image:latest",
ignoreErrors: false,
expectedError: false,
expectedResult: []byte("package1\t1.2.3\tx86_64\npackage2\t2.3.4\tx86_64"),
expectedResult: []byte("package1\t1.2.3\tx86_64\npackage2\t2.3.4\tx86_64\ntdnf"),
},
{
name: "Successful update all packages",
mockSetup: func(mr *mocks.MockReference) {
mr.On("ReadFile", mock.Anything, mock.Anything).Return([]byte(nil), nil)
mr.On("ReadFile", mock.Anything, mock.Anything).Return([]byte("tdnf"), nil)
},
updates: nil,
toolImage: "test-tool-image:latest",
ignoreErrors: false,
expectedResult: nil,
expectedResult: []byte("tdnf"),
expectedError: false,
},
{
name: "Ignore errors during update",
mockSetup: func(mr *mocks.MockReference) {
mr.On("ReadFile", mock.Anything, mock.Anything).Return([]byte("package1\t1.0.1\n"), nil)
mr.On("ReadFile", mock.Anything, mock.Anything).Return([]byte("package1\t1.0.1\ntdnf"), nil)
},
updates: unversioned.UpdatePackages{
{Name: "package1", FixedVersion: "2.0.0"},
},
toolImage: "test-tool-image:latest",
ignoreErrors: true,
expectedError: false,
expectedResult: []byte("package1\t1.0.1\n"),
expectedResult: []byte("package1\t1.0.1\ntdnf"),
},
}

Expand Down
Loading