Merge pull request #9884 from rhatdan/build

Fix missing podman-remote build options
This commit is contained in:
OpenShift Merge Robot
2021-04-04 01:26:22 +02:00
committed by GitHub
3 changed files with 210 additions and 64 deletions

View File

@ -10,6 +10,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/containers/buildah" "github.com/containers/buildah"
@ -63,52 +64,55 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
}() }()
query := struct { query := struct {
AddHosts string `schema:"extrahosts"` AddHosts string `schema:"extrahosts"`
AdditionalCapabilities string `schema:"addcaps"` AdditionalCapabilities string `schema:"addcaps"`
Annotations string `schema:"annotations"` Annotations string `schema:"annotations"`
BuildArgs string `schema:"buildargs"` AppArmor string `schema:"apparmor"`
CacheFrom string `schema:"cachefrom"` BuildArgs string `schema:"buildargs"`
Compression uint64 `schema:"compression"` CacheFrom string `schema:"cachefrom"`
ConfigureNetwork string `schema:"networkmode"` Compression uint64 `schema:"compression"`
CpuPeriod uint64 `schema:"cpuperiod"` // nolint ConfigureNetwork string `schema:"networkmode"`
CpuQuota int64 `schema:"cpuquota"` // nolint CpuPeriod uint64 `schema:"cpuperiod"` // nolint
CpuSetCpus string `schema:"cpusetcpus"` // nolint CpuQuota int64 `schema:"cpuquota"` // nolint
CpuShares uint64 `schema:"cpushares"` // nolint CpuSetCpus string `schema:"cpusetcpus"` // nolint
Devices string `schema:"devices"` CpuShares uint64 `schema:"cpushares"` // nolint
Dockerfile string `schema:"dockerfile"` DNSOptions string `schema:"dnsoptions"`
DropCapabilities string `schema:"dropcaps"` DNSSearch string `schema:"dnssearch"`
DNSServers string `schema:"dnsservers"` DNSServers string `schema:"dnsservers"`
DNSOptions string `schema:"dnsoptions"` Devices string `schema:"devices"`
DNSSearch string `schema:"dnssearch"` Dockerfile string `schema:"dockerfile"`
Excludes string `schema:"excludes"` DropCapabilities string `schema:"dropcaps"`
ForceRm bool `schema:"forcerm"` Excludes string `schema:"excludes"`
From string `schema:"from"` ForceRm bool `schema:"forcerm"`
HTTPProxy bool `schema:"httpproxy"` From string `schema:"from"`
Isolation string `schema:"isolation"` HTTPProxy bool `schema:"httpproxy"`
Ignore bool `schema:"ignore"` Ignore bool `schema:"ignore"`
Jobs int `schema:"jobs"` // nolint Isolation string `schema:"isolation"`
Labels string `schema:"labels"` Jobs int `schema:"jobs"` // nolint
Layers bool `schema:"layers"` LabelOpts string `schema:"labelopts"`
LogRusage bool `schema:"rusage"` Labels string `schema:"labels"`
Manifest string `schema:"manifest"` Layers bool `schema:"layers"`
MemSwap int64 `schema:"memswap"` LogRusage bool `schema:"rusage"`
Memory int64 `schema:"memory"` Manifest string `schema:"manifest"`
NamespaceOptions string `schema:"nsoptions"` MemSwap int64 `schema:"memswap"`
NoCache bool `schema:"nocache"` Memory int64 `schema:"memory"`
OutputFormat string `schema:"outputformat"` NamespaceOptions string `schema:"nsoptions"`
Platform string `schema:"platform"` NoCache bool `schema:"nocache"`
Pull bool `schema:"pull"` OutputFormat string `schema:"outputformat"`
PullPolicy string `schema:"pullpolicy"` Platform string `schema:"platform"`
Quiet bool `schema:"q"` Pull bool `schema:"pull"`
Registry string `schema:"registry"` PullPolicy string `schema:"pullpolicy"`
Rm bool `schema:"rm"` Quiet bool `schema:"q"`
//FIXME SecurityOpt in remote API is not handled Registry string `schema:"registry"`
SecurityOpt string `schema:"securityopt"` Rm bool `schema:"rm"`
ShmSize int `schema:"shmsize"` Seccomp string `schema:"seccomp"`
Squash bool `schema:"squash"` SecurityOpt string `schema:"securityopt"`
Tag []string `schema:"t"` ShmSize int `schema:"shmsize"`
Target string `schema:"target"` Squash bool `schema:"squash"`
Timestamp int64 `schema:"timestamp"` Tag []string `schema:"t"`
Target string `schema:"target"`
Timestamp int64 `schema:"timestamp"`
Ulimits string `schema:"ulimits"`
}{ }{
Dockerfile: "Dockerfile", Dockerfile: "Dockerfile",
Registry: "docker.io", Registry: "docker.io",
@ -123,7 +127,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
return return
} }
// convert label formats // convert addcaps formats
var addCaps = []string{} var addCaps = []string{}
if _, found := r.URL.Query()["addcaps"]; found { if _, found := r.URL.Query()["addcaps"]; found {
var m = []string{} var m = []string{}
@ -133,6 +137,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
} }
addCaps = m addCaps = m
} }
addhosts := []string{} addhosts := []string{}
if _, found := r.URL.Query()["extrahosts"]; found { if _, found := r.URL.Query()["extrahosts"]; found {
if err := json.Unmarshal([]byte(query.AddHosts), &addhosts); err != nil { if err := json.Unmarshal([]byte(query.AddHosts), &addhosts); err != nil {
@ -142,7 +147,8 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
} }
compression := archive.Compression(query.Compression) compression := archive.Compression(query.Compression)
// convert label formats
// convert dropcaps formats
var dropCaps = []string{} var dropCaps = []string{}
if _, found := r.URL.Query()["dropcaps"]; found { if _, found := r.URL.Query()["dropcaps"]; found {
var m = []string{} var m = []string{}
@ -153,7 +159,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
dropCaps = m dropCaps = m
} }
// convert label formats // convert devices formats
var devices = []string{} var devices = []string{}
if _, found := r.URL.Query()["devices"]; found { if _, found := r.URL.Query()["devices"]; found {
var m = []string{} var m = []string{}
@ -233,7 +239,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
} }
} }
// convert label formats // convert annotations formats
var annotations = []string{} var annotations = []string{}
if _, found := r.URL.Query()["annotations"]; found { if _, found := r.URL.Query()["annotations"]; found {
if err := json.Unmarshal([]byte(query.Annotations), &annotations); err != nil { if err := json.Unmarshal([]byte(query.Annotations), &annotations); err != nil {
@ -242,7 +248,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
} }
} }
// convert label formats // convert nsoptions formats
nsoptions := buildah.NamespaceOptions{} nsoptions := buildah.NamespaceOptions{}
if _, found := r.URL.Query()["nsoptions"]; found { if _, found := r.URL.Query()["nsoptions"]; found {
if err := json.Unmarshal([]byte(query.NamespaceOptions), &nsoptions); err != nil { if err := json.Unmarshal([]byte(query.NamespaceOptions), &nsoptions); err != nil {
@ -271,11 +277,75 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
} }
} }
} }
jobs := 1 jobs := 1
if _, found := r.URL.Query()["jobs"]; found { if _, found := r.URL.Query()["jobs"]; found {
jobs = query.Jobs jobs = query.Jobs
} }
var (
labelOpts = []string{}
seccomp string
apparmor string
)
if utils.IsLibpodRequest(r) {
seccomp = query.Seccomp
apparmor = query.AppArmor
// convert labelopts formats
if _, found := r.URL.Query()["labelopts"]; found {
var m = []string{}
if err := json.Unmarshal([]byte(query.LabelOpts), &m); err != nil {
utils.BadRequest(w, "labelopts", query.LabelOpts, err)
return
}
labelOpts = m
}
} else {
// handle security-opt
if _, found := r.URL.Query()["securityopt"]; found {
var securityOpts = []string{}
if err := json.Unmarshal([]byte(query.SecurityOpt), &securityOpts); err != nil {
utils.BadRequest(w, "securityopt", query.SecurityOpt, err)
return
}
for _, opt := range securityOpts {
if opt == "no-new-privileges" {
utils.BadRequest(w, "securityopt", query.SecurityOpt, errors.New("no-new-privileges is not supported"))
return
}
con := strings.SplitN(opt, "=", 2)
if len(con) != 2 {
utils.BadRequest(w, "securityopt", query.SecurityOpt, errors.Errorf("Invalid --security-opt name=value pair: %q", opt))
return
}
switch con[0] {
case "label":
labelOpts = append(labelOpts, con[1])
case "apparmor":
apparmor = con[1]
case "seccomp":
seccomp = con[1]
default:
utils.BadRequest(w, "securityopt", query.SecurityOpt, errors.Errorf("Invalid --security-opt 2: %q", opt))
return
}
}
}
}
// convert ulimits formats
var ulimits = []string{}
if _, found := r.URL.Query()["ulimits"]; found {
var m = []string{}
if err := json.Unmarshal([]byte(query.Ulimits), &m); err != nil {
utils.BadRequest(w, "ulimits", query.Ulimits, err)
return
}
ulimits = m
}
pullPolicy := buildahDefine.PullIfMissing pullPolicy := buildahDefine.PullIfMissing
if utils.IsLibpodRequest(r) { if utils.IsLibpodRequest(r) {
pullPolicy = buildahDefine.PolicyMap[query.PullPolicy] pullPolicy = buildahDefine.PolicyMap[query.PullPolicy]
@ -320,18 +390,22 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
Annotations: annotations, Annotations: annotations,
Args: buildArgs, Args: buildArgs,
CommonBuildOpts: &buildah.CommonBuildOptions{ CommonBuildOpts: &buildah.CommonBuildOptions{
AddHost: addhosts, AddHost: addhosts,
CPUPeriod: query.CpuPeriod, ApparmorProfile: apparmor,
CPUQuota: query.CpuQuota, CPUPeriod: query.CpuPeriod,
CPUShares: query.CpuShares, CPUQuota: query.CpuQuota,
CPUSetCPUs: query.CpuSetCpus, CPUSetCPUs: query.CpuSetCpus,
DNSServers: dnsservers, CPUShares: query.CpuShares,
DNSOptions: dnsoptions, DNSOptions: dnsoptions,
DNSSearch: dnssearch, DNSSearch: dnssearch,
HTTPProxy: query.HTTPProxy, DNSServers: dnsservers,
Memory: query.Memory, HTTPProxy: query.HTTPProxy,
MemorySwap: query.MemSwap, LabelOpts: labelOpts,
ShmSize: strconv.Itoa(query.ShmSize), Memory: query.Memory,
MemorySwap: query.MemSwap,
SeccompProfilePath: seccomp,
ShmSize: strconv.Itoa(query.ShmSize),
Ulimit: ulimits,
}, },
CNIConfigDir: rtc.Network.CNIPluginDirs[0], CNIConfigDir: rtc.Network.CNIPluginDirs[0],
CNIPluginPath: util.DefaultCNIPluginPath, CNIPluginPath: util.DefaultCNIPluginPath,
@ -364,11 +438,11 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
RemoveIntermediateCtrs: query.Rm, RemoveIntermediateCtrs: query.Rm,
ReportWriter: reporter, ReportWriter: reporter,
Squash: query.Squash, Squash: query.Squash,
Target: query.Target,
SystemContext: &types.SystemContext{ SystemContext: &types.SystemContext{
AuthFilePath: authfile, AuthFilePath: authfile,
DockerAuthConfig: creds, DockerAuthConfig: creds,
}, },
Target: query.Target,
} }
if _, found := r.URL.Query()["timestamp"]; found { if _, found := r.URL.Query()["timestamp"]; found {

View File

@ -120,6 +120,9 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
if options.ForceRmIntermediateCtrs { if options.ForceRmIntermediateCtrs {
params.Set("forcerm", "1") params.Set("forcerm", "1")
} }
if options.RemoveIntermediateCtrs {
params.Set("rm", "1")
}
if len(options.From) > 0 { if len(options.From) > 0 {
params.Set("from", options.From) params.Set("from", options.From)
} }
@ -140,6 +143,23 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
} }
params.Set("labels", l) params.Set("labels", l)
} }
if opt := options.CommonBuildOpts.LabelOpts; len(opt) > 0 {
o, err := jsoniter.MarshalToString(opt)
if err != nil {
return nil, err
}
params.Set("labelopts", o)
}
if len(options.CommonBuildOpts.SeccompProfilePath) > 0 {
params.Set("seccomp", options.CommonBuildOpts.SeccompProfilePath)
}
if len(options.CommonBuildOpts.ApparmorProfile) > 0 {
params.Set("apparmor", options.CommonBuildOpts.ApparmorProfile)
}
if options.Layers { if options.Layers {
params.Set("layers", "1") params.Set("layers", "1")
} }
@ -174,6 +194,7 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
if len(platform) > 0 { if len(platform) > 0 {
params.Set("platform", platform) params.Set("platform", platform)
} }
params.Set("pullpolicy", options.PullPolicy.String()) params.Set("pullpolicy", options.PullPolicy.String())
if options.Quiet { if options.Quiet {
@ -182,6 +203,10 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
if options.RemoveIntermediateCtrs { if options.RemoveIntermediateCtrs {
params.Set("rm", "1") params.Set("rm", "1")
} }
if len(options.Target) > 0 {
params.Set("target", options.Target)
}
if hosts := options.CommonBuildOpts.AddHost; len(hosts) > 0 { if hosts := options.CommonBuildOpts.AddHost; len(hosts) > 0 {
h, err := jsoniter.MarshalToString(hosts) h, err := jsoniter.MarshalToString(hosts)
if err != nil { if err != nil {
@ -212,6 +237,13 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
params.Set("timestamp", strconv.FormatInt(t.Unix(), 10)) params.Set("timestamp", strconv.FormatInt(t.Unix(), 10))
} }
if len(options.CommonBuildOpts.Ulimit) > 0 {
ulimitsJSON, err := json.Marshal(options.CommonBuildOpts.Ulimit)
if err != nil {
return nil, err
}
params.Set("ulimits", string(ulimitsJSON))
}
var ( var (
headers map[string]string headers map[string]string
err error err error

View File

@ -712,6 +712,46 @@ EOF
run_podman rmi -f build_test run_podman rmi -f build_test
} }
@test "podman build check_label" {
skip_if_no_selinux
tmpdir=$PODMAN_TMPDIR/build-test
mkdir -p $tmpdir
tmpbuilddir=$tmpdir/build
mkdir -p $tmpbuilddir
dockerfile=$tmpbuilddir/Dockerfile
cat >$dockerfile <<EOF
FROM $IMAGE
RUN cat /proc/self/attr/current
EOF
run_podman build -t build_test --security-opt label=level:s0:c3,c4 --format=docker $tmpbuilddir
is "$output" ".*s0:c3,c4STEP 3: COMMIT" "label setting level"
run_podman rmi -f build_test
}
@test "podman build check_seccomp_ulimits" {
tmpdir=$PODMAN_TMPDIR/build-test
mkdir -p $tmpdir
tmpbuilddir=$tmpdir/build
mkdir -p $tmpbuilddir
dockerfile=$tmpbuilddir/Dockerfile
cat >$dockerfile <<EOF
FROM $IMAGE
RUN grep Seccomp: /proc/self/status |awk '{ print \$1\$2 }'
RUN grep "Max open files" /proc/self/limits |awk '{ print \$4":"\$5 }'
EOF
run_podman build --ulimit nofile=101:102 -t build_test $tmpbuilddir
is "$output" ".*Seccomp:2" "setting seccomp"
is "$output" ".*101:102" "setting ulimits"
run_podman rmi -f build_test
run_podman build -t build_test --security-opt seccomp=unconfined $tmpbuilddir
is "$output" ".*Seccomp:0" "setting seccomp"
run_podman rmi -f build_test
}
function teardown() { function teardown() {
# A timeout or other error in 'build' can leave behind stale images # A timeout or other error in 'build' can leave behind stale images
# that podman can't even see and which will cascade into subsequent # that podman can't even see and which will cascade into subsequent