Skip to content

Commit

Permalink
feat: add http proxy support when executing package managers (#79)
Browse files Browse the repository at this point in the history
Co-authored-by: Serta莽 脰zercan <852750+sozercan@users.noreply.github.com>
  • Loading branch information
derdanne and sozercan committed Mar 29, 2023
1 parent 397b611 commit a9c5e17
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 13 deletions.
7 changes: 4 additions & 3 deletions pkg/pkgmgr/apk.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/moby/buildkit/client/llb"
"github.com/project-copacetic/copacetic/pkg/buildkit"
"github.com/project-copacetic/copacetic/pkg/types"
"github.com/project-copacetic/copacetic/pkg/utils"
log "github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -153,7 +154,7 @@ func (am *apkManager) InstallUpdates(ctx context.Context, manifest *types.Update
// mounting a copy of apk-tools-static into the image and invoking apk-static directly.
func (am *apkManager) upgradePackages(ctx context.Context, updates types.UpdatePackages) (*llb.State, error) {
// TODO: Add support for custom APK config
apkUpdated := am.config.ImageState.Run(llb.Shlex("apk update")).Root()
apkUpdated := am.config.ImageState.Run(llb.Shlex("apk update"), llb.WithProxy(utils.GetProxy())).Root()

// Add all requested update packages
// This works around cases where some packages (for example, tiff) require other packages in it's dependency tree to be updated
Expand All @@ -163,15 +164,15 @@ func (am *apkManager) upgradePackages(ctx context.Context, updates types.UpdateP
pkgStrings = append(pkgStrings, u.Name)
}
addCmd := fmt.Sprintf(apkAddTemplate, strings.Join(pkgStrings, " "))
apkAdded := apkUpdated.Run(llb.Shlex(addCmd)).Root()
apkAdded := apkUpdated.Run(llb.Shlex(addCmd), llb.WithProxy(utils.GetProxy())).Root()

// Install all requested update packages without specifying the version. This works around:
// - Reports being slightly out of date, where a newer security revision has displaced the one specified leading to not found errors.
// - Reports not specifying version epochs correct (e.g. bsdutils=2.36.1-8+deb11u1 instead of with epoch as 1:2.36.1-8+dev11u1)
// Note that this keeps the log files from the operation, which we can consider removing as a size optimization in the future.
const apkInstallTemplate = `apk upgrade --no-cache %s`
installCmd := fmt.Sprintf(apkInstallTemplate, strings.Join(pkgStrings, " "))
apkInstalled := apkAdded.Run(llb.Shlex(installCmd)).Root()
apkInstalled := apkAdded.Run(llb.Shlex(installCmd), llb.WithProxy(utils.GetProxy())).Root()

// Write updates-manifest to host for post-patch validation
const outputResultsTemplate = `sh -c 'apk info --installed -v %s > %s; if [[ $? -ne 0 ]]; then echo "WARN: apk info --installed returned $?"; fi'`
Expand Down
12 changes: 6 additions & 6 deletions pkg/pkgmgr/dpkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,10 @@ func (dm *dpkgManager) probeDPKGStatus(ctx context.Context, toolImage string) er
llb.Platform(dm.config.Platform),
llb.ResolveModeDefault,
)
updated := toolingBase.Run(llb.Shlex("apt update")).Root()
updated := toolingBase.Run(llb.Shlex("apt update"), llb.WithProxy(utils.GetProxy())).Root()

const installBusyBoxCmd = "apt install busybox-static"
busyBoxInstalled := updated.Run(llb.Shlex(installBusyBoxCmd)).Root()
busyBoxInstalled := updated.Run(llb.Shlex(installBusyBoxCmd), llb.WithProxy(utils.GetProxy())).Root()
busyBoxApplied := dm.config.ImageState.File(llb.Copy(busyBoxInstalled, "/bin/busybox", "/bin/busybox"))
mkFolders := busyBoxApplied.File(llb.Mkdir(resultsPath, 0o744, llb.WithParents(true)))

Expand Down Expand Up @@ -197,7 +197,7 @@ func (dm *dpkgManager) installUpdates(ctx context.Context, updates types.UpdateP
// Since this takes place in the target container, it can interfere with install actions
// such as the installation of the updated debian-archive-keyring package, so it's probably best
// to separate it out to an explicit container edit command or opt-in before patching.
aptUpdated := dm.config.ImageState.Run(llb.Shlex("apt update")).Root()
aptUpdated := dm.config.ImageState.Run(llb.Shlex("apt update"), llb.WithProxy(utils.GetProxy())).Root()

// Install all requested update packages without specifying the version. This works around:
// - Reports being slightly out of date, where a newer security revision has displaced the one specified leading to not found errors.
Expand All @@ -209,7 +209,7 @@ func (dm *dpkgManager) installUpdates(ctx context.Context, updates types.UpdateP
pkgStrings = append(pkgStrings, u.Name)
}
installCmd := fmt.Sprintf(aptInstallTemplate, strings.Join(pkgStrings, " "))
aptInstalled := aptUpdated.Run(llb.Shlex(installCmd)).Root()
aptInstalled := aptUpdated.Run(llb.Shlex(installCmd), llb.WithProxy(utils.GetProxy())).Root()

// Write results.manifest to host for post-patch validation
const outputResultsTemplate = `sh -c 'grep "^Package:\|^Version:" "%s" >> "%s"'`
Expand All @@ -236,7 +236,7 @@ func (dm *dpkgManager) unpackAndMergeUpdates(ctx context.Context, updates types.
)

// Run apt update && apt download list of updates to target folder
updated := toolingBase.Run(llb.Shlex("apt update")).Root()
updated := toolingBase.Run(llb.Shlex("apt update"), llb.WithProxy(utils.GetProxy())).Root()

// Download all requested update packages without specifying the version. This works around:
// - Reports being slightly out of date, where a newer security revision has displaced the one specified leading to not found errors.
Expand All @@ -247,7 +247,7 @@ func (dm *dpkgManager) unpackAndMergeUpdates(ctx context.Context, updates types.
pkgStrings = append(pkgStrings, u.Name)
}
downloadCmd := fmt.Sprintf(aptDownloadTemplate, strings.Join(pkgStrings, " "))
downloaded := updated.Dir(downloadPath).Run(llb.Shlex(downloadCmd)).Root()
downloaded := updated.Dir(downloadPath).Run(llb.Shlex(downloadCmd), llb.WithProxy(utils.GetProxy())).Root()

// Scripted enumeration and dpkg unpack of all downloaded packages [layer to merge with target]
const extractTemplate = `find %s -name '*.deb' -exec dpkg-deb -x '{}' %s \;`
Expand Down
8 changes: 4 additions & 4 deletions pkg/pkgmgr/rpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func (rm *rpmManager) probeRPMStatus(ctx context.Context, toolImage string) erro
llb.ResolveModeDefault,
)

toolsInstalled := toolingBase.Run(llb.Shlex(installToolsCmd)).Root()
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)))

Expand Down Expand Up @@ -324,7 +324,7 @@ func (rm *rpmManager) installUpdates(ctx context.Context, updates types.UpdatePa
err := errors.New("unexpected: no package manager tools were found for patching")
return nil, err
}
installed := rm.config.ImageState.Run(llb.Shlex(installCmd)).Root()
installed := rm.config.ImageState.Run(llb.Shlex(installCmd), llb.WithProxy(utils.GetProxy())).Root()

// Write results.manifest to host for post-patch validation
const rpmResultsTemplate = `sh -c 'rpm -qa --queryformat "%s" %s > "%s"'`
Expand All @@ -351,7 +351,7 @@ func (rm *rpmManager) unpackAndMergeUpdates(ctx context.Context, updates types.U
)

// Install busybox. This should reuse the layer cached from probeRPMStatus.
toolsInstalled := toolingBase.Run(llb.Shlex(installToolsCmd)).Root()
toolsInstalled := toolingBase.Run(llb.Shlex(installToolsCmd), llb.WithProxy(utils.GetProxy())).Root()
busyboxCopied := toolsInstalled.Dir(downloadPath).Run(llb.Shlex("cp /usr/sbin/busybox .")).Root()

// Download all requested update packages without specifying the version. This works around:
Expand All @@ -364,7 +364,7 @@ func (rm *rpmManager) unpackAndMergeUpdates(ctx context.Context, updates types.U
pkgStrings = append(pkgStrings, u.Name)
}
downloadCmd := fmt.Sprintf(aptDownloadTemplate, strings.Join(pkgStrings, " "))
downloaded := busyboxCopied.Run(llb.Shlex(downloadCmd)).Root()
downloaded := busyboxCopied.Run(llb.Shlex(downloadCmd), llb.WithProxy(utils.GetProxy())).Root()

// Scripted enumeration and rpm install of all downloaded packages under the download folder as root
// `rpm -i` doesn't support installing to a target directory, so chroot into the download folder to install the packages.
Expand Down
21 changes: 21 additions & 0 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"io/fs"
"os"
"path/filepath"

"github.com/moby/buildkit/client/llb"
)

func EnsurePath(path string, perm fs.FileMode) (bool, error) {
Expand Down Expand Up @@ -36,3 +38,22 @@ func IsNonEmptyFile(dir, file string) bool {
}
return !info.IsDir() && info.Size() > 0
}

func getEnvAny(names ...string) string {
for _, n := range names {
if val := os.Getenv(n); val != "" {
return val
}
}
return ""
}

func GetProxy() llb.ProxyEnv {
proxy := llb.ProxyEnv{
HTTPProxy: getEnvAny("HTTP_PROXY"),
HTTPSProxy: getEnvAny("HTTPS_PROXY"),
NoProxy: getEnvAny("NO_PROXY"),
AllProxy: getEnvAny("HTTP_PROXY"),
}
return proxy
}
37 changes: 37 additions & 0 deletions pkg/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"os"
"path"
"testing"

"github.com/moby/buildkit/client/llb"
)

const (
Expand Down Expand Up @@ -140,3 +142,38 @@ func TestIsNonEmptyFile(t *testing.T) {
})
}
}

func TestGetProxy(t *testing.T) {
var got llb.ProxyEnv
var want llb.ProxyEnv

// Test with configured proxy
os.Setenv("HTTP_PROXY", "httpproxy")
os.Setenv("HTTPS_PROXY", "httpsproxy")
os.Setenv("NO_PROXY", "noproxy")
got = GetProxy()
want = llb.ProxyEnv{
HTTPProxy: "httpproxy",
HTTPSProxy: "httpsproxy",
NoProxy: "noproxy",
AllProxy: "httpproxy",
}
if got != want {
t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
}

// Test with unconfigured proxy
os.Unsetenv("HTTP_PROXY")
os.Unsetenv("HTTPS_PROXY")
os.Unsetenv("NO_PROXY")
got = GetProxy()
want = llb.ProxyEnv{
HTTPProxy: "",
HTTPSProxy: "",
NoProxy: "",
AllProxy: "",
}
if got != want {
t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
}
}

0 comments on commit a9c5e17

Please sign in to comment.