diff --git a/pkg/credentialprovider/keyring.go b/pkg/credentialprovider/keyring.go index ed712ccfdc7..635e03f06b5 100644 --- a/pkg/credentialprovider/keyring.go +++ b/pkg/credentialprovider/keyring.go @@ -27,7 +27,7 @@ import ( "github.com/golang/glog" dockertypes "github.com/docker/engine-api/types" - "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/util/sets" ) @@ -306,17 +306,17 @@ func (k *unionDockerKeyring) Lookup(image string) ([]LazyAuthConfiguration, bool // MakeDockerKeyring inspects the passedSecrets to see if they contain any DockerConfig secrets. If they do, // then a DockerKeyring is built based on every hit and unioned with the defaultKeyring. // If they do not, then the default keyring is returned -func MakeDockerKeyring(passedSecrets []api.Secret, defaultKeyring DockerKeyring) (DockerKeyring, error) { +func MakeDockerKeyring(passedSecrets []v1.Secret, defaultKeyring DockerKeyring) (DockerKeyring, error) { passedCredentials := []DockerConfig{} for _, passedSecret := range passedSecrets { - if dockerConfigJsonBytes, dockerConfigJsonExists := passedSecret.Data[api.DockerConfigJsonKey]; (passedSecret.Type == api.SecretTypeDockerConfigJson) && dockerConfigJsonExists && (len(dockerConfigJsonBytes) > 0) { + if dockerConfigJsonBytes, dockerConfigJsonExists := passedSecret.Data[v1.DockerConfigJsonKey]; (passedSecret.Type == v1.SecretTypeDockerConfigJson) && dockerConfigJsonExists && (len(dockerConfigJsonBytes) > 0) { dockerConfigJson := DockerConfigJson{} if err := json.Unmarshal(dockerConfigJsonBytes, &dockerConfigJson); err != nil { return nil, err } passedCredentials = append(passedCredentials, dockerConfigJson.Auths) - } else if dockercfgBytes, dockercfgExists := passedSecret.Data[api.DockerConfigKey]; (passedSecret.Type == api.SecretTypeDockercfg) && dockercfgExists && (len(dockercfgBytes) > 0) { + } else if dockercfgBytes, dockercfgExists := passedSecret.Data[v1.DockerConfigKey]; (passedSecret.Type == v1.SecretTypeDockercfg) && dockercfgExists && (len(dockercfgBytes) > 0) { dockercfg := DockerConfig{} if err := json.Unmarshal(dockercfgBytes, &dockercfg); err != nil { return nil, err diff --git a/pkg/fieldpath/fieldpath.go b/pkg/fieldpath/fieldpath.go index 08460c00ee8..429aea5b727 100644 --- a/pkg/fieldpath/fieldpath.go +++ b/pkg/fieldpath/fieldpath.go @@ -25,6 +25,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/resource" + "k8s.io/kubernetes/pkg/api/v1" ) // formatMap formats map[string]string to a string. @@ -65,9 +66,10 @@ func ExtractFieldPathAsString(obj interface{}, fieldPath string) (string, error) return "", fmt.Errorf("Unsupported fieldPath: %v", fieldPath) } +// TODO: move the functions below to pkg/api/util/resources // ExtractResourceValueByContainerName extracts the value of a resource // by providing container name -func ExtractResourceValueByContainerName(fs *api.ResourceFieldSelector, pod *api.Pod, containerName string) (string, error) { +func ExtractResourceValueByContainerName(fs *v1.ResourceFieldSelector, pod *v1.Pod, containerName string) (string, error) { container, err := findContainerInPod(pod, containerName) if err != nil { return "", err @@ -77,7 +79,7 @@ func ExtractResourceValueByContainerName(fs *api.ResourceFieldSelector, pod *api // ExtractResourceValueByContainerNameAndNodeAllocatable extracts the value of a resource // by providing container name and node allocatable -func ExtractResourceValueByContainerNameAndNodeAllocatable(fs *api.ResourceFieldSelector, pod *api.Pod, containerName string, nodeAllocatable api.ResourceList) (string, error) { +func ExtractResourceValueByContainerNameAndNodeAllocatable(fs *v1.ResourceFieldSelector, pod *v1.Pod, containerName string, nodeAllocatable v1.ResourceList) (string, error) { realContainer, err := findContainerInPod(pod, containerName) if err != nil { return "", err @@ -88,7 +90,7 @@ func ExtractResourceValueByContainerNameAndNodeAllocatable(fs *api.ResourceField return "", fmt.Errorf("failed to perform a deep copy of container object: %v", err) } - container, ok := containerCopy.(*api.Container) + container, ok := containerCopy.(*v1.Container) if !ok { return "", fmt.Errorf("unexpected type returned from deep copy of container object") } @@ -100,7 +102,32 @@ func ExtractResourceValueByContainerNameAndNodeAllocatable(fs *api.ResourceField // ExtractContainerResourceValue extracts the value of a resource // in an already known container -func ExtractContainerResourceValue(fs *api.ResourceFieldSelector, container *api.Container) (string, error) { +func ExtractContainerResourceValue(fs *v1.ResourceFieldSelector, container *v1.Container) (string, error) { + divisor := resource.Quantity{} + if divisor.Cmp(fs.Divisor) == 0 { + divisor = resource.MustParse("1") + } else { + divisor = fs.Divisor + } + + switch fs.Resource { + case "limits.cpu": + return convertResourceCPUToString(container.Resources.Limits.Cpu(), divisor) + case "limits.memory": + return convertResourceMemoryToString(container.Resources.Limits.Memory(), divisor) + case "requests.cpu": + return convertResourceCPUToString(container.Resources.Requests.Cpu(), divisor) + case "requests.memory": + return convertResourceMemoryToString(container.Resources.Requests.Memory(), divisor) + } + + return "", fmt.Errorf("Unsupported container resource : %v", fs.Resource) +} + +// TODO: remove this duplicate +// InternalExtractContainerResourceValue extracts the value of a resource +// in an already known container +func InternalExtractContainerResourceValue(fs *api.ResourceFieldSelector, container *api.Container) (string, error) { divisor := resource.Quantity{} if divisor.Cmp(fs.Divisor) == 0 { divisor = resource.MustParse("1") @@ -123,7 +150,7 @@ func ExtractContainerResourceValue(fs *api.ResourceFieldSelector, container *api } // findContainerInPod finds a container by its name in the provided pod -func findContainerInPod(pod *api.Pod, containerName string) (*api.Container, error) { +func findContainerInPod(pod *v1.Pod, containerName string) (*v1.Container, error) { for _, container := range pod.Spec.Containers { if container.Name == containerName { return &container, nil @@ -148,12 +175,12 @@ func convertResourceMemoryToString(memory *resource.Quantity, divisor resource.Q // MergeContainerResourceLimits checks if a limit is applied for // the container, and if not, it sets the limit to the passed resource list. -func MergeContainerResourceLimits(container *api.Container, - allocatable api.ResourceList) { +func MergeContainerResourceLimits(container *v1.Container, + allocatable v1.ResourceList) { if container.Resources.Limits == nil { - container.Resources.Limits = make(api.ResourceList) + container.Resources.Limits = make(v1.ResourceList) } - for _, resource := range []api.ResourceName{api.ResourceCPU, api.ResourceMemory} { + for _, resource := range []v1.ResourceName{v1.ResourceCPU, v1.ResourceMemory} { if quantity, exists := container.Resources.Limits[resource]; !exists || quantity.IsZero() { if cap, exists := allocatable[resource]; exists { container.Resources.Limits[resource] = *cap.Copy() diff --git a/pkg/fieldpath/fieldpath_test.go b/pkg/fieldpath/fieldpath_test.go index 5bfb1061bb7..6fa865edb11 100644 --- a/pkg/fieldpath/fieldpath_test.go +++ b/pkg/fieldpath/fieldpath_test.go @@ -22,8 +22,8 @@ import ( "github.com/stretchr/testify/assert" - "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/resource" + "k8s.io/kubernetes/pkg/api/v1" ) func TestExtractFieldPathAsString(t *testing.T) { @@ -43,8 +43,8 @@ func TestExtractFieldPathAsString(t *testing.T) { { name: "ok - namespace", fieldPath: "metadata.namespace", - obj: &api.Pod{ - ObjectMeta: api.ObjectMeta{ + obj: &v1.Pod{ + ObjectMeta: v1.ObjectMeta{ Namespace: "object-namespace", }, }, @@ -53,8 +53,8 @@ func TestExtractFieldPathAsString(t *testing.T) { { name: "ok - name", fieldPath: "metadata.name", - obj: &api.Pod{ - ObjectMeta: api.ObjectMeta{ + obj: &v1.Pod{ + ObjectMeta: v1.ObjectMeta{ Name: "object-name", }, }, @@ -63,8 +63,8 @@ func TestExtractFieldPathAsString(t *testing.T) { { name: "ok - labels", fieldPath: "metadata.labels", - obj: &api.Pod{ - ObjectMeta: api.ObjectMeta{ + obj: &v1.Pod{ + ObjectMeta: v1.ObjectMeta{ Labels: map[string]string{"key": "value"}, }, }, @@ -73,8 +73,8 @@ func TestExtractFieldPathAsString(t *testing.T) { { name: "ok - labels bslash n", fieldPath: "metadata.labels", - obj: &api.Pod{ - ObjectMeta: api.ObjectMeta{ + obj: &v1.Pod{ + ObjectMeta: v1.ObjectMeta{ Labels: map[string]string{"key": "value\n"}, }, }, @@ -83,8 +83,8 @@ func TestExtractFieldPathAsString(t *testing.T) { { name: "ok - annotations", fieldPath: "metadata.annotations", - obj: &api.Pod{ - ObjectMeta: api.ObjectMeta{ + obj: &v1.Pod{ + ObjectMeta: v1.ObjectMeta{ Annotations: map[string]string{"builder": "john-doe"}, }, }, @@ -94,8 +94,8 @@ func TestExtractFieldPathAsString(t *testing.T) { { name: "invalid expression", fieldPath: "metadata.whoops", - obj: &api.Pod{ - ObjectMeta: api.ObjectMeta{ + obj: &v1.Pod{ + ObjectMeta: v1.ObjectMeta{ Namespace: "object-namespace", }, }, @@ -119,26 +119,26 @@ func TestExtractFieldPathAsString(t *testing.T) { } } -func getPod(cname, cpuRequest, cpuLimit, memoryRequest, memoryLimit string) *api.Pod { - resources := api.ResourceRequirements{ - Limits: make(api.ResourceList), - Requests: make(api.ResourceList), +func getPod(cname, cpuRequest, cpuLimit, memoryRequest, memoryLimit string) *v1.Pod { + resources := v1.ResourceRequirements{ + Limits: make(v1.ResourceList), + Requests: make(v1.ResourceList), } if cpuLimit != "" { - resources.Limits[api.ResourceCPU] = resource.MustParse(cpuLimit) + resources.Limits[v1.ResourceCPU] = resource.MustParse(cpuLimit) } if memoryLimit != "" { - resources.Limits[api.ResourceMemory] = resource.MustParse(memoryLimit) + resources.Limits[v1.ResourceMemory] = resource.MustParse(memoryLimit) } if cpuRequest != "" { - resources.Requests[api.ResourceCPU] = resource.MustParse(cpuRequest) + resources.Requests[v1.ResourceCPU] = resource.MustParse(cpuRequest) } if memoryRequest != "" { - resources.Requests[api.ResourceMemory] = resource.MustParse(memoryRequest) + resources.Requests[v1.ResourceMemory] = resource.MustParse(memoryRequest) } - return &api.Pod{ - Spec: api.PodSpec{ - Containers: []api.Container{ + return &v1.Pod{ + Spec: v1.PodSpec{ + Containers: []v1.Container{ { Name: cname, Resources: resources, @@ -150,14 +150,14 @@ func getPod(cname, cpuRequest, cpuLimit, memoryRequest, memoryLimit string) *api func TestExtractResourceValue(t *testing.T) { cases := []struct { - fs *api.ResourceFieldSelector - pod *api.Pod + fs *v1.ResourceFieldSelector + pod *v1.Pod cName string expectedValue string expectedError error }{ { - fs: &api.ResourceFieldSelector{ + fs: &v1.ResourceFieldSelector{ Resource: "limits.cpu", }, cName: "foo", @@ -165,7 +165,7 @@ func TestExtractResourceValue(t *testing.T) { expectedValue: "9", }, { - fs: &api.ResourceFieldSelector{ + fs: &v1.ResourceFieldSelector{ Resource: "requests.cpu", }, cName: "foo", @@ -173,7 +173,7 @@ func TestExtractResourceValue(t *testing.T) { expectedValue: "0", }, { - fs: &api.ResourceFieldSelector{ + fs: &v1.ResourceFieldSelector{ Resource: "requests.cpu", }, cName: "foo", @@ -181,7 +181,7 @@ func TestExtractResourceValue(t *testing.T) { expectedValue: "8", }, { - fs: &api.ResourceFieldSelector{ + fs: &v1.ResourceFieldSelector{ Resource: "requests.cpu", }, cName: "foo", @@ -189,7 +189,7 @@ func TestExtractResourceValue(t *testing.T) { expectedValue: "1", }, { - fs: &api.ResourceFieldSelector{ + fs: &v1.ResourceFieldSelector{ Resource: "requests.cpu", Divisor: resource.MustParse("100m"), }, @@ -198,7 +198,7 @@ func TestExtractResourceValue(t *testing.T) { expectedValue: "12", }, { - fs: &api.ResourceFieldSelector{ + fs: &v1.ResourceFieldSelector{ Resource: "requests.memory", }, cName: "foo", @@ -206,7 +206,7 @@ func TestExtractResourceValue(t *testing.T) { expectedValue: "104857600", }, { - fs: &api.ResourceFieldSelector{ + fs: &v1.ResourceFieldSelector{ Resource: "requests.memory", Divisor: resource.MustParse("1Mi"), }, @@ -215,7 +215,7 @@ func TestExtractResourceValue(t *testing.T) { expectedValue: "100", }, { - fs: &api.ResourceFieldSelector{ + fs: &v1.ResourceFieldSelector{ Resource: "limits.memory", }, cName: "foo", diff --git a/pkg/metrics/metrics_grabber.go b/pkg/metrics/metrics_grabber.go index 61dfccc7949..f9d61f4aa41 100644 --- a/pkg/metrics/metrics_grabber.go +++ b/pkg/metrics/metrics_grabber.go @@ -21,7 +21,8 @@ import ( "time" "k8s.io/kubernetes/pkg/api" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + "k8s.io/kubernetes/pkg/api/v1" + clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5" "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/master/ports" "k8s.io/kubernetes/pkg/util/system" @@ -53,7 +54,7 @@ type MetricsGrabber struct { func NewMetricsGrabber(c clientset.Interface, kubelets bool, scheduler bool, controllers bool, apiServer bool) (*MetricsGrabber, error) { registeredMaster := false masterName := "" - nodeList, err := c.Core().Nodes().List(api.ListOptions{}) + nodeList, err := c.Core().Nodes().List(v1.ListOptions{}) if err != nil { return nil, err } @@ -61,7 +62,7 @@ func NewMetricsGrabber(c clientset.Interface, kubelets bool, scheduler bool, con glog.Warning("Can't find any Nodes in the API server to grab metrics from") } for _, node := range nodeList.Items { - if system.IsMasterNode(&node) { + if system.IsMasterNode(node.Name) { registeredMaster = true masterName = node.Name break @@ -85,7 +86,7 @@ func NewMetricsGrabber(c clientset.Interface, kubelets bool, scheduler bool, con } func (g *MetricsGrabber) GrabFromKubelet(nodeName string) (KubeletMetrics, error) { - nodes, err := g.client.Core().Nodes().List(api.ListOptions{FieldSelector: fields.Set{api.ObjectNameField: nodeName}.AsSelector()}) + nodes, err := g.client.Core().Nodes().List(v1.ListOptions{FieldSelector: fields.Set{api.ObjectNameField: nodeName}.AsSelector().String()}) if err != nil { return KubeletMetrics{}, err } @@ -166,7 +167,7 @@ func (g *MetricsGrabber) Grab() (MetricsCollection, error) { } if g.grabFromKubelets { result.KubeletMetrics = make(map[string]KubeletMetrics) - nodes, err := g.client.Core().Nodes().List(api.ListOptions{}) + nodes, err := g.client.Core().Nodes().List(v1.ListOptions{}) if err != nil { errs = append(errs, err) } else { diff --git a/pkg/security/apparmor/helpers.go b/pkg/security/apparmor/helpers.go index eb576bf3824..4412d2a9a1d 100644 --- a/pkg/security/apparmor/helpers.go +++ b/pkg/security/apparmor/helpers.go @@ -19,7 +19,7 @@ package apparmor import ( "strings" - "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/v1" ) // TODO: Move these values into the API package. @@ -38,7 +38,7 @@ const ( ) // Checks whether app armor is required for pod to be run. -func isRequired(pod *api.Pod) bool { +func isRequired(pod *v1.Pod) bool { for key := range pod.Annotations { if strings.HasPrefix(key, ContainerAnnotationKeyPrefix) { return true @@ -48,7 +48,7 @@ func isRequired(pod *api.Pod) bool { } // Returns the name of the profile to use with the container. -func GetProfileName(pod *api.Pod, containerName string) string { +func GetProfileName(pod *v1.Pod, containerName string) string { return GetProfileNameFromPodAnnotations(pod.Annotations, containerName) } @@ -59,10 +59,19 @@ func GetProfileNameFromPodAnnotations(annotations map[string]string, containerNa } // Sets the name of the profile to use with the container. -func SetProfileName(pod *api.Pod, containerName, profileName string) error { +func SetProfileName(pod *v1.Pod, containerName, profileName string) error { if pod.Annotations == nil { pod.Annotations = map[string]string{} } pod.Annotations[ContainerAnnotationKeyPrefix+containerName] = profileName return nil } + +// Sets the name of the profile to use with the container. +func SetProfileNameFromPodAnnotations(annotations map[string]string, containerName, profileName string) error { + if annotations == nil { + return nil + } + annotations[ContainerAnnotationKeyPrefix+containerName] = profileName + return nil +} diff --git a/pkg/security/apparmor/validate.go b/pkg/security/apparmor/validate.go index 79790c2a0c2..deed85fcec1 100644 --- a/pkg/security/apparmor/validate.go +++ b/pkg/security/apparmor/validate.go @@ -25,7 +25,7 @@ import ( "path" "strings" - "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/util" utilconfig "k8s.io/kubernetes/pkg/util/config" ) @@ -36,7 +36,7 @@ var isDisabledBuild bool // Interface for validating that a pod with with an AppArmor profile can be run by a Node. type Validator interface { - Validate(pod *api.Pod) error + Validate(pod *v1.Pod) error ValidateHost() error } @@ -60,7 +60,7 @@ type validator struct { appArmorFS string } -func (v *validator) Validate(pod *api.Pod) error { +func (v *validator) Validate(pod *v1.Pod) error { if !isRequired(pod) { return nil } diff --git a/pkg/security/apparmor/validate_test.go b/pkg/security/apparmor/validate_test.go index 5085b6ab4e8..2c293a5f3dd 100644 --- a/pkg/security/apparmor/validate_test.go +++ b/pkg/security/apparmor/validate_test.go @@ -21,7 +21,7 @@ import ( "fmt" "testing" - "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/v1" "github.com/stretchr/testify/assert" ) @@ -133,19 +133,19 @@ func TestValidateValidHost(t *testing.T) { } // Test multi-container pod. - pod := &api.Pod{ - ObjectMeta: api.ObjectMeta{ + pod := &v1.Pod{ + ObjectMeta: v1.ObjectMeta{ Annotations: map[string]string{ ContainerAnnotationKeyPrefix + "init": ProfileNamePrefix + "foo-container", ContainerAnnotationKeyPrefix + "test1": ProfileRuntimeDefault, ContainerAnnotationKeyPrefix + "test2": ProfileNamePrefix + "docker-default", }, }, - Spec: api.PodSpec{ - InitContainers: []api.Container{ + Spec: v1.PodSpec{ + InitContainers: []v1.Container{ {Name: "init"}, }, - Containers: []api.Container{ + Containers: []v1.Container{ {Name: "test1"}, {Name: "test2"}, {Name: "no-profile"}, @@ -172,7 +172,7 @@ func TestParseProfileName(t *testing.T) { } } -func getPodWithProfile(profile string) *api.Pod { +func getPodWithProfile(profile string) *v1.Pod { annotations := map[string]string{ ContainerAnnotationKeyPrefix + "test": profile, } @@ -181,12 +181,12 @@ func getPodWithProfile(profile string) *api.Pod { "foo": "bar", } } - return &api.Pod{ - ObjectMeta: api.ObjectMeta{ + return &v1.Pod{ + ObjectMeta: v1.ObjectMeta{ Annotations: annotations, }, - Spec: api.PodSpec{ - Containers: []api.Container{ + Spec: v1.PodSpec{ + Containers: []v1.Container{ { Name: "test", }, diff --git a/pkg/security/podsecuritypolicy/apparmor/strategy.go b/pkg/security/podsecuritypolicy/apparmor/strategy.go index 2fa8bff6878..d2a1963e198 100644 --- a/pkg/security/podsecuritypolicy/apparmor/strategy.go +++ b/pkg/security/podsecuritypolicy/apparmor/strategy.go @@ -92,7 +92,7 @@ func (s *strategy) Validate(pod *api.Pod, container *api.Container) field.ErrorL allErrs := field.ErrorList{} fieldPath := field.NewPath("pod", "metadata", "annotations").Key(apparmor.ContainerAnnotationKeyPrefix + container.Name) - profile := apparmor.GetProfileName(pod, container.Name) + profile := apparmor.GetProfileNameFromPodAnnotations(pod.Annotations, container.Name) if profile == "" { if len(s.allowedProfiles) > 0 { allErrs = append(allErrs, field.Forbidden(fieldPath, "AppArmor profile must be set")) diff --git a/pkg/security/podsecuritypolicy/provider_test.go b/pkg/security/podsecuritypolicy/provider_test.go index 26702032ad6..26e5749cc2b 100644 --- a/pkg/security/podsecuritypolicy/provider_test.go +++ b/pkg/security/podsecuritypolicy/provider_test.go @@ -25,6 +25,7 @@ import ( "github.com/davecgh/go-spew/spew" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/security/apparmor" "k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp" @@ -373,8 +374,11 @@ func TestValidateContainerSecurityContextFailures(t *testing.T) { } failNilAppArmorPod := defaultPod() - failInvalidAppArmorPod := defaultPod() - apparmor.SetProfileName(failInvalidAppArmorPod, defaultContainerName, apparmor.ProfileNamePrefix+"foo") + v1FailInvalidAppArmorPod := defaultV1Pod() + apparmor.SetProfileName(v1FailInvalidAppArmorPod, defaultContainerName, apparmor.ProfileNamePrefix+"foo") + failInvalidAppArmorPod := &api.Pod{} + v1.Convert_v1_Pod_To_api_Pod(v1FailInvalidAppArmorPod, failInvalidAppArmorPod, nil) + failAppArmorPSP := defaultPSP() failAppArmorPSP.Annotations = map[string]string{ apparmor.AllowedProfilesAnnotationKey: apparmor.ProfileRuntimeDefault, @@ -669,8 +673,10 @@ func TestValidateContainerSecurityContextSuccess(t *testing.T) { appArmorPSP.Annotations = map[string]string{ apparmor.AllowedProfilesAnnotationKey: apparmor.ProfileRuntimeDefault, } - appArmorPod := defaultPod() - apparmor.SetProfileName(appArmorPod, defaultContainerName, apparmor.ProfileRuntimeDefault) + v1AppArmorPod := defaultV1Pod() + apparmor.SetProfileName(v1AppArmorPod, defaultContainerName, apparmor.ProfileRuntimeDefault) + appArmorPod := &api.Pod{} + v1.Convert_v1_Pod_To_api_Pod(v1AppArmorPod, appArmorPod, nil) privPSP := defaultPSP() privPSP.Spec.Privileged = true @@ -930,6 +936,30 @@ func defaultPod() *api.Pod { } } +func defaultV1Pod() *v1.Pod { + var notPriv bool = false + return &v1.Pod{ + ObjectMeta: v1.ObjectMeta{ + Annotations: map[string]string{}, + }, + Spec: v1.PodSpec{ + SecurityContext: &v1.PodSecurityContext{ + // fill in for test cases + }, + Containers: []v1.Container{ + { + Name: defaultContainerName, + SecurityContext: &v1.SecurityContext{ + // expected to be set by defaulting mechanisms + Privileged: ¬Priv, + // fill in the rest for test cases + }, + }, + }, + }, + } +} + // TestValidateAllowedVolumes will test that for every field of VolumeSource we can create // a pod with that type of volume and deny it, accept it explicitly, or accept it with // the FSTypeAll wildcard. diff --git a/pkg/securitycontext/fake.go b/pkg/securitycontext/fake.go index ef86de3c868..0f4edb13911 100644 --- a/pkg/securitycontext/fake.go +++ b/pkg/securitycontext/fake.go @@ -18,16 +18,17 @@ package securitycontext import ( "k8s.io/kubernetes/pkg/api" +"k8s.io/kubernetes/pkg/api/v1" dockercontainer "github.com/docker/engine-api/types/container" ) // ValidSecurityContextWithContainerDefaults creates a valid security context provider based on // empty container defaults. Used for testing. -func ValidSecurityContextWithContainerDefaults() *api.SecurityContext { +func ValidSecurityContextWithContainerDefaults() *v1.SecurityContext { priv := false - return &api.SecurityContext{ - Capabilities: &api.Capabilities{}, + return &v1.SecurityContext{ + Capabilities: &v1.Capabilities{}, Privileged: &priv, } } @@ -39,7 +40,17 @@ func NewFakeSecurityContextProvider() SecurityContextProvider { type FakeSecurityContextProvider struct{} -func (p FakeSecurityContextProvider) ModifyContainerConfig(pod *api.Pod, container *api.Container, config *dockercontainer.Config) { +func (p FakeSecurityContextProvider) ModifyContainerConfig(pod *v1.Pod, container *v1.Container, config *dockercontainer.Config) { } -func (p FakeSecurityContextProvider) ModifyHostConfig(pod *api.Pod, container *api.Container, hostConfig *dockercontainer.HostConfig, supplementalGids []int64) { +func (p FakeSecurityContextProvider) ModifyHostConfig(pod *v1.Pod, container *v1.Container, hostConfig *dockercontainer.HostConfig, supplementalGids []int64) { +} + +// ValidInternalSecurityContextWithContainerDefaults creates a valid security context provider based on +// empty container defaults. Used for testing. +func ValidInternalSecurityContextWithContainerDefaults() *api.SecurityContext { + priv := false + return &api.SecurityContext{ + Capabilities: &api.Capabilities{}, + Privileged: &priv, + } } diff --git a/pkg/securitycontext/provider.go b/pkg/securitycontext/provider.go index 1b17a2abc0c..5a2dc46cfb2 100644 --- a/pkg/securitycontext/provider.go +++ b/pkg/securitycontext/provider.go @@ -20,7 +20,8 @@ import ( "fmt" "strconv" - "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/v1" +"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/kubelet/leaky" dockercontainer "github.com/docker/engine-api/types/container" @@ -37,7 +38,7 @@ 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 *dockercontainer.Config) { +func (p SimpleSecurityContextProvider) ModifyContainerConfig(pod *v1.Pod, container *v1.Container, config *dockercontainer.Config) { effectiveSC := DetermineEffectiveSecurityContext(pod, container) if effectiveSC == nil { return @@ -50,7 +51,7 @@ func (p SimpleSecurityContextProvider) ModifyContainerConfig(pod *api.Pod, conta // 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. -func (p SimpleSecurityContextProvider) ModifyHostConfig(pod *api.Pod, container *api.Container, hostConfig *dockercontainer.HostConfig, supplementalGids []int64) { +func (p SimpleSecurityContextProvider) ModifyHostConfig(pod *v1.Pod, container *v1.Container, hostConfig *dockercontainer.HostConfig, supplementalGids []int64) { // Apply supplemental groups if container.Name != leaky.PodInfraContainerName { // TODO: We skip application of supplemental groups to the @@ -96,7 +97,7 @@ func (p SimpleSecurityContextProvider) ModifyHostConfig(pod *api.Pod, container } // ModifySecurityOptions adds SELinux options to config. -func ModifySecurityOptions(config []string, selinuxOpts *api.SELinuxOptions) []string { +func ModifySecurityOptions(config []string, selinuxOpts *v1.SELinuxOptions) []string { config = modifySecurityOption(config, DockerLabelUser, selinuxOpts.User) config = modifySecurityOption(config, DockerLabelRole, selinuxOpts.Role) config = modifySecurityOption(config, DockerLabelType, selinuxOpts.Type) @@ -115,7 +116,7 @@ func modifySecurityOption(config []string, name, value string) []string { } // MakeCapabilities creates string slices from Capability slices -func MakeCapabilities(capAdd []api.Capability, capDrop []api.Capability) ([]string, []string) { +func MakeCapabilities(capAdd []v1.Capability, capDrop []v1.Capability) ([]string, []string) { var ( addCaps []string dropCaps []string @@ -129,7 +130,7 @@ func MakeCapabilities(capAdd []api.Capability, capDrop []api.Capability) ([]stri return addCaps, dropCaps } -func DetermineEffectiveSecurityContext(pod *api.Pod, container *api.Container) *api.SecurityContext { +func DetermineEffectiveSecurityContext(pod *v1.Pod, container *v1.Container) *v1.SecurityContext { effectiveSc := securityContextFromPodSecurityContext(pod) containerSc := container.SecurityContext @@ -143,6 +144,78 @@ func DetermineEffectiveSecurityContext(pod *api.Pod, container *api.Container) * return containerSc } + if containerSc.SELinuxOptions != nil { + effectiveSc.SELinuxOptions = new(v1.SELinuxOptions) + *effectiveSc.SELinuxOptions = *containerSc.SELinuxOptions + } + + if containerSc.Capabilities != nil { + effectiveSc.Capabilities = new(v1.Capabilities) + *effectiveSc.Capabilities = *containerSc.Capabilities + } + + if containerSc.Privileged != nil { + effectiveSc.Privileged = new(bool) + *effectiveSc.Privileged = *containerSc.Privileged + } + + if containerSc.RunAsUser != nil { + effectiveSc.RunAsUser = new(int64) + *effectiveSc.RunAsUser = *containerSc.RunAsUser + } + + if containerSc.RunAsNonRoot != nil { + effectiveSc.RunAsNonRoot = new(bool) + *effectiveSc.RunAsNonRoot = *containerSc.RunAsNonRoot + } + + if containerSc.ReadOnlyRootFilesystem != nil { + effectiveSc.ReadOnlyRootFilesystem = new(bool) + *effectiveSc.ReadOnlyRootFilesystem = *containerSc.ReadOnlyRootFilesystem + } + + return effectiveSc +} + +func securityContextFromPodSecurityContext(pod *v1.Pod) *v1.SecurityContext { + if pod.Spec.SecurityContext == nil { + return nil + } + + synthesized := &v1.SecurityContext{} + + if pod.Spec.SecurityContext.SELinuxOptions != nil { + synthesized.SELinuxOptions = &v1.SELinuxOptions{} + *synthesized.SELinuxOptions = *pod.Spec.SecurityContext.SELinuxOptions + } + if pod.Spec.SecurityContext.RunAsUser != nil { + synthesized.RunAsUser = new(int64) + *synthesized.RunAsUser = *pod.Spec.SecurityContext.RunAsUser + } + + if pod.Spec.SecurityContext.RunAsNonRoot != nil { + synthesized.RunAsNonRoot = new(bool) + *synthesized.RunAsNonRoot = *pod.Spec.SecurityContext.RunAsNonRoot + } + + return synthesized +} + +// TODO: remove the duplicate code +func InternalDetermineEffectiveSecurityContext(pod *api.Pod, container *api.Container) *api.SecurityContext { + effectiveSc := internalSecurityContextFromPodSecurityContext(pod) + containerSc := container.SecurityContext + + if effectiveSc == nil && containerSc == nil { + return nil + } + if effectiveSc != nil && containerSc == nil { + return effectiveSc + } + if effectiveSc == nil && containerSc != nil { + return containerSc + } + if containerSc.SELinuxOptions != nil { effectiveSc.SELinuxOptions = new(api.SELinuxOptions) *effectiveSc.SELinuxOptions = *containerSc.SELinuxOptions @@ -176,7 +249,7 @@ func DetermineEffectiveSecurityContext(pod *api.Pod, container *api.Container) * return effectiveSc } -func securityContextFromPodSecurityContext(pod *api.Pod) *api.SecurityContext { +func internalSecurityContextFromPodSecurityContext(pod *api.Pod) *api.SecurityContext { if pod.Spec.SecurityContext == nil { return nil } diff --git a/pkg/securitycontext/provider_test.go b/pkg/securitycontext/provider_test.go index 0c955647ba4..2f848ee42a4 100644 --- a/pkg/securitycontext/provider_test.go +++ b/pkg/securitycontext/provider_test.go @@ -23,8 +23,8 @@ import ( "testing" dockercontainer "github.com/docker/engine-api/types/container" - "k8s.io/kubernetes/pkg/api" apitesting "k8s.io/kubernetes/pkg/api/testing" + "k8s.io/kubernetes/pkg/api/v1" ) func TestModifyContainerConfig(t *testing.T) { @@ -33,13 +33,13 @@ func TestModifyContainerConfig(t *testing.T) { cases := []struct { name string - podSc *api.PodSecurityContext - sc *api.SecurityContext + podSc *v1.PodSecurityContext + sc *v1.SecurityContext expected *dockercontainer.Config }{ { name: "container.SecurityContext.RunAsUser set", - sc: &api.SecurityContext{ + sc: &v1.SecurityContext{ RunAsUser: &uid, }, expected: &dockercontainer.Config{ @@ -48,12 +48,12 @@ func TestModifyContainerConfig(t *testing.T) { }, { name: "no RunAsUser value set", - sc: &api.SecurityContext{}, + sc: &v1.SecurityContext{}, expected: &dockercontainer.Config{}, }, { name: "pod.Spec.SecurityContext.RunAsUser set", - podSc: &api.PodSecurityContext{ + podSc: &v1.PodSecurityContext{ RunAsUser: &uid, }, expected: &dockercontainer.Config{ @@ -62,10 +62,10 @@ func TestModifyContainerConfig(t *testing.T) { }, { name: "container.SecurityContext.RunAsUser overrides pod.Spec.SecurityContext.RunAsUser", - podSc: &api.PodSecurityContext{ + podSc: &v1.PodSecurityContext{ RunAsUser: &uid, }, - sc: &api.SecurityContext{ + sc: &v1.SecurityContext{ RunAsUser: &overrideUid, }, expected: &dockercontainer.Config{ @@ -75,9 +75,9 @@ func TestModifyContainerConfig(t *testing.T) { } provider := NewSimpleSecurityContextProvider() - dummyContainer := &api.Container{} + dummyContainer := &v1.Container{} for _, tc := range cases { - pod := &api.Pod{Spec: api.PodSpec{SecurityContext: tc.podSc}} + pod := &v1.Pod{Spec: v1.PodSpec{SecurityContext: tc.podSc}} dummyContainer.SecurityContext = tc.sc dockerCfg := &dockercontainer.Config{} @@ -91,7 +91,7 @@ func TestModifyContainerConfig(t *testing.T) { func TestModifyHostConfig(t *testing.T) { priv := true - setPrivSC := &api.SecurityContext{} + setPrivSC := &v1.SecurityContext{} setPrivSC.Privileged = &priv setPrivHC := &dockercontainer.HostConfig{ Privileged: true, @@ -115,8 +115,8 @@ func TestModifyHostConfig(t *testing.T) { cases := []struct { name string - podSc *api.PodSecurityContext - sc *api.SecurityContext + podSc *v1.PodSecurityContext + sc *v1.SecurityContext expected *dockercontainer.HostConfig }{ { @@ -131,21 +131,21 @@ func TestModifyHostConfig(t *testing.T) { }, { name: "container.SecurityContext.Capabilities", - sc: &api.SecurityContext{ + sc: &v1.SecurityContext{ Capabilities: inputCapabilities(), }, expected: setCapsHC, }, { name: "container.SecurityContext.SELinuxOptions", - sc: &api.SecurityContext{ + sc: &v1.SecurityContext{ SELinuxOptions: inputSELinuxOptions(), }, expected: setSELinuxHC, }, { name: "pod.Spec.SecurityContext.SELinuxOptions", - podSc: &api.PodSecurityContext{ + podSc: &v1.PodSecurityContext{ SELinuxOptions: inputSELinuxOptions(), }, expected: setSELinuxHC, @@ -159,10 +159,10 @@ func TestModifyHostConfig(t *testing.T) { } provider := NewSimpleSecurityContextProvider() - dummyContainer := &api.Container{} + dummyContainer := &v1.Container{} for _, tc := range cases { - pod := &api.Pod{Spec: api.PodSpec{SecurityContext: tc.podSc}} + pod := &v1.Pod{Spec: v1.PodSpec{SecurityContext: tc.podSc}} dummyContainer.SecurityContext = tc.sc dockerCfg := &dockercontainer.HostConfig{} @@ -175,7 +175,7 @@ func TestModifyHostConfig(t *testing.T) { } func TestModifyHostConfigPodSecurityContext(t *testing.T) { - supplementalGroupsSC := &api.PodSecurityContext{} + supplementalGroupsSC := &v1.PodSecurityContext{} supplementalGroupsSC.SupplementalGroups = []int64{2222} supplementalGroupHC := fullValidHostConfig() supplementalGroupHC.GroupAdd = []string{"2222"} @@ -189,7 +189,7 @@ func TestModifyHostConfigPodSecurityContext(t *testing.T) { extraSupplementalGroup := []int64{1234} testCases := map[string]struct { - securityContext *api.PodSecurityContext + securityContext *v1.PodSecurityContext expected *dockercontainer.HostConfig extraSupplementalGroups []int64 }{ @@ -204,12 +204,12 @@ func TestModifyHostConfigPodSecurityContext(t *testing.T) { extraSupplementalGroups: nil, }, "FSGroup": { - securityContext: &api.PodSecurityContext{FSGroup: &fsGroup}, + securityContext: &v1.PodSecurityContext{FSGroup: &fsGroup}, expected: fsGroupHC, extraSupplementalGroups: nil, }, "FSGroup + SupplementalGroups": { - securityContext: &api.PodSecurityContext{ + securityContext: &v1.PodSecurityContext{ SupplementalGroups: []int64{2222}, FSGroup: &fsGroup, }, @@ -229,10 +229,10 @@ func TestModifyHostConfigPodSecurityContext(t *testing.T) { } provider := NewSimpleSecurityContextProvider() - dummyContainer := &api.Container{} + dummyContainer := &v1.Container{} dummyContainer.SecurityContext = fullValidSecurityContext() - dummyPod := &api.Pod{ - Spec: apitesting.DeepEqualSafePodSpec(), + dummyPod := &v1.Pod{ + Spec: apitesting.V1DeepEqualSafePodSpec(), } for k, v := range testCases { @@ -277,9 +277,9 @@ func TestModifySecurityOption(t *testing.T) { } } -func overridePodSecurityContext() *api.PodSecurityContext { - return &api.PodSecurityContext{ - SELinuxOptions: &api.SELinuxOptions{ +func overridePodSecurityContext() *v1.PodSecurityContext { + return &v1.PodSecurityContext{ + SELinuxOptions: &v1.SELinuxOptions{ User: "user2", Role: "role2", Type: "type2", @@ -288,30 +288,30 @@ func overridePodSecurityContext() *api.PodSecurityContext { } } -func fullValidPodSecurityContext() *api.PodSecurityContext { - return &api.PodSecurityContext{ +func fullValidPodSecurityContext() *v1.PodSecurityContext { + return &v1.PodSecurityContext{ SELinuxOptions: inputSELinuxOptions(), } } -func fullValidSecurityContext() *api.SecurityContext { +func fullValidSecurityContext() *v1.SecurityContext { priv := true - return &api.SecurityContext{ + return &v1.SecurityContext{ Privileged: &priv, Capabilities: inputCapabilities(), SELinuxOptions: inputSELinuxOptions(), } } -func inputCapabilities() *api.Capabilities { - return &api.Capabilities{ - Add: []api.Capability{"addCapA", "addCapB"}, - Drop: []api.Capability{"dropCapA", "dropCapB"}, +func inputCapabilities() *v1.Capabilities { + return &v1.Capabilities{ + Add: []v1.Capability{"addCapA", "addCapB"}, + Drop: []v1.Capability{"dropCapA", "dropCapB"}, } } -func inputSELinuxOptions() *api.SELinuxOptions { - return &api.SELinuxOptions{ +func inputSELinuxOptions() *v1.SELinuxOptions { + return &v1.SELinuxOptions{ User: "user", Role: "role", Type: "type", diff --git a/pkg/securitycontext/types.go b/pkg/securitycontext/types.go index 500c2ba2b64..fba98398a52 100644 --- a/pkg/securitycontext/types.go +++ b/pkg/securitycontext/types.go @@ -17,7 +17,7 @@ limitations under the License. package securitycontext import ( - "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/v1" dockercontainer "github.com/docker/engine-api/types/container" ) @@ -26,7 +26,7 @@ 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 *dockercontainer.Config) + ModifyContainerConfig(pod *v1.Pod, container *v1.Container, config *dockercontainer.Config) // ModifyHostConfig is called before the Docker createContainer call. // The security context provider can make changes to the HostConfig, affecting @@ -37,7 +37,7 @@ type SecurityContextProvider interface { // - pod: the pod to modify the docker hostconfig for // - container: the container to modify the hostconfig for // - supplementalGids: additional supplemental GIDs associated with the pod's volumes - ModifyHostConfig(pod *api.Pod, container *api.Container, hostConfig *dockercontainer.HostConfig, supplementalGids []int64) + ModifyHostConfig(pod *v1.Pod, container *v1.Container, hostConfig *dockercontainer.HostConfig, supplementalGids []int64) } const ( diff --git a/pkg/securitycontext/util.go b/pkg/securitycontext/util.go index 13d48a258f6..0d71b1d667e 100644 --- a/pkg/securitycontext/util.go +++ b/pkg/securitycontext/util.go @@ -20,12 +20,12 @@ import ( "fmt" "strings" - "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/v1" ) // HasPrivilegedRequest returns the value of SecurityContext.Privileged, taking into account // the possibility of nils -func HasPrivilegedRequest(container *api.Container) bool { +func HasPrivilegedRequest(container *v1.Container) bool { if container.SecurityContext == nil { return false } @@ -37,7 +37,7 @@ func HasPrivilegedRequest(container *api.Container) bool { // HasCapabilitiesRequest returns true if Adds or Drops are defined in the security context // capabilities, taking into account nils -func HasCapabilitiesRequest(container *api.Container) bool { +func HasCapabilitiesRequest(container *v1.Container) bool { if container.SecurityContext == nil { return false } @@ -52,14 +52,14 @@ const expectedSELinuxFields = 4 // ParseSELinuxOptions parses a string containing a full SELinux context // (user, role, type, and level) into an SELinuxOptions object. If the // context is malformed, an error is returned. -func ParseSELinuxOptions(context string) (*api.SELinuxOptions, error) { +func ParseSELinuxOptions(context string) (*v1.SELinuxOptions, error) { fields := strings.SplitN(context, ":", expectedSELinuxFields) if len(fields) != expectedSELinuxFields { return nil, fmt.Errorf("expected %v fields in selinux; got %v (context: %v)", expectedSELinuxFields, len(fields), context) } - return &api.SELinuxOptions{ + return &v1.SELinuxOptions{ User: fields[0], Role: fields[1], Type: fields[2], @@ -68,7 +68,7 @@ func ParseSELinuxOptions(context string) (*api.SELinuxOptions, error) { } // HasNonRootUID returns true if the runAsUser is set and is greater than 0. -func HasRootUID(container *api.Container) bool { +func HasRootUID(container *v1.Container) bool { if container.SecurityContext == nil { return false } @@ -79,11 +79,11 @@ func HasRootUID(container *api.Container) bool { } // HasRunAsUser determines if the sc's runAsUser field is set. -func HasRunAsUser(container *api.Container) bool { +func HasRunAsUser(container *v1.Container) bool { return container.SecurityContext != nil && container.SecurityContext.RunAsUser != nil } // HasRootRunAsUser returns true if the run as user is set and it is set to 0. -func HasRootRunAsUser(container *api.Container) bool { +func HasRootRunAsUser(container *v1.Container) bool { return HasRunAsUser(container) && HasRootUID(container) } diff --git a/pkg/securitycontext/util_test.go b/pkg/securitycontext/util_test.go index 523a7f52d21..92a61054742 100644 --- a/pkg/securitycontext/util_test.go +++ b/pkg/securitycontext/util_test.go @@ -19,19 +19,19 @@ package securitycontext import ( "testing" - "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/v1" ) func TestParseSELinuxOptions(t *testing.T) { cases := []struct { name string input string - expected *api.SELinuxOptions + expected *v1.SELinuxOptions }{ { name: "simple", input: "user_t:role_t:type_t:s0", - expected: &api.SELinuxOptions{ + expected: &v1.SELinuxOptions{ User: "user_t", Role: "role_t", Type: "type_t", @@ -41,7 +41,7 @@ func TestParseSELinuxOptions(t *testing.T) { { name: "simple + categories", input: "user_t:role_t:type_t:s0:c0", - expected: &api.SELinuxOptions{ + expected: &v1.SELinuxOptions{ User: "user_t", Role: "role_t", Type: "type_t", @@ -69,7 +69,7 @@ func TestParseSELinuxOptions(t *testing.T) { } } -func compareContexts(name string, ex, ac *api.SELinuxOptions, t *testing.T) { +func compareContexts(name string, ex, ac *v1.SELinuxOptions, t *testing.T) { if e, a := ex.User, ac.User; e != a { t.Errorf("%v: expected user: %v, got: %v", name, e, a) } @@ -84,8 +84,8 @@ func compareContexts(name string, ex, ac *api.SELinuxOptions, t *testing.T) { } } -func containerWithUser(ptr *int64) *api.Container { - return &api.Container{SecurityContext: &api.SecurityContext{RunAsUser: ptr}} +func containerWithUser(ptr *int64) *v1.Container { + return &v1.Container{SecurityContext: &v1.SecurityContext{RunAsUser: ptr}} } func TestHaRootUID(t *testing.T) { @@ -93,11 +93,11 @@ func TestHaRootUID(t *testing.T) { var root int64 = 0 tests := map[string]struct { - container *api.Container + container *v1.Container expect bool }{ "nil sc": { - container: &api.Container{SecurityContext: nil}, + container: &v1.Container{SecurityContext: nil}, }, "nil runAsuser": { container: containerWithUser(nil), @@ -123,11 +123,11 @@ func TestHasRunAsUser(t *testing.T) { var runAsUser int64 = 0 tests := map[string]struct { - container *api.Container + container *v1.Container expect bool }{ "nil sc": { - container: &api.Container{SecurityContext: nil}, + container: &v1.Container{SecurityContext: nil}, }, "nil runAsUser": { container: containerWithUser(nil), @@ -151,11 +151,11 @@ func TestHasRootRunAsUser(t *testing.T) { var root int64 = 0 tests := map[string]struct { - container *api.Container + container *v1.Container expect bool }{ "nil sc": { - container: &api.Container{SecurityContext: nil}, + container: &v1.Container{SecurityContext: nil}, }, "nil runAsuser": { container: containerWithUser(nil), diff --git a/pkg/serviceaccount/jwt.go b/pkg/serviceaccount/jwt.go index c9b4b770764..111afe1c5dc 100644 --- a/pkg/serviceaccount/jwt.go +++ b/pkg/serviceaccount/jwt.go @@ -26,7 +26,7 @@ import ( "fmt" "io/ioutil" - "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/auth/authenticator" "k8s.io/kubernetes/pkg/auth/user" @@ -47,14 +47,14 @@ const ( // ServiceAccountTokenGetter defines functions to retrieve a named service account and secret type ServiceAccountTokenGetter interface { - GetServiceAccount(namespace, name string) (*api.ServiceAccount, error) - GetSecret(namespace, name string) (*api.Secret, error) + GetServiceAccount(namespace, name string) (*v1.ServiceAccount, error) + GetSecret(namespace, name string) (*v1.Secret, error) } type TokenGenerator interface { // GenerateToken generates a token which will identify the given ServiceAccount. // The returned token will be stored in the given (and yet-unpersisted) Secret. - GenerateToken(serviceAccount api.ServiceAccount, secret api.Secret) (string, error) + GenerateToken(serviceAccount v1.ServiceAccount, secret v1.Secret) (string, error) } // ReadPrivateKey is a helper function for reading a private key from a PEM-encoded file @@ -148,7 +148,7 @@ type jwtTokenGenerator struct { privateKey interface{} } -func (j *jwtTokenGenerator) GenerateToken(serviceAccount api.ServiceAccount, secret api.Secret) (string, error) { +func (j *jwtTokenGenerator) GenerateToken(serviceAccount v1.ServiceAccount, secret v1.Secret) (string, error) { var method jwt.SigningMethod switch privateKey := j.privateKey.(type) { case *rsa.PrivateKey: @@ -299,7 +299,7 @@ func (j *jwtTokenAuthenticator) AuthenticateToken(token string) (user.Info, bool glog.V(4).Infof("Could not retrieve token %s/%s for service account %s/%s: %v", namespace, secretName, namespace, serviceAccountName, err) return nil, false, errors.New("Token has been invalidated") } - if bytes.Compare(secret.Data[api.ServiceAccountTokenKey], []byte(token)) != 0 { + if bytes.Compare(secret.Data[v1.ServiceAccountTokenKey], []byte(token)) != 0 { glog.V(4).Infof("Token contents no longer matches %s/%s for service account %s/%s", namespace, secretName, namespace, serviceAccountName) return nil, false, errors.New("Token does not match server's copy") } diff --git a/pkg/serviceaccount/jwt_test.go b/pkg/serviceaccount/jwt_test.go index 3705aee3894..e412a7fb6c9 100644 --- a/pkg/serviceaccount/jwt_test.go +++ b/pkg/serviceaccount/jwt_test.go @@ -22,9 +22,9 @@ import ( "reflect" "testing" - "k8s.io/kubernetes/pkg/api" - clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" + "k8s.io/kubernetes/pkg/api/v1" + clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5" + "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/fake" serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount" "k8s.io/kubernetes/pkg/serviceaccount" ) @@ -164,21 +164,21 @@ func TestTokenGenerateAndValidate(t *testing.T) { expectedUserUID := "12345" // Related API objects - serviceAccount := &api.ServiceAccount{ - ObjectMeta: api.ObjectMeta{ + serviceAccount := &v1.ServiceAccount{ + ObjectMeta: v1.ObjectMeta{ Name: "my-service-account", UID: "12345", Namespace: "test", }, } - rsaSecret := &api.Secret{ - ObjectMeta: api.ObjectMeta{ + rsaSecret := &v1.Secret{ + ObjectMeta: v1.ObjectMeta{ Name: "my-rsa-secret", Namespace: "test", }, } - ecdsaSecret := &api.Secret{ - ObjectMeta: api.ObjectMeta{ + ecdsaSecret := &v1.Secret{ + ObjectMeta: v1.ObjectMeta{ Name: "my-ecdsa-secret", Namespace: "test", }, diff --git a/pkg/serviceaccount/util.go b/pkg/serviceaccount/util.go index 712b086ad48..d8fbc442f32 100644 --- a/pkg/serviceaccount/util.go +++ b/pkg/serviceaccount/util.go @@ -21,6 +21,7 @@ import ( "strings" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/auth/user" ) @@ -84,7 +85,28 @@ func UserInfo(namespace, name, uid string) user.Info { } // IsServiceAccountToken returns true if the secret is a valid api token for the service account -func IsServiceAccountToken(secret *api.Secret, sa *api.ServiceAccount) bool { +func IsServiceAccountToken(secret *v1.Secret, sa *v1.ServiceAccount) bool { + if secret.Type != v1.SecretTypeServiceAccountToken { + return false + } + + name := secret.Annotations[v1.ServiceAccountNameKey] + uid := secret.Annotations[v1.ServiceAccountUIDKey] + if name != sa.Name { + // Name must match + return false + } + if len(uid) > 0 && uid != string(sa.UID) { + // If UID is specified, it must match + return false + } + + return true +} + +// TODO: remove the duplicate code +// InternalIsServiceAccountToken returns true if the secret is a valid api token for the service account +func InternalIsServiceAccountToken(secret *api.Secret, sa *api.ServiceAccount) bool { if secret.Type != api.SecretTypeServiceAccountToken { return false } diff --git a/pkg/storage/cacher.go b/pkg/storage/cacher.go index ae64f741dcb..b004b50538c 100644 --- a/pkg/storage/cacher.go +++ b/pkg/storage/cacher.go @@ -28,6 +28,7 @@ import ( "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/client/cache" "k8s.io/kubernetes/pkg/conversion" "k8s.io/kubernetes/pkg/runtime" @@ -631,7 +632,7 @@ func newCacherListerWatcher(storage Interface, resourcePrefix string, newListFun } // Implements cache.ListerWatcher interface. -func (lw *cacherListerWatcher) List(options api.ListOptions) (runtime.Object, error) { +func (lw *cacherListerWatcher) List(options v1.ListOptions) (runtime.Object, error) { list := lw.newListFunc() if err := lw.storage.List(context.TODO(), lw.resourcePrefix, "", Everything, list); err != nil { return nil, err @@ -640,7 +641,7 @@ func (lw *cacherListerWatcher) List(options api.ListOptions) (runtime.Object, er } // Implements cache.ListerWatcher interface. -func (lw *cacherListerWatcher) Watch(options api.ListOptions) (watch.Interface, error) { +func (lw *cacherListerWatcher) Watch(options v1.ListOptions) (watch.Interface, error) { return lw.storage.WatchList(context.TODO(), lw.resourcePrefix, options.ResourceVersion, Everything) } diff --git a/pkg/storage/testing/types.generated.go b/pkg/storage/testing/types.generated.go index c3cd8bf231d..71a07365361 100644 --- a/pkg/storage/testing/types.generated.go +++ b/pkg/storage/testing/types.generated.go @@ -24,13 +24,14 @@ package testing import ( "errors" "fmt" + "reflect" + "runtime" + time "time" + codec1978 "github.com/ugorji/go/codec" pkg2_api "k8s.io/kubernetes/pkg/api" pkg1_unversioned "k8s.io/kubernetes/pkg/api/unversioned" pkg3_types "k8s.io/kubernetes/pkg/types" - "reflect" - "runtime" - time "time" ) const ( diff --git a/pkg/storage/watch_cache_test.go b/pkg/storage/watch_cache_test.go index 8a930ff0876..0a19fa31175 100644 --- a/pkg/storage/watch_cache_test.go +++ b/pkg/storage/watch_cache_test.go @@ -24,6 +24,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/client/cache" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util/clock" @@ -312,14 +313,14 @@ func TestWaitUntilFreshAndListTimeout(t *testing.T) { } type testLW struct { - ListFunc func(options api.ListOptions) (runtime.Object, error) - WatchFunc func(options api.ListOptions) (watch.Interface, error) + ListFunc func(options v1.ListOptions) (runtime.Object, error) + WatchFunc func(options v1.ListOptions) (watch.Interface, error) } -func (t *testLW) List(options api.ListOptions) (runtime.Object, error) { +func (t *testLW) List(options v1.ListOptions) (runtime.Object, error) { return t.ListFunc(options) } -func (t *testLW) Watch(options api.ListOptions) (watch.Interface, error) { +func (t *testLW) Watch(options v1.ListOptions) (watch.Interface, error) { return t.WatchFunc(options) } @@ -337,12 +338,12 @@ func TestReflectorForWatchCache(t *testing.T) { } lw := &testLW{ - WatchFunc: func(options api.ListOptions) (watch.Interface, error) { + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { fw := watch.NewFake() go fw.Stop() return fw, nil }, - ListFunc: func(options api.ListOptions) (runtime.Object, error) { + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return &api.PodList{ListMeta: unversioned.ListMeta{ResourceVersion: "10"}}, nil }, }