Merge pull request #13939 from pmorie/pod-sc-minimal

Add PodSecurityContext and backward compatibility tests
This commit is contained in:
Derek Carr 2015-10-07 09:56:58 -04:00
commit 87fe1f4af8
41 changed files with 717 additions and 236 deletions

View File

@ -12646,6 +12646,10 @@
"type": "boolean",
"description": "Use the host's ipc namespace. Optional: Default to false."
},
"securityContext": {
"$ref": "v1.PodSecurityContext",
"description": "SecurityContext holds pod-level security attributes and common container settings"
},
"imagePullSecrets": {
"type": "array",
"items": {
@ -13201,6 +13205,11 @@
}
}
},
"v1.PodSecurityContext": {
"id": "v1.PodSecurityContext",
"description": "PodSecurityContext holds pod-level security attributes and common container settings.",
"properties": {}
},
"v1.PodStatus": {
"id": "v1.PodStatus",
"description": "PodStatus represents information about the status of a pod. Status may trail the actual state of a system.",

View File

@ -24,6 +24,9 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/util"
"github.com/google/gofuzz"
)
func TestDeepCopyApiObjects(t *testing.T) {
@ -31,21 +34,34 @@ func TestDeepCopyApiObjects(t *testing.T) {
for _, version := range []string{"", testapi.Default.Version()} {
f := apitesting.FuzzerFor(t, version, rand.NewSource(rand.Int63()))
for kind := range api.Scheme.KnownTypes(version) {
item, err := api.Scheme.New(version, kind)
if err != nil {
t.Fatalf("Could not create a %s: %s", kind, err)
}
f.Fuzz(item)
itemCopy, err := api.Scheme.DeepCopy(item)
if err != nil {
t.Errorf("Could not deep copy a %s: %s", kind, err)
continue
}
if !reflect.DeepEqual(item, itemCopy) {
t.Errorf("\nexpected %#v\ngot %#v", item, itemCopy)
}
doDeepCopyTest(t, version, kind, f)
}
}
}
}
func doDeepCopyTest(t *testing.T, version, kind string, f *fuzz.Fuzzer) {
item, err := api.Scheme.New(version, kind)
if err != nil {
t.Fatalf("Could not create a %s: %s", kind, err)
}
f.Fuzz(item)
itemCopy, err := api.Scheme.DeepCopy(item)
if err != nil {
t.Errorf("Could not deep copy a %s: %s", kind, err)
return
}
if !reflect.DeepEqual(item, itemCopy) {
t.Errorf("\nexpected: %#v\n\ngot: %#v\n\ndiff: %v", item, itemCopy, util.ObjectDiff(item, itemCopy))
}
}
func TestDeepCopySingleType(t *testing.T) {
for i := 0; i < *fuzzIters; i++ {
for _, version := range []string{"", testapi.Default.Version()} {
f := apitesting.FuzzerFor(t, version, rand.NewSource(rand.Int63()))
doDeepCopyTest(t, version, "Pod", f)
}
}
}

View File

@ -1481,6 +1481,13 @@ func deepCopy_api_PodProxyOptions(in PodProxyOptions, out *PodProxyOptions, c *c
return nil
}
func deepCopy_api_PodSecurityContext(in PodSecurityContext, out *PodSecurityContext, c *conversion.Cloner) error {
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
return nil
}
func deepCopy_api_PodSpec(in PodSpec, out *PodSpec, c *conversion.Cloner) error {
if in.Volumes != nil {
out.Volumes = make([]Volume, len(in.Volumes))
@ -1526,9 +1533,14 @@ func deepCopy_api_PodSpec(in PodSpec, out *PodSpec, c *conversion.Cloner) error
}
out.ServiceAccountName = in.ServiceAccountName
out.NodeName = in.NodeName
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
if in.SecurityContext != nil {
out.SecurityContext = new(PodSecurityContext)
if err := deepCopy_api_PodSecurityContext(*in.SecurityContext, out.SecurityContext, c); err != nil {
return err
}
} else {
out.SecurityContext = nil
}
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {
@ -2380,6 +2392,7 @@ func init() {
deepCopy_api_PodList,
deepCopy_api_PodLogOptions,
deepCopy_api_PodProxyOptions,
deepCopy_api_PodSecurityContext,
deepCopy_api_PodSpec,
deepCopy_api_PodStatus,
deepCopy_api_PodStatusResult,

View File

@ -108,7 +108,7 @@ func TestSpecificKind(t *testing.T) {
api.Scheme.Log(t)
defer api.Scheme.Log(nil)
kind := "PodList"
kind := "Pod"
doRoundTripTest(kind, t)
}
@ -169,6 +169,8 @@ func TestEncode_Ptr(t *testing.T) {
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
SecurityContext: &api.PodSecurityContext{},
},
}
obj := runtime.Object(pod)
@ -181,7 +183,8 @@ func TestEncode_Ptr(t *testing.T) {
t.Fatalf("Got wrong type")
}
if !api.Semantic.DeepEqual(obj2, pod) {
t.Errorf("Expected:\n %#v,\n Got:\n %#v", pod, obj2)
t.Errorf("\nExpected:\n\n %#v,\n\nGot:\n\n %#vDiff: %v\n\n", pod, obj2, util.ObjectDiff(obj2, pod))
}
}

View File

@ -0,0 +1,144 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package compat
import (
"encoding/json"
"fmt"
"os"
"reflect"
"regexp"
"strconv"
"strings"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/fielderrors"
"k8s.io/kubernetes/pkg/kubectl"
)
// Based on: https://github.com/openshift/origin/blob/master/pkg/api/compatibility_test.go
//
// TestCompatibility reencodes the input using the codec for the given
// version and checks for the presence of the expected keys and absent
// keys in the resulting JSON.
func TestCompatibility(
t *testing.T,
version string,
input []byte,
validator func(obj runtime.Object) fielderrors.ValidationErrorList,
expectedKeys map[string]string,
absentKeys []string,
) {
// Decode
codec := runtime.CodecFor(api.Scheme, version)
obj, err := codec.Decode(input)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
// Validate
errs := validator(obj)
if len(errs) != 0 {
t.Fatalf("Unexpected validation errors: %v", errs)
}
// Encode
output, err := codec.Encode(obj)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
// Validate old and new fields are encoded
generic := map[string]interface{}{}
if err := json.Unmarshal(output, &generic); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
hasError := false
for k, expectedValue := range expectedKeys {
keys := strings.Split(k, ".")
if actualValue, ok, err := getJSONValue(generic, keys...); err != nil || !ok {
t.Errorf("Unexpected error for %s: %v", k, err)
hasError = true
} else if !reflect.DeepEqual(expectedValue, fmt.Sprintf("%v", actualValue)) {
hasError = true
t.Errorf("Unexpected value for %v: expected %v, got %v", k, expectedValue, actualValue)
}
}
for _, absentKey := range absentKeys {
keys := strings.Split(absentKey, ".")
actualValue, ok, err := getJSONValue(generic, keys...)
if err == nil || ok {
t.Errorf("Unexpected value found for for key %s: %v", absentKey, actualValue)
hasError = true
}
}
if hasError {
printer := new(kubectl.JSONPrinter)
printer.PrintObj(obj, os.Stdout)
t.Logf("2: Encoded value: %#v", string(output))
}
}
func getJSONValue(data map[string]interface{}, keys ...string) (interface{}, bool, error) {
// No keys, current value is it
if len(keys) == 0 {
return data, true, nil
}
// Get the key (and optional index)
key := keys[0]
index := -1
if matches := regexp.MustCompile(`^(.*)\[(\d+)\]$`).FindStringSubmatch(key); len(matches) > 0 {
key = matches[1]
index, _ = strconv.Atoi(matches[2])
}
// Look up the value
value, ok := data[key]
if !ok {
return nil, false, fmt.Errorf("No key %s found", key)
}
// Get the indexed value if an index is specified
if index >= 0 {
valueSlice, ok := value.([]interface{})
if !ok {
return nil, false, fmt.Errorf("Key %s did not hold a slice", key)
}
if index >= len(valueSlice) {
return nil, false, fmt.Errorf("Index %d out of bounds for slice at key: %v", index, key)
}
value = valueSlice[index]
}
if len(keys) == 1 {
return value, true, nil
}
childData, ok := value.(map[string]interface{})
if !ok {
return nil, false, fmt.Errorf("Key %s did not hold a map", keys[0])
}
return getJSONValue(childData, keys[1:]...)
}

View File

@ -92,14 +92,18 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
j.LabelSelector, _ = labels.Parse("a=b")
j.FieldSelector, _ = fields.ParseSelector("a=b")
},
func(j *api.PodSpec, c fuzz.Continue) {
c.FuzzNoCustom(j)
func(s *api.PodSpec, c fuzz.Continue) {
c.FuzzNoCustom(s)
// has a default value
ttl := int64(30)
if c.RandBool() {
ttl = int64(c.Uint32())
}
j.TerminationGracePeriodSeconds = &ttl
s.TerminationGracePeriodSeconds = &ttl
if s.SecurityContext == nil {
s.SecurityContext = &api.PodSecurityContext{}
}
},
func(j *api.PodPhase, c fuzz.Continue) {
statuses := []api.PodPhase{api.PodPending, api.PodRunning, api.PodFailed, api.PodUnknown}

View File

@ -0,0 +1,32 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testing
import (
"k8s.io/kubernetes/pkg/api"
)
// DeepEqualSafePodSpec returns a PodSpec which is ready to be used with api.Semantic.DeepEqual
func DeepEqualSafePodSpec() api.PodSpec {
grace := int64(30)
return api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
SecurityContext: &api.PodSecurityContext{},
}
}

View File

@ -986,20 +986,27 @@ type PodSpec struct {
// the scheduler simply schedules this pod onto that node, assuming that it fits resource
// requirements.
NodeName string `json:"nodeName,omitempty"`
// Use the host's network namespace. If this option is set, the ports that will be
// SecurityContext holds pod-level security attributes and common container settings
SecurityContext *PodSecurityContext `json:"securityContext,omitempty"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
// in the case of docker, only DockerConfig type secrets are honored.
ImagePullSecrets []LocalObjectReference `json:"imagePullSecrets,omitempty"`
}
// PodSecurityContext holds pod-level security attributes and common container settings.
type PodSecurityContext struct {
// Use the host's network namespace. If this option is set, the ports that will be
// used must be specified.
// Optional: Default to false.
// Optional: Default to false
HostNetwork bool `json:"hostNetwork,omitempty"`
// Use the host's pid namespace.
// Optional: Default to false.
HostPID bool `json:"hostPID,omitempty"`
// Use the host's ipc namespace.
// Optional: Default to false.
HostIPC bool `json:"hostIPC,omitempty"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
// in the case of docker, only DockerConfig type secrets are honored.
ImagePullSecrets []LocalObjectReference `json:"imagePullSecrets,omitempty"`
}
// PodStatus represents information about the status of a pod. Status may trail the actual

View File

@ -0,0 +1,166 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1_test
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testing/compat"
"k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/fielderrors"
)
func TestCompatibility_v1_PodSecurityContext(t *testing.T) {
cases := []struct {
name string
input string
expectedKeys map[string]string
absentKeys []string
}{
{
name: "hostNetwork = true",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostNetwork": true,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
expectedKeys: map[string]string{
"spec.hostNetwork": "true",
},
},
{
name: "hostNetwork = false",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostNetwork": false,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
absentKeys: []string{
"spec.hostNetwork",
},
},
{
name: "hostIPC = true",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostIPC": true,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
expectedKeys: map[string]string{
"spec.hostIPC": "true",
},
},
{
name: "hostIPC = false",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostIPC": false,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
absentKeys: []string{
"spec.hostIPC",
},
},
{
name: "hostPID = true",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostPID": true,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
expectedKeys: map[string]string{
"spec.hostPID": "true",
},
},
{
name: "hostPID = false",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostPID": false,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
absentKeys: []string{
"spec.hostPID",
},
},
}
validator := func(obj runtime.Object) fielderrors.ValidationErrorList {
return validation.ValidatePodSpec(&(obj.(*api.Pod).Spec))
}
for _, tc := range cases {
t.Logf("Testing 1.0.0 backward compatibility for %v", tc.name)
compat.TestCompatibility(t, "v1", []byte(tc.input), validator, tc.expectedKeys, tc.absentKeys)
}
}

View File

@ -283,9 +283,16 @@ func convert_api_PodSpec_To_v1_PodSpec(in *api.PodSpec, out *PodSpec, s conversi
// DeprecatedServiceAccount is an alias for ServiceAccountName.
out.DeprecatedServiceAccount = in.ServiceAccountName
out.NodeName = in.NodeName
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
if in.SecurityContext != nil {
out.SecurityContext = new(PodSecurityContext)
if err := convert_api_PodSecurityContext_To_v1_PodSecurityContext(in.SecurityContext, out.SecurityContext, s); err != nil {
return err
}
out.HostPID = in.SecurityContext.HostPID
out.HostNetwork = in.SecurityContext.HostNetwork
out.HostIPC = in.SecurityContext.HostIPC
}
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {
@ -352,9 +359,18 @@ func convert_v1_PodSpec_To_api_PodSpec(in *PodSpec, out *api.PodSpec, s conversi
out.ServiceAccountName = in.DeprecatedServiceAccount
}
out.NodeName = in.NodeName
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
if in.SecurityContext != nil {
out.SecurityContext = new(api.PodSecurityContext)
if err := convert_v1_PodSecurityContext_To_api_PodSecurityContext(in.SecurityContext, out.SecurityContext, s); err != nil {
return err
}
}
if out.SecurityContext == nil {
out.SecurityContext = new(api.PodSecurityContext)
}
out.SecurityContext.HostNetwork = in.HostNetwork
out.SecurityContext.HostPID = in.HostPID
out.SecurityContext.HostIPC = in.HostIPC
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {
@ -392,3 +408,17 @@ func convert_v1_ServiceSpec_To_api_ServiceSpec(in *ServiceSpec, out *api.Service
}
return nil
}
func convert_api_PodSecurityContext_To_v1_PodSecurityContext(in *api.PodSecurityContext, out *PodSecurityContext, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*api.PodSecurityContext))(in)
}
return nil
}
func convert_v1_PodSecurityContext_To_api_PodSecurityContext(in *PodSecurityContext, out *api.PodSecurityContext, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*PodSecurityContext))(in)
}
return nil
}

View File

@ -2084,9 +2084,13 @@ func autoconvert_api_PodSpec_To_v1_PodSpec(in *api.PodSpec, out *PodSpec, s conv
}
out.ServiceAccountName = in.ServiceAccountName
out.NodeName = in.NodeName
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
if in.SecurityContext != nil {
if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil {
return err
}
} else {
out.SecurityContext = nil
}
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {
@ -5094,9 +5098,16 @@ func autoconvert_v1_PodSpec_To_api_PodSpec(in *PodSpec, out *api.PodSpec, s conv
out.ServiceAccountName = in.ServiceAccountName
// in.DeprecatedServiceAccount has no peer in out
out.NodeName = in.NodeName
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
// in.HostNetwork has no peer in out
// in.HostPID has no peer in out
// in.HostIPC has no peer in out
if in.SecurityContext != nil {
if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil {
return err
}
} else {
out.SecurityContext = nil
}
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {

View File

@ -1501,6 +1501,10 @@ func deepCopy_v1_PodProxyOptions(in PodProxyOptions, out *PodProxyOptions, c *co
return nil
}
func deepCopy_v1_PodSecurityContext(in PodSecurityContext, out *PodSecurityContext, c *conversion.Cloner) error {
return nil
}
func deepCopy_v1_PodSpec(in PodSpec, out *PodSpec, c *conversion.Cloner) error {
if in.Volumes != nil {
out.Volumes = make([]Volume, len(in.Volumes))
@ -1550,6 +1554,14 @@ func deepCopy_v1_PodSpec(in PodSpec, out *PodSpec, c *conversion.Cloner) error {
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
if in.SecurityContext != nil {
out.SecurityContext = new(PodSecurityContext)
if err := deepCopy_v1_PodSecurityContext(*in.SecurityContext, out.SecurityContext, c); err != nil {
return err
}
} else {
out.SecurityContext = nil
}
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {
@ -2393,6 +2405,7 @@ func init() {
deepCopy_v1_PodList,
deepCopy_v1_PodLogOptions,
deepCopy_v1_PodProxyOptions,
deepCopy_v1_PodSecurityContext,
deepCopy_v1_PodSpec,
deepCopy_v1_PodStatus,
deepCopy_v1_PodStatusResult,

View File

@ -116,6 +116,9 @@ func addDefaultingFuncs() {
if obj.HostNetwork {
defaultHostNetworkPorts(&obj.Containers)
}
if obj.SecurityContext == nil {
obj.SecurityContext = &PodSecurityContext{}
}
if obj.TerminationGracePeriodSeconds == nil {
period := int64(DefaultTerminationGracePeriodSeconds)
obj.TerminationGracePeriodSeconds = &period

View File

@ -1238,6 +1238,8 @@ type PodSpec struct {
// Use the host's ipc namespace.
// Optional: Default to false.
HostIPC bool `json:"hostIPC,omitempty"`
// SecurityContext holds pod-level security attributes and common container settings
SecurityContext *PodSecurityContext `json:"securityContext,omitempty"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
// in the case of docker, only DockerConfig type secrets are honored.
@ -1245,6 +1247,10 @@ type PodSpec struct {
ImagePullSecrets []LocalObjectReference `json:"imagePullSecrets,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
}
// PodSecurityContext holds pod-level security attributes and common container settings.
type PodSecurityContext struct {
}
// PodStatus represents information about the status of a pod. Status may trail the actual
// state of a system.
type PodStatus struct {

View File

@ -973,6 +973,14 @@ func (PodProxyOptions) SwaggerDoc() map[string]string {
return map_PodProxyOptions
}
var map_PodSecurityContext = map[string]string{
"": "PodSecurityContext holds pod-level security attributes and common container settings.",
}
func (PodSecurityContext) SwaggerDoc() map[string]string {
return map_PodSecurityContext
}
var map_PodSpec = map[string]string{
"": "PodSpec is a description of a pod.",
"volumes": "List of volumes that can be mounted by containers belonging to the pod. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md",
@ -988,6 +996,7 @@ var map_PodSpec = map[string]string{
"hostNetwork": "Host networking requested for this pod. Use the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false.",
"hostPID": "Use the host's pid namespace. Optional: Default to false.",
"hostIPC": "Use the host's ipc namespace. Optional: Default to false.",
"securityContext": "SecurityContext holds pod-level security attributes and common container settings",
"imagePullSecrets": "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. For example, in the case of docker, only DockerConfig type secrets are honored. More info: http://releases.k8s.io/HEAD/docs/user-guide/images.md#specifying-imagepullsecrets-on-a-pod",
}

View File

@ -1107,7 +1107,7 @@ func ValidatePodSpec(spec *api.PodSpec) errs.ValidationErrorList {
allErrs = append(allErrs, validateRestartPolicy(&spec.RestartPolicy).Prefix("restartPolicy")...)
allErrs = append(allErrs, validateDNSPolicy(&spec.DNSPolicy).Prefix("dnsPolicy")...)
allErrs = append(allErrs, ValidateLabels(spec.NodeSelector, "nodeSelector")...)
allErrs = append(allErrs, validateHostNetwork(spec.HostNetwork, spec.Containers).Prefix("hostNetwork")...)
allErrs = append(allErrs, ValidatePodSecurityContext(spec.SecurityContext, spec).Prefix("securityContext")...)
allErrs = append(allErrs, validateImagePullSecrets(spec.ImagePullSecrets).Prefix("imagePullSecrets")...)
if len(spec.ServiceAccountName) > 0 {
if ok, msg := ValidateServiceAccountName(spec.ServiceAccountName, false); !ok {
@ -1123,6 +1123,17 @@ func ValidatePodSpec(spec *api.PodSpec) errs.ValidationErrorList {
return allErrs
}
// ValidatePodSecurityContext test that the specified PodSecurityContext has valid data.
func ValidatePodSecurityContext(securityContext *api.PodSecurityContext, spec *api.PodSpec) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
if securityContext != nil {
allErrs = append(allErrs, validateHostNetwork(securityContext.HostNetwork, spec.Containers).Prefix("hostNetwork")...)
}
return allErrs
}
// ValidatePodUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
// that cannot be changed.
func ValidatePodUpdate(newPod, oldPod *api.Pod) errs.ValidationErrorList {

View File

@ -1259,20 +1259,25 @@ func TestValidatePodSpec(t *testing.T) {
{HostPort: 8080, ContainerPort: 8080, Protocol: "TCP"}},
},
},
HostNetwork: true,
HostIPC: true,
SecurityContext: &api.PodSecurityContext{
HostNetwork: true,
},
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
},
{ // Populate HostIPC.
HostIPC: true,
SecurityContext: &api.PodSecurityContext{
HostIPC: true,
},
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
},
{ // Populate HostPID.
HostPID: true,
SecurityContext: &api.PodSecurityContext{
HostPID: true,
},
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
RestartPolicy: api.RestartPolicyAlways,
@ -1324,7 +1329,9 @@ func TestValidatePodSpec(t *testing.T) {
{HostPort: 8080, ContainerPort: 2600, Protocol: "TCP"}},
},
},
HostNetwork: true,
SecurityContext: &api.PodSecurityContext{
HostNetwork: true,
},
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
},

View File

@ -459,6 +459,13 @@ func deepCopy_api_PersistentVolumeClaimVolumeSource(in api.PersistentVolumeClaim
return nil
}
func deepCopy_api_PodSecurityContext(in api.PodSecurityContext, out *api.PodSecurityContext, c *conversion.Cloner) error {
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
return nil
}
func deepCopy_api_PodSpec(in api.PodSpec, out *api.PodSpec, c *conversion.Cloner) error {
if in.Volumes != nil {
out.Volumes = make([]api.Volume, len(in.Volumes))
@ -504,9 +511,14 @@ func deepCopy_api_PodSpec(in api.PodSpec, out *api.PodSpec, c *conversion.Cloner
}
out.ServiceAccountName = in.ServiceAccountName
out.NodeName = in.NodeName
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
if in.SecurityContext != nil {
out.SecurityContext = new(api.PodSecurityContext)
if err := deepCopy_api_PodSecurityContext(*in.SecurityContext, out.SecurityContext, c); err != nil {
return err
}
} else {
out.SecurityContext = nil
}
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {
@ -1525,6 +1537,7 @@ func init() {
deepCopy_api_ObjectFieldSelector,
deepCopy_api_ObjectMeta,
deepCopy_api_PersistentVolumeClaimVolumeSource,
deepCopy_api_PodSecurityContext,
deepCopy_api_PodSpec,
deepCopy_api_PodTemplateSpec,
deepCopy_api_Probe,

View File

@ -97,9 +97,16 @@ func convert_api_PodSpec_To_v1_PodSpec(in *api.PodSpec, out *v1.PodSpec, s conve
// DeprecatedServiceAccount is an alias for ServiceAccountName.
out.DeprecatedServiceAccount = in.ServiceAccountName
out.NodeName = in.NodeName
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
if in.SecurityContext != nil {
out.SecurityContext = new(v1.PodSecurityContext)
if err := convert_api_PodSecurityContext_To_v1_PodSecurityContext(in.SecurityContext, out.SecurityContext, s); err != nil {
return err
}
out.HostNetwork = in.SecurityContext.HostNetwork
out.HostPID = in.SecurityContext.HostPID
out.HostIPC = in.SecurityContext.HostIPC
}
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]v1.LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {
@ -166,9 +173,19 @@ func convert_v1_PodSpec_To_api_PodSpec(in *v1.PodSpec, out *api.PodSpec, s conve
out.ServiceAccountName = in.DeprecatedServiceAccount
}
out.NodeName = in.NodeName
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
if in.SecurityContext != nil {
out.SecurityContext = new(api.PodSecurityContext)
if err := convert_v1_PodSecurityContext_To_api_PodSecurityContext(in.SecurityContext, out.SecurityContext, s); err != nil {
return err
}
}
if out.SecurityContext == nil {
out.SecurityContext = new(api.PodSecurityContext)
}
out.SecurityContext.HostNetwork = in.HostNetwork
out.SecurityContext.HostPID = in.HostPID
out.SecurityContext.HostIPC = in.HostIPC
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {
@ -309,3 +326,17 @@ func convert_v1alpha1_RollingUpdateDeployment_To_experimental_RollingUpdateDeplo
out.MinReadySeconds = in.MinReadySeconds
return nil
}
func convert_api_PodSecurityContext_To_v1_PodSecurityContext(in *api.PodSecurityContext, out *v1.PodSecurityContext, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*api.PodSecurityContext))(in)
}
return nil
}
func convert_v1_PodSecurityContext_To_api_PodSecurityContext(in *v1.PodSecurityContext, out *api.PodSecurityContext, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*v1.PodSecurityContext))(in)
}
return nil
}

View File

@ -708,9 +708,13 @@ func autoconvert_api_PodSpec_To_v1_PodSpec(in *api.PodSpec, out *v1.PodSpec, s c
}
out.ServiceAccountName = in.ServiceAccountName
out.NodeName = in.NodeName
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
if in.SecurityContext != nil {
if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil {
return err
}
} else {
out.SecurityContext = nil
}
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]v1.LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {
@ -1755,9 +1759,16 @@ func autoconvert_v1_PodSpec_To_api_PodSpec(in *v1.PodSpec, out *api.PodSpec, s c
out.ServiceAccountName = in.ServiceAccountName
// in.DeprecatedServiceAccount has no peer in out
out.NodeName = in.NodeName
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
// in.HostNetwork has no peer in out
// in.HostPID has no peer in out
// in.HostIPC has no peer in out
if in.SecurityContext != nil {
if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil {
return err
}
} else {
out.SecurityContext = nil
}
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {

View File

@ -497,6 +497,10 @@ func deepCopy_v1_PersistentVolumeClaimVolumeSource(in v1.PersistentVolumeClaimVo
return nil
}
func deepCopy_v1_PodSecurityContext(in v1.PodSecurityContext, out *v1.PodSecurityContext, c *conversion.Cloner) error {
return nil
}
func deepCopy_v1_PodSpec(in v1.PodSpec, out *v1.PodSpec, c *conversion.Cloner) error {
if in.Volumes != nil {
out.Volumes = make([]v1.Volume, len(in.Volumes))
@ -546,6 +550,14 @@ func deepCopy_v1_PodSpec(in v1.PodSpec, out *v1.PodSpec, c *conversion.Cloner) e
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
if in.SecurityContext != nil {
out.SecurityContext = new(v1.PodSecurityContext)
if err := deepCopy_v1_PodSecurityContext(*in.SecurityContext, out.SecurityContext, c); err != nil {
return err
}
} else {
out.SecurityContext = nil
}
if in.ImagePullSecrets != nil {
out.ImagePullSecrets = make([]v1.LocalObjectReference, len(in.ImagePullSecrets))
for i := range in.ImagePullSecrets {
@ -1551,6 +1563,7 @@ func init() {
deepCopy_v1_ObjectFieldSelector,
deepCopy_v1_ObjectMeta,
deepCopy_v1_PersistentVolumeClaimVolumeSource,
deepCopy_v1_PodSecurityContext,
deepCopy_v1_PodSpec,
deepCopy_v1_PodTemplateSpec,
deepCopy_v1_Probe,

View File

@ -29,6 +29,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/unversioned"
client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/fake"
@ -39,7 +40,6 @@ import (
)
func testData() (*api.PodList, *api.ServiceList, *api.ReplicationControllerList) {
grace := int64(30)
pods := &api.PodList{
ListMeta: unversioned.ListMeta{
ResourceVersion: "15",
@ -47,19 +47,11 @@ func testData() (*api.PodList, *api.ServiceList, *api.ReplicationControllerList)
Items: []api.Pod{
{
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
{
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "test", ResourceVersion: "11"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
},
}
@ -567,7 +559,6 @@ func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) {
}
}
func watchTestData() ([]api.Pod, []watch.Event) {
grace := int64(30)
pods := []api.Pod{
{
ObjectMeta: api.ObjectMeta{
@ -575,11 +566,7 @@ func watchTestData() ([]api.Pod, []watch.Event) {
Namespace: "test",
ResourceVersion: "10",
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
}
events := []watch.Event{
@ -591,11 +578,7 @@ func watchTestData() ([]api.Pod, []watch.Event) {
Namespace: "test",
ResourceVersion: "11",
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
},
{
@ -606,11 +589,7 @@ func watchTestData() ([]api.Pod, []watch.Event) {
Namespace: "test",
ResourceVersion: "12",
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
},
}
@ -652,7 +631,7 @@ func TestWatchSelector(t *testing.T) {
expected := []runtime.Object{&api.PodList{Items: pods}, events[0].Object, events[1].Object}
actual := tf.Printer.(*testPrinter).Objects
if !reflect.DeepEqual(expected, actual) {
t.Errorf("unexpected object: %#v %#v", expected[0], actual[0])
t.Errorf("unexpected object:\nExpected: %#v\n\nGot: %#v\n\n", expected[0], actual[0])
}
if len(buf.String()) == 0 {
t.Errorf("unexpected empty output")
@ -690,7 +669,7 @@ func TestWatchResource(t *testing.T) {
expected := []runtime.Object{&pods[0], events[0].Object, events[1].Object}
actual := tf.Printer.(*testPrinter).Objects
if !reflect.DeepEqual(expected, actual) {
t.Errorf("unexpected object: %#v", actual)
t.Errorf("unexpected object:\nExpected: %#v\n\nGot: %#v\n\n", expected, actual)
}
if len(buf.String()) == 0 {
t.Errorf("unexpected empty output")

View File

@ -29,6 +29,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/fielderrors"
)
@ -54,11 +55,7 @@ func TestMerge(t *testing.T) {
ObjectMeta: api.ObjectMeta{
Name: "foo",
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
},
/* TODO: uncomment this test once Merge is updated to use
@ -127,6 +124,7 @@ func TestMerge(t *testing.T) {
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
SecurityContext: &api.PodSecurityContext{},
},
},
},

View File

@ -32,6 +32,7 @@ import (
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/fake"
"k8s.io/kubernetes/pkg/runtime"
@ -83,7 +84,6 @@ func fakeClientWith(testName string, t *testing.T, data map[string]string) Clien
}
func testData() (*api.PodList, *api.ServiceList) {
grace := int64(30)
pods := &api.PodList{
ListMeta: unversioned.ListMeta{
ResourceVersion: "15",
@ -91,19 +91,11 @@ func testData() (*api.PodList, *api.ServiceList) {
Items: []api.Pod{
{
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
{
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "test", ResourceVersion: "11"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
},
}

View File

@ -28,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/fake"
"k8s.io/kubernetes/pkg/labels"
@ -129,7 +130,6 @@ func TestHelperCreate(t *testing.T) {
return true
}
grace := int64(30)
tests := []struct {
Resp *http.Response
RespFunc fake.HTTPClientFunc
@ -173,11 +173,7 @@ func TestHelperCreate(t *testing.T) {
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
ExpectObject: &api.Pod{
ObjectMeta: api.ObjectMeta{Name: "foo"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
Resp: &http.Response{StatusCode: http.StatusOK, Body: objBody(&unversioned.Status{Status: unversioned.StatusSuccess})},
Req: expectPost,
@ -384,7 +380,6 @@ func TestHelperReplace(t *testing.T) {
return true
}
grace := int64(30)
tests := []struct {
Resp *http.Response
RespFunc fake.HTTPClientFunc
@ -421,11 +416,7 @@ func TestHelperReplace(t *testing.T) {
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
ExpectObject: &api.Pod{
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
Overwrite: true,
RespFunc: func(req *http.Request) (*http.Response, error) {

View File

@ -28,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/fake"
"k8s.io/kubernetes/pkg/client/unversioned/testclient"
@ -1011,7 +1012,6 @@ func TestUpdateExistingReplicationController(t *testing.T) {
func TestUpdateWithRetries(t *testing.T) {
codec := testapi.Default.Codec()
grace := int64(30)
rc := &api.ReplicationController{
ObjectMeta: api.ObjectMeta{Name: "rc",
Labels: map[string]string{
@ -1028,11 +1028,7 @@ func TestUpdateWithRetries(t *testing.T) {
"foo": "bar",
},
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
},
}

View File

@ -53,6 +53,7 @@ func TestDecodeSinglePod(t *testing.T) {
TerminationMessagePath: "/dev/termination-log",
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
}},
SecurityContext: &api.PodSecurityContext{},
},
}
json, err := testapi.Default.Codec().Encode(pod)
@ -115,6 +116,7 @@ func TestDecodePodList(t *testing.T) {
TerminationMessagePath: "/dev/termination-log",
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
}},
SecurityContext: &api.PodSecurityContext{},
},
}
podList := &api.PodList{

View File

@ -90,7 +90,8 @@ func TestReadPodsFromFile(t *testing.T) {
Namespace: "mynamespace",
},
Spec: api.PodSpec{
Containers: []api.Container{{Name: "image", Image: "test/image", SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
Containers: []api.Container{{Name: "image", Image: "test/image", SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
SecurityContext: &api.PodSecurityContext{},
},
},
expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{
@ -111,6 +112,7 @@ func TestReadPodsFromFile(t *testing.T) {
TerminationMessagePath: "/dev/termination-log",
ImagePullPolicy: "IfNotPresent",
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
SecurityContext: &api.PodSecurityContext{},
},
}),
},

View File

@ -143,8 +143,9 @@ func TestExtractPodsFromHTTP(t *testing.T) {
Namespace: "mynamespace",
},
Spec: api.PodSpec{
NodeName: hostname,
Containers: []api.Container{{Name: "1", Image: "foo", ImagePullPolicy: api.PullAlways}},
NodeName: hostname,
Containers: []api.Container{{Name: "1", Image: "foo", ImagePullPolicy: api.PullAlways}},
SecurityContext: &api.PodSecurityContext{},
},
},
expected: CreatePodUpdate(kubelet.SET,
@ -161,6 +162,7 @@ func TestExtractPodsFromHTTP(t *testing.T) {
NodeName: hostname,
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
SecurityContext: &api.PodSecurityContext{},
TerminationGracePeriodSeconds: &grace,
Containers: []api.Container{{
@ -186,8 +188,9 @@ func TestExtractPodsFromHTTP(t *testing.T) {
UID: "111",
},
Spec: api.PodSpec{
NodeName: hostname,
Containers: []api.Container{{Name: "1", Image: "foo", ImagePullPolicy: api.PullAlways}},
NodeName: hostname,
Containers: []api.Container{{Name: "1", Image: "foo", ImagePullPolicy: api.PullAlways}},
SecurityContext: &api.PodSecurityContext{},
},
},
{
@ -196,8 +199,9 @@ func TestExtractPodsFromHTTP(t *testing.T) {
UID: "222",
},
Spec: api.PodSpec{
NodeName: hostname,
Containers: []api.Container{{Name: "2", Image: "bar", ImagePullPolicy: ""}},
NodeName: hostname,
Containers: []api.Container{{Name: "2", Image: "bar", ImagePullPolicy: ""}},
SecurityContext: &api.PodSecurityContext{},
},
},
},
@ -217,6 +221,7 @@ func TestExtractPodsFromHTTP(t *testing.T) {
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
SecurityContext: &api.PodSecurityContext{},
Containers: []api.Container{{
Name: "1",
@ -239,6 +244,7 @@ func TestExtractPodsFromHTTP(t *testing.T) {
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
SecurityContext: &api.PodSecurityContext{},
Containers: []api.Container{{
Name: "2",

View File

@ -942,9 +942,9 @@ func (dm *DockerManager) podInfraContainerChanged(pod *api.Pod, podInfraContaine
if dockerPodInfraContainer.HostConfig != nil {
networkMode = dockerPodInfraContainer.HostConfig.NetworkMode
}
if pod.Spec.HostNetwork {
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.HostNetwork {
if networkMode != "host" {
glog.V(4).Infof("host: %v, %v", pod.Spec.HostNetwork, networkMode)
glog.V(4).Infof("host: %v, %v", pod.Spec.SecurityContext.HostNetwork, networkMode)
return true, nil
}
} else {
@ -1468,7 +1468,7 @@ func (dm *DockerManager) runContainerInPod(pod *api.Pod, container *api.Containe
}
utsMode := ""
if pod.Spec.HostNetwork {
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.HostNetwork {
utsMode = "host"
}
id, err := dm.runContainer(pod, container, opts, ref, netMode, ipcMode, utsMode, pidMode)
@ -1585,7 +1585,7 @@ func (dm *DockerManager) createPodInfraContainer(pod *api.Pod) (kubeletTypes.Doc
netNamespace = "none"
}
if pod.Spec.HostNetwork {
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.HostNetwork {
netNamespace = "host"
} else {
// Docker only exports ports from the pod infra container. Let's
@ -1985,7 +1985,7 @@ func (dm *DockerManager) doBackOff(pod *api.Pod, container *api.Container, podSt
// getPidMode returns the pid mode to use on the docker container based on pod.Spec.HostPID.
func getPidMode(pod *api.Pod) string {
pidMode := ""
if pod.Spec.HostPID {
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.HostPID {
pidMode = "host"
}
return pidMode
@ -1994,7 +1994,7 @@ func getPidMode(pod *api.Pod) string {
// getIPCMode returns the ipc mode to use on the docker container based on pod.Spec.HostIPC.
func getIPCMode(pod *api.Pod) string {
ipcMode := ""
if pod.Spec.HostIPC {
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.HostIPC {
ipcMode = "host"
}
return ipcMode

View File

@ -517,7 +517,7 @@ func TestIsAExitError(t *testing.T) {
func generatePodInfraContainerHash(pod *api.Pod) uint64 {
var ports []api.ContainerPort
if !pod.Spec.HostNetwork {
if pod.Spec.SecurityContext == nil || !pod.Spec.SecurityContext.HostNetwork {
for _, container := range pod.Spec.Containers {
ports = append(ports, container.Ports...)
}
@ -1819,7 +1819,9 @@ func TestSyncPodWithHostNetwork(t *testing.T) {
Containers: []api.Container{
{Name: "bar"},
},
HostNetwork: true,
SecurityContext: &api.PodSecurityContext{
HostNetwork: true,
},
},
}
@ -2041,7 +2043,8 @@ func TestGetPidMode(t *testing.T) {
}
// test true
pod.Spec.HostPID = true
pod.Spec.SecurityContext = &api.PodSecurityContext{}
pod.Spec.SecurityContext.HostPID = true
pidMode = getPidMode(pod)
if pidMode != "host" {
t.Errorf("expected host pid mode for pod but got %v", pidMode)
@ -2058,7 +2061,8 @@ func TestGetIPCMode(t *testing.T) {
}
// test true
pod.Spec.HostIPC = true
pod.Spec.SecurityContext = &api.PodSecurityContext{}
pod.Spec.SecurityContext.HostIPC = true
ipcMode = getIPCMode(pod)
if ipcMode != "host" {
t.Errorf("expected host ipc mode for pod but got %v", ipcMode)

View File

@ -1352,7 +1352,7 @@ func (kl *Kubelet) syncPod(pod *api.Pod, mirrorPod *api.Pod, runningPod kubecont
return err
}
if egress != nil || ingress != nil {
if pod.Spec.HostNetwork {
if podUsesHostNetwork(pod) {
kl.recorder.Event(pod, "HostNetworkNotSupported", "Bandwidth shaping is not currently supported on the host network")
} else if kl.shaper != nil {
status, found := kl.statusManager.GetPodStatus(pod.UID)
@ -1391,6 +1391,10 @@ func (kl *Kubelet) syncPod(pod *api.Pod, mirrorPod *api.Pod, runningPod kubecont
return nil
}
func podUsesHostNetwork(pod *api.Pod) bool {
return pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.HostNetwork
}
// getPullSecretsForPod inspects the Pod and retrieves the referenced pull secrets
// TODO duplicate secrets are being retrieved multiple times and there is no cache. Creating and using a secret manager interface will make this easier to address.
func (kl *Kubelet) getPullSecretsForPod(pod *api.Pod) ([]api.Secret, error) {
@ -2632,7 +2636,7 @@ func (kl *Kubelet) generatePodStatus(pod *api.Pod) (api.PodStatus, error) {
glog.V(4).Infof("Cannot get host IP: %v", err)
} else {
podStatus.HostIP = hostIP.String()
if pod.Spec.HostNetwork && podStatus.PodIP == "" {
if podUsesHostNetwork(pod) && podStatus.PodIP == "" {
podStatus.PodIP = hostIP.String()
}
}

View File

@ -2920,7 +2920,9 @@ func TestHostNetworkAllowed(t *testing.T) {
Containers: []api.Container{
{Name: "foo"},
},
HostNetwork: true,
SecurityContext: &api.PodSecurityContext{
HostNetwork: true,
},
},
}
kubelet.podManager.SetPods([]*api.Pod{pod})
@ -2952,7 +2954,9 @@ func TestHostNetworkDisallowed(t *testing.T) {
Containers: []api.Container{
{Name: "foo"},
},
HostNetwork: true,
SecurityContext: &api.PodSecurityContext{
HostNetwork: true,
},
},
}
err := kubelet.syncPod(pod, nil, container.Pod{}, SyncPodUpdate)

View File

@ -585,7 +585,7 @@ func (r *Runtime) preparePod(pod *api.Pod, pullSecrets []api.Secret) (string, *k
}
var runPrepared string
if pod.Spec.HostNetwork {
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.HostNetwork {
runPrepared = fmt.Sprintf("%s run-prepared --mds-register=false %s", r.rktBinAbsPath, uuid)
} else {
runPrepared = fmt.Sprintf("%s run-prepared --mds-register=false --private-net %s", r.rktBinAbsPath, uuid)

View File

@ -40,7 +40,7 @@ func CapacityFromMachineInfo(info *cadvisorApi.MachineInfo) api.ResourceList {
// Check whether we have the capabilities to run the specified pod.
func canRunPod(pod *api.Pod) error {
if pod.Spec.HostNetwork {
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.HostNetwork {
allowed, err := allowHostNetwork(pod)
if err != nil {
return err
@ -50,7 +50,7 @@ func canRunPod(pod *api.Pod) error {
}
}
if pod.Spec.HostPID {
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.HostPID {
allowed, err := allowHostPID(pod)
if err != nil {
return err
@ -60,7 +60,7 @@ func canRunPod(pod *api.Pod) error {
}
}
if pod.Spec.HostIPC {
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.HostIPC {
allowed, err := allowHostIPC(pod)
if err != nil {
return err

View File

@ -64,6 +64,7 @@ func validNewPod() *api.Pod {
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
},
},
SecurityContext: &api.PodSecurityContext{},
},
}
}
@ -617,6 +618,7 @@ func TestEtcdUpdateScheduled(t *testing.T) {
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
},
},
SecurityContext: &api.PodSecurityContext{},
},
}), 1)
@ -631,19 +633,18 @@ func TestEtcdUpdateScheduled(t *testing.T) {
},
Spec: api.PodSpec{
NodeName: "machine",
Containers: []api.Container{
{
Name: "foobar",
Image: "foo:v2",
ImagePullPolicy: api.PullIfNotPresent,
TerminationMessagePath: api.TerminationMessagePathDefault,
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
},
},
Containers: []api.Container{{
Name: "foobar",
Image: "foo:v2",
ImagePullPolicy: api.PullIfNotPresent,
TerminationMessagePath: api.TerminationMessagePathDefault,
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
}},
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
SecurityContext: &api.PodSecurityContext{},
},
}
_, _, err := storage.Update(ctx, &podIn)
@ -682,6 +683,7 @@ func TestEtcdUpdateStatus(t *testing.T) {
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
},
},
SecurityContext: &api.PodSecurityContext{},
},
}
fakeClient.Set(key, runtime.EncodeOrDie(testapi.Default.Codec(), &podStart), 0)
@ -703,6 +705,7 @@ func TestEtcdUpdateStatus(t *testing.T) {
TerminationMessagePath: api.TerminationMessagePathDefault,
},
},
SecurityContext: &api.PodSecurityContext{},
},
Status: api.PodStatus{
Phase: api.PodRunning,

View File

@ -27,6 +27,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
@ -56,14 +57,9 @@ func newTestCacher(client tools.EtcdClient) *storage.Cacher {
}
func makeTestPod(name string) *api.Pod {
gracePeriod := int64(30)
return &api.Pod{
ObjectMeta: api.ObjectMeta{Namespace: "ns", Name: name},
Spec: api.PodSpec{
TerminationGracePeriodSeconds: &gracePeriod,
DNSPolicy: api.DNSClusterFirst,
RestartPolicy: api.RestartPolicyAlways,
},
Spec: apitesting.DeepEqualSafePodSpec(),
}
}

View File

@ -34,6 +34,7 @@ import (
"github.com/stretchr/testify/assert"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/conversion"
"k8s.io/kubernetes/pkg/runtime"
@ -124,33 +125,20 @@ func TestList(t *testing.T) {
},
},
}
grace := int64(30)
expect := api.PodList{
ListMeta: unversioned.ListMeta{ResourceVersion: "10"},
Items: []api.Pod{
{
ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
{
ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "3"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
{
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
},
}
@ -197,17 +185,12 @@ func TestListFiltered(t *testing.T) {
},
},
}
grace := int64(30)
expect := api.PodList{
ListMeta: unversioned.ListMeta{ResourceVersion: "10"},
Items: []api.Pod{
{
ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
},
}
@ -273,34 +256,21 @@ func TestListAcrossDirectories(t *testing.T) {
},
},
}
grace := int64(30)
expect := api.PodList{
ListMeta: unversioned.ListMeta{ResourceVersion: "10"},
Items: []api.Pod{
// We expect list to be sorted by directory (e.g. namespace) first, then by name.
{
ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "3"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
{
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
{
ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
},
}
@ -349,33 +319,20 @@ func TestListExcludesDirectories(t *testing.T) {
},
},
}
grace := int64(30)
expect := api.PodList{
ListMeta: unversioned.ListMeta{ResourceVersion: "10"},
Items: []api.Pod{
{
ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
{
ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "3"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
{
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
},
},
}
@ -394,14 +351,9 @@ func TestGet(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(t)
helper := newEtcdHelper(fakeClient, testapi.Default.Codec(), etcdtest.PathPrefix())
key := etcdtest.AddPrefix("/some/key")
grace := int64(30)
expect := api.Pod{
ObjectMeta: api.ObjectMeta{Name: "foo"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
}
fakeClient.Set(key, runtime.EncodeOrDie(testapi.Default.Codec(), &expect), 0)
var got api.Pod

View File

@ -90,11 +90,11 @@ func (d *denyExec) Admit(a admission.Attributes) (err error) {
return admission.NewForbidden(a, err)
}
if d.hostPID && pod.Spec.HostPID {
if d.hostPID && pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.HostPID {
return admission.NewForbidden(a, fmt.Errorf("Cannot exec into or attach to a container using host pid"))
}
if d.hostIPC && pod.Spec.HostIPC {
if d.hostIPC && pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.HostIPC {
return admission.NewForbidden(a, fmt.Errorf("Cannot exec into or attach to a container using host ipc"))
}

View File

@ -34,10 +34,12 @@ func TestAdmission(t *testing.T) {
}
hostPIDPod := validPod("hostPID")
hostPIDPod.Spec.HostPID = true
hostPIDPod.Spec.SecurityContext = &api.PodSecurityContext{}
hostPIDPod.Spec.SecurityContext.HostPID = true
hostIPCPod := validPod("hostIPC")
hostIPCPod.Spec.HostIPC = true
hostIPCPod.Spec.SecurityContext = &api.PodSecurityContext{}
hostIPCPod.Spec.SecurityContext.HostIPC = true
testCases := map[string]struct {
pod *api.Pod
@ -130,10 +132,12 @@ func TestDenyExecOnPrivileged(t *testing.T) {
}
hostPIDPod := validPod("hostPID")
hostPIDPod.Spec.HostPID = true
hostPIDPod.Spec.SecurityContext = &api.PodSecurityContext{}
hostPIDPod.Spec.SecurityContext.HostPID = true
hostIPCPod := validPod("hostIPC")
hostIPCPod.Spec.HostIPC = true
hostIPCPod.Spec.SecurityContext = &api.PodSecurityContext{}
hostIPCPod.Spec.SecurityContext.HostIPC = true
testCases := map[string]struct {
pod *api.Pod

View File

@ -25,6 +25,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/client/cache"
client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/runtime"
@ -132,14 +133,9 @@ func PriorityTwo(pod *api.Pod, podLister algorithm.PodLister, nodeLister algorit
}
func TestDefaultErrorFunc(t *testing.T) {
grace := int64(30)
testPod := &api.Pod{
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
},
Spec: apitesting.DeepEqualSafePodSpec(),
}
handler := util.FakeHandler{
StatusCode: 200,