mirror of
https://github.com/containers/podman
synced 2024-10-19 08:44:11 +00:00
Add missing params for podman-remote build
Fixes: https://github.com/containers/podman/issues/9290 Currently we still have hard coded --isolation=chroot for podman-remote build. Implement missing arguments for podman build Implements --jobs, --disable-compression, --excludes Fixes: MaxPullPushRetries RetryDuration Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
parent
ac9a048b59
commit
690c02f602
|
@ -10,9 +10,11 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containers/buildah"
|
"github.com/containers/buildah"
|
||||||
"github.com/containers/buildah/imagebuildah"
|
"github.com/containers/buildah/imagebuildah"
|
||||||
|
"github.com/containers/buildah/util"
|
||||||
"github.com/containers/image/v5/types"
|
"github.com/containers/image/v5/types"
|
||||||
"github.com/containers/podman/v2/libpod"
|
"github.com/containers/podman/v2/libpod"
|
||||||
"github.com/containers/podman/v2/pkg/api/handlers/utils"
|
"github.com/containers/podman/v2/pkg/api/handlers/utils"
|
||||||
|
@ -20,6 +22,7 @@ import (
|
||||||
"github.com/containers/podman/v2/pkg/channel"
|
"github.com/containers/podman/v2/pkg/channel"
|
||||||
"github.com/containers/storage/pkg/archive"
|
"github.com/containers/storage/pkg/archive"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
@ -65,6 +68,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
||||||
Annotations string `schema:"annotations"`
|
Annotations string `schema:"annotations"`
|
||||||
BuildArgs string `schema:"buildargs"`
|
BuildArgs string `schema:"buildargs"`
|
||||||
CacheFrom string `schema:"cachefrom"`
|
CacheFrom string `schema:"cachefrom"`
|
||||||
|
Compression uint64 `schema:"compression"`
|
||||||
ConfigureNetwork int64 `schema:"networkmode"`
|
ConfigureNetwork int64 `schema:"networkmode"`
|
||||||
CpuPeriod uint64 `schema:"cpuperiod"` // nolint
|
CpuPeriod uint64 `schema:"cpuperiod"` // nolint
|
||||||
CpuQuota int64 `schema:"cpuquota"` // nolint
|
CpuQuota int64 `schema:"cpuquota"` // nolint
|
||||||
|
@ -73,17 +77,20 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
||||||
Devices string `schema:"devices"`
|
Devices string `schema:"devices"`
|
||||||
Dockerfile string `schema:"dockerfile"`
|
Dockerfile string `schema:"dockerfile"`
|
||||||
DropCapabilities string `schema:"dropcaps"`
|
DropCapabilities string `schema:"dropcaps"`
|
||||||
|
Excludes string `schema:"excludes"`
|
||||||
ForceRm bool `schema:"forcerm"`
|
ForceRm bool `schema:"forcerm"`
|
||||||
From string `schema:"from"`
|
From string `schema:"from"`
|
||||||
HTTPProxy bool `schema:"httpproxy"`
|
HTTPProxy bool `schema:"httpproxy"`
|
||||||
Isolation int64 `schema:"isolation"`
|
Isolation int64 `schema:"isolation"`
|
||||||
Jobs uint64 `schema:"jobs"` // nolint
|
Ignore bool `schema:"ignore"`
|
||||||
|
Jobs int `schema:"jobs"` // nolint
|
||||||
Labels string `schema:"labels"`
|
Labels string `schema:"labels"`
|
||||||
Layers bool `schema:"layers"`
|
Layers bool `schema:"layers"`
|
||||||
LogRusage bool `schema:"rusage"`
|
LogRusage bool `schema:"rusage"`
|
||||||
Manifest string `schema:"manifest"`
|
Manifest string `schema:"manifest"`
|
||||||
MemSwap int64 `schema:"memswap"`
|
MemSwap int64 `schema:"memswap"`
|
||||||
Memory int64 `schema:"memory"`
|
Memory int64 `schema:"memory"`
|
||||||
|
NamespaceOptions string `schema:"nsoptions"`
|
||||||
NoCache bool `schema:"nocache"`
|
NoCache bool `schema:"nocache"`
|
||||||
OutputFormat string `schema:"outputformat"`
|
OutputFormat string `schema:"outputformat"`
|
||||||
Platform string `schema:"platform"`
|
Platform string `schema:"platform"`
|
||||||
|
@ -129,6 +136,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compression := archive.Compression(query.Compression)
|
||||||
// convert label formats
|
// convert label formats
|
||||||
var dropCaps = []string{}
|
var dropCaps = []string{}
|
||||||
if _, found := r.URL.Query()["dropcaps"]; found {
|
if _, found := r.URL.Query()["dropcaps"]; found {
|
||||||
|
@ -156,7 +164,15 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
||||||
output = query.Tag[0]
|
output = query.Tag[0]
|
||||||
}
|
}
|
||||||
format := buildah.Dockerv2ImageManifest
|
format := buildah.Dockerv2ImageManifest
|
||||||
|
registry := query.Registry
|
||||||
|
isolation := buildah.IsolationChroot
|
||||||
|
/*
|
||||||
|
// FIXME, This is very broken. Buildah will only work with chroot
|
||||||
|
isolation := buildah.IsolationDefault
|
||||||
|
*/
|
||||||
if utils.IsLibpodRequest(r) {
|
if utils.IsLibpodRequest(r) {
|
||||||
|
// isolation = buildah.Isolation(query.Isolation)
|
||||||
|
registry = ""
|
||||||
format = query.OutputFormat
|
format = query.OutputFormat
|
||||||
}
|
}
|
||||||
var additionalTags []string
|
var additionalTags []string
|
||||||
|
@ -172,6 +188,14 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var excludes = []string{}
|
||||||
|
if _, found := r.URL.Query()["excludes"]; found {
|
||||||
|
if err := json.Unmarshal([]byte(query.Excludes), &excludes); err != nil {
|
||||||
|
utils.BadRequest(w, "excludes", query.Excludes, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// convert label formats
|
// convert label formats
|
||||||
var annotations = []string{}
|
var annotations = []string{}
|
||||||
if _, found := r.URL.Query()["annotations"]; found {
|
if _, found := r.URL.Query()["annotations"]; found {
|
||||||
|
@ -181,6 +205,19 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convert label formats
|
||||||
|
nsoptions := buildah.NamespaceOptions{}
|
||||||
|
if _, found := r.URL.Query()["nsoptions"]; found {
|
||||||
|
if err := json.Unmarshal([]byte(query.NamespaceOptions), &nsoptions); err != nil {
|
||||||
|
utils.BadRequest(w, "nsoptions", query.NamespaceOptions, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nsoptions = append(nsoptions, buildah.NamespaceOption{
|
||||||
|
Name: string(specs.NetworkNamespace),
|
||||||
|
Host: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
// convert label formats
|
// convert label formats
|
||||||
var labels = []string{}
|
var labels = []string{}
|
||||||
if _, found := r.URL.Query()["labels"]; found {
|
if _, found := r.URL.Query()["labels"]; found {
|
||||||
|
@ -189,6 +226,10 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
jobs := 1
|
||||||
|
if _, found := r.URL.Query()["jobs"]; found {
|
||||||
|
jobs = query.Jobs
|
||||||
|
}
|
||||||
|
|
||||||
pullPolicy := buildah.PullIfMissing
|
pullPolicy := buildah.PullIfMissing
|
||||||
if _, found := r.URL.Query()["pull"]; found {
|
if _, found := r.URL.Query()["pull"]; found {
|
||||||
|
@ -218,6 +259,12 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
||||||
reporter := channel.NewWriter(make(chan []byte, 1))
|
reporter := channel.NewWriter(make(chan []byte, 1))
|
||||||
defer reporter.Close()
|
defer reporter.Close()
|
||||||
|
|
||||||
|
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||||
|
rtc, err := runtime.GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
||||||
|
return
|
||||||
|
}
|
||||||
buildOptions := imagebuildah.BuildOptions{
|
buildOptions := imagebuildah.BuildOptions{
|
||||||
AddCapabilities: addCaps,
|
AddCapabilities: addCaps,
|
||||||
AdditionalTags: additionalTags,
|
AdditionalTags: additionalTags,
|
||||||
|
@ -234,32 +281,36 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
||||||
MemorySwap: query.MemSwap,
|
MemorySwap: query.MemSwap,
|
||||||
ShmSize: strconv.Itoa(query.ShmSize),
|
ShmSize: strconv.Itoa(query.ShmSize),
|
||||||
},
|
},
|
||||||
Compression: archive.Gzip,
|
CNIConfigDir: rtc.Network.CNIPluginDirs[0],
|
||||||
|
CNIPluginPath: util.DefaultCNIPluginPath,
|
||||||
|
Compression: compression,
|
||||||
ConfigureNetwork: buildah.NetworkConfigurationPolicy(query.ConfigureNetwork),
|
ConfigureNetwork: buildah.NetworkConfigurationPolicy(query.ConfigureNetwork),
|
||||||
ContextDirectory: contextDirectory,
|
ContextDirectory: contextDirectory,
|
||||||
Devices: devices,
|
Devices: devices,
|
||||||
DropCapabilities: dropCaps,
|
DropCapabilities: dropCaps,
|
||||||
Err: auxout,
|
Err: auxout,
|
||||||
|
Excludes: excludes,
|
||||||
ForceRmIntermediateCtrs: query.ForceRm,
|
ForceRmIntermediateCtrs: query.ForceRm,
|
||||||
From: query.From,
|
From: query.From,
|
||||||
IgnoreUnrecognizedInstructions: true,
|
IgnoreUnrecognizedInstructions: query.Ignore,
|
||||||
// FIXME, This is very broken. Buildah will only work with chroot
|
Isolation: isolation,
|
||||||
// Isolation: buildah.Isolation(query.Isolation),
|
Jobs: &jobs,
|
||||||
Isolation: buildah.IsolationChroot,
|
Labels: labels,
|
||||||
|
Layers: query.Layers,
|
||||||
Labels: labels,
|
Manifest: query.Manifest,
|
||||||
Layers: query.Layers,
|
MaxPullPushRetries: 3,
|
||||||
Manifest: query.Manifest,
|
NamespaceOptions: nsoptions,
|
||||||
NoCache: query.NoCache,
|
NoCache: query.NoCache,
|
||||||
Out: stdout,
|
Out: stdout,
|
||||||
Output: output,
|
Output: output,
|
||||||
OutputFormat: format,
|
OutputFormat: format,
|
||||||
PullPolicy: pullPolicy,
|
PullPolicy: pullPolicy,
|
||||||
Quiet: query.Quiet,
|
PullPushRetryDelay: time.Duration(2 * time.Second),
|
||||||
Registry: query.Registry,
|
Quiet: query.Quiet,
|
||||||
RemoveIntermediateCtrs: query.Rm,
|
Registry: registry,
|
||||||
ReportWriter: reporter,
|
RemoveIntermediateCtrs: query.Rm,
|
||||||
Squash: query.Squash,
|
ReportWriter: reporter,
|
||||||
|
Squash: query.Squash,
|
||||||
SystemContext: &types.SystemContext{
|
SystemContext: &types.SystemContext{
|
||||||
AuthFilePath: authfile,
|
AuthFilePath: authfile,
|
||||||
DockerAuthConfig: creds,
|
DockerAuthConfig: creds,
|
||||||
|
@ -267,7 +318,6 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
||||||
Target: query.Target,
|
Target: query.Target,
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
|
||||||
runCtx, cancel := context.WithCancel(context.Background())
|
runCtx, cancel := context.WithCancel(context.Background())
|
||||||
var imageID string
|
var imageID string
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
@ -57,6 +57,13 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
|
||||||
}
|
}
|
||||||
params.Set("buildargs", bArgs)
|
params.Set("buildargs", bArgs)
|
||||||
}
|
}
|
||||||
|
if excludes := options.Excludes; len(excludes) > 0 {
|
||||||
|
bArgs, err := jsoniter.MarshalToString(excludes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
params.Set("excludes", bArgs)
|
||||||
|
}
|
||||||
if cpuShares := options.CommonBuildOpts.CPUShares; cpuShares > 0 {
|
if cpuShares := options.CommonBuildOpts.CPUShares; cpuShares > 0 {
|
||||||
params.Set("cpushares", strconv.Itoa(int(cpuShares)))
|
params.Set("cpushares", strconv.Itoa(int(cpuShares)))
|
||||||
}
|
}
|
||||||
|
@ -94,7 +101,9 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
|
||||||
if len(options.From) > 0 {
|
if len(options.From) > 0 {
|
||||||
params.Set("from", options.From)
|
params.Set("from", options.From)
|
||||||
}
|
}
|
||||||
|
if options.IgnoreUnrecognizedInstructions {
|
||||||
|
params.Set("ignore", "1")
|
||||||
|
}
|
||||||
params.Set("isolation", strconv.Itoa(int(options.Isolation)))
|
params.Set("isolation", strconv.Itoa(int(options.Isolation)))
|
||||||
if options.CommonBuildOpts.HTTPProxy {
|
if options.CommonBuildOpts.HTTPProxy {
|
||||||
params.Set("httpproxy", "1")
|
params.Set("httpproxy", "1")
|
||||||
|
@ -159,6 +168,13 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
|
||||||
}
|
}
|
||||||
params.Set("extrahosts", h)
|
params.Set("extrahosts", h)
|
||||||
}
|
}
|
||||||
|
if nsoptions := options.NamespaceOptions; len(nsoptions) > 0 {
|
||||||
|
ns, err := jsoniter.MarshalToString(nsoptions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
params.Set("nsoptions", ns)
|
||||||
|
}
|
||||||
if shmSize := options.CommonBuildOpts.ShmSize; len(shmSize) > 0 {
|
if shmSize := options.CommonBuildOpts.ShmSize; len(shmSize) > 0 {
|
||||||
shmBytes, err := units.RAMInBytes(shmSize)
|
shmBytes, err := units.RAMInBytes(shmSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -489,7 +489,7 @@ RUN grep CapEff /proc/self/status`
|
||||||
To(ContainElement("0000000000000400"))
|
To(ContainElement("0000000000000400"))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman build --arch", func() {
|
It("podman build --isolation && --arch", func() {
|
||||||
targetPath, err := CreateTempDirInTempDir()
|
targetPath, err := CreateTempDirInTempDir()
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
|
@ -502,11 +502,34 @@ RUN grep CapEff /proc/self/status`
|
||||||
|
|
||||||
// When
|
// When
|
||||||
session := podmanTest.Podman([]string{
|
session := podmanTest.Podman([]string{
|
||||||
"build", "--arch", "arm64", targetPath,
|
"build", "--isolation", "oci", "--arch", "arm64", targetPath,
|
||||||
})
|
})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
// When
|
||||||
|
session = podmanTest.Podman([]string{
|
||||||
|
"build", "--isolation", "chroot", "--arch", "arm64", targetPath,
|
||||||
|
})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
// Then
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
// When
|
||||||
|
session = podmanTest.Podman([]string{
|
||||||
|
"build", "--isolation", "rootless", "--arch", "arm64", targetPath,
|
||||||
|
})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
// Then
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
// When
|
||||||
|
session = podmanTest.Podman([]string{
|
||||||
|
"build", "--isolation", "bogus", "--arch", "arm64", targetPath,
|
||||||
|
})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
// Then
|
||||||
|
Expect(session.ExitCode()).To(Equal(125))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -111,7 +111,6 @@ var _ = Describe("Podman prune", func() {
|
||||||
It("podman image prune dangling images", func() {
|
It("podman image prune dangling images", func() {
|
||||||
podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
|
podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
|
||||||
podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
|
podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
|
||||||
|
|
||||||
none := podmanTest.Podman([]string{"images", "-a"})
|
none := podmanTest.Podman([]string{"images", "-a"})
|
||||||
none.WaitWithDefaultTimeout()
|
none.WaitWithDefaultTimeout()
|
||||||
Expect(none.ExitCode()).To(Equal(0))
|
Expect(none.ExitCode()).To(Equal(0))
|
||||||
|
|
|
@ -453,6 +453,45 @@ EOF
|
||||||
run_podman rmi -a --force
|
run_podman rmi -a --force
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "build with copy-from referencing the base image" {
|
||||||
|
skip_if_rootless "cannot mount as rootless"
|
||||||
|
target=busybox-derived
|
||||||
|
target_mt=busybox-mt-derived
|
||||||
|
tmpdir=$PODMAN_TMPDIR/build-test
|
||||||
|
mkdir -p $tmpdir
|
||||||
|
containerfile1=$tmpdir/Containerfile1
|
||||||
|
cat >$containerfile1 <<EOF
|
||||||
|
FROM quay.io/libpod/busybox AS build
|
||||||
|
RUN rm -f /bin/paste
|
||||||
|
USER 1001
|
||||||
|
COPY --from=quay.io/libpod/busybox /bin/paste /test/
|
||||||
|
EOF
|
||||||
|
containerfile2=$tmpdir/Containerfile2
|
||||||
|
cat >$containerfile2 <<EOF
|
||||||
|
FROM quay.io/libpod/busybox AS test
|
||||||
|
RUN rm -f /bin/nl
|
||||||
|
FROM quay.io/libpod/alpine AS final
|
||||||
|
COPY --from=quay.io/libpod/busybox /bin/nl /test/
|
||||||
|
EOF
|
||||||
|
run_podman build -t ${target} -f ${containerfile1} ${tmpdir}
|
||||||
|
run_podman build --jobs 4 -t ${target} -f ${containerfile1} ${tmpdir}
|
||||||
|
|
||||||
|
run_podman build -t ${target} -f ${containerfile2} ${tmpdir}
|
||||||
|
run_podman build --no-cache --jobs 4 -t ${target_mt} -f ${containerfile2} ${tmpdir}
|
||||||
|
|
||||||
|
# (can only test locally; podman-remote has no image mount command)
|
||||||
|
if ! is_remote; then
|
||||||
|
run_podman image mount ${target}
|
||||||
|
root_single_job=$output
|
||||||
|
|
||||||
|
run_podman image mount ${target_mt}
|
||||||
|
root_multi_job=$output
|
||||||
|
|
||||||
|
# Check that both the version with --jobs 1 and --jobs=N have the same number of files
|
||||||
|
test $(find $root_single_job -type f | wc -l) = $(find $root_multi_job -type f | wc -l)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
@test "podman build --logfile test" {
|
@test "podman build --logfile test" {
|
||||||
tmpdir=$PODMAN_TMPDIR/build-test
|
tmpdir=$PODMAN_TMPDIR/build-test
|
||||||
mkdir -p $tmpdir
|
mkdir -p $tmpdir
|
||||||
|
|
Loading…
Reference in a new issue