Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
4f3d0e3b
Commit
4f3d0e3b
authored
Nov 18, 2016
by
Chao Xu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
more dependencies packages:
pkg/metrics pkg/credentialprovider pkg/security pkg/securitycontext pkg/serviceaccount pkg/storage pkg/fieldpath
parent
f8b36bdd
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
352 additions
and
176 deletions
+352
-176
keyring.go
pkg/credentialprovider/keyring.go
+4
-4
fieldpath.go
pkg/fieldpath/fieldpath.go
+36
-9
fieldpath_test.go
pkg/fieldpath/fieldpath_test.go
+34
-34
metrics_grabber.go
pkg/metrics/metrics_grabber.go
+6
-5
helpers.go
pkg/security/apparmor/helpers.go
+13
-4
validate.go
pkg/security/apparmor/validate.go
+3
-3
validate_test.go
pkg/security/apparmor/validate_test.go
+11
-11
strategy.go
pkg/security/podsecuritypolicy/apparmor/strategy.go
+1
-1
provider_test.go
pkg/security/podsecuritypolicy/provider_test.go
+34
-4
fake.go
pkg/securitycontext/fake.go
+16
-5
provider.go
pkg/securitycontext/provider.go
+80
-7
provider_test.go
pkg/securitycontext/provider_test.go
+38
-38
types.go
pkg/securitycontext/types.go
+3
-3
util.go
pkg/securitycontext/util.go
+8
-8
util_test.go
pkg/securitycontext/util_test.go
+13
-13
jwt.go
pkg/serviceaccount/jwt.go
+6
-6
jwt_test.go
pkg/serviceaccount/jwt_test.go
+9
-9
util.go
pkg/serviceaccount/util.go
+23
-1
cacher.go
pkg/storage/cacher.go
+3
-2
types.generated.go
pkg/storage/testing/types.generated.go
+4
-3
watch_cache_test.go
pkg/storage/watch_cache_test.go
+7
-6
No files found.
pkg/credentialprovider/keyring.go
View file @
4f3d0e3b
...
...
@@ -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
...
...
pkg/fieldpath/fieldpath.go
View file @
4f3d0e3b
...
...
@@ -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
()
...
...
pkg/fieldpath/fieldpath_test.go
View file @
4f3d0e3b
...
...
@@ -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"
,
...
...
pkg/metrics/metrics_grabber.go
View file @
4f3d0e3b
...
...
@@ -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
(
&
nod
e
)
{
if
system
.
IsMasterNode
(
node
.
Nam
e
)
{
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
{
...
...
pkg/security/apparmor/helpers.go
View file @
4f3d0e3b
...
...
@@ -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
}
pkg/security/apparmor/validate.go
View file @
4f3d0e3b
...
...
@@ -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
}
...
...
pkg/security/apparmor/validate_test.go
View file @
4f3d0e3b
...
...
@@ -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"
,
},
...
...
pkg/security/podsecuritypolicy/apparmor/strategy.go
View file @
4f3d0e3b
...
...
@@ -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
.
GetProfileName
FromPodAnnotations
(
pod
.
Annotations
,
container
.
Name
)
if
profile
==
""
{
if
len
(
s
.
allowedProfiles
)
>
0
{
allErrs
=
append
(
allErrs
,
field
.
Forbidden
(
fieldPath
,
"AppArmor profile must be set"
))
...
...
pkg/security/podsecuritypolicy/provider_test.go
View file @
4f3d0e3b
...
...
@@ -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
:
&
notPriv
,
// 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.
...
...
pkg/securitycontext/fake.go
View file @
4f3d0e3b
...
...
@@ -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
*
v1
.
Pod
,
container
*
v1
.
Container
,
hostConfig
*
dockercontainer
.
HostConfig
,
supplementalGids
[]
int64
)
{
}
func
(
p
FakeSecurityContextProvider
)
ModifyHostConfig
(
pod
*
api
.
Pod
,
container
*
api
.
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
,
}
}
pkg/securitycontext/provider.go
View file @
4f3d0e3b
...
...
@@ -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
...
...
@@ -144,6 +145,78 @@ func DetermineEffectiveSecurityContext(pod *api.Pod, container *api.Container) *
}
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
s
ecurityContextFromPodSecurityContext
(
pod
*
api
.
Pod
)
*
api
.
SecurityContext
{
func
internalS
ecurityContextFromPodSecurityContext
(
pod
*
api
.
Pod
)
*
api
.
SecurityContext
{
if
pod
.
Spec
.
SecurityContext
==
nil
{
return
nil
}
...
...
pkg/securitycontext/provider_test.go
View file @
4f3d0e3b
...
...
@@ -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
.
V1
DeepEqualSafePodSpec
(),
}
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"
,
...
...
pkg/securitycontext/types.go
View file @
4f3d0e3b
...
...
@@ -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
(
...
...
pkg/securitycontext/util.go
View file @
4f3d0e3b
...
...
@@ -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
)
}
pkg/securitycontext/util_test.go
View file @
4f3d0e3b
...
...
@@ -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
),
...
...
pkg/serviceaccount/jwt.go
View file @
4f3d0e3b
...
...
@@ -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"
)
}
...
...
pkg/serviceaccount/jwt_test.go
View file @
4f3d0e3b
...
...
@@ -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"
,
},
...
...
pkg/serviceaccount/util.go
View file @
4f3d0e3b
...
...
@@ -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
}
...
...
pkg/storage/cacher.go
View file @
4f3d0e3b
...
...
@@ -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
)
}
...
...
pkg/storage/testing/types.generated.go
View file @
4f3d0e3b
...
...
@@ -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
(
...
...
pkg/storage/watch_cache_test.go
View file @
4f3d0e3b
...
...
@@ -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
},
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment