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
2643c6ae
Commit
2643c6ae
authored
Nov 08, 2017
by
Joe Betz
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix admission metrics to track mutating/validating correctly
Also update admission test mocks to better reflect typical usage and fix broken tests.
parent
9d13d1ba
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
285 additions
and
282 deletions
+285
-282
admission_test.go
...n/pkg/admission/namespace/autoprovision/admission_test.go
+0
-1
admission_test.go
...in/pkg/admission/persistentvolume/label/admission_test.go
+9
-7
BUILD
staging/src/k8s.io/apiserver/pkg/admission/BUILD
+1
-2
chain.go
staging/src/k8s.io/apiserver/pkg/admission/chain.go
+26
-17
chain_test.go
staging/src/k8s.io/apiserver/pkg/admission/chain_test.go
+74
-71
metrics.go
staging/src/k8s.io/apiserver/pkg/admission/metrics.go
+41
-75
metrics_test.go
staging/src/k8s.io/apiserver/pkg/admission/metrics_test.go
+37
-31
plugins.go
staging/src/k8s.io/apiserver/pkg/admission/plugins.go
+7
-3
testutil_test.go
staging/src/k8s.io/apiserver/pkg/admission/testutil_test.go
+90
-75
No files found.
plugin/pkg/admission/namespace/autoprovision/admission_test.go
View file @
2643c6ae
...
@@ -129,7 +129,6 @@ func TestAdmissionNamespaceExists(t *testing.T) {
...
@@ -129,7 +129,6 @@ func TestAdmissionNamespaceExists(t *testing.T) {
// TestIgnoreAdmission validates that a request is ignored if its not a create
// TestIgnoreAdmission validates that a request is ignored if its not a create
func
TestIgnoreAdmission
(
t
*
testing
.
T
)
{
func
TestIgnoreAdmission
(
t
*
testing
.
T
)
{
namespace
:=
"test"
mockClient
:=
newMockClientForTest
([]
string
{})
mockClient
:=
newMockClientForTest
([]
string
{})
handler
,
informerFactory
,
err
:=
newHandlerForTest
(
mockClient
)
handler
,
informerFactory
,
err
:=
newHandlerForTest
(
mockClient
)
if
err
!=
nil
{
if
err
!=
nil
{
...
...
plugin/pkg/admission/persistentvolume/label/admission_test.go
View file @
2643c6ae
...
@@ -77,7 +77,8 @@ func mockVolumeLabels(labels map[string]string) *mockVolumes {
...
@@ -77,7 +77,8 @@ func mockVolumeLabels(labels map[string]string) *mockVolumes {
// TestAdmission
// TestAdmission
func
TestAdmission
(
t
*
testing
.
T
)
{
func
TestAdmission
(
t
*
testing
.
T
)
{
handler
:=
NewPersistentVolumeLabel
()
pvHandler
:=
NewPersistentVolumeLabel
()
handler
:=
admission
.
NewChainHandler
(
admission
.
NewNamedHandler
(
"pv"
,
pvHandler
))
ignoredPV
:=
api
.
PersistentVolume
{
ignoredPV
:=
api
.
PersistentVolume
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"noncloud"
,
Namespace
:
"myns"
},
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"noncloud"
,
Namespace
:
"myns"
},
Spec
:
api
.
PersistentVolumeSpec
{
Spec
:
api
.
PersistentVolumeSpec
{
...
@@ -100,8 +101,9 @@ func TestAdmission(t *testing.T) {
...
@@ -100,8 +101,9 @@ func TestAdmission(t *testing.T) {
}
}
// Non-cloud PVs are ignored
// Non-cloud PVs are ignored
if
handler
.
Handles
(
admission
.
Delete
)
{
err
:=
handler
.
Admit
(
admission
.
NewAttributesRecord
(
&
ignoredPV
,
nil
,
api
.
Kind
(
"PersistentVolume"
)
.
WithVersion
(
"version"
),
ignoredPV
.
Namespace
,
ignoredPV
.
Name
,
api
.
Resource
(
"persistentvolumes"
)
.
WithVersion
(
"version"
),
""
,
admission
.
Create
,
nil
))
t
.
Errorf
(
"Expected to only handle create"
)
if
err
!=
nil
{
t
.
Errorf
(
"Unexpected error returned from admission handler (on ignored pv): %v"
,
err
)
}
}
// We only add labels on creation
// We only add labels on creation
...
@@ -111,7 +113,7 @@ func TestAdmission(t *testing.T) {
...
@@ -111,7 +113,7 @@ func TestAdmission(t *testing.T) {
}
}
// Errors from the cloudprovider block creation of the volume
// Errors from the cloudprovider block creation of the volume
h
andler
.
ebsVolumes
=
mockVolumeFailure
(
fmt
.
Errorf
(
"invalid volume"
))
pvH
andler
.
ebsVolumes
=
mockVolumeFailure
(
fmt
.
Errorf
(
"invalid volume"
))
err
=
handler
.
Admit
(
admission
.
NewAttributesRecord
(
&
awsPV
,
nil
,
api
.
Kind
(
"PersistentVolume"
)
.
WithVersion
(
"version"
),
awsPV
.
Namespace
,
awsPV
.
Name
,
api
.
Resource
(
"persistentvolumes"
)
.
WithVersion
(
"version"
),
""
,
admission
.
Create
,
nil
))
err
=
handler
.
Admit
(
admission
.
NewAttributesRecord
(
&
awsPV
,
nil
,
api
.
Kind
(
"PersistentVolume"
)
.
WithVersion
(
"version"
),
awsPV
.
Namespace
,
awsPV
.
Name
,
api
.
Resource
(
"persistentvolumes"
)
.
WithVersion
(
"version"
),
""
,
admission
.
Create
,
nil
))
if
err
==
nil
{
if
err
==
nil
{
t
.
Errorf
(
"Expected error when aws pv info fails"
)
t
.
Errorf
(
"Expected error when aws pv info fails"
)
...
@@ -119,7 +121,7 @@ func TestAdmission(t *testing.T) {
...
@@ -119,7 +121,7 @@ func TestAdmission(t *testing.T) {
// Don't add labels if the cloudprovider doesn't return any
// Don't add labels if the cloudprovider doesn't return any
labels
:=
make
(
map
[
string
]
string
)
labels
:=
make
(
map
[
string
]
string
)
h
andler
.
ebsVolumes
=
mockVolumeLabels
(
labels
)
pvH
andler
.
ebsVolumes
=
mockVolumeLabels
(
labels
)
err
=
handler
.
Admit
(
admission
.
NewAttributesRecord
(
&
awsPV
,
nil
,
api
.
Kind
(
"PersistentVolume"
)
.
WithVersion
(
"version"
),
awsPV
.
Namespace
,
awsPV
.
Name
,
api
.
Resource
(
"persistentvolumes"
)
.
WithVersion
(
"version"
),
""
,
admission
.
Create
,
nil
))
err
=
handler
.
Admit
(
admission
.
NewAttributesRecord
(
&
awsPV
,
nil
,
api
.
Kind
(
"PersistentVolume"
)
.
WithVersion
(
"version"
),
awsPV
.
Namespace
,
awsPV
.
Name
,
api
.
Resource
(
"persistentvolumes"
)
.
WithVersion
(
"version"
),
""
,
admission
.
Create
,
nil
))
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Errorf
(
"Expected no error when creating aws pv"
)
t
.
Errorf
(
"Expected no error when creating aws pv"
)
...
@@ -129,7 +131,7 @@ func TestAdmission(t *testing.T) {
...
@@ -129,7 +131,7 @@ func TestAdmission(t *testing.T) {
}
}
// Don't panic if the cloudprovider returns nil, nil
// Don't panic if the cloudprovider returns nil, nil
h
andler
.
ebsVolumes
=
mockVolumeFailure
(
nil
)
pvH
andler
.
ebsVolumes
=
mockVolumeFailure
(
nil
)
err
=
handler
.
Admit
(
admission
.
NewAttributesRecord
(
&
awsPV
,
nil
,
api
.
Kind
(
"PersistentVolume"
)
.
WithVersion
(
"version"
),
awsPV
.
Namespace
,
awsPV
.
Name
,
api
.
Resource
(
"persistentvolumes"
)
.
WithVersion
(
"version"
),
""
,
admission
.
Create
,
nil
))
err
=
handler
.
Admit
(
admission
.
NewAttributesRecord
(
&
awsPV
,
nil
,
api
.
Kind
(
"PersistentVolume"
)
.
WithVersion
(
"version"
),
awsPV
.
Namespace
,
awsPV
.
Name
,
api
.
Resource
(
"persistentvolumes"
)
.
WithVersion
(
"version"
),
""
,
admission
.
Create
,
nil
))
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Errorf
(
"Expected no error when cloud provider returns empty labels"
)
t
.
Errorf
(
"Expected no error when cloud provider returns empty labels"
)
...
@@ -139,7 +141,7 @@ func TestAdmission(t *testing.T) {
...
@@ -139,7 +141,7 @@ func TestAdmission(t *testing.T) {
labels
=
make
(
map
[
string
]
string
)
labels
=
make
(
map
[
string
]
string
)
labels
[
"a"
]
=
"1"
labels
[
"a"
]
=
"1"
labels
[
"b"
]
=
"2"
labels
[
"b"
]
=
"2"
h
andler
.
ebsVolumes
=
mockVolumeLabels
(
labels
)
pvH
andler
.
ebsVolumes
=
mockVolumeLabels
(
labels
)
err
=
handler
.
Admit
(
admission
.
NewAttributesRecord
(
&
awsPV
,
nil
,
api
.
Kind
(
"PersistentVolume"
)
.
WithVersion
(
"version"
),
awsPV
.
Namespace
,
awsPV
.
Name
,
api
.
Resource
(
"persistentvolumes"
)
.
WithVersion
(
"version"
),
""
,
admission
.
Create
,
nil
))
err
=
handler
.
Admit
(
admission
.
NewAttributesRecord
(
&
awsPV
,
nil
,
api
.
Kind
(
"PersistentVolume"
)
.
WithVersion
(
"version"
),
awsPV
.
Namespace
,
awsPV
.
Name
,
api
.
Resource
(
"persistentvolumes"
)
.
WithVersion
(
"version"
),
""
,
admission
.
Create
,
nil
))
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Errorf
(
"Expected no error when creating aws pv"
)
t
.
Errorf
(
"Expected no error when creating aws pv"
)
...
...
staging/src/k8s.io/apiserver/pkg/admission/BUILD
View file @
2643c6ae
...
@@ -21,9 +21,8 @@ go_test(
...
@@ -21,9 +21,8 @@ go_test(
deps = [
deps = [
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
"//vendor/github.com/prometheus/client_model/go:go_default_library",
"//vendor/github.com/prometheus/client_model/go:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/github.com/stretchr/testify/require:go_default_library",
"//vendor/k8s.io/api/admissionregistration/v1alpha1:go_default_library",
"//vendor/k8s.io/api/admissionregistration/v1alpha1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/apiserver:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/apiserver:go_default_library",
...
...
staging/src/k8s.io/apiserver/pkg/admission/chain.go
View file @
2643c6ae
...
@@ -27,6 +27,13 @@ func NewChainHandler(handlers ...NamedHandler) chainAdmissionHandler {
...
@@ -27,6 +27,13 @@ func NewChainHandler(handlers ...NamedHandler) chainAdmissionHandler {
return
chainAdmissionHandler
(
handlers
)
return
chainAdmissionHandler
(
handlers
)
}
}
func
NewNamedHandler
(
name
string
,
i
Interface
)
NamedHandler
{
return
&
pluginHandler
{
i
:
i
,
name
:
name
,
}
}
const
(
const
(
stepValidating
=
"validating"
stepValidating
=
"validating"
stepMutating
=
"mutating"
stepMutating
=
"mutating"
...
@@ -34,20 +41,21 @@ const (
...
@@ -34,20 +41,21 @@ const (
// Admit performs an admission control check using a chain of handlers, and returns immediately on first error
// Admit performs an admission control check using a chain of handlers, and returns immediately on first error
func
(
admissionHandler
chainAdmissionHandler
)
Admit
(
a
Attributes
)
error
{
func
(
admissionHandler
chainAdmissionHandler
)
Admit
(
a
Attributes
)
error
{
var
err
error
start
:=
time
.
Now
()
start
:=
time
.
Now
()
defer
func
()
{
err
:=
admissionHandler
.
admit
(
a
)
Metrics
.
ObserveAdmissionStep
(
time
.
Since
(
start
),
err
!=
nil
,
a
,
stepMutating
)
Metrics
.
ObserveAdmissionStep
(
time
.
Since
(
start
),
err
!=
nil
,
a
,
stepMutating
)
}()
return
err
}
func
(
admissionHandler
chainAdmissionHandler
)
admit
(
a
Attributes
)
error
{
for
_
,
handler
:=
range
admissionHandler
{
for
_
,
handler
:=
range
admissionHandler
{
if
!
handler
.
Handles
(
a
.
GetOperation
())
{
if
!
handler
.
Interface
()
.
Handles
(
a
.
GetOperation
())
{
continue
continue
}
}
if
mutator
,
ok
:=
handler
.
(
MutationInterface
);
ok
{
if
mutator
,
ok
:=
handler
.
Interface
()
.
(
MutationInterface
);
ok
{
t
:=
time
.
Now
()
t
:=
time
.
Now
()
err
=
mutator
.
Admit
(
a
)
err
:
=
mutator
.
Admit
(
a
)
Metrics
.
ObserveAdmissionController
(
time
.
Since
(
t
),
err
!=
nil
,
handler
,
a
)
Metrics
.
ObserveAdmissionController
(
time
.
Since
(
t
),
err
!=
nil
,
handler
,
a
,
stepMutating
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
@@ -58,20 +66,21 @@ func (admissionHandler chainAdmissionHandler) Admit(a Attributes) error {
...
@@ -58,20 +66,21 @@ func (admissionHandler chainAdmissionHandler) Admit(a Attributes) error {
// Validate performs an admission control check using a chain of handlers, and returns immediately on first error
// Validate performs an admission control check using a chain of handlers, and returns immediately on first error
func
(
admissionHandler
chainAdmissionHandler
)
Validate
(
a
Attributes
)
error
{
func
(
admissionHandler
chainAdmissionHandler
)
Validate
(
a
Attributes
)
error
{
var
err
error
start
:=
time
.
Now
()
start
:=
time
.
Now
()
defer
func
()
{
err
:=
admissionHandler
.
validate
(
a
)
Metrics
.
ObserveAdmissionStep
(
time
.
Since
(
start
),
err
!=
nil
,
a
,
stepValidating
)
Metrics
.
ObserveAdmissionStep
(
time
.
Since
(
start
),
err
!=
nil
,
a
,
stepValidating
)
}()
return
err
}
func
(
admissionHandler
chainAdmissionHandler
)
validate
(
a
Attributes
)
(
err
error
)
{
for
_
,
handler
:=
range
admissionHandler
{
for
_
,
handler
:=
range
admissionHandler
{
if
!
handler
.
Handles
(
a
.
GetOperation
())
{
if
!
handler
.
Interface
()
.
Handles
(
a
.
GetOperation
())
{
continue
continue
}
}
if
validator
,
ok
:=
handler
.
(
ValidationInterface
);
ok
{
if
validator
,
ok
:=
handler
.
Interface
()
.
(
ValidationInterface
);
ok
{
t
:=
time
.
Now
()
t
:=
time
.
Now
()
err
=
validator
.
Validate
(
a
)
err
:
=
validator
.
Validate
(
a
)
Metrics
.
ObserveAdmissionController
(
time
.
Since
(
t
),
err
!=
nil
,
handler
,
a
)
Metrics
.
ObserveAdmissionController
(
time
.
Since
(
t
),
err
!=
nil
,
handler
,
a
,
stepValidating
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
@@ -83,7 +92,7 @@ func (admissionHandler chainAdmissionHandler) Validate(a Attributes) error {
...
@@ -83,7 +92,7 @@ func (admissionHandler chainAdmissionHandler) Validate(a Attributes) error {
// Handles will return true if any of the handlers handles the given operation
// Handles will return true if any of the handlers handles the given operation
func
(
admissionHandler
chainAdmissionHandler
)
Handles
(
operation
Operation
)
bool
{
func
(
admissionHandler
chainAdmissionHandler
)
Handles
(
operation
Operation
)
bool
{
for
_
,
handler
:=
range
admissionHandler
{
for
_
,
handler
:=
range
admissionHandler
{
if
handler
.
Handles
(
operation
)
{
if
handler
.
Interface
()
.
Handles
(
operation
)
{
return
true
return
true
}
}
}
}
...
...
staging/src/k8s.io/apiserver/pkg/admission/chain_test.go
View file @
2643c6ae
...
@@ -17,46 +17,15 @@ limitations under the License.
...
@@ -17,46 +17,15 @@ limitations under the License.
package
admission
package
admission
import
(
import
(
"
fmt
"
"
strconv
"
"testing"
"testing"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/schema"
)
)
type
FakeHandler
struct
{
*
Handler
name
string
admit
,
admitCalled
bool
validate
,
validateCalled
bool
}
func
(
h
*
FakeHandler
)
Admit
(
a
Attributes
)
(
err
error
)
{
h
.
admitCalled
=
true
if
h
.
admit
{
return
nil
}
return
fmt
.
Errorf
(
"Don't admit"
)
}
func
(
h
*
FakeHandler
)
Validate
(
a
Attributes
)
(
err
error
)
{
h
.
validateCalled
=
true
if
h
.
validate
{
return
nil
}
return
fmt
.
Errorf
(
"Don't validate"
)
}
func
makeHandler
(
name
string
,
accept
bool
,
ops
...
Operation
)
Interface
{
return
&
FakeHandler
{
name
:
name
,
admit
:
accept
,
validate
:
accept
,
Handler
:
NewHandler
(
ops
...
),
}
}
func
TestAdmitAndValidate
(
t
*
testing
.
T
)
{
func
TestAdmitAndValidate
(
t
*
testing
.
T
)
{
sysns
:=
"kube-system"
sysns
:=
metav1
.
NamespaceSystem
otherns
:=
"default"
otherns
:=
"default"
tests
:=
[]
struct
{
tests
:=
[]
struct
{
name
string
name
string
...
@@ -64,7 +33,6 @@ func TestAdmitAndValidate(t *testing.T) {
...
@@ -64,7 +33,6 @@ func TestAdmitAndValidate(t *testing.T) {
operation
Operation
operation
Operation
chain
chainAdmissionHandler
chain
chainAdmissionHandler
accept
bool
accept
bool
reject
bool
calls
map
[
string
]
bool
calls
map
[
string
]
bool
}{
}{
{
{
...
@@ -72,9 +40,9 @@ func TestAdmitAndValidate(t *testing.T) {
...
@@ -72,9 +40,9 @@ func TestAdmitAndValidate(t *testing.T) {
ns
:
sysns
,
ns
:
sysns
,
operation
:
Create
,
operation
:
Create
,
chain
:
[]
NamedHandler
{
chain
:
[]
NamedHandler
{
makeHandler
(
"a"
,
true
,
Update
,
Delete
,
Create
),
make
Named
Handler
(
"a"
,
true
,
Update
,
Delete
,
Create
),
makeHandler
(
"b"
,
true
,
Delete
,
Create
),
make
Named
Handler
(
"b"
,
true
,
Delete
,
Create
),
makeHandler
(
"c"
,
true
,
Create
),
make
Named
Handler
(
"c"
,
true
,
Create
),
},
},
calls
:
map
[
string
]
bool
{
"a"
:
true
,
"b"
:
true
,
"c"
:
true
},
calls
:
map
[
string
]
bool
{
"a"
:
true
,
"b"
:
true
,
"c"
:
true
},
accept
:
true
,
accept
:
true
,
...
@@ -84,9 +52,9 @@ func TestAdmitAndValidate(t *testing.T) {
...
@@ -84,9 +52,9 @@ func TestAdmitAndValidate(t *testing.T) {
ns
:
otherns
,
ns
:
otherns
,
operation
:
Create
,
operation
:
Create
,
chain
:
[]
NamedHandler
{
chain
:
[]
NamedHandler
{
makeHandler
(
"a"
,
true
,
Update
,
Delete
,
Create
),
make
Named
Handler
(
"a"
,
true
,
Update
,
Delete
,
Create
),
makeHandler
(
"b"
,
false
,
Delete
),
make
Named
Handler
(
"b"
,
false
,
Delete
),
makeHandler
(
"c"
,
true
,
Create
),
make
Named
Handler
(
"c"
,
true
,
Create
),
},
},
calls
:
map
[
string
]
bool
{
"a"
:
true
,
"c"
:
true
},
calls
:
map
[
string
]
bool
{
"a"
:
true
,
"c"
:
true
},
accept
:
true
,
accept
:
true
,
...
@@ -96,9 +64,9 @@ func TestAdmitAndValidate(t *testing.T) {
...
@@ -96,9 +64,9 @@ func TestAdmitAndValidate(t *testing.T) {
ns
:
sysns
,
ns
:
sysns
,
operation
:
Connect
,
operation
:
Connect
,
chain
:
[]
NamedHandler
{
chain
:
[]
NamedHandler
{
makeHandler
(
"a"
,
true
,
Update
,
Delete
,
Create
),
make
Named
Handler
(
"a"
,
true
,
Update
,
Delete
,
Create
),
makeHandler
(
"b"
,
false
,
Delete
),
make
Named
Handler
(
"b"
,
false
,
Delete
),
makeHandler
(
"c"
,
true
,
Create
),
make
Named
Handler
(
"c"
,
true
,
Create
),
},
},
calls
:
map
[
string
]
bool
{},
calls
:
map
[
string
]
bool
{},
accept
:
true
,
accept
:
true
,
...
@@ -108,77 +76,112 @@ func TestAdmitAndValidate(t *testing.T) {
...
@@ -108,77 +76,112 @@ func TestAdmitAndValidate(t *testing.T) {
ns
:
otherns
,
ns
:
otherns
,
operation
:
Delete
,
operation
:
Delete
,
chain
:
[]
NamedHandler
{
chain
:
[]
NamedHandler
{
makeHandler
(
"a"
,
true
,
Update
,
Delete
,
Create
),
make
Named
Handler
(
"a"
,
true
,
Update
,
Delete
,
Create
),
makeHandler
(
"b"
,
false
,
Delete
),
make
Named
Handler
(
"b"
,
false
,
Delete
),
makeHandler
(
"c"
,
true
,
Create
),
make
Named
Handler
(
"c"
,
true
,
Create
),
},
},
calls
:
map
[
string
]
bool
{
"a"
:
true
,
"b"
:
true
},
calls
:
map
[
string
]
bool
{
"a"
:
true
,
"b"
:
true
},
accept
:
false
,
accept
:
false
,
reject
:
true
,
},
},
}
}
for
_
,
test
:=
range
tests
{
for
_
,
test
:=
range
tests
{
Metrics
.
reset
()
Metrics
.
reset
()
t
.
Logf
(
"testcase = %s"
,
test
.
name
)
t
.
Logf
(
"testcase = %s"
,
test
.
name
)
// call admit and check that validate was not called at all
// call admit and check that validate was not called at all
err
=
test
.
chain
.
Admit
(
NewAttributesRecord
(
nil
,
nil
,
schema
.
GroupVersionKind
{},
""
,
""
,
schema
.
GroupVersionResource
{},
""
,
test
.
operation
,
nil
))
err
:=
test
.
chain
.
Admit
(
NewAttributesRecord
(
nil
,
nil
,
schema
.
GroupVersionKind
{},
test
.
ns
,
""
,
schema
.
GroupVersionResource
{},
""
,
test
.
operation
,
nil
))
accepted
:=
(
err
==
nil
)
accepted
:=
(
err
==
nil
)
if
accepted
!=
test
.
accept
{
if
accepted
!=
test
.
accept
{
t
.
Errorf
(
"unexpected result of admit call: %v"
,
accepted
)
t
.
Errorf
(
"unexpected result of admit call: %v"
,
accepted
)
}
}
for
_
,
h
:=
range
test
.
chain
{
for
_
,
h
:=
range
test
.
chain
{
fake
:=
h
.
(
*
FakeHandler
)
fake
:=
h
.
Interface
()
.
(
*
FakeHandler
)
_
,
shouldBeCalled
:=
test
.
calls
[
fake
.
name
]
_
,
shouldBeCalled
:=
test
.
calls
[
h
.
Name
()
]
if
shouldBeCalled
!=
fake
.
admitCalled
{
if
shouldBeCalled
!=
fake
.
admitCalled
{
t
.
Errorf
(
"
%s: admit handler %s not called as expected: %v"
,
test
.
name
,
fake
.
name
,
fake
.
admitCalled
)
t
.
Errorf
(
"
admit handler %s not called as expected: %v"
,
h
.
Name
()
,
fake
.
admitCalled
)
continue
continue
}
}
if
fake
.
validateCalled
{
if
fake
.
validateCalled
{
t
.
Errorf
(
"
%s: validate handler %s called during admit"
,
test
.
name
,
fake
.
name
)
t
.
Errorf
(
"
validate handler %s called during admit"
,
h
.
Name
()
)
}
}
// reset value for validation test
//
reset value for validation test
fake
.
admitCalled
=
false
fake
.
admitCalled
=
false
}
}
labelFilter
:=
map
[
string
]
string
{
"is_system_ns"
:
strconv
.
FormatBool
(
test
.
ns
==
sysns
),
"type"
:
"mutating"
,
}
checkAdmitAndValidateMetrics
(
t
,
labelFilter
,
test
.
accept
,
test
.
calls
)
Metrics
.
reset
()
// call validate and check that admit was not called at all
// call validate and check that admit was not called at all
err
=
test
.
chain
.
Validate
(
NewAttributesRecord
(
nil
,
nil
,
schema
.
GroupVersionKind
{},
""
,
""
,
schema
.
GroupVersionResource
{},
""
,
test
.
operation
,
nil
))
err
=
test
.
chain
.
Validate
(
NewAttributesRecord
(
nil
,
nil
,
schema
.
GroupVersionKind
{},
test
.
ns
,
""
,
schema
.
GroupVersionResource
{},
""
,
test
.
operation
,
nil
))
accepted
=
(
err
==
nil
)
accepted
=
(
err
==
nil
)
if
accepted
!=
test
.
accept
{
if
accepted
!=
test
.
accept
{
t
.
Errorf
(
"
%s: unexpected result of validate call: %v
\n
"
,
test
.
name
,
accepted
)
t
.
Errorf
(
"
unexpected result of validate call: %v
\n
"
,
accepted
)
}
}
for
_
,
h
:=
range
test
.
chain
{
for
_
,
h
:=
range
test
.
chain
{
fake
:=
h
.
(
*
FakeHandler
)
fake
:=
h
.
Interface
()
.
(
*
FakeHandler
)
_
,
shouldBeCalled
:=
test
.
calls
[
fake
.
name
]
_
,
shouldBeCalled
:=
test
.
calls
[
h
.
Name
()]
if
shouldBeCalled
!=
fake
.
validateCalled
{
if
shouldBeCalled
!=
fake
.
validateCalled
{
t
.
Errorf
(
"
%s: validate handler %s not called as expected: %v"
,
test
.
name
,
fake
.
name
,
fake
.
validateCalled
)
t
.
Errorf
(
"
validate handler %s not called as expected: %v"
,
h
.
Name
()
,
fake
.
validateCalled
)
continue
continue
}
}
if
fake
.
admitCalled
{
if
fake
.
admitCalled
{
t
.
Errorf
(
"
%s: admit handler %s called during admit"
,
test
.
name
,
fake
.
name
)
t
.
Errorf
(
"
mutating handler unexpectedly called: %s"
,
h
.
Name
()
)
}
}
}
}
labels
:=
metricLabels
{
labelFilter
=
map
[
string
]
string
{
isSystemNs
:
test
.
ns
==
sysns
,
"is_system_ns"
:
strconv
.
FormatBool
(
test
.
ns
==
sysns
),
}
"type"
:
"validating"
,
if
test
.
reject
{
expectCountMetric
(
t
,
"apiserver_admission_step_rejected_total"
,
labels
,
1
)
}
}
if
test
.
accept
{
checkAdmitAndValidateMetrics
(
t
,
labelFilter
,
test
.
accept
,
test
.
calls
)
expectCountMetric
(
t
,
"apiserver_admission_step_total"
,
labels
,
1
)
}
}
}
func
checkAdmitAndValidateMetrics
(
t
*
testing
.
T
,
labelFilter
map
[
string
]
string
,
accept
bool
,
calls
map
[
string
]
bool
)
{
acceptFilter
:=
map
[
string
]
string
{
"rejected"
:
"false"
}
for
k
,
v
:=
range
labelFilter
{
acceptFilter
[
k
]
=
v
}
rejectFilter
:=
map
[
string
]
string
{
"rejected"
:
"true"
}
for
k
,
v
:=
range
labelFilter
{
rejectFilter
[
k
]
=
v
}
if
accept
{
// Ensure exactly one admission end-to-end admission accept should have been recorded.
expectHistogramCountTotal
(
t
,
"apiserver_admission_step_latencies"
,
acceptFilter
,
1
)
// Ensure the expected count of admission controllers have been executed.
expectHistogramCountTotal
(
t
,
"apiserver_admission_controller_latencies"
,
acceptFilter
,
len
(
calls
))
}
else
{
// When not accepted, ensure exactly one end-to-end rejection has been recorded.
expectHistogramCountTotal
(
t
,
"apiserver_admission_step_latencies"
,
rejectFilter
,
1
)
if
len
(
calls
)
>
0
{
if
len
(
calls
)
>
1
{
// When not accepted, ensure that all but the last controller had been accepted, since
// the chain stops execution at the first rejection.
expectHistogramCountTotal
(
t
,
"apiserver_admission_controller_latencies"
,
acceptFilter
,
len
(
calls
)
-
1
)
}
// When not accepted, ensure exactly one controller has been rejected.
expectHistogramCountTotal
(
t
,
"apiserver_admission_controller_latencies"
,
rejectFilter
,
1
)
}
}
}
}
}
func
TestHandles
(
t
*
testing
.
T
)
{
func
TestHandles
(
t
*
testing
.
T
)
{
chain
:=
chainAdmissionHandler
{
chain
:=
chainAdmissionHandler
{
makeHandler
(
"a"
,
true
,
Update
,
Delete
,
Create
),
make
Named
Handler
(
"a"
,
true
,
Update
,
Delete
,
Create
),
makeHandler
(
"b"
,
true
,
Delete
,
Create
),
make
Named
Handler
(
"b"
,
true
,
Delete
,
Create
),
makeHandler
(
"c"
,
true
,
Create
),
make
Named
Handler
(
"c"
,
true
,
Create
),
}
}
tests
:=
[]
struct
{
tests
:=
[]
struct
{
...
...
staging/src/k8s.io/apiserver/pkg/admission/metrics.go
View file @
2643c6ae
...
@@ -34,33 +34,42 @@ const (
...
@@ -34,33 +34,42 @@ const (
)
)
var
(
var
(
latencyBuckets
=
prometheus
.
ExponentialBuckets
(
10000
,
2.0
,
8
)
latencyBuckets
=
prometheus
.
ExponentialBuckets
(
25000
,
2.0
,
7
)
latencySummaryMaxAge
=
5
*
time
.
Hour
latencySummaryMaxAge
=
5
*
time
.
Hour
// Metrics provides access to all admission metrics.
Metrics
=
newAdmissionMetrics
()
Metrics
=
newAdmissionMetrics
()
)
)
// NamedHandler requires each admission.Interface be named, primarly for metrics tracking purposes.
type
NamedHandler
interface
{
Interface
()
Interface
Name
()
string
}
// AdmissionMetrics instruments admission with prometheus metrics.
type
AdmissionMetrics
struct
{
type
AdmissionMetrics
struct
{
step
*
metricSet
step
*
metricSet
controller
*
metricSet
controller
*
metricSet
externalWebhook
*
metricSet
externalWebhook
*
metricSet
}
}
// newAdmissionMetrics create a new AdmissionMetrics, configured with default metric names.
func
newAdmissionMetrics
()
*
AdmissionMetrics
{
func
newAdmissionMetrics
()
*
AdmissionMetrics
{
// Admission metrics for a step of the admission flow. The entire admission flow is broken down into a series of steps
// Admission metrics for a step of the admission flow. The entire admission flow is broken down into a series of steps
// Each step is identified by a distinct type label value.
// Each step is identified by a distinct type label value.
step
:=
newMetricSet
(
"step
_
"
,
step
:=
newMetricSet
(
"step"
,
[]
string
{
"
operation"
,
"group"
,
"version"
,
"resource"
,
"subresource"
,
"type"
,
"is_system_ns
"
},
[]
string
{
"
type"
,
"operation"
,
"group"
,
"version"
,
"resource"
,
"subresource"
,
"is_system_ns"
,
"rejected
"
},
"Admission sub-step %s, broken out for each operation and API resource and step type (validating or mutating)."
)
"Admission sub-step %s, broken out for each operation and API resource and step type (validating or mutating)."
)
// Built-in admission controller metrics. Each admission controller is identified by name.
// Built-in admission controller metrics. Each admission controller is identified by name.
controller
:=
newMetricSet
(
"controller
_
"
,
controller
:=
newMetricSet
(
"controller"
,
[]
string
{
"name"
,
"type"
,
"operation"
,
"group"
,
"version"
,
"resource"
,
"subresource"
,
"is_system_ns"
},
[]
string
{
"name"
,
"type"
,
"operation"
,
"group"
,
"version"
,
"resource"
,
"subresource"
,
"is_system_ns"
,
"rejected"
},
"Admission controller %s, identified by name and broken out for each operation and API resource and type (validating or mutating)."
)
"Admission controller %s, identified by name and broken out for each operation and API resource and type (validating or mutating)."
)
// External admission webhook metrics. Each webhook is identified by name.
// External admission webhook metrics. Each webhook is identified by name.
externalWebhook
:=
newMetricSet
(
"external_webhook
_
"
,
externalWebhook
:=
newMetricSet
(
"external_webhook"
,
[]
string
{
"name"
,
"type"
,
"operation"
,
"group"
,
"version"
,
"resource"
,
"subresource"
,
"is_system_ns"
},
[]
string
{
"name"
,
"type"
,
"operation"
,
"group"
,
"version"
,
"resource"
,
"subresource"
,
"is_system_ns"
,
"rejected"
},
"External admission webhook %s, identified by name and broken out for each operation and API resource and type (validating or mutating)."
)
"External admission webhook %s, identified by name and broken out for each operation and API resource and type (validating or mutating)."
)
step
.
mustRegister
()
step
.
mustRegister
()
...
@@ -75,30 +84,23 @@ func (m *AdmissionMetrics) reset() {
...
@@ -75,30 +84,23 @@ func (m *AdmissionMetrics) reset() {
m
.
externalWebhook
.
reset
()
m
.
externalWebhook
.
reset
()
}
}
// namedHandler requires each admission.Interface be named, primarly for metrics tracking purposes.
type
NamedHandler
interface
{
Interface
GetName
()
string
}
// ObserveAdmissionStep records admission related metrics for a admission step, identified by step type.
// ObserveAdmissionStep records admission related metrics for a admission step, identified by step type.
func
(
m
*
AdmissionMetrics
)
ObserveAdmissionStep
(
elapsed
time
.
Duration
,
rejected
bool
,
attr
Attributes
,
stepType
string
)
{
func
(
m
*
AdmissionMetrics
)
ObserveAdmissionStep
(
elapsed
time
.
Duration
,
rejected
bool
,
attr
Attributes
,
stepType
string
)
{
gvr
:=
attr
.
GetResource
()
gvr
:=
attr
.
GetResource
()
m
.
step
.
observe
(
elapsed
,
rejected
,
string
(
attr
.
GetOperation
()),
gvr
.
Group
,
gvr
.
Version
,
gvr
.
Resource
,
attr
.
GetSubresource
(),
stepType
,
isSystemNsLabel
(
attr
))
m
.
step
.
observe
(
elapsed
,
stepType
,
string
(
attr
.
GetOperation
()),
gvr
.
Group
,
gvr
.
Version
,
gvr
.
Resource
,
attr
.
GetSubresource
(),
isSystemNsLabel
(
attr
),
strconv
.
FormatBool
(
rejected
))
}
}
// ObserveAdmissionController records admission related metrics for a built-in admission controller, identified by it's plugin handler name.
// ObserveAdmissionController records admission related metrics for a built-in admission controller, identified by it's plugin handler name.
func
(
m
*
AdmissionMetrics
)
ObserveAdmissionController
(
elapsed
time
.
Duration
,
rejected
bool
,
handler
NamedHandler
,
attr
Attributes
)
{
func
(
m
*
AdmissionMetrics
)
ObserveAdmissionController
(
elapsed
time
.
Duration
,
rejected
bool
,
handler
NamedHandler
,
attr
Attributes
,
stepType
string
)
{
t
:=
typeToLabel
(
handler
)
gvr
:=
attr
.
GetResource
()
gvr
:=
attr
.
GetResource
()
m
.
controller
.
observe
(
elapsed
,
rejected
,
handler
.
GetName
(),
t
,
string
(
attr
.
GetOperation
()),
gvr
.
Group
,
gvr
.
Version
,
gvr
.
Resource
,
attr
.
GetSubresource
(),
isSystemNsLabel
(
attr
))
m
.
controller
.
observe
(
elapsed
,
handler
.
Name
(),
stepType
,
string
(
attr
.
GetOperation
()),
gvr
.
Group
,
gvr
.
Version
,
gvr
.
Resource
,
attr
.
GetSubresource
(),
isSystemNsLabel
(
attr
),
strconv
.
FormatBool
(
rejected
))
}
}
// ObserveExternalWebhook records admission related metrics for a external admission webhook.
// ObserveExternalWebhook records admission related metrics for a external admission webhook.
func
(
m
*
AdmissionMetrics
)
ObserveExternalWebhook
(
elapsed
time
.
Duration
,
rejected
bool
,
hook
*
v1alpha1
.
ExternalAdmissionHook
,
attr
Attributes
)
{
func
(
m
*
AdmissionMetrics
)
ObserveExternalWebhook
(
elapsed
time
.
Duration
,
rejected
bool
,
hook
*
v1alpha1
.
ExternalAdmissionHook
,
attr
Attributes
)
{
t
:=
"validating"
// TODO: pass in type (validating|mutating) once mutating webhook functionality has been implemented
t
:=
"validating"
// TODO: pass in type (validating|mutating) once mutating webhook functionality has been implemented
gvr
:=
attr
.
GetResource
()
gvr
:=
attr
.
GetResource
()
m
.
externalWebhook
.
observe
(
elapsed
,
rejected
,
hook
.
Name
,
t
,
string
(
attr
.
GetOperation
()),
gvr
.
Group
,
gvr
.
Version
,
gvr
.
Resource
,
attr
.
GetSubresource
(),
isSystemNsLabel
(
attr
))
m
.
externalWebhook
.
observe
(
elapsed
,
hook
.
Name
,
t
,
string
(
attr
.
GetOperation
()),
gvr
.
Group
,
gvr
.
Version
,
gvr
.
Resource
,
attr
.
GetSubresource
(),
isSystemNsLabel
(
attr
),
strconv
.
FormatBool
(
rejected
))
}
}
// isSystemNsLabel returns the value to use for the `is_system_ns` metric label.
// isSystemNsLabel returns the value to use for the `is_system_ns` metric label.
...
@@ -106,73 +108,18 @@ func isSystemNsLabel(a Attributes) string {
...
@@ -106,73 +108,18 @@ func isSystemNsLabel(a Attributes) string {
return
strconv
.
FormatBool
(
a
.
GetNamespace
()
==
metav1
.
NamespaceSystem
)
return
strconv
.
FormatBool
(
a
.
GetNamespace
()
==
metav1
.
NamespaceSystem
)
}
}
func
typeToLabel
(
i
Interface
)
string
{
switch
i
.
(
type
)
{
case
MutationInterface
:
return
"mutating"
case
ValidationInterface
:
return
"validating"
default
:
return
"UNRECOGNIZED_ADMISSION_TYPE"
}
}
type
metricSet
struct
{
type
metricSet
struct
{
total
*
prometheus
.
CounterVec
rejectedTotal
*
prometheus
.
CounterVec
latencies
*
prometheus
.
HistogramVec
latencies
*
prometheus
.
HistogramVec
latenciesSummary
*
prometheus
.
SummaryVec
latenciesSummary
*
prometheus
.
SummaryVec
}
}
func
(
m
*
metricSet
)
mustRegister
()
{
prometheus
.
MustRegister
(
m
.
total
)
prometheus
.
MustRegister
(
m
.
rejectedTotal
)
prometheus
.
MustRegister
(
m
.
latencies
)
prometheus
.
MustRegister
(
m
.
latenciesSummary
)
}
func
(
m
*
metricSet
)
reset
()
{
m
.
total
.
Reset
()
m
.
rejectedTotal
.
Reset
()
m
.
latencies
.
Reset
()
m
.
latenciesSummary
.
Reset
()
}
func
(
m
*
metricSet
)
observe
(
elapsed
time
.
Duration
,
rejected
bool
,
labels
...
string
)
{
elapsedMicroseconds
:=
float64
(
elapsed
/
time
.
Microsecond
)
m
.
total
.
WithLabelValues
(
labels
...
)
.
Inc
()
if
rejected
{
m
.
rejectedTotal
.
WithLabelValues
(
labels
...
)
.
Inc
()
}
m
.
latencies
.
WithLabelValues
(
labels
...
)
.
Observe
(
elapsedMicroseconds
)
m
.
latenciesSummary
.
WithLabelValues
(
labels
...
)
.
Observe
(
elapsedMicroseconds
)
}
func
newMetricSet
(
name
string
,
labels
[]
string
,
helpTemplate
string
)
*
metricSet
{
func
newMetricSet
(
name
string
,
labels
[]
string
,
helpTemplate
string
)
*
metricSet
{
return
&
metricSet
{
return
&
metricSet
{
total
:
prometheus
.
NewCounterVec
(
prometheus
.
CounterOpts
{
Namespace
:
namespace
,
Subsystem
:
subsystem
,
Name
:
fmt
.
Sprintf
(
"%stotal"
,
name
),
Help
:
fmt
.
Sprintf
(
helpTemplate
,
"count"
),
},
labels
,
),
rejectedTotal
:
prometheus
.
NewCounterVec
(
prometheus
.
CounterOpts
{
Namespace
:
namespace
,
Subsystem
:
subsystem
,
Name
:
fmt
.
Sprintf
(
"%srejected_total"
,
name
),
Help
:
fmt
.
Sprintf
(
helpTemplate
,
"rejected count"
),
},
labels
,
),
latencies
:
prometheus
.
NewHistogramVec
(
latencies
:
prometheus
.
NewHistogramVec
(
prometheus
.
HistogramOpts
{
prometheus
.
HistogramOpts
{
Namespace
:
namespace
,
Namespace
:
namespace
,
Subsystem
:
subsystem
,
Subsystem
:
subsystem
,
Name
:
fmt
.
Sprintf
(
"%slatencies"
,
name
),
Name
:
fmt
.
Sprintf
(
"%s
_
latencies"
,
name
),
Help
:
fmt
.
Sprintf
(
helpTemplate
,
"latency histogram"
),
Help
:
fmt
.
Sprintf
(
helpTemplate
,
"latency histogram"
),
Buckets
:
latencyBuckets
,
Buckets
:
latencyBuckets
,
},
},
...
@@ -182,7 +129,7 @@ func newMetricSet(name string, labels []string, helpTemplate string) *metricSet
...
@@ -182,7 +129,7 @@ func newMetricSet(name string, labels []string, helpTemplate string) *metricSet
prometheus
.
SummaryOpts
{
prometheus
.
SummaryOpts
{
Namespace
:
namespace
,
Namespace
:
namespace
,
Subsystem
:
subsystem
,
Subsystem
:
subsystem
,
Name
:
fmt
.
Sprintf
(
"%slatencies_summary"
,
name
),
Name
:
fmt
.
Sprintf
(
"%s
_
latencies_summary"
,
name
),
Help
:
fmt
.
Sprintf
(
helpTemplate
,
"latency summary"
),
Help
:
fmt
.
Sprintf
(
helpTemplate
,
"latency summary"
),
MaxAge
:
latencySummaryMaxAge
,
MaxAge
:
latencySummaryMaxAge
,
},
},
...
@@ -190,3 +137,22 @@ func newMetricSet(name string, labels []string, helpTemplate string) *metricSet
...
@@ -190,3 +137,22 @@ func newMetricSet(name string, labels []string, helpTemplate string) *metricSet
),
),
}
}
}
}
// MustRegister registers all the prometheus metrics in the metricSet.
func
(
m
*
metricSet
)
mustRegister
()
{
prometheus
.
MustRegister
(
m
.
latencies
)
prometheus
.
MustRegister
(
m
.
latenciesSummary
)
}
// Reset resets all the prometheus metrics in the metricSet.
func
(
m
*
metricSet
)
reset
()
{
m
.
latencies
.
Reset
()
m
.
latenciesSummary
.
Reset
()
}
// Observe records an observed admission event to all metrics in the metricSet.
func
(
m
*
metricSet
)
observe
(
elapsed
time
.
Duration
,
labels
...
string
)
{
elapsedMicroseconds
:=
float64
(
elapsed
/
time
.
Microsecond
)
m
.
latencies
.
WithLabelValues
(
labels
...
)
.
Observe
(
elapsedMicroseconds
)
m
.
latenciesSummary
.
WithLabelValues
(
labels
...
)
.
Observe
(
elapsedMicroseconds
)
}
staging/src/k8s.io/apiserver/pkg/admission/metrics_test.go
View file @
2643c6ae
...
@@ -34,48 +34,54 @@ var (
...
@@ -34,48 +34,54 @@ var (
func
TestObserveAdmissionStep
(
t
*
testing
.
T
)
{
func
TestObserveAdmissionStep
(
t
*
testing
.
T
)
{
Metrics
.
reset
()
Metrics
.
reset
()
Metrics
.
ObserveAdmissionStep
(
2
*
time
.
Second
,
false
,
attr
,
"mutating"
)
Metrics
.
ObserveAdmissionStep
(
2
*
time
.
Second
,
false
,
attr
,
"mutating"
)
wantLabels
:=
metricLabels
{
wantLabels
:=
map
[
string
]
string
{
operation
:
string
(
Create
),
"operation"
:
string
(
Create
),
group
:
resource
.
Group
,
"group"
:
resource
.
Group
,
version
:
resource
.
Version
,
"version"
:
resource
.
Version
,
resource
:
resource
.
Resource
,
"resource"
:
resource
.
Resource
,
subresource
:
"subresource"
,
"subresource"
:
"subresource"
,
tpe
:
"mutating"
,
"type"
:
"mutating"
,
isSystemNs
:
false
,
"isSystemNs"
:
"false"
,
"rejected"
:
"false"
,
}
}
expectCountMetric
(
t
,
"apiserver_admission_step_total"
,
wantLabels
,
1
)
expectHistogramCountTotal
(
t
,
"apiserver_admission_step_latencies"
,
wantLabels
,
1
)
expectFindMetric
(
t
,
"apiserver_admission_step_latencies_summary"
,
wantLabels
)
}
}
func
TestObserveAdmissionController
(
t
*
testing
.
T
)
{
func
TestObserveAdmissionController
(
t
*
testing
.
T
)
{
Metrics
.
reset
()
Metrics
.
reset
()
handler
:=
makeHandler
(
"a"
,
true
,
Create
)
handler
:=
makeValidatingNamedHandler
(
"a"
,
true
,
Create
)
Metrics
.
ObserveAdmissionController
(
2
*
time
.
Second
,
false
,
handler
,
attr
)
Metrics
.
ObserveAdmissionController
(
2
*
time
.
Second
,
false
,
handler
,
attr
,
"validating"
)
wantLabels
:=
metricLabels
{
wantLabels
:=
map
[
string
]
string
{
name
:
"a"
,
"name"
:
"a"
,
operation
:
string
(
Create
),
"operation"
:
string
(
Create
),
group
:
resource
.
Group
,
"group"
:
resource
.
Group
,
version
:
resource
.
Version
,
"version"
:
resource
.
Version
,
resource
:
resource
.
Resource
,
"resource"
:
resource
.
Resource
,
subresource
:
"subresource"
,
"subresource"
:
"subresource"
,
tpe
:
"mutating"
,
"type"
:
"validating"
,
isSystemNs
:
false
,
"isSystemNs"
:
"false"
,
"rejected"
:
"false"
,
}
}
expectCountMetric
(
t
,
"apiserver_admission_controller_total"
,
wantLabels
,
1
)
expectHistogramCountTotal
(
t
,
"apiserver_admission_controller_latencies"
,
wantLabels
,
1
)
expectFindMetric
(
t
,
"apiserver_admission_controller_latencies_summary"
,
wantLabels
)
}
}
func
TestObserveExternalWebhook
(
t
*
testing
.
T
)
{
func
TestObserveExternalWebhook
(
t
*
testing
.
T
)
{
Metrics
.
reset
()
Metrics
.
reset
()
hook
:=
&
v1alpha1
.
ExternalAdmissionHook
{
Name
:
"x"
}
hook
:=
&
v1alpha1
.
ExternalAdmissionHook
{
Name
:
"x"
}
Metrics
.
ObserveExternalWebhook
(
2
*
time
.
Second
,
false
,
hook
,
attr
)
Metrics
.
ObserveExternalWebhook
(
2
*
time
.
Second
,
false
,
hook
,
attr
)
wantLabels
:=
metricLabels
{
wantLabels
:=
map
[
string
]
string
{
name
:
"x"
,
"name"
:
"x"
,
operation
:
string
(
Create
),
"operation"
:
string
(
Create
),
group
:
resource
.
Group
,
"group"
:
resource
.
Group
,
version
:
resource
.
Version
,
"version"
:
resource
.
Version
,
resource
:
resource
.
Resource
,
"resource"
:
resource
.
Resource
,
subresource
:
"subresource"
,
"subresource"
:
"subresource"
,
tpe
:
"validating"
,
"type"
:
"validating"
,
isSystemNs
:
false
,
"isSystemNs"
:
"false"
,
"rejected"
:
"false"
,
}
}
expectCountMetric
(
t
,
"apiserver_admission_external_webhook_total"
,
wantLabels
,
1
)
expectHistogramCountTotal
(
t
,
"apiserver_admission_external_webhook_latencies"
,
wantLabels
,
1
)
expectFindMetric
(
t
,
"apiserver_admission_external_webhook_latencies_summary"
,
wantLabels
)
}
}
staging/src/k8s.io/apiserver/pkg/admission/plugins.go
View file @
2643c6ae
...
@@ -41,11 +41,15 @@ type Plugins struct {
...
@@ -41,11 +41,15 @@ type Plugins struct {
// pluginHandler associates name with a admission.Interface handler.
// pluginHandler associates name with a admission.Interface handler.
type
pluginHandler
struct
{
type
pluginHandler
struct
{
Interface
i
Interface
name
string
name
string
}
}
func
(
h
*
pluginHandler
)
GetName
()
string
{
func
(
h
*
pluginHandler
)
Interface
()
Interface
{
return
h
.
i
}
func
(
h
*
pluginHandler
)
Name
()
string
{
return
h
.
name
return
h
.
name
}
}
...
@@ -143,7 +147,7 @@ func (ps *Plugins) NewFromPlugins(pluginNames []string, configProvider ConfigPro
...
@@ -143,7 +147,7 @@ func (ps *Plugins) NewFromPlugins(pluginNames []string, configProvider ConfigPro
return
nil
,
err
return
nil
,
err
}
}
if
plugin
!=
nil
{
if
plugin
!=
nil
{
handler
:=
&
pluginHandler
{
Interface
:
plugin
,
name
:
pluginName
}
handler
:=
&
pluginHandler
{
i
:
plugin
,
name
:
pluginName
}
handlers
=
append
(
handlers
,
handler
)
handlers
=
append
(
handlers
,
handler
)
}
}
}
}
...
...
staging/src/k8s.io/apiserver/pkg/admission/testutil_test.go
View file @
2643c6ae
...
@@ -18,24 +18,19 @@ package admission
...
@@ -18,24 +18,19 @@ package admission
import
(
import
(
"fmt"
"fmt"
"strconv"
"testing"
"testing"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus"
ptype
"github.com/prometheus/client_model/go"
ptype
"github.com/prometheus/client_model/go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
)
// FakeHandler provide a mock implement both MutationInterface and ValidationInterface that tracks which
// methods have been called and always returns an error if admit is false.
type
FakeHandler
struct
{
type
FakeHandler
struct
{
*
Handler
*
Handler
name
string
admit
bool
admit
,
admitCalled
bool
admitCalled
bool
validate
,
validateCalled
bool
validateCalled
bool
}
func
(
h
*
FakeHandler
)
GetName
()
string
{
return
h
.
name
}
}
func
(
h
*
FakeHandler
)
Admit
(
a
Attributes
)
(
err
error
)
{
func
(
h
*
FakeHandler
)
Admit
(
a
Attributes
)
(
err
error
)
{
...
@@ -47,105 +42,125 @@ func (h *FakeHandler) Admit(a Attributes) (err error) {
...
@@ -47,105 +42,125 @@ func (h *FakeHandler) Admit(a Attributes) (err error) {
}
}
func
(
h
*
FakeHandler
)
Validate
(
a
Attributes
)
(
err
error
)
{
func
(
h
*
FakeHandler
)
Validate
(
a
Attributes
)
(
err
error
)
{
h
.
admit
Called
=
true
h
.
validate
Called
=
true
if
h
.
admit
{
if
h
.
admit
{
return
nil
return
nil
}
}
return
fmt
.
Errorf
(
"Don't admit"
)
return
fmt
.
Errorf
(
"Don't admit"
)
}
}
// makeHandler creates a mock handler for testing purposes.
func
makeHandler
(
admit
bool
,
ops
...
Operation
)
*
FakeHandler
{
func
makeHandler
(
name
string
,
admit
bool
,
ops
...
Operation
)
*
FakeHandler
{
return
&
FakeHandler
{
return
&
FakeHandler
{
name
:
name
,
admit
:
admit
,
admit
:
admit
,
Handler
:
NewHandler
(
ops
...
),
Handler
:
NewHandler
(
ops
...
),
}
}
}
}
type
metricLabels
struct
{
func
makeNamedHandler
(
name
string
,
admit
bool
,
ops
...
Operation
)
NamedHandler
{
operation
string
return
&
pluginHandler
{
group
string
i
:
&
FakeHandler
{
version
string
admit
:
admit
,
resource
string
Handler
:
NewHandler
(
ops
...
),
subresource
string
},
name
string
name
:
name
,
tpe
string
}
isSystemNs
bool
}
// FakeValidatingHandler provide a mock of ValidationInterface that tracks which
// methods have been called and always returns an error if validate is false.
type
FakeValidatingHandler
struct
{
*
Handler
validate
,
validateCalled
bool
}
func
(
h
*
FakeValidatingHandler
)
Validate
(
a
Attributes
)
(
err
error
)
{
h
.
validateCalled
=
true
if
h
.
validate
{
return
nil
}
return
fmt
.
Errorf
(
"Don't validate"
)
}
}
// matches checks if the reciever matches the pattern. Empty strings in the pattern are treated as wildcards.
func
makeValidatingHandler
(
validate
bool
,
ops
...
Operation
)
*
FakeValidatingHandler
{
func
(
l
metricLabels
)
matches
(
pattern
metricLabels
)
bool
{
return
&
FakeValidatingHandler
{
return
matches
(
l
.
operation
,
pattern
.
operation
)
&&
validate
:
validate
,
matches
(
l
.
group
,
pattern
.
group
)
&&
Handler
:
NewHandler
(
ops
...
),
matches
(
l
.
version
,
pattern
.
version
)
&&
}
matches
(
l
.
resource
,
pattern
.
resource
)
&&
matches
(
l
.
subresource
,
pattern
.
subresource
)
&&
matches
(
l
.
tpe
,
pattern
.
tpe
)
&&
l
.
isSystemNs
==
pattern
.
isSystemNs
}
}
// matches checks if a string matches a "pattern" string, where an empty pattern string is treated as a wildcard.
func
makeValidatingNamedHandler
(
name
string
,
validate
bool
,
ops
...
Operation
)
NamedHandler
{
func
matches
(
s
string
,
pattern
string
)
bool
{
return
&
pluginHandler
{
return
pattern
==
""
||
s
==
pattern
i
:
&
FakeValidatingHandler
{
validate
:
validate
,
Handler
:
NewHandler
(
ops
...
),
},
name
:
name
,
}
}
}
// readLabels marshalls the labels from a prometheus metric type to a simple struct, producing test errors if
func
labelsMatch
(
metric
*
ptype
.
Metric
,
labelFilter
map
[
string
]
string
)
bool
{
// if any unrecognized labels are encountered.
func
readLabels
(
t
*
testing
.
T
,
metric
*
ptype
.
Metric
)
metricLabels
{
l
:=
metricLabels
{}
for
_
,
lp
:=
range
metric
.
GetLabel
()
{
for
_
,
lp
:=
range
metric
.
GetLabel
()
{
val
:=
lp
.
GetValue
()
if
value
,
ok
:=
labelFilter
[
lp
.
GetName
()];
ok
&&
lp
.
GetValue
()
!=
value
{
switch
lp
.
GetName
()
{
return
false
case
"operation"
:
}
l
.
operation
=
val
}
case
"group"
:
return
true
l
.
group
=
val
}
case
"version"
:
l
.
version
=
val
// expectFindMetric find a metric with the given name nad labels or reports a fatal test error.
case
"resource"
:
func
expectFindMetric
(
t
*
testing
.
T
,
name
string
,
expectedLabels
map
[
string
]
string
)
*
ptype
.
Metric
{
l
.
resource
=
val
metrics
,
err
:=
prometheus
.
DefaultGatherer
.
Gather
()
case
"subresource"
:
if
err
!=
nil
{
l
.
subresource
=
val
t
.
Fatalf
(
"Failed to gather metrics: %s"
,
err
)
case
"name"
:
}
l
.
name
=
val
case
"type"
:
for
_
,
mf
:=
range
metrics
{
l
.
tpe
=
val
if
mf
.
GetName
()
==
name
{
case
"is_system_ns"
:
for
_
,
metric
:=
range
mf
.
GetMetric
()
{
ns
,
err
:=
strconv
.
ParseBool
(
lp
.
GetValue
())
if
labelsMatch
(
metric
,
expectedLabels
)
{
if
err
!=
nil
{
gotLabelCount
:=
len
(
metric
.
GetLabel
())
t
.
Errorf
(
"Expected boole for is_system_ns label value, got %s"
,
lp
.
GetValue
())
wantLabelCount
:=
len
(
expectedLabels
)
}
else
{
if
wantLabelCount
!=
gotLabelCount
{
l
.
isSystemNs
=
ns
t
.
Errorf
(
"Got metric with %d labels, but wanted %d labels. Wanted %#+v for %s"
,
gotLabelCount
,
wantLabelCount
,
expectedLabels
,
metric
.
String
())
}
return
metric
}
}
}
default
:
t
.
Errorf
(
"Unexpected metric label %s"
,
lp
.
GetName
())
}
}
}
}
return
l
t
.
Fatalf
(
"No metric found with name %s and labels %#+v"
,
name
,
expectedLabels
)
return
nil
}
}
// expect
CounterMetric ensures that exactly one counter metric with the given name and patternLabels exists and h
as
// expect
HistogramCountTotal ensures that the sum of counts of metrics matching the labelFilter is
as
//
the provided count
.
//
expected
.
func
expect
CountMetric
(
t
*
testing
.
T
,
name
string
,
patternLabels
metricLabels
,
wantCount
int64
)
{
func
expect
HistogramCountTotal
(
t
*
testing
.
T
,
name
string
,
labelFilter
map
[
string
]
string
,
wantCount
int
)
{
metrics
,
err
:=
prometheus
.
DefaultGatherer
.
Gather
()
metrics
,
err
:=
prometheus
.
DefaultGatherer
.
Gather
()
require
.
NoError
(
t
,
err
)
if
err
!=
nil
{
t
.
Fatalf
(
"Failed to gather metrics: %s"
,
err
)
}
count
:=
0
count
erSum
:=
0
for
_
,
mf
:=
range
metrics
{
for
_
,
mf
:=
range
metrics
{
if
mf
.
GetName
()
!=
name
{
if
mf
.
GetName
()
!=
name
{
continue
// Ignore other metrics.
continue
// Ignore other metrics.
}
}
for
_
,
metric
:=
range
mf
.
GetMetric
()
{
for
_
,
metric
:=
range
mf
.
GetMetric
()
{
gotLabels
:=
readLabels
(
t
,
metric
)
if
!
labelsMatch
(
metric
,
labelFilter
)
{
if
!
gotLabels
.
matches
(
patternLabels
)
{
continue
continue
}
}
count
+=
1
counterSum
+=
int
(
metric
.
GetHistogram
()
.
GetSampleCount
())
assert
.
EqualValues
(
t
,
wantCount
,
metric
.
GetCounter
()
.
GetValue
())
}
}
}
}
if
count
!=
1
{
if
wantCount
!=
counterSum
{
t
.
Errorf
(
"Want 1 metric with name %s, got %d"
,
name
,
count
)
t
.
Errorf
(
"Wanted count %d, got %d for metric %s with labels %#+v"
,
wantCount
,
counterSum
,
name
,
labelFilter
)
for
_
,
mf
:=
range
metrics
{
if
mf
.
GetName
()
==
name
{
for
_
,
metric
:=
range
mf
.
GetMetric
()
{
t
.
Logf
(
"
\t
near match: %s"
,
metric
.
String
())
}
}
}
}
}
}
}
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