mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 23:37:01 +00:00
more dependencies packages:
pkg/metrics pkg/credentialprovider pkg/security pkg/securitycontext pkg/serviceaccount pkg/storage pkg/fieldpath
This commit is contained in:
parent
f8b36bdd40
commit
4f3d0e3bde
@ -27,7 +27,7 @@ import (
|
|||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
dockertypes "github.com/docker/engine-api/types"
|
dockertypes "github.com/docker/engine-api/types"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/util/sets"
|
"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,
|
// 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.
|
// then a DockerKeyring is built based on every hit and unioned with the defaultKeyring.
|
||||||
// If they do not, then the default keyring is returned
|
// 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{}
|
passedCredentials := []DockerConfig{}
|
||||||
for _, passedSecret := range passedSecrets {
|
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{}
|
dockerConfigJson := DockerConfigJson{}
|
||||||
if err := json.Unmarshal(dockerConfigJsonBytes, &dockerConfigJson); err != nil {
|
if err := json.Unmarshal(dockerConfigJsonBytes, &dockerConfigJson); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
passedCredentials = append(passedCredentials, dockerConfigJson.Auths)
|
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{}
|
dockercfg := DockerConfig{}
|
||||||
if err := json.Unmarshal(dockercfgBytes, &dockercfg); err != nil {
|
if err := json.Unmarshal(dockercfgBytes, &dockercfg); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/meta"
|
"k8s.io/kubernetes/pkg/api/meta"
|
||||||
"k8s.io/kubernetes/pkg/api/resource"
|
"k8s.io/kubernetes/pkg/api/resource"
|
||||||
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// formatMap formats map[string]string to a string.
|
// 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)
|
return "", fmt.Errorf("Unsupported fieldPath: %v", fieldPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move the functions below to pkg/api/util/resources
|
||||||
// ExtractResourceValueByContainerName extracts the value of a resource
|
// ExtractResourceValueByContainerName extracts the value of a resource
|
||||||
// by providing container name
|
// 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)
|
container, err := findContainerInPod(pod, containerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -77,7 +79,7 @@ func ExtractResourceValueByContainerName(fs *api.ResourceFieldSelector, pod *api
|
|||||||
|
|
||||||
// ExtractResourceValueByContainerNameAndNodeAllocatable extracts the value of a resource
|
// ExtractResourceValueByContainerNameAndNodeAllocatable extracts the value of a resource
|
||||||
// by providing container name and node allocatable
|
// 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)
|
realContainer, err := findContainerInPod(pod, containerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
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)
|
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 {
|
if !ok {
|
||||||
return "", fmt.Errorf("unexpected type returned from deep copy of container object")
|
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
|
// ExtractContainerResourceValue extracts the value of a resource
|
||||||
// in an already known container
|
// 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{}
|
divisor := resource.Quantity{}
|
||||||
if divisor.Cmp(fs.Divisor) == 0 {
|
if divisor.Cmp(fs.Divisor) == 0 {
|
||||||
divisor = resource.MustParse("1")
|
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
|
// 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 {
|
for _, container := range pod.Spec.Containers {
|
||||||
if container.Name == containerName {
|
if container.Name == containerName {
|
||||||
return &container, nil
|
return &container, nil
|
||||||
@ -148,12 +175,12 @@ func convertResourceMemoryToString(memory *resource.Quantity, divisor resource.Q
|
|||||||
|
|
||||||
// MergeContainerResourceLimits checks if a limit is applied for
|
// MergeContainerResourceLimits checks if a limit is applied for
|
||||||
// the container, and if not, it sets the limit to the passed resource list.
|
// the container, and if not, it sets the limit to the passed resource list.
|
||||||
func MergeContainerResourceLimits(container *api.Container,
|
func MergeContainerResourceLimits(container *v1.Container,
|
||||||
allocatable api.ResourceList) {
|
allocatable v1.ResourceList) {
|
||||||
if container.Resources.Limits == nil {
|
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 quantity, exists := container.Resources.Limits[resource]; !exists || quantity.IsZero() {
|
||||||
if cap, exists := allocatable[resource]; exists {
|
if cap, exists := allocatable[resource]; exists {
|
||||||
container.Resources.Limits[resource] = *cap.Copy()
|
container.Resources.Limits[resource] = *cap.Copy()
|
||||||
|
@ -22,8 +22,8 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
|
||||||
"k8s.io/kubernetes/pkg/api/resource"
|
"k8s.io/kubernetes/pkg/api/resource"
|
||||||
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestExtractFieldPathAsString(t *testing.T) {
|
func TestExtractFieldPathAsString(t *testing.T) {
|
||||||
@ -43,8 +43,8 @@ func TestExtractFieldPathAsString(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "ok - namespace",
|
name: "ok - namespace",
|
||||||
fieldPath: "metadata.namespace",
|
fieldPath: "metadata.namespace",
|
||||||
obj: &api.Pod{
|
obj: &v1.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Namespace: "object-namespace",
|
Namespace: "object-namespace",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -53,8 +53,8 @@ func TestExtractFieldPathAsString(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "ok - name",
|
name: "ok - name",
|
||||||
fieldPath: "metadata.name",
|
fieldPath: "metadata.name",
|
||||||
obj: &api.Pod{
|
obj: &v1.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Name: "object-name",
|
Name: "object-name",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -63,8 +63,8 @@ func TestExtractFieldPathAsString(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "ok - labels",
|
name: "ok - labels",
|
||||||
fieldPath: "metadata.labels",
|
fieldPath: "metadata.labels",
|
||||||
obj: &api.Pod{
|
obj: &v1.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Labels: map[string]string{"key": "value"},
|
Labels: map[string]string{"key": "value"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -73,8 +73,8 @@ func TestExtractFieldPathAsString(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "ok - labels bslash n",
|
name: "ok - labels bslash n",
|
||||||
fieldPath: "metadata.labels",
|
fieldPath: "metadata.labels",
|
||||||
obj: &api.Pod{
|
obj: &v1.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Labels: map[string]string{"key": "value\n"},
|
Labels: map[string]string{"key": "value\n"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -83,8 +83,8 @@ func TestExtractFieldPathAsString(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "ok - annotations",
|
name: "ok - annotations",
|
||||||
fieldPath: "metadata.annotations",
|
fieldPath: "metadata.annotations",
|
||||||
obj: &api.Pod{
|
obj: &v1.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Annotations: map[string]string{"builder": "john-doe"},
|
Annotations: map[string]string{"builder": "john-doe"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -94,8 +94,8 @@ func TestExtractFieldPathAsString(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "invalid expression",
|
name: "invalid expression",
|
||||||
fieldPath: "metadata.whoops",
|
fieldPath: "metadata.whoops",
|
||||||
obj: &api.Pod{
|
obj: &v1.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Namespace: "object-namespace",
|
Namespace: "object-namespace",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -119,26 +119,26 @@ func TestExtractFieldPathAsString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPod(cname, cpuRequest, cpuLimit, memoryRequest, memoryLimit string) *api.Pod {
|
func getPod(cname, cpuRequest, cpuLimit, memoryRequest, memoryLimit string) *v1.Pod {
|
||||||
resources := api.ResourceRequirements{
|
resources := v1.ResourceRequirements{
|
||||||
Limits: make(api.ResourceList),
|
Limits: make(v1.ResourceList),
|
||||||
Requests: make(api.ResourceList),
|
Requests: make(v1.ResourceList),
|
||||||
}
|
}
|
||||||
if cpuLimit != "" {
|
if cpuLimit != "" {
|
||||||
resources.Limits[api.ResourceCPU] = resource.MustParse(cpuLimit)
|
resources.Limits[v1.ResourceCPU] = resource.MustParse(cpuLimit)
|
||||||
}
|
}
|
||||||
if memoryLimit != "" {
|
if memoryLimit != "" {
|
||||||
resources.Limits[api.ResourceMemory] = resource.MustParse(memoryLimit)
|
resources.Limits[v1.ResourceMemory] = resource.MustParse(memoryLimit)
|
||||||
}
|
}
|
||||||
if cpuRequest != "" {
|
if cpuRequest != "" {
|
||||||
resources.Requests[api.ResourceCPU] = resource.MustParse(cpuRequest)
|
resources.Requests[v1.ResourceCPU] = resource.MustParse(cpuRequest)
|
||||||
}
|
}
|
||||||
if memoryRequest != "" {
|
if memoryRequest != "" {
|
||||||
resources.Requests[api.ResourceMemory] = resource.MustParse(memoryRequest)
|
resources.Requests[v1.ResourceMemory] = resource.MustParse(memoryRequest)
|
||||||
}
|
}
|
||||||
return &api.Pod{
|
return &v1.Pod{
|
||||||
Spec: api.PodSpec{
|
Spec: v1.PodSpec{
|
||||||
Containers: []api.Container{
|
Containers: []v1.Container{
|
||||||
{
|
{
|
||||||
Name: cname,
|
Name: cname,
|
||||||
Resources: resources,
|
Resources: resources,
|
||||||
@ -150,14 +150,14 @@ func getPod(cname, cpuRequest, cpuLimit, memoryRequest, memoryLimit string) *api
|
|||||||
|
|
||||||
func TestExtractResourceValue(t *testing.T) {
|
func TestExtractResourceValue(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
fs *api.ResourceFieldSelector
|
fs *v1.ResourceFieldSelector
|
||||||
pod *api.Pod
|
pod *v1.Pod
|
||||||
cName string
|
cName string
|
||||||
expectedValue string
|
expectedValue string
|
||||||
expectedError error
|
expectedError error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
fs: &api.ResourceFieldSelector{
|
fs: &v1.ResourceFieldSelector{
|
||||||
Resource: "limits.cpu",
|
Resource: "limits.cpu",
|
||||||
},
|
},
|
||||||
cName: "foo",
|
cName: "foo",
|
||||||
@ -165,7 +165,7 @@ func TestExtractResourceValue(t *testing.T) {
|
|||||||
expectedValue: "9",
|
expectedValue: "9",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fs: &api.ResourceFieldSelector{
|
fs: &v1.ResourceFieldSelector{
|
||||||
Resource: "requests.cpu",
|
Resource: "requests.cpu",
|
||||||
},
|
},
|
||||||
cName: "foo",
|
cName: "foo",
|
||||||
@ -173,7 +173,7 @@ func TestExtractResourceValue(t *testing.T) {
|
|||||||
expectedValue: "0",
|
expectedValue: "0",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fs: &api.ResourceFieldSelector{
|
fs: &v1.ResourceFieldSelector{
|
||||||
Resource: "requests.cpu",
|
Resource: "requests.cpu",
|
||||||
},
|
},
|
||||||
cName: "foo",
|
cName: "foo",
|
||||||
@ -181,7 +181,7 @@ func TestExtractResourceValue(t *testing.T) {
|
|||||||
expectedValue: "8",
|
expectedValue: "8",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fs: &api.ResourceFieldSelector{
|
fs: &v1.ResourceFieldSelector{
|
||||||
Resource: "requests.cpu",
|
Resource: "requests.cpu",
|
||||||
},
|
},
|
||||||
cName: "foo",
|
cName: "foo",
|
||||||
@ -189,7 +189,7 @@ func TestExtractResourceValue(t *testing.T) {
|
|||||||
expectedValue: "1",
|
expectedValue: "1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fs: &api.ResourceFieldSelector{
|
fs: &v1.ResourceFieldSelector{
|
||||||
Resource: "requests.cpu",
|
Resource: "requests.cpu",
|
||||||
Divisor: resource.MustParse("100m"),
|
Divisor: resource.MustParse("100m"),
|
||||||
},
|
},
|
||||||
@ -198,7 +198,7 @@ func TestExtractResourceValue(t *testing.T) {
|
|||||||
expectedValue: "12",
|
expectedValue: "12",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fs: &api.ResourceFieldSelector{
|
fs: &v1.ResourceFieldSelector{
|
||||||
Resource: "requests.memory",
|
Resource: "requests.memory",
|
||||||
},
|
},
|
||||||
cName: "foo",
|
cName: "foo",
|
||||||
@ -206,7 +206,7 @@ func TestExtractResourceValue(t *testing.T) {
|
|||||||
expectedValue: "104857600",
|
expectedValue: "104857600",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fs: &api.ResourceFieldSelector{
|
fs: &v1.ResourceFieldSelector{
|
||||||
Resource: "requests.memory",
|
Resource: "requests.memory",
|
||||||
Divisor: resource.MustParse("1Mi"),
|
Divisor: resource.MustParse("1Mi"),
|
||||||
},
|
},
|
||||||
@ -215,7 +215,7 @@ func TestExtractResourceValue(t *testing.T) {
|
|||||||
expectedValue: "100",
|
expectedValue: "100",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fs: &api.ResourceFieldSelector{
|
fs: &v1.ResourceFieldSelector{
|
||||||
Resource: "limits.memory",
|
Resource: "limits.memory",
|
||||||
},
|
},
|
||||||
cName: "foo",
|
cName: "foo",
|
||||||
|
@ -21,7 +21,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"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/fields"
|
||||||
"k8s.io/kubernetes/pkg/master/ports"
|
"k8s.io/kubernetes/pkg/master/ports"
|
||||||
"k8s.io/kubernetes/pkg/util/system"
|
"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) {
|
func NewMetricsGrabber(c clientset.Interface, kubelets bool, scheduler bool, controllers bool, apiServer bool) (*MetricsGrabber, error) {
|
||||||
registeredMaster := false
|
registeredMaster := false
|
||||||
masterName := ""
|
masterName := ""
|
||||||
nodeList, err := c.Core().Nodes().List(api.ListOptions{})
|
nodeList, err := c.Core().Nodes().List(v1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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")
|
glog.Warning("Can't find any Nodes in the API server to grab metrics from")
|
||||||
}
|
}
|
||||||
for _, node := range nodeList.Items {
|
for _, node := range nodeList.Items {
|
||||||
if system.IsMasterNode(&node) {
|
if system.IsMasterNode(node.Name) {
|
||||||
registeredMaster = true
|
registeredMaster = true
|
||||||
masterName = node.Name
|
masterName = node.Name
|
||||||
break
|
break
|
||||||
@ -85,7 +86,7 @@ func NewMetricsGrabber(c clientset.Interface, kubelets bool, scheduler bool, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *MetricsGrabber) GrabFromKubelet(nodeName string) (KubeletMetrics, error) {
|
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 {
|
if err != nil {
|
||||||
return KubeletMetrics{}, err
|
return KubeletMetrics{}, err
|
||||||
}
|
}
|
||||||
@ -166,7 +167,7 @@ func (g *MetricsGrabber) Grab() (MetricsCollection, error) {
|
|||||||
}
|
}
|
||||||
if g.grabFromKubelets {
|
if g.grabFromKubelets {
|
||||||
result.KubeletMetrics = make(map[string]KubeletMetrics)
|
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 {
|
if err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -19,7 +19,7 @@ package apparmor
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Move these values into the API package.
|
// TODO: Move these values into the API package.
|
||||||
@ -38,7 +38,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Checks whether app armor is required for pod to be run.
|
// 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 {
|
for key := range pod.Annotations {
|
||||||
if strings.HasPrefix(key, ContainerAnnotationKeyPrefix) {
|
if strings.HasPrefix(key, ContainerAnnotationKeyPrefix) {
|
||||||
return true
|
return true
|
||||||
@ -48,7 +48,7 @@ func isRequired(pod *api.Pod) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns the name of the profile to use with the container.
|
// 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)
|
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.
|
// 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 {
|
if pod.Annotations == nil {
|
||||||
pod.Annotations = map[string]string{}
|
pod.Annotations = map[string]string{}
|
||||||
}
|
}
|
||||||
pod.Annotations[ContainerAnnotationKeyPrefix+containerName] = profileName
|
pod.Annotations[ContainerAnnotationKeyPrefix+containerName] = profileName
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
@ -25,7 +25,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/util"
|
"k8s.io/kubernetes/pkg/util"
|
||||||
utilconfig "k8s.io/kubernetes/pkg/util/config"
|
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.
|
// Interface for validating that a pod with with an AppArmor profile can be run by a Node.
|
||||||
type Validator interface {
|
type Validator interface {
|
||||||
Validate(pod *api.Pod) error
|
Validate(pod *v1.Pod) error
|
||||||
ValidateHost() error
|
ValidateHost() error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ type validator struct {
|
|||||||
appArmorFS string
|
appArmorFS string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *validator) Validate(pod *api.Pod) error {
|
func (v *validator) Validate(pod *v1.Pod) error {
|
||||||
if !isRequired(pod) {
|
if !isRequired(pod) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@ -133,19 +133,19 @@ func TestValidateValidHost(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test multi-container pod.
|
// Test multi-container pod.
|
||||||
pod := &api.Pod{
|
pod := &v1.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
ContainerAnnotationKeyPrefix + "init": ProfileNamePrefix + "foo-container",
|
ContainerAnnotationKeyPrefix + "init": ProfileNamePrefix + "foo-container",
|
||||||
ContainerAnnotationKeyPrefix + "test1": ProfileRuntimeDefault,
|
ContainerAnnotationKeyPrefix + "test1": ProfileRuntimeDefault,
|
||||||
ContainerAnnotationKeyPrefix + "test2": ProfileNamePrefix + "docker-default",
|
ContainerAnnotationKeyPrefix + "test2": ProfileNamePrefix + "docker-default",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: v1.PodSpec{
|
||||||
InitContainers: []api.Container{
|
InitContainers: []v1.Container{
|
||||||
{Name: "init"},
|
{Name: "init"},
|
||||||
},
|
},
|
||||||
Containers: []api.Container{
|
Containers: []v1.Container{
|
||||||
{Name: "test1"},
|
{Name: "test1"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
{Name: "no-profile"},
|
{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{
|
annotations := map[string]string{
|
||||||
ContainerAnnotationKeyPrefix + "test": profile,
|
ContainerAnnotationKeyPrefix + "test": profile,
|
||||||
}
|
}
|
||||||
@ -181,12 +181,12 @@ func getPodWithProfile(profile string) *api.Pod {
|
|||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &api.Pod{
|
return &v1.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Annotations: annotations,
|
Annotations: annotations,
|
||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: v1.PodSpec{
|
||||||
Containers: []api.Container{
|
Containers: []v1.Container{
|
||||||
{
|
{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
},
|
},
|
||||||
|
@ -92,7 +92,7 @@ func (s *strategy) Validate(pod *api.Pod, container *api.Container) field.ErrorL
|
|||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
fieldPath := field.NewPath("pod", "metadata", "annotations").Key(apparmor.ContainerAnnotationKeyPrefix + container.Name)
|
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 profile == "" {
|
||||||
if len(s.allowedProfiles) > 0 {
|
if len(s.allowedProfiles) > 0 {
|
||||||
allErrs = append(allErrs, field.Forbidden(fieldPath, "AppArmor profile must be set"))
|
allErrs = append(allErrs, field.Forbidden(fieldPath, "AppArmor profile must be set"))
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/security/apparmor"
|
"k8s.io/kubernetes/pkg/security/apparmor"
|
||||||
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp"
|
"k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp"
|
||||||
@ -373,8 +374,11 @@ func TestValidateContainerSecurityContextFailures(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
failNilAppArmorPod := defaultPod()
|
failNilAppArmorPod := defaultPod()
|
||||||
failInvalidAppArmorPod := defaultPod()
|
v1FailInvalidAppArmorPod := defaultV1Pod()
|
||||||
apparmor.SetProfileName(failInvalidAppArmorPod, defaultContainerName, apparmor.ProfileNamePrefix+"foo")
|
apparmor.SetProfileName(v1FailInvalidAppArmorPod, defaultContainerName, apparmor.ProfileNamePrefix+"foo")
|
||||||
|
failInvalidAppArmorPod := &api.Pod{}
|
||||||
|
v1.Convert_v1_Pod_To_api_Pod(v1FailInvalidAppArmorPod, failInvalidAppArmorPod, nil)
|
||||||
|
|
||||||
failAppArmorPSP := defaultPSP()
|
failAppArmorPSP := defaultPSP()
|
||||||
failAppArmorPSP.Annotations = map[string]string{
|
failAppArmorPSP.Annotations = map[string]string{
|
||||||
apparmor.AllowedProfilesAnnotationKey: apparmor.ProfileRuntimeDefault,
|
apparmor.AllowedProfilesAnnotationKey: apparmor.ProfileRuntimeDefault,
|
||||||
@ -669,8 +673,10 @@ func TestValidateContainerSecurityContextSuccess(t *testing.T) {
|
|||||||
appArmorPSP.Annotations = map[string]string{
|
appArmorPSP.Annotations = map[string]string{
|
||||||
apparmor.AllowedProfilesAnnotationKey: apparmor.ProfileRuntimeDefault,
|
apparmor.AllowedProfilesAnnotationKey: apparmor.ProfileRuntimeDefault,
|
||||||
}
|
}
|
||||||
appArmorPod := defaultPod()
|
v1AppArmorPod := defaultV1Pod()
|
||||||
apparmor.SetProfileName(appArmorPod, defaultContainerName, apparmor.ProfileRuntimeDefault)
|
apparmor.SetProfileName(v1AppArmorPod, defaultContainerName, apparmor.ProfileRuntimeDefault)
|
||||||
|
appArmorPod := &api.Pod{}
|
||||||
|
v1.Convert_v1_Pod_To_api_Pod(v1AppArmorPod, appArmorPod, nil)
|
||||||
|
|
||||||
privPSP := defaultPSP()
|
privPSP := defaultPSP()
|
||||||
privPSP.Spec.Privileged = true
|
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
|
// 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
|
// a pod with that type of volume and deny it, accept it explicitly, or accept it with
|
||||||
// the FSTypeAll wildcard.
|
// the FSTypeAll wildcard.
|
||||||
|
@ -18,16 +18,17 @@ package securitycontext
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
|
||||||
dockercontainer "github.com/docker/engine-api/types/container"
|
dockercontainer "github.com/docker/engine-api/types/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidSecurityContextWithContainerDefaults creates a valid security context provider based on
|
// ValidSecurityContextWithContainerDefaults creates a valid security context provider based on
|
||||||
// empty container defaults. Used for testing.
|
// empty container defaults. Used for testing.
|
||||||
func ValidSecurityContextWithContainerDefaults() *api.SecurityContext {
|
func ValidSecurityContextWithContainerDefaults() *v1.SecurityContext {
|
||||||
priv := false
|
priv := false
|
||||||
return &api.SecurityContext{
|
return &v1.SecurityContext{
|
||||||
Capabilities: &api.Capabilities{},
|
Capabilities: &v1.Capabilities{},
|
||||||
Privileged: &priv,
|
Privileged: &priv,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,7 +40,17 @@ func NewFakeSecurityContextProvider() SecurityContextProvider {
|
|||||||
|
|
||||||
type FakeSecurityContextProvider struct{}
|
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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/leaky"
|
"k8s.io/kubernetes/pkg/kubelet/leaky"
|
||||||
|
|
||||||
dockercontainer "github.com/docker/engine-api/types/container"
|
dockercontainer "github.com/docker/engine-api/types/container"
|
||||||
@ -37,7 +38,7 @@ type SimpleSecurityContextProvider struct{}
|
|||||||
// ModifyContainerConfig is called before the Docker createContainer call.
|
// ModifyContainerConfig is called before the Docker createContainer call.
|
||||||
// The security context provider can make changes to the Config with which
|
// The security context provider can make changes to the Config with which
|
||||||
// the container is created.
|
// 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)
|
effectiveSC := DetermineEffectiveSecurityContext(pod, container)
|
||||||
if effectiveSC == nil {
|
if effectiveSC == nil {
|
||||||
return
|
return
|
||||||
@ -50,7 +51,7 @@ func (p SimpleSecurityContextProvider) ModifyContainerConfig(pod *api.Pod, conta
|
|||||||
// ModifyHostConfig is called before the Docker runContainer call. The
|
// ModifyHostConfig is called before the Docker runContainer call. The
|
||||||
// security context provider can make changes to the HostConfig, affecting
|
// security context provider can make changes to the HostConfig, affecting
|
||||||
// security options, whether the container is privileged, volume binds, etc.
|
// 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
|
// Apply supplemental groups
|
||||||
if container.Name != leaky.PodInfraContainerName {
|
if container.Name != leaky.PodInfraContainerName {
|
||||||
// TODO: We skip application of supplemental groups to the
|
// 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.
|
// 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, DockerLabelUser, selinuxOpts.User)
|
||||||
config = modifySecurityOption(config, DockerLabelRole, selinuxOpts.Role)
|
config = modifySecurityOption(config, DockerLabelRole, selinuxOpts.Role)
|
||||||
config = modifySecurityOption(config, DockerLabelType, selinuxOpts.Type)
|
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
|
// 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 (
|
var (
|
||||||
addCaps []string
|
addCaps []string
|
||||||
dropCaps []string
|
dropCaps []string
|
||||||
@ -129,7 +130,7 @@ func MakeCapabilities(capAdd []api.Capability, capDrop []api.Capability) ([]stri
|
|||||||
return addCaps, dropCaps
|
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)
|
effectiveSc := securityContextFromPodSecurityContext(pod)
|
||||||
containerSc := container.SecurityContext
|
containerSc := container.SecurityContext
|
||||||
|
|
||||||
@ -143,6 +144,78 @@ func DetermineEffectiveSecurityContext(pod *api.Pod, container *api.Container) *
|
|||||||
return containerSc
|
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 {
|
if containerSc.SELinuxOptions != nil {
|
||||||
effectiveSc.SELinuxOptions = new(api.SELinuxOptions)
|
effectiveSc.SELinuxOptions = new(api.SELinuxOptions)
|
||||||
*effectiveSc.SELinuxOptions = *containerSc.SELinuxOptions
|
*effectiveSc.SELinuxOptions = *containerSc.SELinuxOptions
|
||||||
@ -176,7 +249,7 @@ func DetermineEffectiveSecurityContext(pod *api.Pod, container *api.Container) *
|
|||||||
return effectiveSc
|
return effectiveSc
|
||||||
}
|
}
|
||||||
|
|
||||||
func securityContextFromPodSecurityContext(pod *api.Pod) *api.SecurityContext {
|
func internalSecurityContextFromPodSecurityContext(pod *api.Pod) *api.SecurityContext {
|
||||||
if pod.Spec.SecurityContext == nil {
|
if pod.Spec.SecurityContext == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
dockercontainer "github.com/docker/engine-api/types/container"
|
dockercontainer "github.com/docker/engine-api/types/container"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
|
||||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||||
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestModifyContainerConfig(t *testing.T) {
|
func TestModifyContainerConfig(t *testing.T) {
|
||||||
@ -33,13 +33,13 @@ func TestModifyContainerConfig(t *testing.T) {
|
|||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
podSc *api.PodSecurityContext
|
podSc *v1.PodSecurityContext
|
||||||
sc *api.SecurityContext
|
sc *v1.SecurityContext
|
||||||
expected *dockercontainer.Config
|
expected *dockercontainer.Config
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "container.SecurityContext.RunAsUser set",
|
name: "container.SecurityContext.RunAsUser set",
|
||||||
sc: &api.SecurityContext{
|
sc: &v1.SecurityContext{
|
||||||
RunAsUser: &uid,
|
RunAsUser: &uid,
|
||||||
},
|
},
|
||||||
expected: &dockercontainer.Config{
|
expected: &dockercontainer.Config{
|
||||||
@ -48,12 +48,12 @@ func TestModifyContainerConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no RunAsUser value set",
|
name: "no RunAsUser value set",
|
||||||
sc: &api.SecurityContext{},
|
sc: &v1.SecurityContext{},
|
||||||
expected: &dockercontainer.Config{},
|
expected: &dockercontainer.Config{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pod.Spec.SecurityContext.RunAsUser set",
|
name: "pod.Spec.SecurityContext.RunAsUser set",
|
||||||
podSc: &api.PodSecurityContext{
|
podSc: &v1.PodSecurityContext{
|
||||||
RunAsUser: &uid,
|
RunAsUser: &uid,
|
||||||
},
|
},
|
||||||
expected: &dockercontainer.Config{
|
expected: &dockercontainer.Config{
|
||||||
@ -62,10 +62,10 @@ func TestModifyContainerConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "container.SecurityContext.RunAsUser overrides pod.Spec.SecurityContext.RunAsUser",
|
name: "container.SecurityContext.RunAsUser overrides pod.Spec.SecurityContext.RunAsUser",
|
||||||
podSc: &api.PodSecurityContext{
|
podSc: &v1.PodSecurityContext{
|
||||||
RunAsUser: &uid,
|
RunAsUser: &uid,
|
||||||
},
|
},
|
||||||
sc: &api.SecurityContext{
|
sc: &v1.SecurityContext{
|
||||||
RunAsUser: &overrideUid,
|
RunAsUser: &overrideUid,
|
||||||
},
|
},
|
||||||
expected: &dockercontainer.Config{
|
expected: &dockercontainer.Config{
|
||||||
@ -75,9 +75,9 @@ func TestModifyContainerConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
provider := NewSimpleSecurityContextProvider()
|
provider := NewSimpleSecurityContextProvider()
|
||||||
dummyContainer := &api.Container{}
|
dummyContainer := &v1.Container{}
|
||||||
for _, tc := range cases {
|
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
|
dummyContainer.SecurityContext = tc.sc
|
||||||
dockerCfg := &dockercontainer.Config{}
|
dockerCfg := &dockercontainer.Config{}
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ func TestModifyContainerConfig(t *testing.T) {
|
|||||||
|
|
||||||
func TestModifyHostConfig(t *testing.T) {
|
func TestModifyHostConfig(t *testing.T) {
|
||||||
priv := true
|
priv := true
|
||||||
setPrivSC := &api.SecurityContext{}
|
setPrivSC := &v1.SecurityContext{}
|
||||||
setPrivSC.Privileged = &priv
|
setPrivSC.Privileged = &priv
|
||||||
setPrivHC := &dockercontainer.HostConfig{
|
setPrivHC := &dockercontainer.HostConfig{
|
||||||
Privileged: true,
|
Privileged: true,
|
||||||
@ -115,8 +115,8 @@ func TestModifyHostConfig(t *testing.T) {
|
|||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
podSc *api.PodSecurityContext
|
podSc *v1.PodSecurityContext
|
||||||
sc *api.SecurityContext
|
sc *v1.SecurityContext
|
||||||
expected *dockercontainer.HostConfig
|
expected *dockercontainer.HostConfig
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -131,21 +131,21 @@ func TestModifyHostConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "container.SecurityContext.Capabilities",
|
name: "container.SecurityContext.Capabilities",
|
||||||
sc: &api.SecurityContext{
|
sc: &v1.SecurityContext{
|
||||||
Capabilities: inputCapabilities(),
|
Capabilities: inputCapabilities(),
|
||||||
},
|
},
|
||||||
expected: setCapsHC,
|
expected: setCapsHC,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "container.SecurityContext.SELinuxOptions",
|
name: "container.SecurityContext.SELinuxOptions",
|
||||||
sc: &api.SecurityContext{
|
sc: &v1.SecurityContext{
|
||||||
SELinuxOptions: inputSELinuxOptions(),
|
SELinuxOptions: inputSELinuxOptions(),
|
||||||
},
|
},
|
||||||
expected: setSELinuxHC,
|
expected: setSELinuxHC,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pod.Spec.SecurityContext.SELinuxOptions",
|
name: "pod.Spec.SecurityContext.SELinuxOptions",
|
||||||
podSc: &api.PodSecurityContext{
|
podSc: &v1.PodSecurityContext{
|
||||||
SELinuxOptions: inputSELinuxOptions(),
|
SELinuxOptions: inputSELinuxOptions(),
|
||||||
},
|
},
|
||||||
expected: setSELinuxHC,
|
expected: setSELinuxHC,
|
||||||
@ -159,10 +159,10 @@ func TestModifyHostConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
provider := NewSimpleSecurityContextProvider()
|
provider := NewSimpleSecurityContextProvider()
|
||||||
dummyContainer := &api.Container{}
|
dummyContainer := &v1.Container{}
|
||||||
|
|
||||||
for _, tc := range cases {
|
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
|
dummyContainer.SecurityContext = tc.sc
|
||||||
dockerCfg := &dockercontainer.HostConfig{}
|
dockerCfg := &dockercontainer.HostConfig{}
|
||||||
|
|
||||||
@ -175,7 +175,7 @@ func TestModifyHostConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestModifyHostConfigPodSecurityContext(t *testing.T) {
|
func TestModifyHostConfigPodSecurityContext(t *testing.T) {
|
||||||
supplementalGroupsSC := &api.PodSecurityContext{}
|
supplementalGroupsSC := &v1.PodSecurityContext{}
|
||||||
supplementalGroupsSC.SupplementalGroups = []int64{2222}
|
supplementalGroupsSC.SupplementalGroups = []int64{2222}
|
||||||
supplementalGroupHC := fullValidHostConfig()
|
supplementalGroupHC := fullValidHostConfig()
|
||||||
supplementalGroupHC.GroupAdd = []string{"2222"}
|
supplementalGroupHC.GroupAdd = []string{"2222"}
|
||||||
@ -189,7 +189,7 @@ func TestModifyHostConfigPodSecurityContext(t *testing.T) {
|
|||||||
extraSupplementalGroup := []int64{1234}
|
extraSupplementalGroup := []int64{1234}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
securityContext *api.PodSecurityContext
|
securityContext *v1.PodSecurityContext
|
||||||
expected *dockercontainer.HostConfig
|
expected *dockercontainer.HostConfig
|
||||||
extraSupplementalGroups []int64
|
extraSupplementalGroups []int64
|
||||||
}{
|
}{
|
||||||
@ -204,12 +204,12 @@ func TestModifyHostConfigPodSecurityContext(t *testing.T) {
|
|||||||
extraSupplementalGroups: nil,
|
extraSupplementalGroups: nil,
|
||||||
},
|
},
|
||||||
"FSGroup": {
|
"FSGroup": {
|
||||||
securityContext: &api.PodSecurityContext{FSGroup: &fsGroup},
|
securityContext: &v1.PodSecurityContext{FSGroup: &fsGroup},
|
||||||
expected: fsGroupHC,
|
expected: fsGroupHC,
|
||||||
extraSupplementalGroups: nil,
|
extraSupplementalGroups: nil,
|
||||||
},
|
},
|
||||||
"FSGroup + SupplementalGroups": {
|
"FSGroup + SupplementalGroups": {
|
||||||
securityContext: &api.PodSecurityContext{
|
securityContext: &v1.PodSecurityContext{
|
||||||
SupplementalGroups: []int64{2222},
|
SupplementalGroups: []int64{2222},
|
||||||
FSGroup: &fsGroup,
|
FSGroup: &fsGroup,
|
||||||
},
|
},
|
||||||
@ -229,10 +229,10 @@ func TestModifyHostConfigPodSecurityContext(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
provider := NewSimpleSecurityContextProvider()
|
provider := NewSimpleSecurityContextProvider()
|
||||||
dummyContainer := &api.Container{}
|
dummyContainer := &v1.Container{}
|
||||||
dummyContainer.SecurityContext = fullValidSecurityContext()
|
dummyContainer.SecurityContext = fullValidSecurityContext()
|
||||||
dummyPod := &api.Pod{
|
dummyPod := &v1.Pod{
|
||||||
Spec: apitesting.DeepEqualSafePodSpec(),
|
Spec: apitesting.V1DeepEqualSafePodSpec(),
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range testCases {
|
for k, v := range testCases {
|
||||||
@ -277,9 +277,9 @@ func TestModifySecurityOption(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func overridePodSecurityContext() *api.PodSecurityContext {
|
func overridePodSecurityContext() *v1.PodSecurityContext {
|
||||||
return &api.PodSecurityContext{
|
return &v1.PodSecurityContext{
|
||||||
SELinuxOptions: &api.SELinuxOptions{
|
SELinuxOptions: &v1.SELinuxOptions{
|
||||||
User: "user2",
|
User: "user2",
|
||||||
Role: "role2",
|
Role: "role2",
|
||||||
Type: "type2",
|
Type: "type2",
|
||||||
@ -288,30 +288,30 @@ func overridePodSecurityContext() *api.PodSecurityContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fullValidPodSecurityContext() *api.PodSecurityContext {
|
func fullValidPodSecurityContext() *v1.PodSecurityContext {
|
||||||
return &api.PodSecurityContext{
|
return &v1.PodSecurityContext{
|
||||||
SELinuxOptions: inputSELinuxOptions(),
|
SELinuxOptions: inputSELinuxOptions(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fullValidSecurityContext() *api.SecurityContext {
|
func fullValidSecurityContext() *v1.SecurityContext {
|
||||||
priv := true
|
priv := true
|
||||||
return &api.SecurityContext{
|
return &v1.SecurityContext{
|
||||||
Privileged: &priv,
|
Privileged: &priv,
|
||||||
Capabilities: inputCapabilities(),
|
Capabilities: inputCapabilities(),
|
||||||
SELinuxOptions: inputSELinuxOptions(),
|
SELinuxOptions: inputSELinuxOptions(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func inputCapabilities() *api.Capabilities {
|
func inputCapabilities() *v1.Capabilities {
|
||||||
return &api.Capabilities{
|
return &v1.Capabilities{
|
||||||
Add: []api.Capability{"addCapA", "addCapB"},
|
Add: []v1.Capability{"addCapA", "addCapB"},
|
||||||
Drop: []api.Capability{"dropCapA", "dropCapB"},
|
Drop: []v1.Capability{"dropCapA", "dropCapB"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func inputSELinuxOptions() *api.SELinuxOptions {
|
func inputSELinuxOptions() *v1.SELinuxOptions {
|
||||||
return &api.SELinuxOptions{
|
return &v1.SELinuxOptions{
|
||||||
User: "user",
|
User: "user",
|
||||||
Role: "role",
|
Role: "role",
|
||||||
Type: "type",
|
Type: "type",
|
||||||
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||||||
package securitycontext
|
package securitycontext
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
|
||||||
dockercontainer "github.com/docker/engine-api/types/container"
|
dockercontainer "github.com/docker/engine-api/types/container"
|
||||||
)
|
)
|
||||||
@ -26,7 +26,7 @@ type SecurityContextProvider interface {
|
|||||||
// ModifyContainerConfig is called before the Docker createContainer call.
|
// ModifyContainerConfig is called before the Docker createContainer call.
|
||||||
// The security context provider can make changes to the Config with which
|
// The security context provider can make changes to the Config with which
|
||||||
// the container is created.
|
// 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.
|
// ModifyHostConfig is called before the Docker createContainer call.
|
||||||
// The security context provider can make changes to the HostConfig, affecting
|
// 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
|
// - pod: the pod to modify the docker hostconfig for
|
||||||
// - container: the container to modify the hostconfig for
|
// - container: the container to modify the hostconfig for
|
||||||
// - supplementalGids: additional supplemental GIDs associated with the pod's volumes
|
// - 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 (
|
const (
|
||||||
|
@ -20,12 +20,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HasPrivilegedRequest returns the value of SecurityContext.Privileged, taking into account
|
// HasPrivilegedRequest returns the value of SecurityContext.Privileged, taking into account
|
||||||
// the possibility of nils
|
// the possibility of nils
|
||||||
func HasPrivilegedRequest(container *api.Container) bool {
|
func HasPrivilegedRequest(container *v1.Container) bool {
|
||||||
if container.SecurityContext == nil {
|
if container.SecurityContext == nil {
|
||||||
return false
|
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
|
// HasCapabilitiesRequest returns true if Adds or Drops are defined in the security context
|
||||||
// capabilities, taking into account nils
|
// capabilities, taking into account nils
|
||||||
func HasCapabilitiesRequest(container *api.Container) bool {
|
func HasCapabilitiesRequest(container *v1.Container) bool {
|
||||||
if container.SecurityContext == nil {
|
if container.SecurityContext == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -52,14 +52,14 @@ const expectedSELinuxFields = 4
|
|||||||
// ParseSELinuxOptions parses a string containing a full SELinux context
|
// ParseSELinuxOptions parses a string containing a full SELinux context
|
||||||
// (user, role, type, and level) into an SELinuxOptions object. If the
|
// (user, role, type, and level) into an SELinuxOptions object. If the
|
||||||
// context is malformed, an error is returned.
|
// 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)
|
fields := strings.SplitN(context, ":", expectedSELinuxFields)
|
||||||
|
|
||||||
if len(fields) != expectedSELinuxFields {
|
if len(fields) != expectedSELinuxFields {
|
||||||
return nil, fmt.Errorf("expected %v fields in selinux; got %v (context: %v)", expectedSELinuxFields, len(fields), context)
|
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],
|
User: fields[0],
|
||||||
Role: fields[1],
|
Role: fields[1],
|
||||||
Type: fields[2],
|
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.
|
// 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 {
|
if container.SecurityContext == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -79,11 +79,11 @@ func HasRootUID(container *api.Container) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasRunAsUser determines if the sc's runAsUser field is set.
|
// 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
|
return container.SecurityContext != nil && container.SecurityContext.RunAsUser != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasRootRunAsUser returns true if the run as user is set and it is set to 0.
|
// 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)
|
return HasRunAsUser(container) && HasRootUID(container)
|
||||||
}
|
}
|
||||||
|
@ -19,19 +19,19 @@ package securitycontext
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseSELinuxOptions(t *testing.T) {
|
func TestParseSELinuxOptions(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
input string
|
input string
|
||||||
expected *api.SELinuxOptions
|
expected *v1.SELinuxOptions
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "simple",
|
name: "simple",
|
||||||
input: "user_t:role_t:type_t:s0",
|
input: "user_t:role_t:type_t:s0",
|
||||||
expected: &api.SELinuxOptions{
|
expected: &v1.SELinuxOptions{
|
||||||
User: "user_t",
|
User: "user_t",
|
||||||
Role: "role_t",
|
Role: "role_t",
|
||||||
Type: "type_t",
|
Type: "type_t",
|
||||||
@ -41,7 +41,7 @@ func TestParseSELinuxOptions(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "simple + categories",
|
name: "simple + categories",
|
||||||
input: "user_t:role_t:type_t:s0:c0",
|
input: "user_t:role_t:type_t:s0:c0",
|
||||||
expected: &api.SELinuxOptions{
|
expected: &v1.SELinuxOptions{
|
||||||
User: "user_t",
|
User: "user_t",
|
||||||
Role: "role_t",
|
Role: "role_t",
|
||||||
Type: "type_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 {
|
if e, a := ex.User, ac.User; e != a {
|
||||||
t.Errorf("%v: expected user: %v, got: %v", name, 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 {
|
func containerWithUser(ptr *int64) *v1.Container {
|
||||||
return &api.Container{SecurityContext: &api.SecurityContext{RunAsUser: ptr}}
|
return &v1.Container{SecurityContext: &v1.SecurityContext{RunAsUser: ptr}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHaRootUID(t *testing.T) {
|
func TestHaRootUID(t *testing.T) {
|
||||||
@ -93,11 +93,11 @@ func TestHaRootUID(t *testing.T) {
|
|||||||
var root int64 = 0
|
var root int64 = 0
|
||||||
|
|
||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
container *api.Container
|
container *v1.Container
|
||||||
expect bool
|
expect bool
|
||||||
}{
|
}{
|
||||||
"nil sc": {
|
"nil sc": {
|
||||||
container: &api.Container{SecurityContext: nil},
|
container: &v1.Container{SecurityContext: nil},
|
||||||
},
|
},
|
||||||
"nil runAsuser": {
|
"nil runAsuser": {
|
||||||
container: containerWithUser(nil),
|
container: containerWithUser(nil),
|
||||||
@ -123,11 +123,11 @@ func TestHasRunAsUser(t *testing.T) {
|
|||||||
var runAsUser int64 = 0
|
var runAsUser int64 = 0
|
||||||
|
|
||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
container *api.Container
|
container *v1.Container
|
||||||
expect bool
|
expect bool
|
||||||
}{
|
}{
|
||||||
"nil sc": {
|
"nil sc": {
|
||||||
container: &api.Container{SecurityContext: nil},
|
container: &v1.Container{SecurityContext: nil},
|
||||||
},
|
},
|
||||||
"nil runAsUser": {
|
"nil runAsUser": {
|
||||||
container: containerWithUser(nil),
|
container: containerWithUser(nil),
|
||||||
@ -151,11 +151,11 @@ func TestHasRootRunAsUser(t *testing.T) {
|
|||||||
var root int64 = 0
|
var root int64 = 0
|
||||||
|
|
||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
container *api.Container
|
container *v1.Container
|
||||||
expect bool
|
expect bool
|
||||||
}{
|
}{
|
||||||
"nil sc": {
|
"nil sc": {
|
||||||
container: &api.Container{SecurityContext: nil},
|
container: &v1.Container{SecurityContext: nil},
|
||||||
},
|
},
|
||||||
"nil runAsuser": {
|
"nil runAsuser": {
|
||||||
container: containerWithUser(nil),
|
container: containerWithUser(nil),
|
||||||
|
@ -26,7 +26,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/auth/authenticator"
|
"k8s.io/kubernetes/pkg/auth/authenticator"
|
||||||
"k8s.io/kubernetes/pkg/auth/user"
|
"k8s.io/kubernetes/pkg/auth/user"
|
||||||
|
|
||||||
@ -47,14 +47,14 @@ const (
|
|||||||
|
|
||||||
// ServiceAccountTokenGetter defines functions to retrieve a named service account and secret
|
// ServiceAccountTokenGetter defines functions to retrieve a named service account and secret
|
||||||
type ServiceAccountTokenGetter interface {
|
type ServiceAccountTokenGetter interface {
|
||||||
GetServiceAccount(namespace, name string) (*api.ServiceAccount, error)
|
GetServiceAccount(namespace, name string) (*v1.ServiceAccount, error)
|
||||||
GetSecret(namespace, name string) (*api.Secret, error)
|
GetSecret(namespace, name string) (*v1.Secret, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type TokenGenerator interface {
|
type TokenGenerator interface {
|
||||||
// GenerateToken generates a token which will identify the given ServiceAccount.
|
// GenerateToken generates a token which will identify the given ServiceAccount.
|
||||||
// The returned token will be stored in the given (and yet-unpersisted) Secret.
|
// 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
|
// ReadPrivateKey is a helper function for reading a private key from a PEM-encoded file
|
||||||
@ -148,7 +148,7 @@ type jwtTokenGenerator struct {
|
|||||||
privateKey interface{}
|
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
|
var method jwt.SigningMethod
|
||||||
switch privateKey := j.privateKey.(type) {
|
switch privateKey := j.privateKey.(type) {
|
||||||
case *rsa.PrivateKey:
|
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)
|
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")
|
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)
|
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")
|
return nil, false, errors.New("Token does not match server's copy")
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,9 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/fake"
|
||||||
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
|
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
|
||||||
"k8s.io/kubernetes/pkg/serviceaccount"
|
"k8s.io/kubernetes/pkg/serviceaccount"
|
||||||
)
|
)
|
||||||
@ -164,21 +164,21 @@ func TestTokenGenerateAndValidate(t *testing.T) {
|
|||||||
expectedUserUID := "12345"
|
expectedUserUID := "12345"
|
||||||
|
|
||||||
// Related API objects
|
// Related API objects
|
||||||
serviceAccount := &api.ServiceAccount{
|
serviceAccount := &v1.ServiceAccount{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Name: "my-service-account",
|
Name: "my-service-account",
|
||||||
UID: "12345",
|
UID: "12345",
|
||||||
Namespace: "test",
|
Namespace: "test",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
rsaSecret := &api.Secret{
|
rsaSecret := &v1.Secret{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Name: "my-rsa-secret",
|
Name: "my-rsa-secret",
|
||||||
Namespace: "test",
|
Namespace: "test",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ecdsaSecret := &api.Secret{
|
ecdsaSecret := &v1.Secret{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Name: "my-ecdsa-secret",
|
Name: "my-ecdsa-secret",
|
||||||
Namespace: "test",
|
Namespace: "test",
|
||||||
},
|
},
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/api/validation"
|
"k8s.io/kubernetes/pkg/api/validation"
|
||||||
"k8s.io/kubernetes/pkg/auth/user"
|
"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
|
// 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 {
|
if secret.Type != api.SecretTypeServiceAccountToken {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
"k8s.io/kubernetes/pkg/api/meta"
|
"k8s.io/kubernetes/pkg/api/meta"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/cache"
|
"k8s.io/kubernetes/pkg/client/cache"
|
||||||
"k8s.io/kubernetes/pkg/conversion"
|
"k8s.io/kubernetes/pkg/conversion"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
@ -631,7 +632,7 @@ func newCacherListerWatcher(storage Interface, resourcePrefix string, newListFun
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Implements cache.ListerWatcher interface.
|
// 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()
|
list := lw.newListFunc()
|
||||||
if err := lw.storage.List(context.TODO(), lw.resourcePrefix, "", Everything, list); err != nil {
|
if err := lw.storage.List(context.TODO(), lw.resourcePrefix, "", Everything, list); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -640,7 +641,7 @@ func (lw *cacherListerWatcher) List(options api.ListOptions) (runtime.Object, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Implements cache.ListerWatcher interface.
|
// 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)
|
return lw.storage.WatchList(context.TODO(), lw.resourcePrefix, options.ResourceVersion, Everything)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,13 +24,14 @@ package testing
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
time "time"
|
||||||
|
|
||||||
codec1978 "github.com/ugorji/go/codec"
|
codec1978 "github.com/ugorji/go/codec"
|
||||||
pkg2_api "k8s.io/kubernetes/pkg/api"
|
pkg2_api "k8s.io/kubernetes/pkg/api"
|
||||||
pkg1_unversioned "k8s.io/kubernetes/pkg/api/unversioned"
|
pkg1_unversioned "k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
pkg3_types "k8s.io/kubernetes/pkg/types"
|
pkg3_types "k8s.io/kubernetes/pkg/types"
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
time "time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/cache"
|
"k8s.io/kubernetes/pkg/client/cache"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/util/clock"
|
"k8s.io/kubernetes/pkg/util/clock"
|
||||||
@ -312,14 +313,14 @@ func TestWaitUntilFreshAndListTimeout(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type testLW struct {
|
type testLW struct {
|
||||||
ListFunc func(options api.ListOptions) (runtime.Object, error)
|
ListFunc func(options v1.ListOptions) (runtime.Object, error)
|
||||||
WatchFunc func(options api.ListOptions) (watch.Interface, 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)
|
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)
|
return t.WatchFunc(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,12 +338,12 @@ func TestReflectorForWatchCache(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lw := &testLW{
|
lw := &testLW{
|
||||||
WatchFunc: func(options api.ListOptions) (watch.Interface, error) {
|
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||||
fw := watch.NewFake()
|
fw := watch.NewFake()
|
||||||
go fw.Stop()
|
go fw.Stop()
|
||||||
return fw, nil
|
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
|
return &api.PodList{ListMeta: unversioned.ListMeta{ResourceVersion: "10"}}, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user