diff --git a/api/swagger-spec/v1beta1.json b/api/swagger-spec/v1beta1.json index 9d84337d4a..de1d6331fb 100644 --- a/api/swagger-spec/v1beta1.json +++ b/api/swagger-spec/v1beta1.json @@ -7501,7 +7501,7 @@ "properties": { "capabilities": { "$ref": "v1beta1.Capabilities", - "description": "capabilities for container; cannot be updated; deprecated; See SecurityContext" + "description": "capabilities for container; cannot be updated" }, "command": { "type": "array", @@ -7563,7 +7563,7 @@ }, "privileged": { "type": "boolean", - "description": "whether or not the container is granted privileged status; defaults to false; cannot be updated; deprecated; See SecurityContext" + "description": "whether or not the container is granted privileged status; defaults to false; cannot be updated" }, "readinessProbe": { "$ref": "v1beta1.LivenessProbe", @@ -7573,10 +7573,6 @@ "$ref": "v1beta1.ResourceRequirements", "description": "Compute Resources required by this container; cannot be updated" }, - "securityContext": { - "$ref": "v1beta1.SecurityContext", - "description": "security options the pod should run with" - }, "terminationMessagePath": { "type": "string", "description": "path at which the file to which the container's termination message will be written is mounted into the container's filesystem; message written is intended to be brief final status, such as an assertion failure message; defaults to /dev/termination-log; cannot be updated" @@ -7627,8 +7623,7 @@ "description": "restart policy for all containers within the pod; one of RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyNever" }, "terminationGracePeriodSeconds": { - "type": "integer", - "format": "int64", + "$ref": "int64", "description": "optional duration in seconds the pod needs to terminate gracefully; may be decreased in delete request; value must be non-negative integer; the value zero indicates delete immediately; if this value is not set, the default grace period will be used instead; the grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal; set this value longer than the expected cleanup time for your process" }, "uuid": { @@ -7705,8 +7700,7 @@ "description": "an optional prefix to use to generate a unique name; has the same validation rules as name; optional, and is applied only name if is not specified" }, "gracePeriodSeconds": { - "type": "integer", - "format": "int64", + "$ref": "int64", "description": "the duration in seconds to wait before deleting this object; defaults to a per object value if not specified; zero means delete immediately" }, "id": { @@ -9823,27 +9817,6 @@ "id": "v1beta1.RestartPolicyOnFailure", "properties": {} }, - "v1beta1.SELinuxOptions": { - "id": "v1beta1.SELinuxOptions", - "properties": { - "level": { - "type": "string", - "description": "the level label to apply to the container" - }, - "role": { - "type": "string", - "description": "the role label to apply to the container" - }, - "type": { - "type": "string", - "description": "the type label to apply to the container" - }, - "user": { - "type": "string", - "description": "the user label to apply to the container" - } - } - }, "v1beta1.Secret": { "id": "v1beta1.Secret", "properties": { @@ -9972,28 +9945,6 @@ } } }, - "v1beta1.SecurityContext": { - "id": "v1beta1.SecurityContext", - "properties": { - "capabilities": { - "$ref": "v1beta1.Capabilities", - "description": "the linux capabilites that should be added or removed" - }, - "privileged": { - "type": "boolean", - "description": "run the container in privileged mode" - }, - "runAsUser": { - "type": "integer", - "format": "int64", - "description": "the user id that runs the first process in the container" - }, - "seLinuxOptions": { - "$ref": "v1beta1.SELinuxOptions", - "description": "options that control the SELinux labels applied" - } - } - }, "v1beta1.Service": { "id": "v1beta1.Service", "required": [ diff --git a/api/swagger-spec/v1beta2.json b/api/swagger-spec/v1beta2.json index dbd3710181..5fed8b8d3a 100644 --- a/api/swagger-spec/v1beta2.json +++ b/api/swagger-spec/v1beta2.json @@ -7501,7 +7501,7 @@ "properties": { "capabilities": { "$ref": "v1beta2.Capabilities", - "description": "capabilities for container; cannot be updated; deprecated; See SecurityContext" + "description": "capabilities for container; cannot be updated" }, "command": { "type": "array", @@ -7563,7 +7563,7 @@ }, "privileged": { "type": "boolean", - "description": "whether or not the container is granted privileged status; defaults to false; cannot be updated; deprecated; See SecurityContext" + "description": "whether or not the container is granted privileged status; defaults to false; cannot be updated" }, "readinessProbe": { "$ref": "v1beta2.LivenessProbe", @@ -7573,10 +7573,6 @@ "$ref": "v1beta2.ResourceRequirements", "description": "Compute Resources required by this container; cannot be updated" }, - "securityContext": { - "$ref": "v1beta2.SecurityContext", - "description": "security options the pod should run with" - }, "terminationMessagePath": { "type": "string", "description": "path at which the file to which the container's termination message will be written is mounted into the container's filesystem; message written is intended to be brief final status, such as an assertion failure message; defaults to /dev/termination-log; cannot be updated" @@ -7627,8 +7623,7 @@ "description": "restart policy for all containers within the pod; one of RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyNever" }, "terminationGracePeriodSeconds": { - "type": "integer", - "format": "int64", + "$ref": "int64", "description": "optional duration in seconds the pod needs to terminate gracefully; may be decreased in delete request; value must be non-negative integer; the value zero indicates delete immediately; if this value is not set, the default grace period will be used instead; the grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal; set this value longer than the expected cleanup time for your process" }, "uuid": { @@ -7705,8 +7700,7 @@ "description": "an optional prefix to use to generate a unique name; has the same validation rules as name; optional, and is applied only name if is not specified" }, "gracePeriodSeconds": { - "type": "integer", - "format": "int64", + "$ref": "int64", "description": "the duration in seconds to wait before deleting this object; defaults to a per object value if not specified; zero means delete immediately" }, "id": { @@ -9237,10 +9231,10 @@ "v1beta2.PersistentVolumeSpec": { "id": "v1beta2.PersistentVolumeSpec", "required": [ + "glusterfs", "persistentDisk", "awsElasticBlockStore", - "hostPath", - "glusterfs" + "hostPath" ], "properties": { "accessModes": { @@ -9812,27 +9806,6 @@ "id": "v1beta2.RestartPolicyOnFailure", "properties": {} }, - "v1beta2.SELinuxOptions": { - "id": "v1beta2.SELinuxOptions", - "properties": { - "level": { - "type": "string", - "description": "the level label to apply to the container" - }, - "role": { - "type": "string", - "description": "the role label to apply to the container" - }, - "type": { - "type": "string", - "description": "the type label to apply to the container" - }, - "user": { - "type": "string", - "description": "the user label to apply to the container" - } - } - }, "v1beta2.Secret": { "id": "v1beta2.Secret", "properties": { @@ -9961,28 +9934,6 @@ } } }, - "v1beta2.SecurityContext": { - "id": "v1beta2.SecurityContext", - "properties": { - "capabilities": { - "$ref": "v1beta2.Capabilities", - "description": "the linux capabilites that should be added or removed" - }, - "privileged": { - "type": "boolean", - "description": "run the container in privileged mode" - }, - "runAsUser": { - "type": "integer", - "format": "int64", - "description": "the user id that runs the first process in the container" - }, - "seLinuxOptions": { - "$ref": "v1beta2.SELinuxOptions", - "description": "options that control the SELinux labels applied" - } - } - }, "v1beta2.Service": { "id": "v1beta2.Service", "required": [ diff --git a/api/swagger-spec/v1beta3.json b/api/swagger-spec/v1beta3.json index 6b3d087a2e..eb92f70430 100644 --- a/api/swagger-spec/v1beta3.json +++ b/api/swagger-spec/v1beta3.json @@ -8458,7 +8458,7 @@ }, "capabilities": { "$ref": "v1beta3.Capabilities", - "description": "capabilities for container; cannot be updated; deprecated; See SecurityContext." + "description": "capabilities for container; cannot be updated" }, "command": { "type": "array", @@ -8503,7 +8503,7 @@ }, "privileged": { "type": "boolean", - "description": "whether or not the container is granted privileged status; defaults to false; cannot be updated; deprecated; See SecurityContext." + "description": "whether or not the container is granted privileged status; defaults to false; cannot be updated" }, "readinessProbe": { "$ref": "v1beta3.Probe", @@ -8513,10 +8513,6 @@ "$ref": "v1beta3.ResourceRequirements", "description": "Compute Resources required by this container; cannot be updated" }, - "securityContext": { - "$ref": "v1beta3.SecurityContext", - "description": "security options the pod should run with" - }, "terminationMessagePath": { "type": "string", "description": "path at which the file to which the container's termination message will be written is mounted into the container's filesystem; message written is intended to be brief final status, such as an assertion failure message; defaults to /dev/termination-log; cannot be updated" @@ -8693,8 +8689,7 @@ "description": "version of the schema the object should have" }, "gracePeriodSeconds": { - "type": "integer", - "format": "int64", + "$ref": "int64", "description": "the duration in seconds to wait before deleting this object; defaults to a per object value if not specified; zero means delete immediately" }, "kind": { @@ -9893,8 +9888,7 @@ "description": "restart policy for all containers within the pod; one of RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyNever" }, "terminationGracePeriodSeconds": { - "type": "integer", - "format": "int64", + "$ref": "int64", "description": "optional duration in seconds the pod needs to terminate gracefully; may be decreased in delete request; value must be non-negative integer; the value zero indicates delete immediately; if this value is not set, the default grace period will be used instead; the grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal; set this value longer than the expected cleanup time for your process" }, "volumes": { @@ -10206,27 +10200,6 @@ } } }, - "v1beta3.SELinuxOptions": { - "id": "v1beta3.SELinuxOptions", - "properties": { - "level": { - "type": "string", - "description": "the level label to apply to the container" - }, - "role": { - "type": "string", - "description": "the role label to apply to the container" - }, - "type": { - "type": "string", - "description": "the type label to apply to the container" - }, - "user": { - "type": "string", - "description": "the user label to apply to the container" - } - } - }, "v1beta3.Secret": { "id": "v1beta3.Secret", "properties": { @@ -10291,28 +10264,6 @@ } } }, - "v1beta3.SecurityContext": { - "id": "v1beta3.SecurityContext", - "properties": { - "capabilities": { - "$ref": "v1beta3.Capabilities", - "description": "the linux capabilites that should be added or removed" - }, - "privileged": { - "type": "boolean", - "description": "run the container in privileged mode" - }, - "runAsUser": { - "type": "integer", - "format": "int64", - "description": "the user id that runs the first process in the container" - }, - "seLinuxOptions": { - "$ref": "v1beta3.SELinuxOptions", - "description": "options that control the SELinux labels applied" - } - } - }, "v1beta3.Service": { "id": "v1beta3.Service", "properties": { @@ -10529,15 +10480,15 @@ "id": "v1beta3.Volume", "required": [ "name", - "gcePersistentDisk", "awsElasticBlockStore", "gitRepo", - "nfs", - "iscsi", - "hostPath", "secret", + "nfs", "glusterfs", - "emptyDir" + "hostPath", + "emptyDir", + "gcePersistentDisk", + "iscsi" ], "properties": { "awsElasticBlockStore": { diff --git a/cluster/aws/config-default.sh b/cluster/aws/config-default.sh index 5d16c72b2f..8ef0d3e769 100644 --- a/cluster/aws/config-default.sh +++ b/cluster/aws/config-default.sh @@ -72,4 +72,4 @@ DNS_DOMAIN="kubernetes.local" DNS_REPLICAS=1 # Admission Controllers to invoke prior to persisting objects in cluster -ADMISSION_CONTROL=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,SecurityContextDeny,ResourceQuota +ADMISSION_CONTROL=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,ResourceQuota diff --git a/cluster/azure/config-default.sh b/cluster/azure/config-default.sh index 8b8f91f061..411fd45945 100644 --- a/cluster/azure/config-default.sh +++ b/cluster/azure/config-default.sh @@ -49,4 +49,4 @@ ELASTICSEARCH_LOGGING_REPLICAS=1 ENABLE_CLUSTER_MONITORING="${KUBE_ENABLE_CLUSTER_MONITORING:-true}" # Admission Controllers to invoke prior to persisting objects in cluster -ADMISSION_CONTROL=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,SecurityContextDeny,ResourceQuota +ADMISSION_CONTROL=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,ResourceQuota diff --git a/cluster/gce/config-default.sh b/cluster/gce/config-default.sh index e1ba5ebb10..1466aa96e0 100755 --- a/cluster/gce/config-default.sh +++ b/cluster/gce/config-default.sh @@ -111,4 +111,4 @@ DNS_DOMAIN="kubernetes.local" DNS_REPLICAS=1 # Admission Controllers to invoke prior to persisting objects in cluster -ADMISSION_CONTROL=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,SecurityContextDeny,ResourceQuota, +ADMISSION_CONTROL=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,ResourceQuota diff --git a/cluster/gce/config-test.sh b/cluster/gce/config-test.sh index c637dcc6bc..5b6b20c8c5 100755 --- a/cluster/gce/config-test.sh +++ b/cluster/gce/config-test.sh @@ -70,4 +70,4 @@ DNS_SERVER_IP="10.0.0.10" DNS_DOMAIN="kubernetes.local" DNS_REPLICAS=1 -ADMISSION_CONTROL=NamespaceAutoProvision,LimitRanger,SecurityContextDeny,ResourceQuota +ADMISSION_CONTROL=NamespaceAutoProvision,LimitRanger,ResourceQuota diff --git a/cluster/vagrant/config-default.sh b/cluster/vagrant/config-default.sh index 2653cbca19..af1e96c202 100755 --- a/cluster/vagrant/config-default.sh +++ b/cluster/vagrant/config-default.sh @@ -50,7 +50,7 @@ MASTER_USER=vagrant MASTER_PASSWD=vagrant # Admission Controllers to invoke prior to persisting objects in cluster -ADMISSION_CONTROL=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,SecurityContextDeny,ResourceQuota +ADMISSION_CONTROL=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,ResourceQuota # Optional: Install node monitoring. ENABLE_NODE_MONITORING=true diff --git a/cmd/kube-apiserver/app/plugins.go b/cmd/kube-apiserver/app/plugins.go index 5a9bf03021..9221b13e0b 100644 --- a/cmd/kube-apiserver/app/plugins.go +++ b/cmd/kube-apiserver/app/plugins.go @@ -36,5 +36,4 @@ import ( _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/namespace/exists" _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/namespace/lifecycle" _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/resourcequota" - _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/securitycontext/scdeny" ) diff --git a/hack/local-up-cluster.sh b/hack/local-up-cluster.sh index 59fa145dd7..a9539f2d8f 100755 --- a/hack/local-up-cluster.sh +++ b/hack/local-up-cluster.sh @@ -117,7 +117,7 @@ echo "Starting etcd" kube::etcd::start # Admission Controllers to invoke prior to persisting objects in cluster -ADMISSION_CONTROL=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,SecurityContextDeny,ResourceQuota +ADMISSION_CONTROL=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,ResourceQuota APISERVER_LOG=/tmp/kube-apiserver.log sudo -E "${GO_OUT}/kube-apiserver" \ diff --git a/pkg/api/testing/fuzzer.go b/pkg/api/testing/fuzzer.go index 49a27c7778..0e53b2c33e 100644 --- a/pkg/api/testing/fuzzer.go +++ b/pkg/api/testing/fuzzer.go @@ -204,17 +204,6 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer { ev.ValueFrom.FieldRef.FieldPath = c.RandString() } }, - func(sc *api.SecurityContext, c fuzz.Continue) { - c.FuzzNoCustom(sc) // fuzz self without calling this function again - priv := c.RandBool() - sc.Privileged = &priv - sc.Capabilities = &api.Capabilities{ - Add: make([]api.CapabilityType, 0), - Drop: make([]api.CapabilityType, 0), - } - c.Fuzz(&sc.Capabilities.Add) - c.Fuzz(&sc.Capabilities.Drop) - }, func(e *api.Event, c fuzz.Continue) { c.FuzzNoCustom(e) // fuzz self without calling this function again // Fix event count to 1, otherwise, if a v1beta1 or v1beta2 event has a count set arbitrarily, it's count is ignored diff --git a/pkg/api/types.go b/pkg/api/types.go index 0243d6fe16..331181df36 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -623,10 +623,12 @@ type Container struct { Lifecycle *Lifecycle `json:"lifecycle,omitempty"` // Required. TerminationMessagePath string `json:"terminationMessagePath,omitempty"` + // Optional: Default to false. + Privileged bool `json:"privileged,omitempty"` // Required: Policy for pulling images for this container ImagePullPolicy PullPolicy `json:"imagePullPolicy"` - // Optional: SecurityContext defines the security options the pod should be run with - SecurityContext *SecurityContext `json:"securityContext,omitempty" description:"security options the pod should run with"` + // Optional: Capabilities for container. + Capabilities Capabilities `json:"capabilities,omitempty"` } // Handler defines a specific action that should be taken @@ -1874,37 +1876,3 @@ type ComponentStatusList struct { Items []ComponentStatus `json:"items"` } - -// SecurityContext holds security configuration that will be applied to a container. SecurityContext -// contains duplication of some existing fields from the Container resource. These duplicate fields -// will be populated based on the Container configuration if they are not set. Defining them on -// both the Container AND the SecurityContext will result in an error. -type SecurityContext struct { - // Capabilities are the capabilities to add/drop when running the container - Capabilities *Capabilities `json:"capabilities,omitempty" description:"the linux capabilites that should be added or removed"` - - // Run the container in privileged mode - Privileged *bool `json:"privileged,omitempty" description:"run the container in privileged mode"` - - // SELinuxOptions are the labels to be applied to the container - // and volumes - SELinuxOptions *SELinuxOptions `json:"seLinuxOptions,omitempty" description:"options that control the SELinux labels applied"` - - // RunAsUser is the UID to run the entrypoint of the container process. - RunAsUser *int64 `json:"runAsUser,omitempty" description:"the user id that runs the first process in the container"` -} - -// SELinuxOptions are the labels to be applied to the container. -type SELinuxOptions struct { - // SELinux user label - User string `json:"user,omitempty" description:"the user label to apply to the container"` - - // SELinux role label - Role string `json:"role,omitempty" description:"the role label to apply to the container"` - - // SELinux type label - Type string `json:"type,omitempty" description:"the type label to apply to the container"` - - // SELinux level label. - Level string `json:"level,omitempty" description:"the level label to apply to the container"` -} diff --git a/pkg/api/v1/conversion.go b/pkg/api/v1/conversion.go index a5aa066556..60210a5eef 100644 --- a/pkg/api/v1/conversion.go +++ b/pkg/api/v1/conversion.go @@ -18,7 +18,6 @@ package v1 import ( "fmt" - "reflect" newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource" @@ -238,22 +237,9 @@ func init() { return err } out.TerminationMessagePath = in.TerminationMessagePath + out.Privileged = in.Privileged out.ImagePullPolicy = newer.PullPolicy(in.ImagePullPolicy) - - if in.SecurityContext != nil { - if in.SecurityContext.Capabilities != nil { - if !reflect.DeepEqual(in.SecurityContext.Capabilities.Add, in.Capabilities.Add) || - !reflect.DeepEqual(in.SecurityContext.Capabilities.Drop, in.Capabilities.Drop) { - return fmt.Errorf("container capability settings do not match security context settings, cannot convert") - } - } - if in.SecurityContext.Privileged != nil { - if in.Privileged != *in.SecurityContext.Privileged { - return fmt.Errorf("container privileged settings do not match security context settings, cannot convert") - } - } - } - if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil { + if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil { return err } return nil @@ -311,19 +297,11 @@ func init() { return err } out.TerminationMessagePath = in.TerminationMessagePath + out.Privileged = in.Privileged out.ImagePullPolicy = PullPolicy(in.ImagePullPolicy) - if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil { + if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil { return err } - - // now that we've converted set the container field from security context - if out.SecurityContext != nil && out.SecurityContext.Privileged != nil { - out.Privileged = *out.SecurityContext.Privileged - } - // now that we've converted set the container field from security context - if out.SecurityContext != nil && out.SecurityContext.Capabilities != nil { - out.Capabilities = *out.SecurityContext.Capabilities - } return nil }, func(in *ContainerPort, out *newer.ContainerPort, s conversion.Scope) error { diff --git a/pkg/api/v1/conversion_test.go b/pkg/api/v1/conversion_test.go index 33c1ff02ff..3722d84d7d 100644 --- a/pkg/api/v1/conversion_test.go +++ b/pkg/api/v1/conversion_test.go @@ -45,62 +45,3 @@ func TestNodeConversion(t *testing.T) { t.Fatalf("unexpected error: %v", err) } } - -func TestBadSecurityContextConversion(t *testing.T) { - priv := false - testCases := map[string]struct { - c *current.Container - err string - }{ - // this use case must use true for the container and false for the sc. Otherwise the defaulter - // will assume privileged was left undefined (since it is the default value) and copy the - // sc setting upwards - "mismatched privileged": { - c: ¤t.Container{ - Privileged: true, - SecurityContext: ¤t.SecurityContext{ - Privileged: &priv, - }, - }, - err: "container privileged settings do not match security context settings, cannot convert", - }, - "mismatched caps add": { - c: ¤t.Container{ - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - }, - SecurityContext: ¤t.SecurityContext{ - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"bar"}, - }, - }, - }, - err: "container capability settings do not match security context settings, cannot convert", - }, - "mismatched caps drop": { - c: ¤t.Container{ - Capabilities: current.Capabilities{ - Drop: []current.CapabilityType{"foo"}, - }, - SecurityContext: ¤t.SecurityContext{ - Capabilities: ¤t.Capabilities{ - Drop: []current.CapabilityType{"bar"}, - }, - }, - }, - err: "container capability settings do not match security context settings, cannot convert", - }, - } - - for k, v := range testCases { - got := newer.Container{} - err := newer.Scheme.Convert(v.c, &got) - if err == nil { - t.Errorf("expected error for case %s but got none", k) - } else { - if err.Error() != v.err { - t.Errorf("unexpected error for case %s. Expected: %s but got: %s", k, v.err, err.Error()) - } - } - } -} diff --git a/pkg/api/v1/defaults.go b/pkg/api/v1/defaults.go index 443e910101..bb542aaed3 100644 --- a/pkg/api/v1/defaults.go +++ b/pkg/api/v1/defaults.go @@ -19,8 +19,6 @@ package v1 import ( "strings" - "github.com/golang/glog" - "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" ) @@ -68,7 +66,6 @@ func init() { if obj.TerminationMessagePath == "" { obj.TerminationMessagePath = TerminationMessagePathDefault } - defaultSecurityContext(obj) }, func(obj *ServiceSpec) { if obj.SessionAffinity == "" { @@ -159,44 +156,3 @@ func defaultHostNetworkPorts(containers *[]Container) { } } } - -// defaultSecurityContext performs the downward and upward merges of a pod definition -func defaultSecurityContext(container *Container) { - if container.SecurityContext == nil { - glog.V(4).Infof("creating security context for container %s", container.Name) - container.SecurityContext = &SecurityContext{} - } - // if there are no capabilities defined on the SecurityContext then copy the container settings - if container.SecurityContext.Capabilities == nil { - glog.V(4).Infof("downward merge of container.Capabilities for container %s", container.Name) - container.SecurityContext.Capabilities = &container.Capabilities - } else { - // if there are capabilities defined on the security context and the container setting is - // empty then assume that it was left off the pod definition and ensure that the container - // settings match the security context settings (checked by the convert functions). If - // there are settings in both then don't touch it, the converter will error if they don't - // match - if len(container.Capabilities.Add) == 0 { - glog.V(4).Infof("upward merge of container.Capabilities.Add for container %s", container.Name) - container.Capabilities.Add = container.SecurityContext.Capabilities.Add - } - if len(container.Capabilities.Drop) == 0 { - glog.V(4).Infof("upward merge of container.Capabilities.Drop for container %s", container.Name) - container.Capabilities.Drop = container.SecurityContext.Capabilities.Drop - } - } - // if there are no privileged settings on the security context then copy the container settings - if container.SecurityContext.Privileged == nil { - glog.V(4).Infof("downward merge of container.Privileged for container %s", container.Name) - container.SecurityContext.Privileged = &container.Privileged - } else { - // we don't have a good way to know if container.Privileged was set or just defaulted to false - // so the best we can do here is check if the securityContext is set to true and the - // container is set to false and assume that the Privileged field was left off the container - // definition and not an intentional mismatch - if *container.SecurityContext.Privileged && !container.Privileged { - glog.V(4).Infof("upward merge of container.Privileged for container %s", container.Name) - container.Privileged = *container.SecurityContext.Privileged - } - } -} diff --git a/pkg/api/v1/defaults_test.go b/pkg/api/v1/defaults_test.go index 4b2a4fd30a..09667ef841 100644 --- a/pkg/api/v1/defaults_test.go +++ b/pkg/api/v1/defaults_test.go @@ -349,104 +349,3 @@ func TestSetDefaultObjectFieldSelectorAPIVersion(t *testing.T) { t.Errorf("Expected default APIVersion v1, got: %v", apiVersion) } } - -func TestSetDefaultSecurityContext(t *testing.T) { - priv := false - privTrue := true - testCases := map[string]struct { - c current.Container - }{ - "downward defaulting caps": { - c: current.Container{ - Privileged: false, - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - SecurityContext: ¤t.SecurityContext{ - Privileged: &priv, - }, - }, - }, - "downward defaulting priv": { - c: current.Container{ - Privileged: false, - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - SecurityContext: ¤t.SecurityContext{ - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - }, - }, - }, - "upward defaulting caps": { - c: current.Container{ - Privileged: false, - SecurityContext: ¤t.SecurityContext{ - Privileged: &priv, - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"biz"}, - Drop: []current.CapabilityType{"baz"}, - }, - }, - }, - }, - "upward defaulting priv": { - c: current.Container{ - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - SecurityContext: ¤t.SecurityContext{ - Privileged: &privTrue, - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - }, - }, - }, - } - - pod := ¤t.Pod{ - Spec: current.PodSpec{}, - } - - for k, v := range testCases { - pod.Spec.Containers = []current.Container{v.c} - obj := roundTrip(t, runtime.Object(pod)) - defaultedPod := obj.(*current.Pod) - c := defaultedPod.Spec.Containers[0] - if isEqual, issues := areSecurityContextAndContainerEqual(&c); !isEqual { - t.Errorf("test case %s expected the security context to have the same values as the container but found %#v", k, issues) - } - } -} - -func areSecurityContextAndContainerEqual(c *current.Container) (bool, []string) { - issues := make([]string, 0) - equal := true - - if c.SecurityContext == nil || c.SecurityContext.Privileged == nil || c.SecurityContext.Capabilities == nil { - equal = false - issues = append(issues, "Expected non nil settings for SecurityContext") - return equal, issues - } - if *c.SecurityContext.Privileged != c.Privileged { - equal = false - issues = append(issues, "The defaulted SecurityContext.Privileged value did not match the container value") - } - if !reflect.DeepEqual(c.Capabilities.Add, c.Capabilities.Add) { - equal = false - issues = append(issues, "The defaulted SecurityContext.Capabilities.Add did not match the container settings") - } - if !reflect.DeepEqual(c.Capabilities.Drop, c.Capabilities.Drop) { - equal = false - issues = append(issues, "The defaulted SecurityContext.Capabilities.Drop did not match the container settings") - } - return equal, issues -} diff --git a/pkg/api/v1/types.go b/pkg/api/v1/types.go index 697c6b01dc..dafa218d7d 100644 --- a/pkg/api/v1/types.go +++ b/pkg/api/v1/types.go @@ -636,14 +636,12 @@ type Container struct { Lifecycle *Lifecycle `json:"lifecycle,omitempty" description:"actions that the management system should take in response to container lifecycle events; cannot be updated"` // Optional: Defaults to /dev/termination-log TerminationMessagePath string `json:"terminationMessagePath,omitempty" description:"path at which the file to which the container's termination message will be written is mounted into the container's filesystem; message written is intended to be brief final status, such as an assertion failure message; defaults to /dev/termination-log; cannot be updated"` - // Deprecated - see SecurityContext. Optional: Default to false. - Privileged bool `json:"privileged,omitempty" description:"hether or not the container is granted privileged status; defaults to false; cannot be updated; deprecated; See SecurityContext"` + // Optional: Default to false. + Privileged bool `json:"privileged,omitempty" description:"whether or not the container is granted privileged status; defaults to false; cannot be updated"` // Optional: Policy for pulling images for this container ImagePullPolicy PullPolicy `json:"imagePullPolicy" description:"image pull policy; one of PullAlways, PullNever, PullIfNotPresent; defaults to PullAlways if :latest tag is specified, or PullIfNotPresent otherwise; cannot be updated"` - // Deprecated - see SecurityContext. Optional: Capabilities for container. - Capabilities Capabilities `json:"capabilities,omitempty" description:"capabilities for container; cannot be updated; deprecated; See SecurityContext"` - // Optional: SecurityContext defines the security options the pod should be run with - SecurityContext *SecurityContext `json:"securityContext,omitempty" description:"security options the pod should run with"` + // Optional: Capabilities for container. + Capabilities Capabilities `json:"capabilities,omitempty" description:"capabilities for container; cannot be updated"` } // Handler defines a specific action that should be taken @@ -1737,39 +1735,3 @@ type ComponentStatusList struct { Items []ComponentStatus `json:"items" description:"list of component status objects"` } - -// SecurityContext holds security configuration that will be applied to a container. SecurityContext -// contains duplication of some existing fields from the Container resource. These duplicate fields -// will be populated based on the Container configuration if they are not set. Defining them on -// both the Container AND the SecurityContext will result in an error. -type SecurityContext struct { - // Capabilities are the capabilities to add/drop when running the container - // Must match Container.Capabilities or be unset. Will be defaulted to Container.Capabilities if left unset - Capabilities *Capabilities `json:"capabilities,omitempty" description:"the linux capabilites that should be added or removed"` - - // Run the container in privileged mode - // Must match Container.Privileged or be unset. Will be defaulted to Container.Privileged if left unset - Privileged *bool `json:"privileged,omitempty" description:"run the container in privileged mode"` - - // SELinuxOptions are the labels to be applied to the container - // and volumes - SELinuxOptions *SELinuxOptions `json:"seLinuxOptions,omitempty" description:"options that control the SELinux labels applied"` - - // RunAsUser is the UID to run the entrypoint of the container process. - RunAsUser *int64 `json:"runAsUser,omitempty" description:"the user id that runs the first process in the container"` -} - -// SELinuxOptions are the labels to be applied to the container -type SELinuxOptions struct { - // SELinux user label - User string `json:"user,omitempty" description:"the user label to apply to the container"` - - // SELinux role label - Role string `json:"role,omitempty" description:"the role label to apply to the container"` - - // SELinux type label - Type string `json:"type,omitempty" description:"the type label to apply to the container"` - - // SELinux level label. - Level string `json:"level,omitempty" description:"the level label to apply to the container"` -} diff --git a/pkg/api/v1beta1/conversion.go b/pkg/api/v1beta1/conversion.go index dba9b5d468..2aff508c53 100644 --- a/pkg/api/v1beta1/conversion.go +++ b/pkg/api/v1beta1/conversion.go @@ -19,7 +19,6 @@ package v1beta1 import ( "fmt" "net" - "reflect" "strconv" newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api" @@ -580,20 +579,15 @@ func init() { if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil { return err } + if err := s.Convert(&in.Privileged, &out.Privileged, 0); err != nil { + return err + } if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil { return err } - if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil { + if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil { return err } - // now that we've converted set the container field from security context - if out.SecurityContext != nil && out.SecurityContext.Privileged != nil { - out.Privileged = *out.SecurityContext.Privileged - } - // now that we've converted set the container field from security context - if out.SecurityContext != nil && out.SecurityContext.Capabilities != nil { - out.Capabilities = *out.SecurityContext.Capabilities - } return nil }, // Internal API does not support CPU to be specified via an explicit field. @@ -671,23 +665,13 @@ func init() { if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil { return err } + if err := s.Convert(&in.Privileged, &out.Privileged, 0); err != nil { + return err + } if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil { return err } - if in.SecurityContext != nil { - if in.SecurityContext.Capabilities != nil { - if !reflect.DeepEqual(in.SecurityContext.Capabilities.Add, in.Capabilities.Add) || - !reflect.DeepEqual(in.SecurityContext.Capabilities.Drop, in.Capabilities.Drop) { - return fmt.Errorf("container capability settings do not match security context settings, cannot convert") - } - } - if in.SecurityContext.Privileged != nil { - if in.Privileged != *in.SecurityContext.Privileged { - return fmt.Errorf("container privileged settings do not match security context settings, cannot convert") - } - } - } - if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil { + if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil { return err } return nil diff --git a/pkg/api/v1beta1/conversion_test.go b/pkg/api/v1beta1/conversion_test.go index d8d21ea7c5..d4997ad032 100644 --- a/pkg/api/v1beta1/conversion_test.go +++ b/pkg/api/v1beta1/conversion_test.go @@ -749,63 +749,3 @@ func TestSecretVolumeSourceConversion(t *testing.T) { t.Errorf("Expected %v; got %v", given, got2) } } - -func TestBadSecurityContextConversion(t *testing.T) { - priv := false - testCases := map[string]struct { - c *current.Container - err string - }{ - // this use case must use true for the container and false for the sc. Otherwise the defaulter - // will assume privileged was left undefined (since it is the default value) and copy the - // sc setting upwards - "mismatched privileged": { - c: ¤t.Container{ - Privileged: true, - SecurityContext: ¤t.SecurityContext{ - Privileged: &priv, - }, - }, - err: "container privileged settings do not match security context settings, cannot convert", - }, - "mismatched caps add": { - c: ¤t.Container{ - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - }, - SecurityContext: ¤t.SecurityContext{ - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"bar"}, - }, - }, - }, - err: "container capability settings do not match security context settings, cannot convert", - }, - "mismatched caps drop": { - c: ¤t.Container{ - Capabilities: current.Capabilities{ - Drop: []current.CapabilityType{"foo"}, - }, - SecurityContext: ¤t.SecurityContext{ - Capabilities: ¤t.Capabilities{ - Drop: []current.CapabilityType{"bar"}, - }, - }, - }, - err: "container capability settings do not match security context settings, cannot convert", - }, - } - - for k, v := range testCases { - got := newer.Container{} - err := Convert(v.c, &got) - if err == nil { - t.Errorf("expected error for case %s but got none", k) - } else { - if err.Error() != v.err { - t.Errorf("unexpected error for case %s. Expected: %s but got: %s", k, v.err, err.Error()) - } - } - } - -} diff --git a/pkg/api/v1beta1/defaults.go b/pkg/api/v1beta1/defaults.go index f217c694bf..1dc6b71a7d 100644 --- a/pkg/api/v1beta1/defaults.go +++ b/pkg/api/v1beta1/defaults.go @@ -62,7 +62,6 @@ func init() { if obj.TerminationMessagePath == "" { obj.TerminationMessagePath = TerminationMessagePathDefault } - defaultSecurityContext(obj) }, func(obj *RestartPolicy) { if util.AllPtrFieldsNil(obj) { @@ -195,44 +194,3 @@ func defaultHostNetworkPorts(containers *[]Container) { } } } - -// defaultSecurityContext performs the downward and upward merges of a pod definition -func defaultSecurityContext(container *Container) { - if container.SecurityContext == nil { - glog.V(4).Infof("creating security context for container %s", container.Name) - container.SecurityContext = &SecurityContext{} - } - // if there are no capabilities defined on the SecurityContext then copy the container settings - if container.SecurityContext.Capabilities == nil { - glog.V(4).Infof("downward merge of container.Capabilities for container %s", container.Name) - container.SecurityContext.Capabilities = &container.Capabilities - } else { - // if there are capabilities defined on the security context and the container setting is - // empty then assume that it was left off the pod definition and ensure that the container - // settings match the security context settings (checked by the convert functions). If - // there are settings in both then don't touch it, the converter will error if they don't - // match - if len(container.Capabilities.Add) == 0 { - glog.V(4).Infof("upward merge of container.Capabilities.Add for container %s", container.Name) - container.Capabilities.Add = container.SecurityContext.Capabilities.Add - } - if len(container.Capabilities.Drop) == 0 { - glog.V(4).Infof("upward merge of container.Capabilities.Drop for container %s", container.Name) - container.Capabilities.Drop = container.SecurityContext.Capabilities.Drop - } - } - // if there are no privileged settings on the security context then copy the container settings - if container.SecurityContext.Privileged == nil { - glog.V(4).Infof("downward merge of container.Privileged for container %s", container.Name) - container.SecurityContext.Privileged = &container.Privileged - } else { - // we don't have a good way to know if container.Privileged was set or just defaulted to false - // so the best we can do here is check if the securityContext is set to true and the - // container is set to false and assume that the Privileged field was left off the container - // definition and not an intentional mismatch - if *container.SecurityContext.Privileged && !container.Privileged { - glog.V(4).Infof("upward merge of container.Privileged for container %s", container.Name) - container.Privileged = *container.SecurityContext.Privileged - } - } -} diff --git a/pkg/api/v1beta1/defaults_test.go b/pkg/api/v1beta1/defaults_test.go index 7a83c93411..988a87d8a0 100644 --- a/pkg/api/v1beta1/defaults_test.go +++ b/pkg/api/v1beta1/defaults_test.go @@ -340,106 +340,3 @@ func TestSetDefaultObjectFieldSelectorAPIVersion(t *testing.T) { t.Errorf("Expected default APIVersion v1beta1, got: %v", apiVersion) } } - -func TestSetDefaultSecurityContext(t *testing.T) { - priv := false - privTrue := true - testCases := map[string]struct { - c current.Container - }{ - "downward defaulting caps": { - c: current.Container{ - Privileged: false, - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - SecurityContext: ¤t.SecurityContext{ - Privileged: &priv, - }, - }, - }, - "downward defaulting priv": { - c: current.Container{ - Privileged: false, - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - SecurityContext: ¤t.SecurityContext{ - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - }, - }, - }, - "upward defaulting caps": { - c: current.Container{ - Privileged: false, - SecurityContext: ¤t.SecurityContext{ - Privileged: &priv, - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"biz"}, - Drop: []current.CapabilityType{"baz"}, - }, - }, - }, - }, - "upward defaulting priv": { - c: current.Container{ - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - SecurityContext: ¤t.SecurityContext{ - Privileged: &privTrue, - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - }, - }, - }, - } - - pod := ¤t.Pod{ - DesiredState: current.PodState{ - Manifest: current.ContainerManifest{}, - }, - } - - for k, v := range testCases { - pod.DesiredState.Manifest.Containers = []current.Container{v.c} - obj := roundTrip(t, runtime.Object(pod)) - defaultedPod := obj.(*current.Pod) - c := defaultedPod.DesiredState.Manifest.Containers[0] - if isEqual, issues := areSecurityContextAndContainerEqual(&c); !isEqual { - t.Errorf("test case %s expected the security context to have the same values as the container but found %#v", k, issues) - } - } -} - -func areSecurityContextAndContainerEqual(c *current.Container) (bool, []string) { - issues := make([]string, 0) - equal := true - - if c.SecurityContext == nil || c.SecurityContext.Privileged == nil || c.SecurityContext.Capabilities == nil { - equal = false - issues = append(issues, "Expected non nil settings for SecurityContext") - return equal, issues - } - if *c.SecurityContext.Privileged != c.Privileged { - equal = false - issues = append(issues, "The defaulted SecurityContext.Privileged value did not match the container value") - } - if !reflect.DeepEqual(c.Capabilities.Add, c.Capabilities.Add) { - equal = false - issues = append(issues, "The defaulted SecurityContext.Capabilities.Add did not match the container settings") - } - if !reflect.DeepEqual(c.Capabilities.Drop, c.Capabilities.Drop) { - equal = false - issues = append(issues, "The defaulted SecurityContext.Capabilities.Drop did not match the container settings") - } - return equal, issues -} diff --git a/pkg/api/v1beta1/types.go b/pkg/api/v1beta1/types.go index 8a63544218..cec76c88b6 100644 --- a/pkg/api/v1beta1/types.go +++ b/pkg/api/v1beta1/types.go @@ -525,14 +525,12 @@ type Container struct { Lifecycle *Lifecycle `json:"lifecycle,omitempty" description:"actions that the management system should take in response to container lifecycle events; cannot be updated"` // Optional: Defaults to /dev/termination-log TerminationMessagePath string `json:"terminationMessagePath,omitempty" description:"path at which the file to which the container's termination message will be written is mounted into the container's filesystem; message written is intended to be brief final status, such as an assertion failure message; defaults to /dev/termination-log; cannot be updated"` - // Deprecated - see SecurityContext. Optional: Default to false. - Privileged bool `json:"privileged,omitempty" description:"whether or not the container is granted privileged status; defaults to false; cannot be updated; deprecated; See SecurityContext"` + // Optional: Default to false. + Privileged bool `json:"privileged,omitempty" description:"whether or not the container is granted privileged status; defaults to false; cannot be updated"` // Optional: Policy for pulling images for this container ImagePullPolicy PullPolicy `json:"imagePullPolicy" description:"image pull policy; one of PullAlways, PullNever, PullIfNotPresent; defaults to PullAlways if :latest tag is specified, or PullIfNotPresent otherwise; cannot be updated"` - // Deprecated - see SecurityContext. Optional: Capabilities for container. - Capabilities Capabilities `json:"capabilities,omitempty" description:"capabilities for container; cannot be updated; deprecated; See SecurityContext"` - // Optional: SecurityContext defines the security options the pod should be run with - SecurityContext *SecurityContext `json:"securityContext,omitempty" description:"security options the pod should run with"` + // Optional: Capabilities for container. + Capabilities Capabilities `json:"capabilities,omitempty" description:"capabilities for container; cannot be updated"` } // Handler defines a specific action that should be taken @@ -1657,39 +1655,3 @@ type ComponentStatusList struct { Items []ComponentStatus `json:"items" description:"list of component status objects"` } - -// SecurityContext holds security configuration that will be applied to a container. SecurityContext -// contains duplication of some existing fields from the Container resource. These duplicate fields -// will be populated based on the Container configuration if they are not set. Defining them on -// both the Container AND the SecurityContext will result in an error. -type SecurityContext struct { - // Capabilities are the capabilities to add/drop when running the container - // Must match Container.Capabilities or be unset. Will be defaulted to Container.Capabilities if left unset - Capabilities *Capabilities `json:"capabilities,omitempty" description:"the linux capabilites that should be added or removed"` - - // Run the container in privileged mode - // Must match Container.Privileged or be unset. Will be defaulted to Container.Privileged if left unset - Privileged *bool `json:"privileged,omitempty" description:"run the container in privileged mode"` - - // SELinuxOptions are the labels to be applied to the container - // and volumes - SELinuxOptions *SELinuxOptions `json:"seLinuxOptions,omitempty" description:"options that control the SELinux labels applied"` - - // RunAsUser is the UID to run the entrypoint of the container process. - RunAsUser *int64 `json:"runAsUser,omitempty" description:"the user id that runs the first process in the container"` -} - -// SELinuxOptions are the labels to be applied to the container. -type SELinuxOptions struct { - // SELinux user label - User string `json:"user,omitempty" description:"the user label to apply to the container"` - - // SELinux role label - Role string `json:"role,omitempty" description:"the role label to apply to the container"` - - // SELinux type label - Type string `json:"type,omitempty" description:"the type label to apply to the container"` - - // SELinux level label. - Level string `json:"level,omitempty" description:"the level label to apply to the container"` -} diff --git a/pkg/api/v1beta2/conversion.go b/pkg/api/v1beta2/conversion.go index 090bc3f87e..63ccdd3079 100644 --- a/pkg/api/v1beta2/conversion.go +++ b/pkg/api/v1beta2/conversion.go @@ -19,7 +19,6 @@ package v1beta2 import ( "fmt" "net" - "reflect" "strconv" newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api" @@ -358,20 +357,15 @@ func init() { if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil { return err } + if err := s.Convert(&in.Privileged, &out.Privileged, 0); err != nil { + return err + } if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil { return err } - if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil { + if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil { return err } - // now that we've converted set the container field from security context - if out.SecurityContext != nil && out.SecurityContext.Privileged != nil { - out.Privileged = *out.SecurityContext.Privileged - } - // now that we've converted set the container field from security context - if out.SecurityContext != nil && out.SecurityContext.Capabilities != nil { - out.Capabilities = *out.SecurityContext.Capabilities - } return nil }, // Internal API does not support CPU to be specified via an explicit field. @@ -451,23 +445,13 @@ func init() { if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil { return err } + if err := s.Convert(&in.Privileged, &out.Privileged, 0); err != nil { + return err + } if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil { return err } - if in.SecurityContext != nil { - if in.SecurityContext.Capabilities != nil { - if !reflect.DeepEqual(in.SecurityContext.Capabilities.Add, in.Capabilities.Add) || - !reflect.DeepEqual(in.SecurityContext.Capabilities.Drop, in.Capabilities.Drop) { - return fmt.Errorf("container capability settings do not match security context settings, cannot convert") - } - } - if in.SecurityContext.Privileged != nil { - if in.Privileged != *in.SecurityContext.Privileged { - return fmt.Errorf("container privileged settings do not match security context settings, cannot convert") - } - } - } - if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil { + if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil { return err } return nil diff --git a/pkg/api/v1beta2/conversion_test.go b/pkg/api/v1beta2/conversion_test.go index df61dcaa70..c482f830bf 100644 --- a/pkg/api/v1beta2/conversion_test.go +++ b/pkg/api/v1beta2/conversion_test.go @@ -564,63 +564,3 @@ func TestSecretVolumeSourceConversion(t *testing.T) { t.Errorf("Expected %v; got %v", given, got2) } } - -func TestBadSecurityContextConversion(t *testing.T) { - priv := false - testCases := map[string]struct { - c *current.Container - err string - }{ - // this use case must use true for the container and false for the sc. Otherwise the defaulter - // will assume privileged was left undefined (since it is the default value) and copy the - // sc setting upwards - "mismatched privileged": { - c: ¤t.Container{ - Privileged: true, - SecurityContext: ¤t.SecurityContext{ - Privileged: &priv, - }, - }, - err: "container privileged settings do not match security context settings, cannot convert", - }, - "mismatched caps add": { - c: ¤t.Container{ - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - }, - SecurityContext: ¤t.SecurityContext{ - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"bar"}, - }, - }, - }, - err: "container capability settings do not match security context settings, cannot convert", - }, - "mismatched caps drop": { - c: ¤t.Container{ - Capabilities: current.Capabilities{ - Drop: []current.CapabilityType{"foo"}, - }, - SecurityContext: ¤t.SecurityContext{ - Capabilities: ¤t.Capabilities{ - Drop: []current.CapabilityType{"bar"}, - }, - }, - }, - err: "container capability settings do not match security context settings, cannot convert", - }, - } - - for k, v := range testCases { - got := newer.Container{} - err := newer.Scheme.Convert(v.c, &got) - if err == nil { - t.Errorf("expected error for case %s but got none", k) - } else { - if err.Error() != v.err { - t.Errorf("unexpected error for case %s. Expected: %s but got: %s", k, v.err, err.Error()) - } - } - } - -} diff --git a/pkg/api/v1beta2/defaults.go b/pkg/api/v1beta2/defaults.go index 53c3ab0a89..10cebbef20 100644 --- a/pkg/api/v1beta2/defaults.go +++ b/pkg/api/v1beta2/defaults.go @@ -63,7 +63,6 @@ func init() { if obj.TerminationMessagePath == "" { obj.TerminationMessagePath = TerminationMessagePathDefault } - defaultSecurityContext(obj) }, func(obj *RestartPolicy) { if util.AllPtrFieldsNil(obj) { @@ -196,44 +195,3 @@ func defaultHostNetworkPorts(containers *[]Container) { } } } - -// defaultSecurityContext performs the downward and upward merges of a pod definition -func defaultSecurityContext(container *Container) { - if container.SecurityContext == nil { - glog.V(4).Infof("creating security context for container %s", container.Name) - container.SecurityContext = &SecurityContext{} - } - // if there are no capabilities defined on the SecurityContext then copy the container settings - if container.SecurityContext.Capabilities == nil { - glog.V(4).Infof("downward merge of container.Capabilities for container %s", container.Name) - container.SecurityContext.Capabilities = &container.Capabilities - } else { - // if there are capabilities defined on the security context and the container setting is - // empty then assume that it was left off the pod definition and ensure that the container - // settings match the security context settings (checked by the convert functions). If - // there are settings in both then don't touch it, the converter will error if they don't - // match - if len(container.Capabilities.Add) == 0 { - glog.V(4).Infof("upward merge of container.Capabilities.Add for container %s", container.Name) - container.Capabilities.Add = container.SecurityContext.Capabilities.Add - } - if len(container.Capabilities.Drop) == 0 { - glog.V(4).Infof("upward merge of container.Capabilities.Drop for container %s", container.Name) - container.Capabilities.Drop = container.SecurityContext.Capabilities.Drop - } - } - // if there are no privileged settings on the security context then copy the container settings - if container.SecurityContext.Privileged == nil { - glog.V(4).Infof("downward merge of container.Privileged for container %s", container.Name) - container.SecurityContext.Privileged = &container.Privileged - } else { - // we don't have a good way to know if container.Privileged was set or just defaulted to false - // so the best we can do here is check if the securityContext is set to true and the - // container is set to false and assume that the Privileged field was left off the container - // definition and not an intentional mismatch - if *container.SecurityContext.Privileged && !container.Privileged { - glog.V(4).Infof("upward merge of container.Privileged for container %s", container.Name) - container.Privileged = *container.SecurityContext.Privileged - } - } -} diff --git a/pkg/api/v1beta2/defaults_test.go b/pkg/api/v1beta2/defaults_test.go index 78af77ac44..10e7ae2532 100644 --- a/pkg/api/v1beta2/defaults_test.go +++ b/pkg/api/v1beta2/defaults_test.go @@ -339,106 +339,3 @@ func TestSetDefaultObjectFieldSelectorAPIVersion(t *testing.T) { t.Errorf("Expected default APIVersion v1beta2, got: %v", apiVersion) } } - -func TestSetDefaultSecurityContext(t *testing.T) { - priv := false - privTrue := true - testCases := map[string]struct { - c current.Container - }{ - "downward defaulting caps": { - c: current.Container{ - Privileged: false, - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - SecurityContext: ¤t.SecurityContext{ - Privileged: &priv, - }, - }, - }, - "downward defaulting priv": { - c: current.Container{ - Privileged: false, - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - SecurityContext: ¤t.SecurityContext{ - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - }, - }, - }, - "upward defaulting caps": { - c: current.Container{ - Privileged: false, - SecurityContext: ¤t.SecurityContext{ - Privileged: &priv, - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"biz"}, - Drop: []current.CapabilityType{"baz"}, - }, - }, - }, - }, - "upward defaulting priv": { - c: current.Container{ - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - SecurityContext: ¤t.SecurityContext{ - Privileged: &privTrue, - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - }, - }, - }, - } - - pod := ¤t.Pod{ - DesiredState: current.PodState{ - Manifest: current.ContainerManifest{}, - }, - } - - for k, v := range testCases { - pod.DesiredState.Manifest.Containers = []current.Container{v.c} - obj := roundTrip(t, runtime.Object(pod)) - defaultedPod := obj.(*current.Pod) - c := defaultedPod.DesiredState.Manifest.Containers[0] - if isEqual, issues := areSecurityContextAndContainerEqual(&c); !isEqual { - t.Errorf("test case %s expected the security context to have the same values as the container but found %#v", k, issues) - } - } -} - -func areSecurityContextAndContainerEqual(c *current.Container) (bool, []string) { - issues := make([]string, 0) - equal := true - - if c.SecurityContext == nil || c.SecurityContext.Privileged == nil || c.SecurityContext.Capabilities == nil { - equal = false - issues = append(issues, "Expected non nil settings for SecurityContext") - return equal, issues - } - if *c.SecurityContext.Privileged != c.Privileged { - equal = false - issues = append(issues, "The defaulted SecurityContext.Privileged value did not match the container value") - } - if !reflect.DeepEqual(c.Capabilities.Add, c.Capabilities.Add) { - equal = false - issues = append(issues, "The defaulted SecurityContext.Capabilities.Add did not match the container settings") - } - if !reflect.DeepEqual(c.Capabilities.Drop, c.Capabilities.Drop) { - equal = false - issues = append(issues, "The defaulted SecurityContext.Capabilities.Drop did not match the container settings") - } - return equal, issues -} diff --git a/pkg/api/v1beta2/types.go b/pkg/api/v1beta2/types.go index c844818025..8d601d904a 100644 --- a/pkg/api/v1beta2/types.go +++ b/pkg/api/v1beta2/types.go @@ -513,14 +513,12 @@ type Container struct { Lifecycle *Lifecycle `json:"lifecycle,omitempty" description:"actions that the management system should take in response to container lifecycle events; cannot be updated"` // Optional: Defaults to /dev/termination-log TerminationMessagePath string `json:"terminationMessagePath,omitempty" description:"path at which the file to which the container's termination message will be written is mounted into the container's filesystem; message written is intended to be brief final status, such as an assertion failure message; defaults to /dev/termination-log; cannot be updated"` - // Deprecated - see SecurityContext. Optional: Default to false. - Privileged bool `json:"privileged,omitempty" description:"whether or not the container is granted privileged status; defaults to false; cannot be updated; deprecated; See SecurityContext"` + // Optional: Default to false. + Privileged bool `json:"privileged,omitempty" description:"whether or not the container is granted privileged status; defaults to false; cannot be updated"` // Optional: Policy for pulling images for this container ImagePullPolicy PullPolicy `json:"imagePullPolicy" description:"image pull policy; one of PullAlways, PullNever, PullIfNotPresent; defaults to PullAlways if :latest tag is specified, or PullIfNotPresent otherwise; cannot be updated"` - // Deprecated - see SecurityContext. Optional: Capabilities for container. - Capabilities Capabilities `json:"capabilities,omitempty" description:"capabilities for container; cannot be updated; deprecated; See SecurityContext"` - // Optional: SecurityContext defines the security options the pod should be run with - SecurityContext *SecurityContext `json:"securityContext,omitempty" description:"security options the pod should run with"` + // Optional: Capabilities for container. + Capabilities Capabilities `json:"capabilities,omitempty" description:"capabilities for container; cannot be updated"` } const ( @@ -1719,39 +1717,3 @@ type ComponentStatusList struct { Items []ComponentStatus `json:"items" description:"list of component status objects"` } - -// SecurityContext holds security configuration that will be applied to a container. SecurityContext -// contains duplication of some existing fields from the Container resource. These duplicate fields -// will be populated based on the Container configuration if they are not set. Defining them on -// both the Container AND the SecurityContext will result in an error. -type SecurityContext struct { - // Capabilities are the capabilities to add/drop when running the container - // Must match Container.Capabilities or be unset. Will be defaulted to Container.Capabilities if left unset - Capabilities *Capabilities `json:"capabilities,omitempty" description:"the linux capabilites that should be added or removed"` - - // Run the container in privileged mode - // Must match Container.Privileged or be unset. Will be defaulted to Container.Privileged if left unset - Privileged *bool `json:"privileged,omitempty" description:"run the container in privileged mode"` - - // SELinuxOptions are the labels to be applied to the container - // and volumes - SELinuxOptions *SELinuxOptions `json:"seLinuxOptions,omitempty" description:"options that control the SELinux labels applied"` - - // RunAsUser is the UID to run the entrypoint of the container process. - RunAsUser *int64 `json:"runAsUser,omitempty" description:"the user id that runs the first process in the container"` -} - -// SELinuxOptions are the labels to be applied to the container. -type SELinuxOptions struct { - // SELinux user label - User string `json:"user,omitempty" description:"the user label to apply to the container"` - - // SELinux role label - Role string `json:"role,omitempty" description:"the role label to apply to the container"` - - // SELinux type label - Type string `json:"type,omitempty" description:"the type label to apply to the container"` - - // SELinux level label. - Level string `json:"level,omitempty" description:"the level label to apply to the container"` -} diff --git a/pkg/api/v1beta3/conversion.go b/pkg/api/v1beta3/conversion.go index 35073f6bfd..c3ebf70fb1 100644 --- a/pkg/api/v1beta3/conversion.go +++ b/pkg/api/v1beta3/conversion.go @@ -18,7 +18,6 @@ package v1beta3 import ( "fmt" - "reflect" newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource" @@ -68,6 +67,38 @@ func convert_api_Binding_To_v1beta3_Binding(in *newer.Binding, out *Binding, s c return nil } +func convert_v1beta3_Capabilities_To_api_Capabilities(in *Capabilities, out *newer.Capabilities, s conversion.Scope) error { + if in.Add != nil { + out.Add = make([]newer.CapabilityType, len(in.Add)) + for i := range in.Add { + out.Add[i] = newer.CapabilityType(in.Add[i]) + } + } + if in.Drop != nil { + out.Drop = make([]newer.CapabilityType, len(in.Drop)) + for i := range in.Drop { + out.Drop[i] = newer.CapabilityType(in.Drop[i]) + } + } + return nil +} + +func convert_api_Capabilities_To_v1beta3_Capabilities(in *newer.Capabilities, out *Capabilities, s conversion.Scope) error { + if in.Add != nil { + out.Add = make([]CapabilityType, len(in.Add)) + for i := range in.Add { + out.Add[i] = CapabilityType(in.Add[i]) + } + } + if in.Drop != nil { + out.Drop = make([]CapabilityType, len(in.Drop)) + for i := range in.Drop { + out.Drop[i] = CapabilityType(in.Drop[i]) + } + } + return nil +} + func convert_v1beta3_ComponentCondition_To_api_ComponentCondition(in *ComponentCondition, out *newer.ComponentCondition, s conversion.Scope) error { out.Type = newer.ComponentConditionType(in.Type) out.Status = newer.ConditionStatus(in.Status) @@ -156,6 +187,128 @@ func convert_api_ComponentStatusList_To_v1beta3_ComponentStatusList(in *newer.Co return nil } +func convert_v1beta3_Container_To_api_Container(in *Container, out *newer.Container, s conversion.Scope) error { + out.Name = in.Name + out.Image = in.Image + if in.Command != nil { + out.Command = make([]string, len(in.Command)) + for i := range in.Command { + out.Command[i] = in.Command[i] + } + } + if in.Args != nil { + out.Args = make([]string, len(in.Args)) + for i := range in.Args { + out.Args[i] = in.Args[i] + } + } + out.WorkingDir = in.WorkingDir + if in.Ports != nil { + out.Ports = make([]newer.ContainerPort, len(in.Ports)) + for i := range in.Ports { + if err := s.Convert(&in.Ports[i], &out.Ports[i], 0); err != nil { + return err + } + } + } + if in.Env != nil { + out.Env = make([]newer.EnvVar, len(in.Env)) + for i := range in.Env { + if err := s.Convert(&in.Env[i], &out.Env[i], 0); err != nil { + return err + } + } + } + if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil { + return err + } + if in.VolumeMounts != nil { + out.VolumeMounts = make([]newer.VolumeMount, len(in.VolumeMounts)) + for i := range in.VolumeMounts { + if err := s.Convert(&in.VolumeMounts[i], &out.VolumeMounts[i], 0); err != nil { + return err + } + } + } + if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil { + return err + } + if err := s.Convert(&in.ReadinessProbe, &out.ReadinessProbe, 0); err != nil { + return err + } + if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil { + return err + } + out.TerminationMessagePath = in.TerminationMessagePath + out.Privileged = in.Privileged + out.ImagePullPolicy = newer.PullPolicy(in.ImagePullPolicy) + if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil { + return err + } + return nil +} + +func convert_api_Container_To_v1beta3_Container(in *newer.Container, out *Container, s conversion.Scope) error { + out.Name = in.Name + out.Image = in.Image + if in.Command != nil { + out.Command = make([]string, len(in.Command)) + for i := range in.Command { + out.Command[i] = in.Command[i] + } + } + if in.Args != nil { + out.Args = make([]string, len(in.Args)) + for i := range in.Args { + out.Args[i] = in.Args[i] + } + } + out.WorkingDir = in.WorkingDir + if in.Ports != nil { + out.Ports = make([]ContainerPort, len(in.Ports)) + for i := range in.Ports { + if err := s.Convert(&in.Ports[i], &out.Ports[i], 0); err != nil { + return err + } + } + } + if in.Env != nil { + out.Env = make([]EnvVar, len(in.Env)) + for i := range in.Env { + if err := s.Convert(&in.Env[i], &out.Env[i], 0); err != nil { + return err + } + } + } + if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil { + return err + } + if in.VolumeMounts != nil { + out.VolumeMounts = make([]VolumeMount, len(in.VolumeMounts)) + for i := range in.VolumeMounts { + if err := s.Convert(&in.VolumeMounts[i], &out.VolumeMounts[i], 0); err != nil { + return err + } + } + } + if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil { + return err + } + if err := s.Convert(&in.ReadinessProbe, &out.ReadinessProbe, 0); err != nil { + return err + } + if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil { + return err + } + out.TerminationMessagePath = in.TerminationMessagePath + out.Privileged = in.Privileged + out.ImagePullPolicy = PullPolicy(in.ImagePullPolicy) + if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil { + return err + } + return nil +} + func convert_v1beta3_ContainerPort_To_api_ContainerPort(in *ContainerPort, out *newer.ContainerPort, s conversion.Scope) error { out.Name = in.Name out.HostPort = in.HostPort @@ -1644,6 +1797,38 @@ func convert_api_PersistentVolumeStatus_To_v1beta3_PersistentVolumeStatus(in *ne return nil } +func convert_v1beta3_Pod_To_api_Pod(in *Pod, out *newer.Pod, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil +} + +func convert_api_Pod_To_v1beta3_Pod(in *newer.Pod, out *Pod, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil +} + func convert_v1beta3_PodCondition_To_api_PodCondition(in *PodCondition, out *newer.PodCondition, s conversion.Scope) error { out.Type = newer.PodConditionType(in.Type) out.Status = newer.ConditionStatus(in.Status) @@ -1692,6 +1877,42 @@ func convert_api_PodExecOptions_To_v1beta3_PodExecOptions(in *newer.PodExecOptio return nil } +func convert_v1beta3_PodList_To_api_PodList(in *PodList, out *newer.PodList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.Pod, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil +} + +func convert_api_PodList_To_v1beta3_PodList(in *newer.PodList, out *PodList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]Pod, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil +} + func convert_v1beta3_PodLogOptions_To_api_PodLogOptions(in *PodLogOptions, out *newer.PodLogOptions, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err @@ -1726,6 +1947,74 @@ func convert_api_PodProxyOptions_To_v1beta3_PodProxyOptions(in *newer.PodProxyOp return nil } +func convert_v1beta3_PodSpec_To_api_PodSpec(in *PodSpec, out *newer.PodSpec, s conversion.Scope) error { + if in.Volumes != nil { + out.Volumes = make([]newer.Volume, len(in.Volumes)) + for i := range in.Volumes { + if err := s.Convert(&in.Volumes[i], &out.Volumes[i], 0); err != nil { + return err + } + } + } + if in.Containers != nil { + out.Containers = make([]newer.Container, len(in.Containers)) + for i := range in.Containers { + if err := s.Convert(&in.Containers[i], &out.Containers[i], 0); err != nil { + return err + } + } + } + out.RestartPolicy = newer.RestartPolicy(in.RestartPolicy) + if in.TerminationGracePeriodSeconds != nil { + out.TerminationGracePeriodSeconds = new(int64) + *out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds + } + out.DNSPolicy = newer.DNSPolicy(in.DNSPolicy) + if in.NodeSelector != nil { + out.NodeSelector = make(map[string]string) + for key, val := range in.NodeSelector { + out.NodeSelector[key] = val + } + } + out.Host = in.Host + out.HostNetwork = in.HostNetwork + return nil +} + +func convert_api_PodSpec_To_v1beta3_PodSpec(in *newer.PodSpec, out *PodSpec, s conversion.Scope) error { + if in.Volumes != nil { + out.Volumes = make([]Volume, len(in.Volumes)) + for i := range in.Volumes { + if err := s.Convert(&in.Volumes[i], &out.Volumes[i], 0); err != nil { + return err + } + } + } + if in.Containers != nil { + out.Containers = make([]Container, len(in.Containers)) + for i := range in.Containers { + if err := s.Convert(&in.Containers[i], &out.Containers[i], 0); err != nil { + return err + } + } + } + out.RestartPolicy = RestartPolicy(in.RestartPolicy) + if in.TerminationGracePeriodSeconds != nil { + out.TerminationGracePeriodSeconds = new(int64) + *out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds + } + out.DNSPolicy = DNSPolicy(in.DNSPolicy) + if in.NodeSelector != nil { + out.NodeSelector = make(map[string]string) + for key, val := range in.NodeSelector { + out.NodeSelector[key] = val + } + } + out.Host = in.Host + out.HostNetwork = in.HostNetwork + return nil +} + func convert_v1beta3_PodStatus_To_api_PodStatus(in *PodStatus, out *newer.PodStatus, s conversion.Scope) error { out.Phase = newer.PodPhase(in.Phase) if in.Conditions != nil { @@ -1800,6 +2089,88 @@ func convert_api_PodStatusResult_To_v1beta3_PodStatusResult(in *newer.PodStatusR return nil } +func convert_v1beta3_PodTemplate_To_api_PodTemplate(in *PodTemplate, out *newer.PodTemplate, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Template, &out.Template, 0); err != nil { + return err + } + return nil +} + +func convert_api_PodTemplate_To_v1beta3_PodTemplate(in *newer.PodTemplate, out *PodTemplate, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Template, &out.Template, 0); err != nil { + return err + } + return nil +} + +func convert_v1beta3_PodTemplateList_To_api_PodTemplateList(in *PodTemplateList, out *newer.PodTemplateList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.PodTemplate, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil +} + +func convert_api_PodTemplateList_To_v1beta3_PodTemplateList(in *newer.PodTemplateList, out *PodTemplateList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]PodTemplate, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil +} + +func convert_v1beta3_PodTemplateSpec_To_api_PodTemplateSpec(in *PodTemplateSpec, out *newer.PodTemplateSpec, s conversion.Scope) error { + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + return nil +} + +func convert_api_PodTemplateSpec_To_v1beta3_PodTemplateSpec(in *newer.PodTemplateSpec, out *PodTemplateSpec, s conversion.Scope) error { + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + return nil +} + func convert_v1beta3_Probe_To_api_Probe(in *Probe, out *newer.Probe, s conversion.Scope) error { if err := s.Convert(&in.Handler, &out.Handler, 0); err != nil { return err @@ -1818,6 +2189,118 @@ func convert_api_Probe_To_v1beta3_Probe(in *newer.Probe, out *Probe, s conversio return nil } +func convert_v1beta3_ReplicationController_To_api_ReplicationController(in *ReplicationController, out *newer.ReplicationController, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil +} + +func convert_api_ReplicationController_To_v1beta3_ReplicationController(in *newer.ReplicationController, out *ReplicationController, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { + return err + } + if err := s.Convert(&in.Status, &out.Status, 0); err != nil { + return err + } + return nil +} + +func convert_v1beta3_ReplicationControllerList_To_api_ReplicationControllerList(in *ReplicationControllerList, out *newer.ReplicationControllerList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]newer.ReplicationController, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil +} + +func convert_api_ReplicationControllerList_To_v1beta3_ReplicationControllerList(in *newer.ReplicationControllerList, out *ReplicationControllerList, s conversion.Scope) error { + if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { + return err + } + if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { + return err + } + if in.Items != nil { + out.Items = make([]ReplicationController, len(in.Items)) + for i := range in.Items { + if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { + return err + } + } + } + return nil +} + +func convert_v1beta3_ReplicationControllerSpec_To_api_ReplicationControllerSpec(in *ReplicationControllerSpec, out *newer.ReplicationControllerSpec, s conversion.Scope) error { + out.Replicas = in.Replicas + if in.Selector != nil { + out.Selector = make(map[string]string) + for key, val := range in.Selector { + out.Selector[key] = val + } + } + if err := s.Convert(&in.TemplateRef, &out.TemplateRef, 0); err != nil { + return err + } + if err := s.Convert(&in.Template, &out.Template, 0); err != nil { + return err + } + return nil +} + +func convert_api_ReplicationControllerSpec_To_v1beta3_ReplicationControllerSpec(in *newer.ReplicationControllerSpec, out *ReplicationControllerSpec, s conversion.Scope) error { + out.Replicas = in.Replicas + if in.Selector != nil { + out.Selector = make(map[string]string) + for key, val := range in.Selector { + out.Selector[key] = val + } + } + if err := s.Convert(&in.TemplateRef, &out.TemplateRef, 0); err != nil { + return err + } + if err := s.Convert(&in.Template, &out.Template, 0); err != nil { + return err + } + return nil +} + +func convert_v1beta3_ReplicationControllerStatus_To_api_ReplicationControllerStatus(in *ReplicationControllerStatus, out *newer.ReplicationControllerStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + return nil +} + +func convert_api_ReplicationControllerStatus_To_v1beta3_ReplicationControllerStatus(in *newer.ReplicationControllerStatus, out *ReplicationControllerStatus, s conversion.Scope) error { + out.Replicas = in.Replicas + return nil +} + func convert_v1beta3_ResourceQuota_To_api_ResourceQuota(in *ResourceQuota, out *newer.ResourceQuota, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err @@ -2456,6 +2939,7 @@ func init() { err := newer.Scheme.AddGeneratedConversionFuncs( convert_api_AWSElasticBlockStoreVolumeSource_To_v1beta3_AWSElasticBlockStoreVolumeSource, convert_api_Binding_To_v1beta3_Binding, + convert_api_Capabilities_To_v1beta3_Capabilities, convert_api_ComponentCondition_To_v1beta3_ComponentCondition, convert_api_ComponentStatusList_To_v1beta3_ComponentStatusList, convert_api_ComponentStatus_To_v1beta3_ComponentStatus, @@ -2465,6 +2949,7 @@ func init() { convert_api_ContainerStateWaiting_To_v1beta3_ContainerStateWaiting, convert_api_ContainerState_To_v1beta3_ContainerState, convert_api_ContainerStatus_To_v1beta3_ContainerStatus, + convert_api_Container_To_v1beta3_Container, convert_api_DeleteOptions_To_v1beta3_DeleteOptions, convert_api_EmptyDirVolumeSource_To_v1beta3_EmptyDirVolumeSource, convert_api_EndpointAddress_To_v1beta3_EndpointAddress, @@ -2518,11 +3003,21 @@ func init() { convert_api_PersistentVolume_To_v1beta3_PersistentVolume, convert_api_PodCondition_To_v1beta3_PodCondition, convert_api_PodExecOptions_To_v1beta3_PodExecOptions, + convert_api_PodList_To_v1beta3_PodList, convert_api_PodLogOptions_To_v1beta3_PodLogOptions, convert_api_PodProxyOptions_To_v1beta3_PodProxyOptions, + convert_api_PodSpec_To_v1beta3_PodSpec, convert_api_PodStatusResult_To_v1beta3_PodStatusResult, convert_api_PodStatus_To_v1beta3_PodStatus, + convert_api_PodTemplateList_To_v1beta3_PodTemplateList, + convert_api_PodTemplateSpec_To_v1beta3_PodTemplateSpec, + convert_api_PodTemplate_To_v1beta3_PodTemplate, + convert_api_Pod_To_v1beta3_Pod, convert_api_Probe_To_v1beta3_Probe, + convert_api_ReplicationControllerList_To_v1beta3_ReplicationControllerList, + convert_api_ReplicationControllerSpec_To_v1beta3_ReplicationControllerSpec, + convert_api_ReplicationControllerStatus_To_v1beta3_ReplicationControllerStatus, + convert_api_ReplicationController_To_v1beta3_ReplicationController, convert_api_ResourceQuotaList_To_v1beta3_ResourceQuotaList, convert_api_ResourceQuotaSpec_To_v1beta3_ResourceQuotaSpec, convert_api_ResourceQuotaStatus_To_v1beta3_ResourceQuotaStatus, @@ -2546,6 +3041,7 @@ func init() { convert_api_Volume_To_v1beta3_Volume, convert_v1beta3_AWSElasticBlockStoreVolumeSource_To_api_AWSElasticBlockStoreVolumeSource, convert_v1beta3_Binding_To_api_Binding, + convert_v1beta3_Capabilities_To_api_Capabilities, convert_v1beta3_ComponentCondition_To_api_ComponentCondition, convert_v1beta3_ComponentStatusList_To_api_ComponentStatusList, convert_v1beta3_ComponentStatus_To_api_ComponentStatus, @@ -2555,6 +3051,7 @@ func init() { convert_v1beta3_ContainerStateWaiting_To_api_ContainerStateWaiting, convert_v1beta3_ContainerState_To_api_ContainerState, convert_v1beta3_ContainerStatus_To_api_ContainerStatus, + convert_v1beta3_Container_To_api_Container, convert_v1beta3_DeleteOptions_To_api_DeleteOptions, convert_v1beta3_EmptyDirVolumeSource_To_api_EmptyDirVolumeSource, convert_v1beta3_EndpointAddress_To_api_EndpointAddress, @@ -2608,11 +3105,21 @@ func init() { convert_v1beta3_PersistentVolume_To_api_PersistentVolume, convert_v1beta3_PodCondition_To_api_PodCondition, convert_v1beta3_PodExecOptions_To_api_PodExecOptions, + convert_v1beta3_PodList_To_api_PodList, convert_v1beta3_PodLogOptions_To_api_PodLogOptions, convert_v1beta3_PodProxyOptions_To_api_PodProxyOptions, + convert_v1beta3_PodSpec_To_api_PodSpec, convert_v1beta3_PodStatusResult_To_api_PodStatusResult, convert_v1beta3_PodStatus_To_api_PodStatus, + convert_v1beta3_PodTemplateList_To_api_PodTemplateList, + convert_v1beta3_PodTemplateSpec_To_api_PodTemplateSpec, + convert_v1beta3_PodTemplate_To_api_PodTemplate, + convert_v1beta3_Pod_To_api_Pod, convert_v1beta3_Probe_To_api_Probe, + convert_v1beta3_ReplicationControllerList_To_api_ReplicationControllerList, + convert_v1beta3_ReplicationControllerSpec_To_api_ReplicationControllerSpec, + convert_v1beta3_ReplicationControllerStatus_To_api_ReplicationControllerStatus, + convert_v1beta3_ReplicationController_To_api_ReplicationController, convert_v1beta3_ResourceQuotaList_To_api_ResourceQuotaList, convert_v1beta3_ResourceQuotaSpec_To_api_ResourceQuotaSpec, convert_v1beta3_ResourceQuotaStatus_To_api_ResourceQuotaStatus, @@ -2636,32 +3143,6 @@ func init() { convert_v1beta3_Volume_To_api_Volume, ) - // Add non-generated conversion functions - newer.Scheme.AddConversionFuncs( - convert_v1beta3_Pod_To_api_Pod, - convert_api_Pod_To_v1beta3_Pod, - convert_v1beta3_ReplicationController_To_api_ReplicationController, - convert_api_ReplicationController_To_v1beta3_ReplicationController, - convert_v1beta3_ReplicationControllerList_To_api_ReplicationControllerList, - convert_api_ReplicationControllerList_To_v1beta3_ReplicationControllerList, - convert_v1beta3_PodList_To_api_PodList, - convert_api_PodList_To_v1beta3_PodList, - convert_v1beta3_PodTemplate_To_api_PodTemplate, - convert_api_PodTemplate_To_v1beta3_PodTemplate, - convert_v1beta3_PodTemplateList_To_api_PodTemplateList, - convert_api_PodTemplateList_To_v1beta3_PodTemplateList, - convert_v1beta3_PodSpec_To_api_PodSpec, - convert_api_PodSpec_To_v1beta3_PodSpec, - convert_v1beta3_PodTemplateSpec_To_api_PodTemplateSpec, - convert_api_PodTemplateSpec_To_v1beta3_PodTemplateSpec, - convert_v1beta3_ReplicationControllerSpec_To_api_ReplicationControllerSpec, - convert_api_ReplicationControllerSpec_To_v1beta3_ReplicationControllerSpec, - convert_v1beta3_ReplicationControllerStatus_To_api_ReplicationControllerStatus, - convert_api_ReplicationControllerStatus_To_v1beta3_ReplicationControllerStatus, - convert_v1beta3_Container_To_api_Container, - convert_api_Container_To_v1beta3_Container, - ) - // Add field conversion funcs. err = newer.Scheme.AddFieldLabelConversionFunc("v1beta3", "Pod", func(label, value string) (string, string, error) { @@ -2756,474 +3237,3 @@ func init() { panic(err) } } - -func convert_v1beta3_Pod_To_api_Pod(in *Pod, out *newer.Pod, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { - return err - } - if err := s.Convert(&in.Status, &out.Status, 0); err != nil { - return err - } - return nil -} - -func convert_api_Pod_To_v1beta3_Pod(in *newer.Pod, out *Pod, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { - return err - } - if err := s.Convert(&in.Status, &out.Status, 0); err != nil { - return err - } - return nil -} - -func convert_v1beta3_ReplicationController_To_api_ReplicationController(in *ReplicationController, out *newer.ReplicationController, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { - return err - } - if err := s.Convert(&in.Status, &out.Status, 0); err != nil { - return err - } - return nil -} - -func convert_api_ReplicationController_To_v1beta3_ReplicationController(in *newer.ReplicationController, out *ReplicationController, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { - return err - } - if err := s.Convert(&in.Status, &out.Status, 0); err != nil { - return err - } - return nil -} - -func convert_v1beta3_ReplicationControllerList_To_api_ReplicationControllerList(in *ReplicationControllerList, out *newer.ReplicationControllerList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { - return err - } - if in.Items != nil { - out.Items = make([]newer.ReplicationController, len(in.Items)) - for i := range in.Items { - if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { - return err - } - } - } - return nil -} - -func convert_api_ReplicationControllerList_To_v1beta3_ReplicationControllerList(in *newer.ReplicationControllerList, out *ReplicationControllerList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { - return err - } - if in.Items != nil { - out.Items = make([]ReplicationController, len(in.Items)) - for i := range in.Items { - if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { - return err - } - } - } - return nil -} - -func convert_v1beta3_PodList_To_api_PodList(in *PodList, out *newer.PodList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { - return err - } - if in.Items != nil { - out.Items = make([]newer.Pod, len(in.Items)) - for i := range in.Items { - if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { - return err - } - } - } - return nil -} - -func convert_api_PodList_To_v1beta3_PodList(in *newer.PodList, out *PodList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { - return err - } - if in.Items != nil { - out.Items = make([]Pod, len(in.Items)) - for i := range in.Items { - if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { - return err - } - } - } - return nil -} - -func convert_v1beta3_PodTemplate_To_api_PodTemplate(in *PodTemplate, out *newer.PodTemplate, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.Template, &out.Template, 0); err != nil { - return err - } - return nil -} - -func convert_api_PodTemplate_To_v1beta3_PodTemplate(in *newer.PodTemplate, out *PodTemplate, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.Template, &out.Template, 0); err != nil { - return err - } - return nil -} - -func convert_v1beta3_PodTemplateList_To_api_PodTemplateList(in *PodTemplateList, out *newer.PodTemplateList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { - return err - } - if in.Items != nil { - out.Items = make([]newer.PodTemplate, len(in.Items)) - for i := range in.Items { - if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { - return err - } - } - } - return nil -} - -func convert_api_PodTemplateList_To_v1beta3_PodTemplateList(in *newer.PodTemplateList, out *PodTemplateList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil { - return err - } - if in.Items != nil { - out.Items = make([]PodTemplate, len(in.Items)) - for i := range in.Items { - if err := s.Convert(&in.Items[i], &out.Items[i], 0); err != nil { - return err - } - } - } - return nil -} - -func convert_v1beta3_PodSpec_To_api_PodSpec(in *PodSpec, out *newer.PodSpec, s conversion.Scope) error { - if in.Volumes != nil { - out.Volumes = make([]newer.Volume, len(in.Volumes)) - for i := range in.Volumes { - if err := s.Convert(&in.Volumes[i], &out.Volumes[i], 0); err != nil { - return err - } - } - } - if in.Containers != nil { - out.Containers = make([]newer.Container, len(in.Containers)) - for i := range in.Containers { - if err := s.Convert(&in.Containers[i], &out.Containers[i], 0); err != nil { - return err - } - } - } - out.RestartPolicy = newer.RestartPolicy(in.RestartPolicy) - if in.TerminationGracePeriodSeconds != nil { - out.TerminationGracePeriodSeconds = new(int64) - *out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds - } - out.DNSPolicy = newer.DNSPolicy(in.DNSPolicy) - if in.NodeSelector != nil { - out.NodeSelector = make(map[string]string) - for key, val := range in.NodeSelector { - out.NodeSelector[key] = val - } - } - out.Host = in.Host - out.HostNetwork = in.HostNetwork - return nil -} - -func convert_api_PodSpec_To_v1beta3_PodSpec(in *newer.PodSpec, out *PodSpec, s conversion.Scope) error { - if in.Volumes != nil { - out.Volumes = make([]Volume, len(in.Volumes)) - for i := range in.Volumes { - if err := s.Convert(&in.Volumes[i], &out.Volumes[i], 0); err != nil { - return err - } - } - } - if in.Containers != nil { - out.Containers = make([]Container, len(in.Containers)) - for i := range in.Containers { - if err := s.Convert(&in.Containers[i], &out.Containers[i], 0); err != nil { - return err - } - } - } - out.RestartPolicy = RestartPolicy(in.RestartPolicy) - if in.TerminationGracePeriodSeconds != nil { - out.TerminationGracePeriodSeconds = new(int64) - *out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds - } - out.DNSPolicy = DNSPolicy(in.DNSPolicy) - if in.NodeSelector != nil { - out.NodeSelector = make(map[string]string) - for key, val := range in.NodeSelector { - out.NodeSelector[key] = val - } - } - out.Host = in.Host - out.HostNetwork = in.HostNetwork - return nil -} - -func convert_v1beta3_PodTemplateSpec_To_api_PodTemplateSpec(in *PodTemplateSpec, out *newer.PodTemplateSpec, s conversion.Scope) error { - if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { - return err - } - return nil -} - -func convert_api_PodTemplateSpec_To_v1beta3_PodTemplateSpec(in *newer.PodTemplateSpec, out *PodTemplateSpec, s conversion.Scope) error { - if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { - return err - } - return nil -} - -func convert_v1beta3_ReplicationControllerSpec_To_api_ReplicationControllerSpec(in *ReplicationControllerSpec, out *newer.ReplicationControllerSpec, s conversion.Scope) error { - out.Replicas = in.Replicas - if in.Selector != nil { - out.Selector = make(map[string]string) - for key, val := range in.Selector { - out.Selector[key] = val - } - } - if err := s.Convert(&in.TemplateRef, &out.TemplateRef, 0); err != nil { - return err - } - if err := s.Convert(&in.Template, &out.Template, 0); err != nil { - return err - } - return nil -} - -func convert_api_ReplicationControllerSpec_To_v1beta3_ReplicationControllerSpec(in *newer.ReplicationControllerSpec, out *ReplicationControllerSpec, s conversion.Scope) error { - out.Replicas = in.Replicas - if in.Selector != nil { - out.Selector = make(map[string]string) - for key, val := range in.Selector { - out.Selector[key] = val - } - } - if err := s.Convert(&in.TemplateRef, &out.TemplateRef, 0); err != nil { - return err - } - if err := s.Convert(&in.Template, &out.Template, 0); err != nil { - return err - } - return nil -} - -func convert_v1beta3_ReplicationControllerStatus_To_api_ReplicationControllerStatus(in *ReplicationControllerStatus, out *newer.ReplicationControllerStatus, s conversion.Scope) error { - out.Replicas = in.Replicas - return nil -} - -func convert_api_ReplicationControllerStatus_To_v1beta3_ReplicationControllerStatus(in *newer.ReplicationControllerStatus, out *ReplicationControllerStatus, s conversion.Scope) error { - out.Replicas = in.Replicas - return nil -} - -func convert_v1beta3_Container_To_api_Container(in *Container, out *newer.Container, s conversion.Scope) error { - out.Name = in.Name - out.Image = in.Image - if in.Command != nil { - out.Command = make([]string, len(in.Command)) - for i := range in.Command { - out.Command[i] = in.Command[i] - } - } - if in.Args != nil { - out.Args = make([]string, len(in.Args)) - for i := range in.Args { - out.Args[i] = in.Args[i] - } - } - out.WorkingDir = in.WorkingDir - if in.Ports != nil { - out.Ports = make([]newer.ContainerPort, len(in.Ports)) - for i := range in.Ports { - if err := s.Convert(&in.Ports[i], &out.Ports[i], 0); err != nil { - return err - } - } - } - if in.Env != nil { - out.Env = make([]newer.EnvVar, len(in.Env)) - for i := range in.Env { - if err := s.Convert(&in.Env[i], &out.Env[i], 0); err != nil { - return err - } - } - } - if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil { - return err - } - if in.VolumeMounts != nil { - out.VolumeMounts = make([]newer.VolumeMount, len(in.VolumeMounts)) - for i := range in.VolumeMounts { - if err := s.Convert(&in.VolumeMounts[i], &out.VolumeMounts[i], 0); err != nil { - return err - } - } - } - if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil { - return err - } - if err := s.Convert(&in.ReadinessProbe, &out.ReadinessProbe, 0); err != nil { - return err - } - if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil { - return err - } - out.TerminationMessagePath = in.TerminationMessagePath - out.ImagePullPolicy = newer.PullPolicy(in.ImagePullPolicy) - if in.SecurityContext != nil { - if in.SecurityContext.Capabilities != nil { - if !reflect.DeepEqual(in.SecurityContext.Capabilities.Add, in.Capabilities.Add) || - !reflect.DeepEqual(in.SecurityContext.Capabilities.Drop, in.Capabilities.Drop) { - return fmt.Errorf("container capability settings do not match security context settings, cannot convert") - } - } - if in.SecurityContext.Privileged != nil { - if in.Privileged != *in.SecurityContext.Privileged { - return fmt.Errorf("container privileged settings do not match security context settings, cannot convert") - } - } - } - if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil { - return err - } - return nil -} - -func convert_api_Container_To_v1beta3_Container(in *newer.Container, out *Container, s conversion.Scope) error { - out.Name = in.Name - out.Image = in.Image - if in.Command != nil { - out.Command = make([]string, len(in.Command)) - for i := range in.Command { - out.Command[i] = in.Command[i] - } - } - if in.Args != nil { - out.Args = make([]string, len(in.Args)) - for i := range in.Args { - out.Args[i] = in.Args[i] - } - } - out.WorkingDir = in.WorkingDir - if in.Ports != nil { - out.Ports = make([]ContainerPort, len(in.Ports)) - for i := range in.Ports { - if err := s.Convert(&in.Ports[i], &out.Ports[i], 0); err != nil { - return err - } - } - } - if in.Env != nil { - out.Env = make([]EnvVar, len(in.Env)) - for i := range in.Env { - if err := s.Convert(&in.Env[i], &out.Env[i], 0); err != nil { - return err - } - } - } - if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil { - return err - } - if in.VolumeMounts != nil { - out.VolumeMounts = make([]VolumeMount, len(in.VolumeMounts)) - for i := range in.VolumeMounts { - if err := s.Convert(&in.VolumeMounts[i], &out.VolumeMounts[i], 0); err != nil { - return err - } - } - } - if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil { - return err - } - if err := s.Convert(&in.ReadinessProbe, &out.ReadinessProbe, 0); err != nil { - return err - } - if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil { - return err - } - out.TerminationMessagePath = in.TerminationMessagePath - out.ImagePullPolicy = PullPolicy(in.ImagePullPolicy) - if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil { - return err - } - // now that we've converted set the container field from security context - if out.SecurityContext != nil && out.SecurityContext.Privileged != nil { - out.Privileged = *out.SecurityContext.Privileged - } - // now that we've converted set the container field from security context - if out.SecurityContext != nil && out.SecurityContext.Capabilities != nil { - out.Capabilities = *out.SecurityContext.Capabilities - } - return nil -} diff --git a/pkg/api/v1beta3/conversion_test.go b/pkg/api/v1beta3/conversion_test.go index 497c1a7c8c..ac1c2962f9 100644 --- a/pkg/api/v1beta3/conversion_test.go +++ b/pkg/api/v1beta3/conversion_test.go @@ -45,63 +45,3 @@ func TestNodeConversion(t *testing.T) { t.Fatalf("unexpected error: %v", err) } } - -func TestBadSecurityContextConversion(t *testing.T) { - priv := false - testCases := map[string]struct { - c *current.Container - err string - }{ - // this use case must use true for the container and false for the sc. Otherwise the defaulter - // will assume privileged was left undefined (since it is the default value) and copy the - // sc setting upwards - "mismatched privileged": { - c: ¤t.Container{ - Privileged: true, - SecurityContext: ¤t.SecurityContext{ - Privileged: &priv, - }, - }, - err: "container privileged settings do not match security context settings, cannot convert", - }, - "mismatched caps add": { - c: ¤t.Container{ - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - }, - SecurityContext: ¤t.SecurityContext{ - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"bar"}, - }, - }, - }, - err: "container capability settings do not match security context settings, cannot convert", - }, - "mismatched caps drop": { - c: ¤t.Container{ - Capabilities: current.Capabilities{ - Drop: []current.CapabilityType{"foo"}, - }, - SecurityContext: ¤t.SecurityContext{ - Capabilities: ¤t.Capabilities{ - Drop: []current.CapabilityType{"bar"}, - }, - }, - }, - err: "container capability settings do not match security context settings, cannot convert", - }, - } - - for k, v := range testCases { - got := newer.Container{} - err := newer.Scheme.Convert(v.c, &got) - if err == nil { - t.Errorf("expected error for case %s but got none", k) - } else { - if err.Error() != v.err { - t.Errorf("unexpected error for case %s. Expected: %s but got: %s", k, v.err, err.Error()) - } - } - } - -} diff --git a/pkg/api/v1beta3/defaults.go b/pkg/api/v1beta3/defaults.go index 0eb7d7d099..fd3491093a 100644 --- a/pkg/api/v1beta3/defaults.go +++ b/pkg/api/v1beta3/defaults.go @@ -21,7 +21,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" - "github.com/golang/glog" ) func init() { @@ -67,7 +66,6 @@ func init() { if obj.TerminationMessagePath == "" { obj.TerminationMessagePath = TerminationMessagePathDefault } - defaultSecurityContext(obj) }, func(obj *ServiceSpec) { if obj.SessionAffinity == "" { @@ -158,44 +156,3 @@ func defaultHostNetworkPorts(containers *[]Container) { } } } - -// defaultSecurityContext performs the downward and upward merges of a pod definition -func defaultSecurityContext(container *Container) { - if container.SecurityContext == nil { - glog.V(4).Infof("creating security context for container %s", container.Name) - container.SecurityContext = &SecurityContext{} - } - // if there are no capabilities defined on the SecurityContext then copy the container settings - if container.SecurityContext.Capabilities == nil { - glog.V(4).Infof("downward merge of container.Capabilities for container %s", container.Name) - container.SecurityContext.Capabilities = &container.Capabilities - } else { - // if there are capabilities defined on the security context and the container setting is - // empty then assume that it was left off the pod definition and ensure that the container - // settings match the security context settings (checked by the convert functions). If - // there are settings in both then don't touch it, the converter will error if they don't - // match - if len(container.Capabilities.Add) == 0 { - glog.V(4).Infof("upward merge of container.Capabilities.Add for container %s", container.Name) - container.Capabilities.Add = container.SecurityContext.Capabilities.Add - } - if len(container.Capabilities.Drop) == 0 { - glog.V(4).Infof("upward merge of container.Capabilities.Drop for container %s", container.Name) - container.Capabilities.Drop = container.SecurityContext.Capabilities.Drop - } - } - // if there are no privileged settings on the security context then copy the container settings - if container.SecurityContext.Privileged == nil { - glog.V(4).Infof("downward merge of container.Privileged for container %s", container.Name) - container.SecurityContext.Privileged = &container.Privileged - } else { - // we don't have a good way to know if container.Privileged was set or just defaulted to false - // so the best we can do here is check if the securityContext is set to true and the - // container is set to false and assume that the Privileged field was left off the container - // definition and not an intentional mismatch - if *container.SecurityContext.Privileged && !container.Privileged { - glog.V(4).Infof("upward merge of container.Privileged for container %s", container.Name) - container.Privileged = *container.SecurityContext.Privileged - } - } -} diff --git a/pkg/api/v1beta3/defaults_test.go b/pkg/api/v1beta3/defaults_test.go index dca59583ec..4bd9f652e2 100644 --- a/pkg/api/v1beta3/defaults_test.go +++ b/pkg/api/v1beta3/defaults_test.go @@ -349,104 +349,3 @@ func TestSetDefaultObjectFieldSelectorAPIVersion(t *testing.T) { t.Errorf("Expected default APIVersion v1beta3, got: %v", apiVersion) } } - -func TestSetDefaultSecurityContext(t *testing.T) { - priv := false - privTrue := true - testCases := map[string]struct { - c current.Container - }{ - "downward defaulting caps": { - c: current.Container{ - Privileged: false, - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - SecurityContext: ¤t.SecurityContext{ - Privileged: &priv, - }, - }, - }, - "downward defaulting priv": { - c: current.Container{ - Privileged: false, - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - SecurityContext: ¤t.SecurityContext{ - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - }, - }, - }, - "upward defaulting caps": { - c: current.Container{ - Privileged: false, - SecurityContext: ¤t.SecurityContext{ - Privileged: &priv, - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"biz"}, - Drop: []current.CapabilityType{"baz"}, - }, - }, - }, - }, - "upward defaulting priv": { - c: current.Container{ - Capabilities: current.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - SecurityContext: ¤t.SecurityContext{ - Privileged: &privTrue, - Capabilities: ¤t.Capabilities{ - Add: []current.CapabilityType{"foo"}, - Drop: []current.CapabilityType{"bar"}, - }, - }, - }, - }, - } - - pod := ¤t.Pod{ - Spec: current.PodSpec{}, - } - - for k, v := range testCases { - pod.Spec.Containers = []current.Container{v.c} - obj := roundTrip(t, runtime.Object(pod)) - defaultedPod := obj.(*current.Pod) - c := defaultedPod.Spec.Containers[0] - if isEqual, issues := areSecurityContextAndContainerEqual(&c); !isEqual { - t.Errorf("test case %s expected the security context to have the same values as the container but found %#v", k, issues) - } - } -} - -func areSecurityContextAndContainerEqual(c *current.Container) (bool, []string) { - issues := make([]string, 0) - equal := true - - if c.SecurityContext == nil || c.SecurityContext.Privileged == nil || c.SecurityContext.Capabilities == nil { - equal = false - issues = append(issues, "Expected non nil settings for SecurityContext") - return equal, issues - } - if *c.SecurityContext.Privileged != c.Privileged { - equal = false - issues = append(issues, "The defaulted SecurityContext.Privileged value did not match the container value") - } - if !reflect.DeepEqual(c.Capabilities.Add, c.Capabilities.Add) { - equal = false - issues = append(issues, "The defaulted SecurityContext.Capabilities.Add did not match the container settings") - } - if !reflect.DeepEqual(c.Capabilities.Drop, c.Capabilities.Drop) { - equal = false - issues = append(issues, "The defaulted SecurityContext.Capabilities.Drop did not match the container settings") - } - return equal, issues -} diff --git a/pkg/api/v1beta3/types.go b/pkg/api/v1beta3/types.go index 54370cbf93..4be4746ab7 100644 --- a/pkg/api/v1beta3/types.go +++ b/pkg/api/v1beta3/types.go @@ -636,14 +636,12 @@ type Container struct { Lifecycle *Lifecycle `json:"lifecycle,omitempty" description:"actions that the management system should take in response to container lifecycle events; cannot be updated"` // Optional: Defaults to /dev/termination-log TerminationMessagePath string `json:"terminationMessagePath,omitempty" description:"path at which the file to which the container's termination message will be written is mounted into the container's filesystem; message written is intended to be brief final status, such as an assertion failure message; defaults to /dev/termination-log; cannot be updated"` - // Deprecated - see SecurityContext. Optional: Default to false. - Privileged bool `json:"privileged,omitempty" description:"whether or not the container is granted privileged status; defaults to false; cannot be updated; deprecated; See SecurityContext."` + // Optional: Default to false. + Privileged bool `json:"privileged,omitempty" description:"whether or not the container is granted privileged status; defaults to false; cannot be updated"` // Optional: Policy for pulling images for this container ImagePullPolicy PullPolicy `json:"imagePullPolicy" description:"image pull policy; one of PullAlways, PullNever, PullIfNotPresent; defaults to PullAlways if :latest tag is specified, or PullIfNotPresent otherwise; cannot be updated"` - // Deprecated - see SecurityContext. Optional: Capabilities for container. - Capabilities Capabilities `json:"capabilities,omitempty" description:"capabilities for container; cannot be updated; deprecated; See SecurityContext."` - // Optional: SecurityContext defines the security options the pod should be run with - SecurityContext *SecurityContext `json:"securityContext,omitempty" description:"security options the pod should run with"` + // Optional: Capabilities for container. + Capabilities Capabilities `json:"capabilities,omitempty" description:"capabilities for container; cannot be updated"` } // Handler defines a specific action that should be taken @@ -1737,39 +1735,3 @@ type ComponentStatusList struct { Items []ComponentStatus `json:"items" description:"list of component status objects"` } - -// SecurityContext holds security configuration that will be applied to a container. SecurityContext -// contains duplication of some existing fields from the Container resource. These duplicate fields -// will be populated based on the Container configuration if they are not set. Defining them on -// both the Container AND the SecurityContext will result in an error. -type SecurityContext struct { - // Capabilities are the capabilities to add/drop when running the container - // Must match Container.Capabilities or be unset. Will be defaulted to Container.Capabilities if left unset - Capabilities *Capabilities `json:"capabilities,omitempty" description:"the linux capabilites that should be added or removed"` - - // Run the container in privileged mode - // Must match Container.Privileged or be unset. Will be defaulted to Container.Privileged if left unset - Privileged *bool `json:"privileged,omitempty" description:"run the container in privileged mode"` - - // SELinuxOptions are the labels to be applied to the container - // and volumes - SELinuxOptions *SELinuxOptions `json:"seLinuxOptions,omitempty" description:"options that control the SELinux labels applied"` - - // RunAsUser is the UID to run the entrypoint of the container process. - RunAsUser *int64 `json:"runAsUser,omitempty" description:"the user id that runs the first process in the container"` -} - -// SELinuxOptions are the labels to be applied to the container. -type SELinuxOptions struct { - // SELinux user label - User string `json:"user,omitempty" description:"the user label to apply to the container"` - - // SELinux role label - Role string `json:"role,omitempty" description:"the role label to apply to the container"` - - // SELinux type label - Type string `json:"type,omitempty" description:"the type label to apply to the container"` - - // SELinux level label. - Level string `json:"level,omitempty" description:"the level label to apply to the container"` -} diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index 1dff82c764..519ecb05ad 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -776,12 +776,15 @@ func validateContainers(containers []api.Container, volumes util.StringSet) errs allNames := util.StringSet{} for i, ctr := range containers { cErrs := errs.ValidationErrorList{} + capabilities := capabilities.Get() if len(ctr.Name) == 0 { cErrs = append(cErrs, errs.NewFieldRequired("name")) } else if !util.IsDNS1123Label(ctr.Name) { cErrs = append(cErrs, errs.NewFieldInvalid("name", ctr.Name, dns1123LabelErrorMsg)) } else if allNames.Has(ctr.Name) { cErrs = append(cErrs, errs.NewFieldDuplicate("name", ctr.Name)) + } else if ctr.Privileged && !capabilities.AllowPrivileged { + cErrs = append(cErrs, errs.NewFieldForbidden("privileged", ctr.Privileged)) } else { allNames.Insert(ctr.Name) } @@ -798,7 +801,6 @@ func validateContainers(containers []api.Container, volumes util.StringSet) errs cErrs = append(cErrs, validateVolumeMounts(ctr.VolumeMounts, volumes).Prefix("volumeMounts")...) cErrs = append(cErrs, validatePullPolicy(&ctr).Prefix("pullPolicy")...) cErrs = append(cErrs, ValidateResourceRequirements(&ctr.Resources).Prefix("resources")...) - cErrs = append(cErrs, ValidateSecurityContext(ctr.SecurityContext).Prefix("securityContext")...) allErrs = append(allErrs, cErrs.PrefixIndex(i)...) } // Check for colliding ports across all containers. @@ -1479,25 +1481,3 @@ func ValidateEndpointsUpdate(oldEndpoints, newEndpoints *api.Endpoints) errs.Val allErrs = append(allErrs, validateEndpointSubsets(newEndpoints.Subsets).Prefix("subsets")...) return allErrs } - -// ValidateSecurityContext ensure the security context contains valid settings -func ValidateSecurityContext(sc *api.SecurityContext) errs.ValidationErrorList { - allErrs := errs.ValidationErrorList{} - //this should only be true for testing since SecurityContext is defaulted by the api - if sc == nil { - return allErrs - } - - if sc.Privileged != nil { - if *sc.Privileged && !capabilities.Get().AllowPrivileged { - allErrs = append(allErrs, errs.NewFieldForbidden("privileged", sc.Privileged)) - } - } - - if sc.RunAsUser != nil { - if *sc.RunAsUser < 0 { - allErrs = append(allErrs, errs.NewFieldInvalid("runAsUser", *sc.RunAsUser, "runAsUser cannot be negative")) - } - } - return allErrs -} diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index 3b8973a560..eb3aac8d87 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -901,7 +901,7 @@ func TestValidateContainers(t *testing.T) { }, ImagePullPolicy: "IfNotPresent", }, - {Name: "abc-1234", Image: "image", ImagePullPolicy: "IfNotPresent", SecurityContext: fakeValidSecurityContext(true)}, + {Name: "abc-1234", Image: "image", Privileged: true, ImagePullPolicy: "IfNotPresent"}, } if errs := validateContainers(successCase, volumes); len(errs) != 0 { t.Errorf("expected success: %v", errs) @@ -1015,7 +1015,7 @@ func TestValidateContainers(t *testing.T) { }, }, "privilege disabled": { - {Name: "abc", Image: "image", SecurityContext: fakeValidSecurityContext(true)}, + {Name: "abc", Image: "image", Privileged: true}, }, "invalid compute resource": { { @@ -3180,89 +3180,3 @@ func TestValidateEndpoints(t *testing.T) { } } } - -func TestValidateSecurityContext(t *testing.T) { - priv := false - var runAsUser int64 = 1 - fullValidSC := func() *api.SecurityContext { - return &api.SecurityContext{ - Privileged: &priv, - Capabilities: &api.Capabilities{ - Add: []api.CapabilityType{"foo"}, - Drop: []api.CapabilityType{"bar"}, - }, - SELinuxOptions: &api.SELinuxOptions{ - User: "user", - Role: "role", - Type: "type", - Level: "level", - }, - RunAsUser: &runAsUser, - } - } - - //setup data - allSettings := fullValidSC() - noCaps := fullValidSC() - noCaps.Capabilities = nil - - noSELinux := fullValidSC() - noSELinux.SELinuxOptions = nil - - noPrivRequest := fullValidSC() - noPrivRequest.Privileged = nil - - noRunAsUser := fullValidSC() - noRunAsUser.RunAsUser = nil - - successCases := map[string]struct { - sc *api.SecurityContext - }{ - "all settings": {allSettings}, - "no capabilities": {noCaps}, - "no selinux": {noSELinux}, - "no priv request": {noPrivRequest}, - "no run as user": {noRunAsUser}, - } - for k, v := range successCases { - if errs := ValidateSecurityContext(v.sc); len(errs) != 0 { - t.Errorf("Expected success for %s, got %v", k, errs) - } - } - - privRequestWithGlobalDeny := fullValidSC() - requestPrivileged := true - privRequestWithGlobalDeny.Privileged = &requestPrivileged - - negativeRunAsUser := fullValidSC() - var negativeUser int64 = -1 - negativeRunAsUser.RunAsUser = &negativeUser - - errorCases := map[string]struct { - sc *api.SecurityContext - errorType fielderrors.ValidationErrorType - errorDetail string - }{ - "request privileged when capabilities forbids": { - sc: privRequestWithGlobalDeny, - errorType: "FieldValueForbidden", - errorDetail: "", - }, - "negative RunAsUser": { - sc: negativeRunAsUser, - errorType: "FieldValueInvalid", - errorDetail: "runAsUser cannot be negative", - }, - } - for k, v := range errorCases { - if errs := ValidateSecurityContext(v.sc); len(errs) == 0 || errs[0].(*errors.ValidationError).Type != v.errorType || errs[0].(*errors.ValidationError).Detail != v.errorDetail { - t.Errorf("Expected error type %s with detail %s for %s, got %v", v.errorType, v.errorDetail, k, errs) - } - } -} - -func fakeValidSecurityContext(priv bool) *api.SecurityContext { - return &api.SecurityContext{ - Privileged: &priv, - } -} diff --git a/pkg/controller/replication_controller_test.go b/pkg/controller/replication_controller_test.go index 8e7b181f05..7667121405 100644 --- a/pkg/controller/replication_controller_test.go +++ b/pkg/controller/replication_controller_test.go @@ -35,7 +35,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/client/testclient" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" - "github.com/GoogleCloudPlatform/kubernetes/pkg/securitycontext" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util/wait" "github.com/GoogleCloudPlatform/kubernetes/pkg/watch" @@ -113,7 +112,6 @@ func newReplicationController(replicas int) *api.ReplicationController { Image: "foo/bar", TerminationMessagePath: api.TerminationMessagePathDefault, ImagePullPolicy: api.PullIfNotPresent, - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(), }, }, RestartPolicy: api.RestartPolicyAlways, diff --git a/pkg/kubelet/config/common_test.go b/pkg/kubelet/config/common_test.go index d311c6b3af..b34ab9bb48 100644 --- a/pkg/kubelet/config/common_test.go +++ b/pkg/kubelet/config/common_test.go @@ -22,7 +22,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" - "github.com/GoogleCloudPlatform/kubernetes/pkg/securitycontext" "github.com/ghodss/yaml" ) @@ -47,7 +46,6 @@ func TestDecodeSinglePod(t *testing.T) { Image: "test/image", ImagePullPolicy: "IfNotPresent", TerminationMessagePath: "/dev/termination-log", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(), }}, }, } @@ -110,7 +108,6 @@ func TestDecodePodList(t *testing.T) { Image: "test/image", ImagePullPolicy: "IfNotPresent", TerminationMessagePath: "/dev/termination-log", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(), }}, }, } diff --git a/pkg/kubelet/config/config_test.go b/pkg/kubelet/config/config_test.go index 9fe1fb860f..f760d80152 100644 --- a/pkg/kubelet/config/config_test.go +++ b/pkg/kubelet/config/config_test.go @@ -23,7 +23,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/record" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" - "github.com/GoogleCloudPlatform/kubernetes/pkg/securitycontext" "github.com/GoogleCloudPlatform/kubernetes/pkg/types" ) @@ -63,14 +62,7 @@ func CreateValidPod(name, namespace, source string) *api.Pod { Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{ - { - Name: "ctr", - Image: "image", - ImagePullPolicy: "IfNotPresent", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(), - }, - }, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, }, } } diff --git a/pkg/kubelet/config/file_test.go b/pkg/kubelet/config/file_test.go index f649fdcacb..7f107f7e26 100644 --- a/pkg/kubelet/config/file_test.go +++ b/pkg/kubelet/config/file_test.go @@ -31,7 +31,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" - "github.com/GoogleCloudPlatform/kubernetes/pkg/securitycontext" "github.com/GoogleCloudPlatform/kubernetes/pkg/types" ) @@ -106,8 +105,7 @@ func TestReadContainerManifestFromFile(t *testing.T) { Name: "image", Image: "test/image", TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "Always", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, + ImagePullPolicy: "Always"}}, }, }), }, @@ -133,8 +131,7 @@ func TestReadContainerManifestFromFile(t *testing.T) { Name: "image", Image: "test/image", TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "Always", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, + ImagePullPolicy: "Always"}}, }, }), }, @@ -185,7 +182,7 @@ 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"}}, }, }, expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{ @@ -203,8 +200,7 @@ func TestReadPodsFromFile(t *testing.T) { Name: "image", Image: "test/image", TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "IfNotPresent", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, + ImagePullPolicy: "IfNotPresent"}}, }, }), }, @@ -220,7 +216,7 @@ func TestReadPodsFromFile(t *testing.T) { UID: "12345", }, Spec: api.PodSpec{ - Containers: []api.Container{{Name: "image", Image: "test/image", SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, + Containers: []api.Container{{Name: "image", Image: "test/image"}}, }, }, expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{ @@ -238,8 +234,7 @@ func TestReadPodsFromFile(t *testing.T) { Name: "image", Image: "test/image", TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "IfNotPresent", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, + ImagePullPolicy: "IfNotPresent"}}, }, }), }, diff --git a/pkg/kubelet/config/http_test.go b/pkg/kubelet/config/http_test.go index 789dd17b9d..bc4ecd0d44 100644 --- a/pkg/kubelet/config/http_test.go +++ b/pkg/kubelet/config/http_test.go @@ -28,7 +28,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" - "github.com/GoogleCloudPlatform/kubernetes/pkg/securitycontext" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors" ) @@ -152,8 +151,7 @@ func TestExtractManifestFromHTTP(t *testing.T) { Name: "1", Image: "foo", TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "Always", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, + ImagePullPolicy: "Always"}}, }, }), }, @@ -179,8 +177,7 @@ func TestExtractManifestFromHTTP(t *testing.T) { Name: "ctr", Image: "image", TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "IfNotPresent", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, + ImagePullPolicy: "IfNotPresent"}}, }, }), }, @@ -206,8 +203,7 @@ func TestExtractManifestFromHTTP(t *testing.T) { Name: "1", Image: "foo", TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "Always", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, + ImagePullPolicy: "Always"}}, }, }), }, @@ -237,8 +233,7 @@ func TestExtractManifestFromHTTP(t *testing.T) { Name: "1", Image: "foo", TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "Always", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, + ImagePullPolicy: "Always"}}, }, }, &api.Pod{ @@ -257,8 +252,7 @@ func TestExtractManifestFromHTTP(t *testing.T) { Name: "1", Image: "foo", TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "IfNotPresent", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, + ImagePullPolicy: "IfNotPresent"}}, }, }), }, @@ -350,8 +344,7 @@ func TestExtractPodsFromHTTP(t *testing.T) { Name: "1", Image: "foo", TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "Always", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, + ImagePullPolicy: "Always"}}, }, }), }, @@ -403,8 +396,7 @@ func TestExtractPodsFromHTTP(t *testing.T) { Name: "1", Image: "foo", TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "Always", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, + ImagePullPolicy: "Always"}}, }, }, &api.Pod{ @@ -423,8 +415,7 @@ func TestExtractPodsFromHTTP(t *testing.T) { Name: "2", Image: "bar", TerminationMessagePath: "/dev/termination-log", - ImagePullPolicy: "IfNotPresent", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, + ImagePullPolicy: "IfNotPresent"}}, }, }), }, diff --git a/pkg/kubelet/dockertools/manager.go b/pkg/kubelet/dockertools/manager.go index eda841f608..0244e761ba 100644 --- a/pkg/kubelet/dockertools/manager.go +++ b/pkg/kubelet/dockertools/manager.go @@ -38,7 +38,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/prober" kubeletTypes "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/types" "github.com/GoogleCloudPlatform/kubernetes/pkg/probe" - "github.com/GoogleCloudPlatform/kubernetes/pkg/securitycontext" "github.com/GoogleCloudPlatform/kubernetes/pkg/types" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" docker "github.com/fsouza/go-dockerclient" @@ -525,8 +524,6 @@ func (dm *DockerManager) runContainer(pod *api.Pod, container *api.Container, op glog.V(3).Infof("Container %v/%v/%v: setting entrypoint \"%v\" and command \"%v\"", pod.Namespace, pod.Name, container.Name, dockerOpts.Config.Entrypoint, dockerOpts.Config.Cmd) - securityContextProvider := securitycontext.NewSimpleSecurityContextProvider() - securityContextProvider.ModifyContainerConfig(pod, container, dockerOpts.Config) dockerContainer, err := dm.client.CreateContainer(dockerOpts) if err != nil { if ref != nil { @@ -557,15 +554,22 @@ func (dm *DockerManager) runContainer(pod *api.Pod, container *api.Container, op } } - if !capabilities.Get().AllowPrivileged && securitycontext.HasPrivilegedRequest(container) { + privileged := false + if capabilities.Get().AllowPrivileged { + privileged = container.Privileged + } else if container.Privileged { return "", fmt.Errorf("container requested privileged mode, but it is disallowed globally.") } + capAdd, capDrop := makeCapabilites(container.Capabilities.Add, container.Capabilities.Drop) hc := &docker.HostConfig{ PortBindings: portBindings, Binds: opts.Binds, NetworkMode: opts.NetMode, IpcMode: opts.IpcMode, + Privileged: privileged, + CapAdd: capAdd, + CapDrop: capDrop, } if len(opts.DNS) > 0 { hc.DNS = opts.DNS @@ -576,7 +580,6 @@ func (dm *DockerManager) runContainer(pod *api.Pod, container *api.Container, op if len(opts.CgroupParent) > 0 { hc.CgroupParent = opts.CgroupParent } - securityContextProvider.ModifyHostConfig(pod, container, hc) if err = dm.client.StartContainer(dockerContainer.ID, hc); err != nil { if ref != nil { @@ -634,6 +637,20 @@ func makePortsAndBindings(container *api.Container) (map[docker.Port]struct{}, m return exposedPorts, portBindings } +func makeCapabilites(capAdd []api.CapabilityType, capDrop []api.CapabilityType) ([]string, []string) { + var ( + addCaps []string + dropCaps []string + ) + for _, cap := range capAdd { + addCaps = append(addCaps, string(cap)) + } + for _, cap := range capDrop { + dropCaps = append(dropCaps, string(cap)) + } + return addCaps, dropCaps +} + // A helper function to get the KubeletContainerName and hash from a docker // container. func getDockerContainerNameInfo(c *docker.APIContainers) (*KubeletContainerName, uint64, error) { diff --git a/pkg/kubelet/rkt/rkt_linux.go b/pkg/kubelet/rkt/rkt_linux.go index 63a40f1fe4..1bd919f65a 100644 --- a/pkg/kubelet/rkt/rkt_linux.go +++ b/pkg/kubelet/rkt/rkt_linux.go @@ -38,7 +38,6 @@ import ( kubecontainer "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/container" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/prober" "github.com/GoogleCloudPlatform/kubernetes/pkg/probe" - "github.com/GoogleCloudPlatform/kubernetes/pkg/securitycontext" "github.com/GoogleCloudPlatform/kubernetes/pkg/types" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/volume" @@ -188,29 +187,23 @@ func rawValue(value string) *json.RawMessage { } // setIsolators overrides the isolators of the pod manifest if necessary. -// TODO need an apply config in security context for rkt func setIsolators(app *appctypes.App, c *api.Container) error { - hasCapRequests := securitycontext.HasCapabilitiesRequest(c) - if hasCapRequests || len(c.Resources.Limits) > 0 || len(c.Resources.Requests) > 0 { + if len(c.Capabilities.Add) > 0 || len(c.Capabilities.Drop) > 0 || len(c.Resources.Limits) > 0 || len(c.Resources.Requests) > 0 { app.Isolators = []appctypes.Isolator{} } // Retained capabilities/privileged. privileged := false - if !capabilities.Get().AllowPrivileged && securitycontext.HasPrivilegedRequest(c) { - return fmt.Errorf("container requested privileged mode, but it is disallowed globally.") - } else { - if c.SecurityContext != nil && c.SecurityContext.Privileged != nil { - privileged = *c.SecurityContext.Privileged - } + if capabilities.Get().AllowPrivileged { + privileged = c.Privileged + } else if c.Privileged { + return fmt.Errorf("privileged is disallowed globally") } var addCaps string if privileged { addCaps = getAllCapabilities() } else { - if hasCapRequests { - addCaps = getCapabilities(c.SecurityContext.Capabilities.Add) - } + addCaps = getCapabilities(c.Capabilities.Add) } if len(addCaps) > 0 { // TODO(yifan): Replace with constructor, see: @@ -223,10 +216,7 @@ func setIsolators(app *appctypes.App, c *api.Container) error { } // Removed capabilities. - var dropCaps string - if hasCapRequests { - dropCaps = getCapabilities(c.SecurityContext.Capabilities.Drop) - } + dropCaps := getCapabilities(c.Capabilities.Drop) if len(dropCaps) > 0 { // TODO(yifan): Replace with constructor, see: // https://github.com/appc/spec/issues/268 diff --git a/pkg/registry/pod/etcd/etcd_test.go b/pkg/registry/pod/etcd/etcd_test.go index 81ede48d04..51e5895886 100644 --- a/pkg/registry/pod/etcd/etcd_test.go +++ b/pkg/registry/pod/etcd/etcd_test.go @@ -32,7 +32,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" - "github.com/GoogleCloudPlatform/kubernetes/pkg/securitycontext" "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" "github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" @@ -69,7 +68,6 @@ func validNewPod() *api.Pod { ImagePullPolicy: api.PullAlways, TerminationMessagePath: api.TerminationMessagePathDefault, - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(), }, }, }, @@ -1110,9 +1108,8 @@ func TestEtcdUpdateScheduled(t *testing.T) { Host: "machine", Containers: []api.Container{ { - Name: "foobar", - Image: "foo:v1", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(), + Name: "foobar", + Image: "foo:v1", }, }, }, @@ -1134,7 +1131,6 @@ func TestEtcdUpdateScheduled(t *testing.T) { Image: "foo:v2", ImagePullPolicy: api.PullIfNotPresent, TerminationMessagePath: api.TerminationMessagePathDefault, - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(), }, }, RestartPolicy: api.RestartPolicyAlways, @@ -1173,8 +1169,7 @@ func TestEtcdUpdateStatus(t *testing.T) { Host: "machine", Containers: []api.Container{ { - Image: "foo:v1", - SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(), + Image: "foo:v1", }, }, }, diff --git a/pkg/securitycontext/doc.go b/pkg/securitycontext/doc.go deleted file mode 100644 index 9e9a84ba10..0000000000 --- a/pkg/securitycontext/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright 2014 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 securitycontext contains security context api implementations -package securitycontext diff --git a/pkg/securitycontext/fake.go b/pkg/securitycontext/fake.go deleted file mode 100644 index 02e4d746e6..0000000000 --- a/pkg/securitycontext/fake.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 2014 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 securitycontext - -import ( - "github.com/GoogleCloudPlatform/kubernetes/pkg/api" - - docker "github.com/fsouza/go-dockerclient" -) - -// ValidSecurityContextWithContainerDefaults creates a valid security context provider based on -// empty container defaults. Used for testing. -func ValidSecurityContextWithContainerDefaults() *api.SecurityContext { - priv := false - return &api.SecurityContext{ - Capabilities: &api.Capabilities{}, - Privileged: &priv, - } -} - -// NewFakeSecurityContextProvider creates a new, no-op security context provider. -func NewFakeSecurityContextProvider() SecurityContextProvider { - return FakeSecurityContextProvider{} -} - -type FakeSecurityContextProvider struct{} - -func (p FakeSecurityContextProvider) ModifyContainerConfig(pod *api.Pod, container *api.Container, config *docker.Config) { -} -func (p FakeSecurityContextProvider) ModifyHostConfig(pod *api.Pod, container *api.Container, hostConfig *docker.HostConfig) { -} diff --git a/pkg/securitycontext/provider.go b/pkg/securitycontext/provider.go deleted file mode 100644 index 0362fcc0f9..0000000000 --- a/pkg/securitycontext/provider.go +++ /dev/null @@ -1,97 +0,0 @@ -/* -Copyright 2014 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 securitycontext - -import ( - "fmt" - "strconv" - - "github.com/GoogleCloudPlatform/kubernetes/pkg/api" - - docker "github.com/fsouza/go-dockerclient" -) - -// NewSimpleSecurityContextProvider creates a new SimpleSecurityContextProvider. -func NewSimpleSecurityContextProvider() SecurityContextProvider { - return SimpleSecurityContextProvider{} -} - -// SimpleSecurityContextProvider is the default implementation of a SecurityContextProvider. -type SimpleSecurityContextProvider struct{} - -// ModifyContainerConfig is called before the Docker createContainer call. -// The security context provider can make changes to the Config with which -// the container is created. -func (p SimpleSecurityContextProvider) ModifyContainerConfig(pod *api.Pod, container *api.Container, config *docker.Config) { - if container.SecurityContext == nil { - return - } - if container.SecurityContext.RunAsUser != nil { - config.User = strconv.FormatInt(*container.SecurityContext.RunAsUser, 10) - } -} - -// ModifyHostConfig is called before the Docker runContainer call. -// The security context provider can make changes to the HostConfig, affecting -// security options, whether the container is privileged, volume binds, etc. -// An error is returned if it's not possible to secure the container as requested -// with a security context. -func (p SimpleSecurityContextProvider) ModifyHostConfig(pod *api.Pod, container *api.Container, hostConfig *docker.HostConfig) { - if container.SecurityContext == nil { - return - } - if container.SecurityContext.Privileged != nil { - hostConfig.Privileged = *container.SecurityContext.Privileged - } - - if container.SecurityContext.Capabilities != nil { - add, drop := makeCapabilites(container.SecurityContext.Capabilities.Add, container.SecurityContext.Capabilities.Drop) - hostConfig.CapAdd = add - hostConfig.CapDrop = drop - } - - if container.SecurityContext.SELinuxOptions != nil { - hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelUser, container.SecurityContext.SELinuxOptions.User) - hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelRole, container.SecurityContext.SELinuxOptions.Role) - hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelType, container.SecurityContext.SELinuxOptions.Type) - hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelLevel, container.SecurityContext.SELinuxOptions.Level) - } -} - -// modifySecurityOption adds the security option of name to the config array with value in the form -// of name:value -func modifySecurityOption(config []string, name, value string) []string { - if len(value) > 0 { - config = append(config, fmt.Sprintf("%s:%s", name, value)) - } - return config -} - -// makeCapabilites creates string slices from CapabilityType slices -func makeCapabilites(capAdd []api.CapabilityType, capDrop []api.CapabilityType) ([]string, []string) { - var ( - addCaps []string - dropCaps []string - ) - for _, cap := range capAdd { - addCaps = append(addCaps, string(cap)) - } - for _, cap := range capDrop { - dropCaps = append(dropCaps, string(cap)) - } - return addCaps, dropCaps -} diff --git a/pkg/securitycontext/provider_test.go b/pkg/securitycontext/provider_test.go deleted file mode 100644 index 609490c7b5..0000000000 --- a/pkg/securitycontext/provider_test.go +++ /dev/null @@ -1,181 +0,0 @@ -/* -Copyright 2014 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 securitycontext - -import ( - "fmt" - "reflect" - "strconv" - "testing" - - "github.com/GoogleCloudPlatform/kubernetes/pkg/api" - - docker "github.com/fsouza/go-dockerclient" -) - -func TestModifyContainerConfig(t *testing.T) { - var uid int64 = 1 - testCases := map[string]struct { - securityContext *api.SecurityContext - expected *docker.Config - }{ - "modify config, value set for user": { - securityContext: &api.SecurityContext{ - RunAsUser: &uid, - }, - expected: &docker.Config{ - User: strconv.FormatInt(uid, 10), - }, - }, - "modify config, nil user value": { - securityContext: &api.SecurityContext{}, - expected: &docker.Config{}, - }, - } - - provider := NewSimpleSecurityContextProvider() - dummyContainer := &api.Container{} - for k, v := range testCases { - dummyContainer.SecurityContext = v.securityContext - dockerCfg := &docker.Config{} - provider.ModifyContainerConfig(nil, dummyContainer, dockerCfg) - if !reflect.DeepEqual(v.expected, dockerCfg) { - t.Errorf("unexpected modification of docker config for %s. Expected: %#v Got: %#v", k, v.expected, dockerCfg) - } - } -} - -func TestModifyHostConfig(t *testing.T) { - nilPrivSC := fullValidSecurityContext() - nilPrivSC.Privileged = nil - nilPrivHC := fullValidHostConfig() - nilPrivHC.Privileged = false - - nilCapsSC := fullValidSecurityContext() - nilCapsSC.Capabilities = nil - nilCapsHC := fullValidHostConfig() - nilCapsHC.CapAdd = *new([]string) - nilCapsHC.CapDrop = *new([]string) - - nilSELinuxSC := fullValidSecurityContext() - nilSELinuxSC.SELinuxOptions = nil - nilSELinuxHC := fullValidHostConfig() - nilSELinuxHC.SecurityOpt = *new([]string) - - seLinuxLabelsSC := fullValidSecurityContext() - seLinuxLabelsHC := fullValidHostConfig() - - testCases := map[string]struct { - securityContext *api.SecurityContext - expected *docker.HostConfig - }{ - "full settings": { - securityContext: fullValidSecurityContext(), - expected: fullValidHostConfig(), - }, - "nil privileged": { - securityContext: nilPrivSC, - expected: nilPrivHC, - }, - "nil capabilities": { - securityContext: nilCapsSC, - expected: nilCapsHC, - }, - "nil selinux options": { - securityContext: nilSELinuxSC, - expected: nilSELinuxHC, - }, - "selinux labels": { - securityContext: seLinuxLabelsSC, - expected: seLinuxLabelsHC, - }, - } - - provider := NewSimpleSecurityContextProvider() - dummyContainer := &api.Container{} - for k, v := range testCases { - dummyContainer.SecurityContext = v.securityContext - dockerCfg := &docker.HostConfig{} - provider.ModifyHostConfig(nil, dummyContainer, dockerCfg) - if !reflect.DeepEqual(v.expected, dockerCfg) { - t.Errorf("unexpected modification of host config for %s. Expected: %#v Got: %#v", k, v.expected, dockerCfg) - } - } -} - -func TestModifySecurityOption(t *testing.T) { - testCases := []struct { - name string - config []string - optName string - optVal string - expected []string - }{ - { - name: "Empty val", - config: []string{"a:b", "c:d"}, - optName: "optA", - optVal: "", - expected: []string{"a:b", "c:d"}, - }, - { - name: "Valid", - config: []string{"a:b", "c:d"}, - optName: "e", - optVal: "f", - expected: []string{"a:b", "c:d", "e:f"}, - }, - } - - for _, tc := range testCases { - actual := modifySecurityOption(tc.config, tc.optName, tc.optVal) - if !reflect.DeepEqual(tc.expected, actual) { - t.Errorf("Failed to apply options correctly for tc: %S. Expected: %v but got %v", tc.name, tc.expected, actual) - } - } -} - -func fullValidSecurityContext() *api.SecurityContext { - priv := true - return &api.SecurityContext{ - Privileged: &priv, - Capabilities: &api.Capabilities{ - Add: []api.CapabilityType{"addCapA", "addCapB"}, - Drop: []api.CapabilityType{"dropCapA", "dropCapB"}, - }, - SELinuxOptions: &api.SELinuxOptions{ - User: "user", - Role: "role", - Type: "type", - Level: "level", - }, - } -} - -func fullValidHostConfig() *docker.HostConfig { - return &docker.HostConfig{ - Privileged: true, - CapAdd: []string{"addCapA", "addCapB"}, - CapDrop: []string{"dropCapA", "dropCapB"}, - SecurityOpt: []string{ - fmt.Sprintf("%s:%s", dockerLabelUser, "user"), - fmt.Sprintf("%s:%s", dockerLabelRole, "role"), - fmt.Sprintf("%s:%s", dockerLabelType, "type"), - fmt.Sprintf("%s:%s", dockerLabelLevel, "level"), - }, - } -} diff --git a/pkg/securitycontext/types.go b/pkg/securitycontext/types.go deleted file mode 100644 index d39f5344b0..0000000000 --- a/pkg/securitycontext/types.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 2014 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 securitycontext - -import ( - "github.com/GoogleCloudPlatform/kubernetes/pkg/api" - - docker "github.com/fsouza/go-dockerclient" -) - -type SecurityContextProvider interface { - // ModifyContainerConfig is called before the Docker createContainer call. - // The security context provider can make changes to the Config with which - // the container is created. - ModifyContainerConfig(pod *api.Pod, container *api.Container, config *docker.Config) - - // ModifyHostConfig is called before the Docker runContainer call. - // The security context provider can make changes to the HostConfig, affecting - // security options, whether the container is privileged, volume binds, etc. - // An error is returned if it's not possible to secure the container as requested - // with a security context. - ModifyHostConfig(pod *api.Pod, container *api.Container, hostConfig *docker.HostConfig) -} - -const ( - dockerLabelUser string = "label:user" - dockerLabelRole string = "label:role" - dockerLabelType string = "label:type" - dockerLabelLevel string = "label:level" - dockerLabelDisable string = "label:disable" -) diff --git a/pkg/securitycontext/util.go b/pkg/securitycontext/util.go deleted file mode 100644 index 64bf7e53ec..0000000000 --- a/pkg/securitycontext/util.go +++ /dev/null @@ -1,43 +0,0 @@ -/* -Copyright 2014 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 securitycontext - -import "github.com/GoogleCloudPlatform/kubernetes/pkg/api" - -// HasPrivilegedRequest returns the value of SecurityContext.Privileged, taking into account -// the possibility of nils -func HasPrivilegedRequest(container *api.Container) bool { - if container.SecurityContext == nil { - return false - } - if container.SecurityContext.Privileged == nil { - return false - } - return *container.SecurityContext.Privileged -} - -// HasCapabilitiesRequest returns true if Adds or Drops are defined in the security context -// capabilities, taking into account nils -func HasCapabilitiesRequest(container *api.Container) bool { - if container.SecurityContext == nil { - return false - } - if container.SecurityContext.Capabilities == nil { - return false - } - return len(container.SecurityContext.Capabilities.Add) > 0 || len(container.SecurityContext.Capabilities.Drop) > 0 -} diff --git a/plugin/pkg/admission/securitycontext/scdeny/admission.go b/plugin/pkg/admission/securitycontext/scdeny/admission.go deleted file mode 100644 index 2362ae3fe5..0000000000 --- a/plugin/pkg/admission/securitycontext/scdeny/admission.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright 2014 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 scdeny - -import ( - "fmt" - "io" - - "github.com/GoogleCloudPlatform/kubernetes/pkg/admission" - "github.com/GoogleCloudPlatform/kubernetes/pkg/api" - apierrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" - "github.com/GoogleCloudPlatform/kubernetes/pkg/client" -) - -func init() { - admission.RegisterPlugin("SecurityContextDeny", func(client client.Interface, config io.Reader) (admission.Interface, error) { - return NewSecurityContextDeny(client), nil - }) -} - -// plugin contains the client used by the SecurityContextDeny admission controller -type plugin struct { - client client.Interface -} - -// NewSecurityContextDeny creates a new instance of the SecurityContextDeny admission controller -func NewSecurityContextDeny(client client.Interface) admission.Interface { - return &plugin{client} -} - -// Admit will deny any SecurityContext that defines options that were not previously available in the api.Container -// struct (Capabilities and Privileged) -func (p *plugin) Admit(a admission.Attributes) (err error) { - if a.GetOperation() == "DELETE" { - return nil - } - if a.GetResource() != string(api.ResourcePods) { - return nil - } - - pod, ok := a.GetObject().(*api.Pod) - if !ok { - return apierrors.NewBadRequest("Resource was marked with kind Pod but was unable to be converted") - } - for _, v := range pod.Spec.Containers { - if v.SecurityContext != nil { - if v.SecurityContext.SELinuxOptions != nil { - return apierrors.NewForbidden(a.GetResource(), pod.Name, fmt.Errorf("SecurityContext.SELinuxOptions is forbidden")) - } - if v.SecurityContext.RunAsUser != nil { - return apierrors.NewForbidden(a.GetResource(), pod.Name, fmt.Errorf("SecurityContext.RunAsUser is forbidden")) - } - } - } - return nil -} diff --git a/plugin/pkg/admission/securitycontext/scdeny/admission_test.go b/plugin/pkg/admission/securitycontext/scdeny/admission_test.go deleted file mode 100644 index 10c11a1a28..0000000000 --- a/plugin/pkg/admission/securitycontext/scdeny/admission_test.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Copyright 2014 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 scdeny - -import ( - "testing" - - "github.com/GoogleCloudPlatform/kubernetes/pkg/admission" - "github.com/GoogleCloudPlatform/kubernetes/pkg/api" -) - -// ensures the SecurityContext is denied if it defines anything more than Caps or Privileged -func TestAdmission(t *testing.T) { - handler := NewSecurityContextDeny(nil) - - var runAsUser int64 = 1 - priv := true - successCases := map[string]*api.SecurityContext{ - "no sc": nil, - "empty sc": {}, - "valid sc": {Privileged: &priv, Capabilities: &api.Capabilities{}}, - } - - pod := api.Pod{ - Spec: api.PodSpec{ - Containers: []api.Container{ - {}, - }, - }, - } - for k, v := range successCases { - pod.Spec.Containers[0].SecurityContext = v - err := handler.Admit(admission.NewAttributesRecord(&pod, "Pod", "foo", string(api.ResourcePods), "ignored")) - if err != nil { - t.Errorf("Unexpected error returned from admission handler for case %s", k) - } - } - - errorCases := map[string]*api.SecurityContext{ - "run as user": {RunAsUser: &runAsUser}, - "se linux optons": {SELinuxOptions: &api.SELinuxOptions{}}, - "mixed settings": {Privileged: &priv, RunAsUser: &runAsUser, SELinuxOptions: &api.SELinuxOptions{}}, - } - for k, v := range errorCases { - pod.Spec.Containers[0].SecurityContext = v - err := handler.Admit(admission.NewAttributesRecord(&pod, "Pod", "foo", string(api.ResourcePods), "ignored")) - if err == nil { - t.Errorf("Expected error returned from admission handler for case %s", k) - } - } -}