summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/libpod/pods.go4
-rw-r--r--pkg/domain/entities/pods.go2
-rw-r--r--pkg/resolvconf/resolvconf.go8
-rw-r--r--pkg/specgen/generate/kube/kube.go69
-rw-r--r--pkg/specgen/generate/kube/play_test.go272
-rw-r--r--pkg/specgen/generate/namespaces.go2
-rw-r--r--pkg/specgen/generate/pod_create.go3
-rw-r--r--pkg/specgen/namespaces.go2
-rw-r--r--pkg/specgen/podspecgen.go2
9 files changed, 284 insertions, 80 deletions
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index afbdf0e5f..d522631b7 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -45,6 +45,10 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
infraOptions.Net = &entities.NetOptions{}
infraOptions.Devices = psg.Devices
infraOptions.SecurityOpt = psg.SecurityOpt
+ if psg.ShareParent == nil {
+ t := true
+ psg.ShareParent = &t
+ }
err = specgenutil.FillOutSpecGen(psg.InfraContainerSpec, &infraOptions, []string{}) // necessary for default values in many cases (userns, idmappings)
if err != nil {
utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error filling out specgen"))
diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go
index aeccc82b4..7922db4e6 100644
--- a/pkg/domain/entities/pods.go
+++ b/pkg/domain/entities/pods.go
@@ -132,6 +132,7 @@ type PodCreateOptions struct {
Name string `json:"name,omitempty"`
Net *NetOptions `json:"net,omitempty"`
Share []string `json:"share,omitempty"`
+ ShareParent *bool `json:"share_parent,omitempty"`
Pid string `json:"pid,omitempty"`
Cpus float64 `json:"cpus,omitempty"`
CpusetCpus string `json:"cpuset_cpus,omitempty"`
@@ -324,6 +325,7 @@ func ToPodSpecGen(s specgen.PodSpecGenerator, p *PodCreateOptions) (*specgen.Pod
}
s.InfraImage = p.InfraImage
s.SharedNamespaces = p.Share
+ s.ShareParent = p.ShareParent
s.PodCreateCommand = p.CreateCommand
s.VolumesFrom = p.VolumesFrom
diff --git a/pkg/resolvconf/resolvconf.go b/pkg/resolvconf/resolvconf.go
index d7505e049..f23cd61b0 100644
--- a/pkg/resolvconf/resolvconf.go
+++ b/pkg/resolvconf/resolvconf.go
@@ -221,9 +221,11 @@ func GetOptions(resolvConf []byte) []string {
// dnsSearch, and an "options" entry for every element in dnsOptions.
func Build(path string, dns, dnsSearch, dnsOptions []string) (*File, error) {
content := bytes.NewBuffer(nil)
- for _, search := range dnsSearch {
- if _, err := content.WriteString("search " + search + "\n"); err != nil {
- return nil, err
+ if len(dnsSearch) > 0 {
+ if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
+ if _, err := content.WriteString("search " + searchString + "\n"); err != nil {
+ return nil, err
+ }
}
}
for _, dns := range dns {
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index beaec1135..475401016 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -4,8 +4,10 @@ import (
"context"
"encoding/json"
"fmt"
+ "math"
"net"
"regexp"
+ "strconv"
"strings"
"time"
@@ -650,6 +652,10 @@ func envVarValue(env v1.EnvVar, opts *CtrSpecGenOptions) (*string, error) {
if env.ValueFrom.FieldRef != nil {
return envVarValueFieldRef(env, opts)
}
+
+ if env.ValueFrom.ResourceFieldRef != nil {
+ return envVarValueResourceFieldRef(env, opts)
+ }
}
return &env.Value, nil
@@ -688,6 +694,69 @@ func envVarValueFieldRef(env v1.EnvVar, opts *CtrSpecGenOptions) (*string, error
)
}
+func envVarValueResourceFieldRef(env v1.EnvVar, opts *CtrSpecGenOptions) (*string, error) {
+ divisor := env.ValueFrom.ResourceFieldRef.Divisor
+ if divisor.IsZero() { // divisor not set, use default
+ divisor.Set(1)
+ }
+
+ var value *resource.Quantity
+ resources := opts.Container.Resources
+ resourceName := env.ValueFrom.ResourceFieldRef.Resource
+ var isValidDivisor bool
+
+ switch resourceName {
+ case "limits.memory":
+ value = resources.Limits.Memory()
+ isValidDivisor = isMemoryDivisor(divisor)
+ case "limits.cpu":
+ value = resources.Limits.Cpu()
+ isValidDivisor = isCPUDivisor(divisor)
+ case "requests.memory":
+ value = resources.Requests.Memory()
+ isValidDivisor = isMemoryDivisor(divisor)
+ case "requests.cpu":
+ value = resources.Requests.Cpu()
+ isValidDivisor = isCPUDivisor(divisor)
+ default:
+ return nil, errors.Errorf(
+ "Can not set env %v. Reason: resource %v is either not valid or not supported",
+ env.Name, resourceName,
+ )
+ }
+
+ if !isValidDivisor {
+ return nil, errors.Errorf(
+ "Can not set env %s. Reason: divisor value %s is not valid",
+ env.Name, divisor.String(),
+ )
+ }
+
+ // k8s rounds up the result to the nearest integer
+ intValue := int(math.Ceil(value.AsApproximateFloat64() / divisor.AsApproximateFloat64()))
+ stringValue := strconv.Itoa(intValue)
+
+ return &stringValue, nil
+}
+
+func isMemoryDivisor(divisor resource.Quantity) bool {
+ switch divisor.String() {
+ case "1", "1k", "1M", "1G", "1T", "1P", "1E", "1Ki", "1Mi", "1Gi", "1Ti", "1Pi", "1Ei":
+ return true
+ default:
+ return false
+ }
+}
+
+func isCPUDivisor(divisor resource.Quantity) bool {
+ switch divisor.String() {
+ case "1", "1m":
+ return true
+ default:
+ return false
+ }
+}
+
// getPodPorts converts a slice of kube container descriptions to an
// array of portmapping
func getPodPorts(containers []v1.Container) []types.PortMapping {
diff --git a/pkg/specgen/generate/kube/play_test.go b/pkg/specgen/generate/kube/play_test.go
index 2ac268c79..282324310 100644
--- a/pkg/specgen/generate/kube/play_test.go
+++ b/pkg/specgen/generate/kube/play_test.go
@@ -2,13 +2,17 @@ package kube
import (
"encoding/json"
+ "fmt"
"io/ioutil"
+ "math"
"os"
+ "strconv"
"testing"
"github.com/containers/common/pkg/secrets"
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/api/resource"
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -189,15 +193,13 @@ func TestEnvVarValue(t *testing.T) {
assert.NoError(t, err)
defer os.RemoveAll(d)
secretsManager := createSecrets(t, d)
- value := "foo"
- emptyValue := ""
tests := []struct {
name string
envVar v1.EnvVar
options CtrSpecGenOptions
succeed bool
- expected *string
+ expected string
}{
{
"ConfigMapExists",
@@ -216,7 +218,7 @@ func TestEnvVarValue(t *testing.T) {
ConfigMaps: configMapList,
},
true,
- &value,
+ "foo",
},
{
"ContainerKeyDoesNotExistInConfigMap",
@@ -235,7 +237,7 @@ func TestEnvVarValue(t *testing.T) {
ConfigMaps: configMapList,
},
false,
- nil,
+ nilString,
},
{
"OptionalContainerKeyDoesNotExistInConfigMap",
@@ -255,7 +257,7 @@ func TestEnvVarValue(t *testing.T) {
ConfigMaps: configMapList,
},
true,
- nil,
+ nilString,
},
{
"ConfigMapDoesNotExist",
@@ -274,7 +276,7 @@ func TestEnvVarValue(t *testing.T) {
ConfigMaps: configMapList,
},
false,
- nil,
+ nilString,
},
{
"OptionalConfigMapDoesNotExist",
@@ -294,7 +296,7 @@ func TestEnvVarValue(t *testing.T) {
ConfigMaps: configMapList,
},
true,
- nil,
+ nilString,
},
{
"EmptyConfigMapList",
@@ -313,7 +315,7 @@ func TestEnvVarValue(t *testing.T) {
ConfigMaps: []v1.ConfigMap{},
},
false,
- nil,
+ nilString,
},
{
"OptionalEmptyConfigMapList",
@@ -333,7 +335,7 @@ func TestEnvVarValue(t *testing.T) {
ConfigMaps: []v1.ConfigMap{},
},
true,
- nil,
+ nilString,
},
{
"SecretExists",
@@ -352,7 +354,7 @@ func TestEnvVarValue(t *testing.T) {
SecretsManager: secretsManager,
},
true,
- &value,
+ "foo",
},
{
"ContainerKeyDoesNotExistInSecret",
@@ -371,7 +373,7 @@ func TestEnvVarValue(t *testing.T) {
SecretsManager: secretsManager,
},
false,
- nil,
+ nilString,
},
{
"OptionalContainerKeyDoesNotExistInSecret",
@@ -391,7 +393,7 @@ func TestEnvVarValue(t *testing.T) {
SecretsManager: secretsManager,
},
true,
- nil,
+ nilString,
},
{
"SecretDoesNotExist",
@@ -410,7 +412,7 @@ func TestEnvVarValue(t *testing.T) {
SecretsManager: secretsManager,
},
false,
- nil,
+ nilString,
},
{
"OptionalSecretDoesNotExist",
@@ -430,7 +432,7 @@ func TestEnvVarValue(t *testing.T) {
SecretsManager: secretsManager,
},
true,
- nil,
+ nilString,
},
{
"FieldRefMetadataName",
@@ -443,10 +445,10 @@ func TestEnvVarValue(t *testing.T) {
},
},
CtrSpecGenOptions{
- PodName: value,
+ PodName: "test",
},
true,
- &value,
+ "test",
},
{
"FieldRefMetadataUID",
@@ -459,10 +461,10 @@ func TestEnvVarValue(t *testing.T) {
},
},
CtrSpecGenOptions{
- PodID: value,
+ PodID: "ec71ff37c67b688598c0008187ab0960dc34e1dfdcbf3a74e3d778bafcfe0977",
},
true,
- &value,
+ "ec71ff37c67b688598c0008187ab0960dc34e1dfdcbf3a74e3d778bafcfe0977",
},
{
"FieldRefMetadataLabelsExist",
@@ -475,10 +477,10 @@ func TestEnvVarValue(t *testing.T) {
},
},
CtrSpecGenOptions{
- Labels: map[string]string{"label": value},
+ Labels: map[string]string{"label": "label"},
},
true,
- &value,
+ "label",
},
{
"FieldRefMetadataLabelsEmpty",
@@ -494,7 +496,7 @@ func TestEnvVarValue(t *testing.T) {
Labels: map[string]string{"label": ""},
},
true,
- &emptyValue,
+ "",
},
{
"FieldRefMetadataLabelsNotExist",
@@ -508,7 +510,7 @@ func TestEnvVarValue(t *testing.T) {
},
CtrSpecGenOptions{},
true,
- &emptyValue,
+ "",
},
{
"FieldRefMetadataAnnotationsExist",
@@ -521,10 +523,10 @@ func TestEnvVarValue(t *testing.T) {
},
},
CtrSpecGenOptions{
- Annotations: map[string]string{"annotation": value},
+ Annotations: map[string]string{"annotation": "annotation"},
},
true,
- &value,
+ "annotation",
},
{
"FieldRefMetadataAnnotationsEmpty",
@@ -540,7 +542,7 @@ func TestEnvVarValue(t *testing.T) {
Annotations: map[string]string{"annotation": ""},
},
true,
- &emptyValue,
+ "",
},
{
"FieldRefMetadataAnnotationsNotExist",
@@ -554,7 +556,7 @@ func TestEnvVarValue(t *testing.T) {
},
CtrSpecGenOptions{},
true,
- &emptyValue,
+ "",
},
{
"FieldRefInvalid1",
@@ -568,7 +570,7 @@ func TestEnvVarValue(t *testing.T) {
},
CtrSpecGenOptions{},
false,
- nil,
+ nilString,
},
{
"FieldRefInvalid2",
@@ -582,7 +584,7 @@ func TestEnvVarValue(t *testing.T) {
},
CtrSpecGenOptions{},
false,
- nil,
+ nilString,
},
{
"FieldRefNotSupported",
@@ -596,7 +598,101 @@ func TestEnvVarValue(t *testing.T) {
},
CtrSpecGenOptions{},
false,
- nil,
+ nilString,
+ },
+ {
+ "ResourceFieldRefNotSupported",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ ResourceFieldRef: &v1.ResourceFieldSelector{
+ Resource: "limits.dummy",
+ },
+ },
+ },
+ CtrSpecGenOptions{},
+ false,
+ nilString,
+ },
+ {
+ "ResourceFieldRefMemoryDivisorNotValid",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ ResourceFieldRef: &v1.ResourceFieldSelector{
+ Resource: "limits.memory",
+ Divisor: resource.MustParse("2M"),
+ },
+ },
+ },
+ CtrSpecGenOptions{},
+ false,
+ nilString,
+ },
+ {
+ "ResourceFieldRefCpuDivisorNotValid",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ ResourceFieldRef: &v1.ResourceFieldSelector{
+ Resource: "limits.cpu",
+ Divisor: resource.MustParse("2m"),
+ },
+ },
+ },
+ CtrSpecGenOptions{},
+ false,
+ nilString,
+ },
+ {
+ "ResourceFieldRefNoDivisor",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ ResourceFieldRef: &v1.ResourceFieldSelector{
+ Resource: "limits.memory",
+ },
+ },
+ },
+ CtrSpecGenOptions{
+ Container: container,
+ },
+ true,
+ memoryString,
+ },
+ {
+ "ResourceFieldRefMemoryDivisor",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ ResourceFieldRef: &v1.ResourceFieldSelector{
+ Resource: "limits.memory",
+ Divisor: resource.MustParse("1Mi"),
+ },
+ },
+ },
+ CtrSpecGenOptions{
+ Container: container,
+ },
+ true,
+ strconv.Itoa(int(math.Ceil(float64(memoryInt) / 1024 / 1024))),
+ },
+ {
+ "ResourceFieldRefCpuDivisor",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ ResourceFieldRef: &v1.ResourceFieldSelector{
+ Resource: "requests.cpu",
+ Divisor: resource.MustParse("1m"),
+ },
+ },
+ },
+ CtrSpecGenOptions{
+ Container: container,
+ },
+ true,
+ strconv.Itoa(int(float64(cpuInt) / 0.001)),
},
}
@@ -605,59 +701,85 @@ func TestEnvVarValue(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
result, err := envVarValue(test.envVar, &test.options)
assert.Equal(t, err == nil, test.succeed)
- assert.Equal(t, test.expected, result)
+ if test.expected == nilString {
+ assert.Nil(t, result)
+ } else {
+ fmt.Println(*result, test.expected)
+ assert.Equal(t, &(test.expected), result)
+ }
})
}
}
-var configMapList = []v1.ConfigMap{
- {
- TypeMeta: v12.TypeMeta{
- Kind: "ConfigMap",
- },
- ObjectMeta: v12.ObjectMeta{
- Name: "bar",
- },
- Data: map[string]string{
- "myvar": "bar",
- },
- },
- {
- TypeMeta: v12.TypeMeta{
- Kind: "ConfigMap",
- },
- ObjectMeta: v12.ObjectMeta{
- Name: "foo",
+var (
+ nilString = "<nil>"
+ configMapList = []v1.ConfigMap{
+ {
+ TypeMeta: v12.TypeMeta{
+ Kind: "ConfigMap",
+ },
+ ObjectMeta: v12.ObjectMeta{
+ Name: "bar",
+ },
+ Data: map[string]string{
+ "myvar": "bar",
+ },
},
- Data: map[string]string{
- "myvar": "foo",
+ {
+ TypeMeta: v12.TypeMeta{
+ Kind: "ConfigMap",
+ },
+ ObjectMeta: v12.ObjectMeta{
+ Name: "foo",
+ },
+ Data: map[string]string{
+ "myvar": "foo",
+ },
},
- },
-}
+ }
-var optional = true
+ optional = true
-var k8sSecrets = []v1.Secret{
- {
- TypeMeta: v12.TypeMeta{
- Kind: "Secret",
- },
- ObjectMeta: v12.ObjectMeta{
- Name: "bar",
- },
- Data: map[string][]byte{
- "myvar": []byte("bar"),
- },
- },
- {
- TypeMeta: v12.TypeMeta{
- Kind: "Secret",
+ k8sSecrets = []v1.Secret{
+ {
+ TypeMeta: v12.TypeMeta{
+ Kind: "Secret",
+ },
+ ObjectMeta: v12.ObjectMeta{
+ Name: "bar",
+ },
+ Data: map[string][]byte{
+ "myvar": []byte("bar"),
+ },
},
- ObjectMeta: v12.ObjectMeta{
- Name: "foo",
+ {
+ TypeMeta: v12.TypeMeta{
+ Kind: "Secret",
+ },
+ ObjectMeta: v12.ObjectMeta{
+ Name: "foo",
+ },
+ Data: map[string][]byte{
+ "myvar": []byte("foo"),
+ },
},
- Data: map[string][]byte{
- "myvar": []byte("foo"),
+ }
+
+ cpuInt = 4
+ cpuString = strconv.Itoa(cpuInt)
+ memoryInt = 30000000
+ memoryString = strconv.Itoa(memoryInt)
+ container = v1.Container{
+ Name: "test",
+ Resources: v1.ResourceRequirements{
+ Limits: v1.ResourceList{
+ v1.ResourceCPU: resource.MustParse(cpuString),
+ v1.ResourceMemory: resource.MustParse(memoryString),
+ },
+ Requests: v1.ResourceList{
+ v1.ResourceCPU: resource.MustParse(cpuString),
+ v1.ResourceMemory: resource.MustParse(memoryString),
+ },
},
- },
-}
+ }
+)
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index 93d9caf4c..3f77cbe76 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -482,7 +482,7 @@ func GetNamespaceOptions(ns []string, netnsIsHost bool) ([]libpod.PodCreateOptio
for _, toShare := range ns {
switch toShare {
case "cgroup":
- options = append(options, libpod.WithPodCgroups())
+ options = append(options, libpod.WithPodCgroup())
case "net":
// share the netns setting with other containers in the pod only when it is not set to host
if !netnsIsHost {
diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go
index 03829e8cf..68fda3ad7 100644
--- a/pkg/specgen/generate/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -166,6 +166,9 @@ func createPodOptions(p *specgen.PodSpecGenerator, rt *libpod.Runtime, infraSpec
)
if !p.NoInfra { //&& infraSpec != nil {
options = append(options, libpod.WithInfraContainer())
+ if p.ShareParent == nil || (p.ShareParent != nil && *p.ShareParent) {
+ options = append(options, libpod.WithPodParent())
+ }
nsOptions, err := GetNamespaceOptions(p.SharedNamespaces, p.InfraContainerSpec.NetNS.IsHost())
if err != nil {
return nil, err
diff --git a/pkg/specgen/namespaces.go b/pkg/specgen/namespaces.go
index f61937078..e672bc65f 100644
--- a/pkg/specgen/namespaces.go
+++ b/pkg/specgen/namespaces.go
@@ -57,7 +57,7 @@ const (
// DefaultKernelNamespaces is a comma-separated list of default kernel
// namespaces.
- DefaultKernelNamespaces = "cgroup,ipc,net,uts"
+ DefaultKernelNamespaces = "ipc,net,uts"
)
// Namespace describes the namespace
diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go
index 91b2599cc..759caa0c0 100644
--- a/pkg/specgen/podspecgen.go
+++ b/pkg/specgen/podspecgen.go
@@ -63,6 +63,8 @@ type PodBasicConfig struct {
// also be used by some tools that wish to recreate the pod
// (e.g. `podman generate systemd --new`).
// Optional.
+ // ShareParent determines if all containers in the pod will share the pod's cgroup as the cgroup parent
+ ShareParent *bool `json:"share_parent,omitempty"`
PodCreateCommand []string `json:"pod_create_command,omitempty"`
// Pid sets the process id namespace of the pod
// Optional (defaults to private if unset). This sets the PID namespace of the infra container