mirror of
https://github.com/containers/podman.git
synced 2025-06-24 03:08:13 +08:00
Merge pull request #9884 from rhatdan/build
Fix missing podman-remote build options
This commit is contained in:
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user