mirror of
https://github.com/containers/podman.git
synced 2025-06-22 18:08:11 +08:00
Merge pull request #9592 from rhatdan/timestamp
Numerous buildah fixes found by Ed's testing of buildah tests against podman.
This commit is contained in:
@ -2,6 +2,7 @@ package images
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@ -19,7 +20,6 @@ import (
|
|||||||
"github.com/containers/podman/v3/cmd/podman/registry"
|
"github.com/containers/podman/v3/cmd/podman/registry"
|
||||||
"github.com/containers/podman/v3/cmd/podman/utils"
|
"github.com/containers/podman/v3/cmd/podman/utils"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/docker/go-units"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -298,6 +298,11 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
commonOpts, err := parse.CommonBuildOptions(c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
pullPolicy := imagebuildah.PullIfMissing
|
pullPolicy := imagebuildah.PullIfMissing
|
||||||
if c.Flags().Changed("pull") && flags.Pull {
|
if c.Flags().Changed("pull") && flags.Pull {
|
||||||
pullPolicy = imagebuildah.PullAlways
|
pullPolicy = imagebuildah.PullAlways
|
||||||
@ -317,7 +322,12 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
|
|||||||
if len(av) > 1 {
|
if len(av) > 1 {
|
||||||
args[av[0]] = av[1]
|
args[av[0]] = av[1]
|
||||||
} else {
|
} else {
|
||||||
delete(args, av[0])
|
// check if the env is set in the local environment and use that value if it is
|
||||||
|
if val, present := os.LookupEnv(av[0]); present {
|
||||||
|
args[av[0]] = val
|
||||||
|
} else {
|
||||||
|
delete(args, av[0])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -356,22 +366,6 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
|
|||||||
reporter = logfile
|
reporter = logfile
|
||||||
}
|
}
|
||||||
|
|
||||||
var memoryLimit, memorySwap int64
|
|
||||||
var err error
|
|
||||||
if c.Flags().Changed("memory") {
|
|
||||||
memoryLimit, err = units.RAMInBytes(flags.Memory)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Flags().Changed("memory-swap") {
|
|
||||||
memorySwap, err = units.RAMInBytes(flags.MemorySwap)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nsValues, networkPolicy, err := parse.NamespaceOptions(c)
|
nsValues, networkPolicy, err := parse.NamespaceOptions(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -449,29 +443,15 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
|
|||||||
}
|
}
|
||||||
|
|
||||||
opts := imagebuildah.BuildOptions{
|
opts := imagebuildah.BuildOptions{
|
||||||
AddCapabilities: flags.CapAdd,
|
AddCapabilities: flags.CapAdd,
|
||||||
AdditionalTags: tags,
|
AdditionalTags: tags,
|
||||||
Annotations: flags.Annotation,
|
Annotations: flags.Annotation,
|
||||||
Architecture: arch,
|
Architecture: arch,
|
||||||
Args: args,
|
Args: args,
|
||||||
BlobDirectory: flags.BlobCache,
|
BlobDirectory: flags.BlobCache,
|
||||||
CNIConfigDir: flags.CNIConfigDir,
|
CNIConfigDir: flags.CNIConfigDir,
|
||||||
CNIPluginPath: flags.CNIPlugInPath,
|
CNIPluginPath: flags.CNIPlugInPath,
|
||||||
CommonBuildOpts: &buildah.CommonBuildOptions{
|
CommonBuildOpts: commonOpts,
|
||||||
AddHost: flags.AddHost,
|
|
||||||
CPUPeriod: flags.CPUPeriod,
|
|
||||||
CPUQuota: flags.CPUQuota,
|
|
||||||
CPUSetCPUs: flags.CPUSetCPUs,
|
|
||||||
CPUSetMems: flags.CPUSetMems,
|
|
||||||
CPUShares: flags.CPUShares,
|
|
||||||
CgroupParent: flags.CgroupParent,
|
|
||||||
HTTPProxy: flags.HTTPProxy,
|
|
||||||
Memory: memoryLimit,
|
|
||||||
MemorySwap: memorySwap,
|
|
||||||
ShmSize: flags.ShmSize,
|
|
||||||
Ulimit: flags.Ulimit,
|
|
||||||
Volumes: flags.Volumes,
|
|
||||||
},
|
|
||||||
Compression: compression,
|
Compression: compression,
|
||||||
ConfigureNetwork: networkPolicy,
|
ConfigureNetwork: networkPolicy,
|
||||||
ContextDirectory: contextDir,
|
ContextDirectory: contextDir,
|
||||||
@ -512,6 +492,14 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
|
|||||||
TransientMounts: flags.Volumes,
|
TransientMounts: flags.Volumes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if flags.IgnoreFile != "" {
|
||||||
|
excludes, err := parseDockerignore(flags.IgnoreFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "unable to obtain decrypt config")
|
||||||
|
}
|
||||||
|
opts.Excludes = excludes
|
||||||
|
}
|
||||||
|
|
||||||
if c.Flag("timestamp").Changed {
|
if c.Flag("timestamp").Changed {
|
||||||
timestamp := time.Unix(flags.Timestamp, 0).UTC()
|
timestamp := time.Unix(flags.Timestamp, 0).UTC()
|
||||||
opts.Timestamp = ×tamp
|
opts.Timestamp = ×tamp
|
||||||
@ -534,3 +522,18 @@ func getDecryptConfig(decryptionKeys []string) (*encconfig.DecryptConfig, error)
|
|||||||
|
|
||||||
return decConfig, nil
|
return decConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseDockerignore(ignoreFile string) ([]string, error) {
|
||||||
|
excludes := []string{}
|
||||||
|
ignore, err := ioutil.ReadFile(ignoreFile)
|
||||||
|
if err != nil {
|
||||||
|
return excludes, err
|
||||||
|
}
|
||||||
|
for _, e := range strings.Split(string(ignore), "\n") {
|
||||||
|
if len(e) == 0 || e[0] == '#' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
excludes = append(excludes, e)
|
||||||
|
}
|
||||||
|
return excludes, nil
|
||||||
|
}
|
||||||
|
@ -259,7 +259,7 @@ solely for scripting compatibility.
|
|||||||
|
|
||||||
#### **--dns**=*dns*
|
#### **--dns**=*dns*
|
||||||
|
|
||||||
Set custom DNS servers
|
Set custom DNS servers to be used during the build.
|
||||||
|
|
||||||
This option can be used to override the DNS configuration passed to the
|
This option can be used to override the DNS configuration passed to the
|
||||||
container. Typically this is necessary when the host DNS configuration is
|
container. Typically this is necessary when the host DNS configuration is
|
||||||
@ -272,11 +272,11 @@ image will be used without changes.
|
|||||||
|
|
||||||
#### **--dns-option**=*option*
|
#### **--dns-option**=*option*
|
||||||
|
|
||||||
Set custom DNS options
|
Set custom DNS options to be used during the build.
|
||||||
|
|
||||||
#### **--dns-search**=*domain*
|
#### **--dns-search**=*domain*
|
||||||
|
|
||||||
Set custom DNS search domains
|
Set custom DNS search domains to be used during the build.
|
||||||
|
|
||||||
#### **--file**, **-f**=*Containerfile*
|
#### **--file**, **-f**=*Containerfile*
|
||||||
|
|
||||||
|
@ -77,6 +77,9 @@ 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"`
|
||||||
|
DNSServers string `schema:"dnsservers"`
|
||||||
|
DNSOptions string `schema:"dnsoptions"`
|
||||||
|
DNSSearch string `schema:"dnssearch"`
|
||||||
Excludes string `schema:"excludes"`
|
Excludes string `schema:"excludes"`
|
||||||
ForceRm bool `schema:"forcerm"`
|
ForceRm bool `schema:"forcerm"`
|
||||||
From string `schema:"from"`
|
From string `schema:"from"`
|
||||||
@ -160,6 +163,36 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
|||||||
devices = m
|
devices = m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var dnsservers = []string{}
|
||||||
|
if _, found := r.URL.Query()["dnsservers"]; found {
|
||||||
|
var m = []string{}
|
||||||
|
if err := json.Unmarshal([]byte(query.DNSServers), &m); err != nil {
|
||||||
|
utils.BadRequest(w, "dnsservers", query.DNSServers, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dnsservers = m
|
||||||
|
}
|
||||||
|
|
||||||
|
var dnsoptions = []string{}
|
||||||
|
if _, found := r.URL.Query()["dnsoptions"]; found {
|
||||||
|
var m = []string{}
|
||||||
|
if err := json.Unmarshal([]byte(query.DNSOptions), &m); err != nil {
|
||||||
|
utils.BadRequest(w, "dnsoptions", query.DNSOptions, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dnsoptions = m
|
||||||
|
}
|
||||||
|
|
||||||
|
var dnssearch = []string{}
|
||||||
|
if _, found := r.URL.Query()["dnssearch"]; found {
|
||||||
|
var m = []string{}
|
||||||
|
if err := json.Unmarshal([]byte(query.DNSSearch), &m); err != nil {
|
||||||
|
utils.BadRequest(w, "dnssearches", query.DNSSearch, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dnssearch = m
|
||||||
|
}
|
||||||
|
|
||||||
var output string
|
var output string
|
||||||
if len(query.Tag) > 0 {
|
if len(query.Tag) > 0 {
|
||||||
output = query.Tag[0]
|
output = query.Tag[0]
|
||||||
@ -285,6 +318,9 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
|||||||
CPUQuota: query.CpuQuota,
|
CPUQuota: query.CpuQuota,
|
||||||
CPUShares: query.CpuShares,
|
CPUShares: query.CpuShares,
|
||||||
CPUSetCPUs: query.CpuSetCpus,
|
CPUSetCPUs: query.CpuSetCpus,
|
||||||
|
DNSServers: dnsservers,
|
||||||
|
DNSOptions: dnsoptions,
|
||||||
|
DNSSearch: dnssearch,
|
||||||
HTTPProxy: query.HTTPProxy,
|
HTTPProxy: query.HTTPProxy,
|
||||||
Memory: query.Memory,
|
Memory: query.Memory,
|
||||||
MemorySwap: query.MemSwap,
|
MemorySwap: query.MemSwap,
|
||||||
|
@ -87,6 +87,28 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
|
|||||||
params.Add("devices", d)
|
params.Add("devices", d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dnsservers := options.CommonBuildOpts.DNSServers; len(dnsservers) > 0 {
|
||||||
|
c, err := jsoniter.MarshalToString(dnsservers)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
params.Add("dnsservers", c)
|
||||||
|
}
|
||||||
|
if dnsoptions := options.CommonBuildOpts.DNSOptions; len(dnsoptions) > 0 {
|
||||||
|
c, err := jsoniter.MarshalToString(dnsoptions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
params.Add("dnsoptions", c)
|
||||||
|
}
|
||||||
|
if dnssearch := options.CommonBuildOpts.DNSSearch; len(dnssearch) > 0 {
|
||||||
|
c, err := jsoniter.MarshalToString(dnssearch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
params.Add("dnssearch", c)
|
||||||
|
}
|
||||||
|
|
||||||
if caps := options.DropCapabilities; len(caps) > 0 {
|
if caps := options.DropCapabilities; len(caps) > 0 {
|
||||||
c, err := jsoniter.MarshalToString(caps)
|
c, err := jsoniter.MarshalToString(caps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -168,6 +168,9 @@ EOF
|
|||||||
CAT_SECRET="cat /run/secrets/$secret_filename"
|
CAT_SECRET="cat /run/secrets/$secret_filename"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# For --dns-search: a domain that is unlikely to exist
|
||||||
|
local nosuchdomain=nx$(random_string 10).net
|
||||||
|
|
||||||
# Command to run on container startup with no args
|
# Command to run on container startup with no args
|
||||||
cat >$tmpdir/mycmd <<EOF
|
cat >$tmpdir/mycmd <<EOF
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
@ -188,11 +191,17 @@ EOF
|
|||||||
https_proxy=https-proxy-in-env-file
|
https_proxy=https-proxy-in-env-file
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
# Build args: one explicit (foo=bar), one implicit (foo)
|
||||||
|
local arg_implicit_value=implicit_$(random_string 15)
|
||||||
|
local arg_explicit_value=explicit_$(random_string 15)
|
||||||
|
|
||||||
# NOTE: it's important to not create the workdir.
|
# NOTE: it's important to not create the workdir.
|
||||||
# Podman will make sure to create a missing workdir
|
# Podman will make sure to create a missing workdir
|
||||||
# if needed. See #9040.
|
# if needed. See #9040.
|
||||||
cat >$tmpdir/Containerfile <<EOF
|
cat >$tmpdir/Containerfile <<EOF
|
||||||
FROM $IMAGE
|
FROM $IMAGE
|
||||||
|
ARG arg_explicit
|
||||||
|
ARG arg_implicit
|
||||||
LABEL $label_name=$label_value
|
LABEL $label_name=$label_value
|
||||||
WORKDIR $workdir
|
WORKDIR $workdir
|
||||||
|
|
||||||
@ -217,18 +226,47 @@ RUN chown 2:3 /bin/mydefaultcmd
|
|||||||
|
|
||||||
RUN $CAT_SECRET
|
RUN $CAT_SECRET
|
||||||
|
|
||||||
|
RUN echo explicit-build-arg=\$arg_explicit
|
||||||
|
RUN echo implicit-build-arg=\$arg_implicit
|
||||||
|
|
||||||
CMD ["/bin/mydefaultcmd","$s_echo"]
|
CMD ["/bin/mydefaultcmd","$s_echo"]
|
||||||
|
RUN cat /etc/resolv.conf
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
# The goal is to test that a missing value will be inherited from
|
||||||
|
# environment - but that can't work with remote, so for simplicity
|
||||||
|
# just make it explicit in that case too.
|
||||||
|
local build_arg_implicit="--build-arg arg_implicit"
|
||||||
|
if is_remote; then
|
||||||
|
build_arg_implicit+="=$arg_implicit_value"
|
||||||
|
fi
|
||||||
|
|
||||||
# cd to the dir, so we test relative paths (important for podman-remote)
|
# cd to the dir, so we test relative paths (important for podman-remote)
|
||||||
cd $PODMAN_TMPDIR
|
cd $PODMAN_TMPDIR
|
||||||
|
export arg_explicit="THIS SHOULD BE OVERRIDDEN BY COMMAND LINE!"
|
||||||
|
export arg_implicit=${arg_implicit_value}
|
||||||
run_podman ${MOUNTS_CONF} build \
|
run_podman ${MOUNTS_CONF} build \
|
||||||
|
--build-arg arg_explicit=${arg_explicit_value} \
|
||||||
|
$build_arg_implicit \
|
||||||
|
--dns-search $nosuchdomain \
|
||||||
-t build_test -f build-test/Containerfile build-test
|
-t build_test -f build-test/Containerfile build-test
|
||||||
local iid="${lines[-1]}"
|
local iid="${lines[-1]}"
|
||||||
|
|
||||||
|
if [[ $output =~ missing.*build.argument ]]; then
|
||||||
|
die "podman did not see the given --build-arg(s)"
|
||||||
|
fi
|
||||||
|
|
||||||
# Make sure 'podman build' had the secret mounted
|
# Make sure 'podman build' had the secret mounted
|
||||||
is "$output" ".*$secret_contents.*" "podman build has /run/secrets mounted"
|
is "$output" ".*$secret_contents.*" "podman build has /run/secrets mounted"
|
||||||
|
|
||||||
|
# --build-arg should be set, both via 'foo=bar' and via just 'foo' ($foo)
|
||||||
|
is "$output" ".*explicit-build-arg=${arg_explicit_value}" \
|
||||||
|
"--build-arg arg_explicit=explicit-value works"
|
||||||
|
is "$output" ".*implicit-build-arg=${arg_implicit_value}" \
|
||||||
|
"--build-arg arg_implicit works (inheriting from environment)"
|
||||||
|
is "$output" ".*search $nosuchdomain" \
|
||||||
|
"--dns-search added to /etc/resolv.conf"
|
||||||
|
|
||||||
if is_remote; then
|
if is_remote; then
|
||||||
ENVHOST=""
|
ENVHOST=""
|
||||||
else
|
else
|
||||||
@ -362,6 +400,82 @@ Labels.$label_name | $label_value
|
|||||||
run_podman rmi -f build_test
|
run_podman rmi -f build_test
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "podman build - COPY with ignore" {
|
||||||
|
local tmpdir=$PODMAN_TMPDIR/build-test-$(random_string 10)
|
||||||
|
mkdir -p $tmpdir/subdir
|
||||||
|
|
||||||
|
# Create a bunch of files. Declare this as an array to avoid duplication
|
||||||
|
# because we iterate over that list below, checking for each file.
|
||||||
|
# A leading "-" indicates that the file SHOULD NOT exist in the built image
|
||||||
|
local -a files=(
|
||||||
|
-test1 -test1.txt
|
||||||
|
test2 test2.txt
|
||||||
|
subdir/sub1 subdir/sub1.txt
|
||||||
|
-subdir/sub2 -subdir/sub2.txt
|
||||||
|
this-file-does-not-match-anything-in-ignore-file
|
||||||
|
comment
|
||||||
|
)
|
||||||
|
for f in ${files[@]}; do
|
||||||
|
# The magic '##-' strips off the '-' prefix
|
||||||
|
echo "$f" > $tmpdir/${f##-}
|
||||||
|
done
|
||||||
|
|
||||||
|
# Directory that doesn't exist in the image; COPY should create it
|
||||||
|
local newdir=/newdir-$(random_string 12)
|
||||||
|
cat >$tmpdir/Containerfile <<EOF
|
||||||
|
FROM $IMAGE
|
||||||
|
COPY ./ $newdir/
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Run twice: first with a custom --ignorefile, then with a default one.
|
||||||
|
# This ordering is deliberate: if we were to run with .dockerignore
|
||||||
|
# first, and forget to rm it, and then run with --ignorefile, _and_
|
||||||
|
# there was a bug in podman where --ignorefile was a NOP (eg #9570),
|
||||||
|
# the test might pass because of the existence of .dockerfile.
|
||||||
|
for ignorefile in ignoreme-$(random_string 5) .dockerignore; do
|
||||||
|
# Patterns to ignore. Mostly copied from buildah/tests/bud/dockerignore
|
||||||
|
cat >$tmpdir/$ignorefile <<EOF
|
||||||
|
# comment
|
||||||
|
test*
|
||||||
|
!test2*
|
||||||
|
subdir
|
||||||
|
!*/sub1*
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Build an image. For .dockerignore
|
||||||
|
local -a ignoreflag
|
||||||
|
unset ignoreflag
|
||||||
|
if [[ $ignorefile != ".dockerignore" ]]; then
|
||||||
|
ignoreflag="--ignorefile $tmpdir/$ignorefile"
|
||||||
|
fi
|
||||||
|
run_podman build -t build_test ${ignoreflag} $tmpdir
|
||||||
|
|
||||||
|
# Delete the ignore file! Otherwise, in the next iteration of the loop,
|
||||||
|
# we could end up with an existing .dockerignore that invisibly
|
||||||
|
# takes precedence over --ignorefile
|
||||||
|
rm -f $tmpdir/$ignorefile
|
||||||
|
|
||||||
|
# It would be much more readable, and probably safer, to iterate
|
||||||
|
# over each file, running 'podman run ... ls -l $f'. But each podman run
|
||||||
|
# takes a second or so, and we are mindful of each second.
|
||||||
|
run_podman run --rm build_test find $newdir -type f
|
||||||
|
for f in ${files[@]}; do
|
||||||
|
if [[ $f =~ ^- ]]; then
|
||||||
|
f=${f##-}
|
||||||
|
if [[ $output =~ $f ]]; then
|
||||||
|
die "File '$f' found in image; it should have been ignored via $ignorefile"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
is "$output" ".*$newdir/$f" \
|
||||||
|
"File '$f' should exist in container (no match in $ignorefile)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
run_podman rmi -f build_test
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
@test "podman build - stdin test" {
|
@test "podman build - stdin test" {
|
||||||
# Random workdir, and random string to verify build output
|
# Random workdir, and random string to verify build output
|
||||||
workdir=/$(random_string 10)
|
workdir=/$(random_string 10)
|
||||||
|
Reference in New Issue
Block a user