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
55ecc454
Commit
55ecc454
authored
May 29, 2019
by
Joe Betz
Committed by
Chao Xu
May 30, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
split admissionregistration.v1beta1/Webhook into MutatingWebhook and ValidatingWebhook
parent
9356561c
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
696 additions
and
168 deletions
+696
-168
.golint_failures
hack/.golint_failures
+1
-0
fuzzer.go
pkg/apis/admissionregistration/fuzzer/fuzzer.go
+15
-1
types.go
pkg/apis/admissionregistration/types.go
+114
-4
defaults.go
pkg/apis/admissionregistration/v1beta1/defaults.go
+29
-1
validation.go
pkg/apis/admissionregistration/validation/validation.go
+62
-7
validation_test.go
pkg/apis/admissionregistration/validation/validation_test.go
+0
-0
types.go
...ing/src/k8s.io/api/admissionregistration/v1beta1/types.go
+122
-4
BUILD
staging/src/k8s.io/apiserver/pkg/admission/BUILD
+1
-12
BUILD
...ng/src/k8s.io/apiserver/pkg/admission/configuration/BUILD
+1
-0
mutating_webhook_manager.go
...r/pkg/admission/configuration/mutating_webhook_manager.go
+10
-7
mutating_webhook_manager_test.go
.../admission/configuration/mutating_webhook_manager_test.go
+10
-3
validating_webhook_manager.go
...pkg/admission/configuration/validating_webhook_manager.go
+10
-9
validating_webhook_manager_test.go
...dmission/configuration/validating_webhook_manager_test.go
+10
-3
BUILD
...g/src/k8s.io/apiserver/pkg/admission/plugin/webhook/BUILD
+41
-0
accessors.go
...8s.io/apiserver/pkg/admission/plugin/webhook/accessors.go
+139
-0
BUILD
...s.io/apiserver/pkg/admission/plugin/webhook/generic/BUILD
+2
-0
interfaces.go
...server/pkg/admission/plugin/webhook/generic/interfaces.go
+3
-4
webhook.go
...apiserver/pkg/admission/plugin/webhook/generic/webhook.go
+14
-13
webhook_test.go
...rver/pkg/admission/plugin/webhook/generic/webhook_test.go
+16
-15
dispatcher.go
...erver/pkg/admission/plugin/webhook/mutating/dispatcher.go
+19
-16
plugin_test.go
...rver/pkg/admission/plugin/webhook/mutating/plugin_test.go
+3
-3
BUILD
...io/apiserver/pkg/admission/plugin/webhook/namespace/BUILD
+2
-1
matcher.go
...iserver/pkg/admission/plugin/webhook/namespace/matcher.go
+3
-3
matcher_test.go
...er/pkg/admission/plugin/webhook/namespace/matcher_test.go
+3
-2
testcase.go
...piserver/pkg/admission/plugin/webhook/testing/testcase.go
+0
-0
BUILD
.../k8s.io/apiserver/pkg/admission/plugin/webhook/util/BUILD
+1
-1
client_config.go
...server/pkg/admission/plugin/webhook/util/client_config.go
+20
-19
dispatcher.go
...ver/pkg/admission/plugin/webhook/validating/dispatcher.go
+19
-18
plugin_test.go
...er/pkg/admission/plugin/webhook/validating/plugin_test.go
+2
-2
webhook.go
test/e2e/apimachinery/webhook.go
+15
-15
admission_test.go
.../integration/apiserver/admissionwebhook/admission_test.go
+5
-2
broken_webhook_test.go
...gration/apiserver/admissionwebhook/broken_webhook_test.go
+1
-1
webhook_test.go
test/integration/examples/webhook_test.go
+2
-2
modules.txt
vendor/modules.txt
+1
-0
No files found.
hack/.golint_failures
View file @
55ecc454
...
...
@@ -423,6 +423,7 @@ staging/src/k8s.io/apimachinery/pkg/watch
staging/src/k8s.io/apiserver/pkg/admission
staging/src/k8s.io/apiserver/pkg/admission/configuration
staging/src/k8s.io/apiserver/pkg/admission/initializer
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1alpha1
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testcerts
...
...
pkg/apis/admissionregistration/fuzzer/fuzzer.go
View file @
55ecc454
...
...
@@ -33,7 +33,21 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
obj
.
Scope
=
&
s
}
},
func
(
obj
*
admissionregistration
.
Webhook
,
c
fuzz
.
Continue
)
{
func
(
obj
*
admissionregistration
.
ValidatingWebhook
,
c
fuzz
.
Continue
)
{
c
.
FuzzNoCustom
(
obj
)
// fuzz self without calling this function again
p
:=
admissionregistration
.
FailurePolicyType
(
"Fail"
)
obj
.
FailurePolicy
=
&
p
m
:=
admissionregistration
.
MatchPolicyType
(
"Exact"
)
obj
.
MatchPolicy
=
&
m
s
:=
admissionregistration
.
SideEffectClassUnknown
obj
.
SideEffects
=
&
s
if
obj
.
TimeoutSeconds
==
nil
{
i
:=
int32
(
30
)
obj
.
TimeoutSeconds
=
&
i
}
obj
.
AdmissionReviewVersions
=
[]
string
{
"v1beta1"
}
},
func
(
obj
*
admissionregistration
.
MutatingWebhook
,
c
fuzz
.
Continue
)
{
c
.
FuzzNoCustom
(
obj
)
// fuzz self without calling this function again
p
:=
admissionregistration
.
FailurePolicyType
(
"Fail"
)
obj
.
FailurePolicy
=
&
p
...
...
pkg/apis/admissionregistration/types.go
View file @
55ecc454
...
...
@@ -123,7 +123,7 @@ type ValidatingWebhookConfiguration struct {
metav1
.
ObjectMeta
// Webhooks is a list of webhooks and the affected resources and operations.
// +optional
Webhooks
[]
Webhook
Webhooks
[]
Validating
Webhook
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
...
...
@@ -149,7 +149,7 @@ type MutatingWebhookConfiguration struct {
metav1
.
ObjectMeta
// Webhooks is a list of webhooks and the affected resources and operations.
// +optional
Webhooks
[]
Webhook
Webhooks
[]
Mutating
Webhook
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
...
...
@@ -165,8 +165,118 @@ type MutatingWebhookConfigurationList struct {
Items
[]
MutatingWebhookConfiguration
}
// Webhook describes an admission webhook and the resources and operations it applies to.
type
Webhook
struct
{
// ValidatingWebhook describes an admission webhook and the resources and operations it applies to.
type
ValidatingWebhook
struct
{
// The name of the admission webhook.
// Name should be fully qualified, e.g., imagepolicy.kubernetes.io, where
// "imagepolicy" is the name of the webhook, and kubernetes.io is the name
// of the organization.
// Required.
Name
string
// ClientConfig defines how to communicate with the hook.
// Required
ClientConfig
WebhookClientConfig
// Rules describes what operations on what resources/subresources the webhook cares about.
// The webhook cares about an operation if it matches _any_ Rule.
Rules
[]
RuleWithOperations
// FailurePolicy defines how unrecognized errors from the admission endpoint are handled -
// allowed values are Ignore or Fail. Defaults to Ignore.
// +optional
FailurePolicy
*
FailurePolicyType
// matchPolicy defines how the "rules" list is used to match incoming requests.
// Allowed values are "Exact" or "Equivalent".
//
// - Exact: match a request only if it exactly matches a specified rule.
// For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1,
// but "rules" only included `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]`,
// a request to apps/v1beta1 or extensions/v1beta1 would not be sent to the webhook.
//
// - Equivalent: match a request if modifies a resource listed in rules, even via another API group or version.
// For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1,
// and "rules" only included `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]`,
// a request to apps/v1beta1 or extensions/v1beta1 would be converted to apps/v1 and sent to the webhook.
//
// +optional
MatchPolicy
*
MatchPolicyType
// NamespaceSelector decides whether to run the webhook on an object based
// on whether the namespace for that object matches the selector. If the
// object itself is a namespace, the matching is performed on
// object.metadata.labels. If the object is another cluster scoped resource,
// it never skips the webhook.
//
// For example, to run the webhook on any objects whose namespace is not
// associated with "runlevel" of "0" or "1"; you will set the selector as
// follows:
// "namespaceSelector": {
// "matchExpressions": [
// {
// "key": "runlevel",
// "operator": "NotIn",
// "values": [
// "0",
// "1"
// ]
// }
// ]
// }
//
// If instead you want to only run the webhook on any objects whose
// namespace is associated with the "environment" of "prod" or "staging";
// you will set the selector as follows:
// "namespaceSelector": {
// "matchExpressions": [
// {
// "key": "environment",
// "operator": "In",
// "values": [
// "prod",
// "staging"
// ]
// }
// ]
// }
//
// See
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
// for more examples of label selectors.
//
// Default to the empty LabelSelector, which matches everything.
// +optional
NamespaceSelector
*
metav1
.
LabelSelector
// SideEffects states whether this webhookk has side effects.
// Acceptable values are: Unknown, None, Some, NoneOnDryRun
// Webhooks with side effects MUST implement a reconciliation system, since a request may be
// rejected by a future step in the admission change and the side effects therefore need to be undone.
// Requests with the dryRun attribute will be auto-rejected if they match a webhook with
// sideEffects == Unknown or Some. Defaults to Unknown.
// +optional
SideEffects
*
SideEffectClass
// TimeoutSeconds specifies the timeout for this webhook. After the timeout passes,
// the webhook call will be ignored or the API call will fail based on the
// failure policy.
// The timeout value must be between 1 and 30 seconds.
// +optional
TimeoutSeconds
*
int32
// AdmissionReviewVersions is an ordered list of preferred `AdmissionReview`
// versions the Webhook expects. API server will try to use first version in
// the list which it supports. If none of the versions specified in this list
// supported by API server, validation will fail for this object.
// If the webhook configuration has already been persisted with a version apiserver
// does not understand, calls to the webhook will fail and be subject to the failure policy.
// +optional
AdmissionReviewVersions
[]
string
}
// MutatingWebhook describes an admission webhook and the resources and operations it applies to.
type
MutatingWebhook
struct
{
// The name of the admission webhook.
// Name should be fully qualified, e.g., imagepolicy.kubernetes.io, where
// "imagepolicy" is the name of the webhook, and kubernetes.io is the name
...
...
pkg/apis/admissionregistration/v1beta1/defaults.go
View file @
55ecc454
...
...
@@ -27,7 +27,35 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error {
return
RegisterDefaults
(
scheme
)
}
func
SetDefaults_Webhook
(
obj
*
admissionregistrationv1beta1
.
Webhook
)
{
func
SetDefaults_ValidatingWebhook
(
obj
*
admissionregistrationv1beta1
.
ValidatingWebhook
)
{
if
obj
.
FailurePolicy
==
nil
{
policy
:=
admissionregistrationv1beta1
.
Ignore
obj
.
FailurePolicy
=
&
policy
}
if
obj
.
MatchPolicy
==
nil
{
policy
:=
admissionregistrationv1beta1
.
Exact
obj
.
MatchPolicy
=
&
policy
}
if
obj
.
NamespaceSelector
==
nil
{
selector
:=
metav1
.
LabelSelector
{}
obj
.
NamespaceSelector
=
&
selector
}
if
obj
.
SideEffects
==
nil
{
// TODO: revisit/remove this default and possibly make the field required when promoting to v1
unknown
:=
admissionregistrationv1beta1
.
SideEffectClassUnknown
obj
.
SideEffects
=
&
unknown
}
if
obj
.
TimeoutSeconds
==
nil
{
obj
.
TimeoutSeconds
=
new
(
int32
)
*
obj
.
TimeoutSeconds
=
30
}
if
len
(
obj
.
AdmissionReviewVersions
)
==
0
{
obj
.
AdmissionReviewVersions
=
[]
string
{
admissionregistrationv1beta1
.
SchemeGroupVersion
.
Version
}
}
}
func
SetDefaults_MutatingWebhook
(
obj
*
admissionregistrationv1beta1
.
MutatingWebhook
)
{
if
obj
.
FailurePolicy
==
nil
{
policy
:=
admissionregistrationv1beta1
.
Ignore
obj
.
FailurePolicy
=
&
policy
...
...
pkg/apis/admissionregistration/validation/validation.go
View file @
55ecc454
...
...
@@ -201,7 +201,7 @@ func ValidateValidatingWebhookConfiguration(e *admissionregistration.ValidatingW
func
validateValidatingWebhookConfiguration
(
e
*
admissionregistration
.
ValidatingWebhookConfiguration
,
requireRecognizedVersion
bool
)
field
.
ErrorList
{
allErrors
:=
genericvalidation
.
ValidateObjectMeta
(
&
e
.
ObjectMeta
,
false
,
genericvalidation
.
NameIsDNSSubdomain
,
field
.
NewPath
(
"metadata"
))
for
i
,
hook
:=
range
e
.
Webhooks
{
allErrors
=
append
(
allErrors
,
validateWebhook
(
&
hook
,
field
.
NewPath
(
"webhooks"
)
.
Index
(
i
))
...
)
allErrors
=
append
(
allErrors
,
validate
Validating
Webhook
(
&
hook
,
field
.
NewPath
(
"webhooks"
)
.
Index
(
i
))
...
)
allErrors
=
append
(
allErrors
,
validateAdmissionReviewVersions
(
hook
.
AdmissionReviewVersions
,
requireRecognizedVersion
,
field
.
NewPath
(
"webhooks"
)
.
Index
(
i
)
.
Child
(
"admissionReviewVersions"
))
...
)
}
return
allErrors
...
...
@@ -214,13 +214,50 @@ func ValidateMutatingWebhookConfiguration(e *admissionregistration.MutatingWebho
func
validateMutatingWebhookConfiguration
(
e
*
admissionregistration
.
MutatingWebhookConfiguration
,
requireRecognizedVersion
bool
)
field
.
ErrorList
{
allErrors
:=
genericvalidation
.
ValidateObjectMeta
(
&
e
.
ObjectMeta
,
false
,
genericvalidation
.
NameIsDNSSubdomain
,
field
.
NewPath
(
"metadata"
))
for
i
,
hook
:=
range
e
.
Webhooks
{
allErrors
=
append
(
allErrors
,
validateWebhook
(
&
hook
,
field
.
NewPath
(
"webhooks"
)
.
Index
(
i
))
...
)
allErrors
=
append
(
allErrors
,
validate
Mutating
Webhook
(
&
hook
,
field
.
NewPath
(
"webhooks"
)
.
Index
(
i
))
...
)
allErrors
=
append
(
allErrors
,
validateAdmissionReviewVersions
(
hook
.
AdmissionReviewVersions
,
requireRecognizedVersion
,
field
.
NewPath
(
"webhooks"
)
.
Index
(
i
)
.
Child
(
"admissionReviewVersions"
))
...
)
}
return
allErrors
}
func
validateWebhook
(
hook
*
admissionregistration
.
Webhook
,
fldPath
*
field
.
Path
)
field
.
ErrorList
{
func
validateValidatingWebhook
(
hook
*
admissionregistration
.
ValidatingWebhook
,
fldPath
*
field
.
Path
)
field
.
ErrorList
{
var
allErrors
field
.
ErrorList
// hook.Name must be fully qualified
allErrors
=
append
(
allErrors
,
utilvalidation
.
IsFullyQualifiedName
(
fldPath
.
Child
(
"name"
),
hook
.
Name
)
...
)
for
i
,
rule
:=
range
hook
.
Rules
{
allErrors
=
append
(
allErrors
,
validateRuleWithOperations
(
&
rule
,
fldPath
.
Child
(
"rules"
)
.
Index
(
i
))
...
)
}
if
hook
.
FailurePolicy
!=
nil
&&
!
supportedFailurePolicies
.
Has
(
string
(
*
hook
.
FailurePolicy
))
{
allErrors
=
append
(
allErrors
,
field
.
NotSupported
(
fldPath
.
Child
(
"failurePolicy"
),
*
hook
.
FailurePolicy
,
supportedFailurePolicies
.
List
()))
}
if
hook
.
MatchPolicy
!=
nil
&&
!
supportedMatchPolicies
.
Has
(
string
(
*
hook
.
MatchPolicy
))
{
allErrors
=
append
(
allErrors
,
field
.
NotSupported
(
fldPath
.
Child
(
"matchPolicy"
),
*
hook
.
MatchPolicy
,
supportedMatchPolicies
.
List
()))
}
if
hook
.
SideEffects
!=
nil
&&
!
supportedSideEffectClasses
.
Has
(
string
(
*
hook
.
SideEffects
))
{
allErrors
=
append
(
allErrors
,
field
.
NotSupported
(
fldPath
.
Child
(
"sideEffects"
),
*
hook
.
SideEffects
,
supportedSideEffectClasses
.
List
()))
}
if
hook
.
TimeoutSeconds
!=
nil
&&
(
*
hook
.
TimeoutSeconds
>
30
||
*
hook
.
TimeoutSeconds
<
1
)
{
allErrors
=
append
(
allErrors
,
field
.
Invalid
(
fldPath
.
Child
(
"timeoutSeconds"
),
*
hook
.
TimeoutSeconds
,
"the timeout value must be between 1 and 30 seconds"
))
}
if
hook
.
NamespaceSelector
!=
nil
{
allErrors
=
append
(
allErrors
,
metav1validation
.
ValidateLabelSelector
(
hook
.
NamespaceSelector
,
fldPath
.
Child
(
"namespaceSelector"
))
...
)
}
cc
:=
hook
.
ClientConfig
switch
{
case
(
cc
.
URL
==
nil
)
==
(
cc
.
Service
==
nil
)
:
allErrors
=
append
(
allErrors
,
field
.
Required
(
fldPath
.
Child
(
"clientConfig"
),
"exactly one of url or service is required"
))
case
cc
.
URL
!=
nil
:
allErrors
=
append
(
allErrors
,
webhook
.
ValidateWebhookURL
(
fldPath
.
Child
(
"clientConfig"
)
.
Child
(
"url"
),
*
cc
.
URL
,
true
)
...
)
case
cc
.
Service
!=
nil
:
allErrors
=
append
(
allErrors
,
webhook
.
ValidateWebhookService
(
fldPath
.
Child
(
"clientConfig"
)
.
Child
(
"service"
),
cc
.
Service
.
Name
,
cc
.
Service
.
Namespace
,
cc
.
Service
.
Path
,
cc
.
Service
.
Port
)
...
)
}
return
allErrors
}
func
validateMutatingWebhook
(
hook
*
admissionregistration
.
MutatingWebhook
,
fldPath
*
field
.
Path
)
field
.
ErrorList
{
var
allErrors
field
.
ErrorList
// hook.Name must be fully qualified
allErrors
=
append
(
allErrors
,
utilvalidation
.
IsFullyQualifiedName
(
fldPath
.
Child
(
"name"
),
hook
.
Name
)
...
)
...
...
@@ -309,9 +346,27 @@ func validateRuleWithOperations(ruleWithOperations *admissionregistration.RuleWi
return
allErrors
}
// hasAcceptedAdmissionReviewVersions returns true if all webhooks have at least one
// mutatingHasAcceptedAdmissionReviewVersions returns true if all webhooks have at least one
// admission review version this apiserver accepts.
func
mutatingHasAcceptedAdmissionReviewVersions
(
webhooks
[]
admissionregistration
.
MutatingWebhook
)
bool
{
for
_
,
hook
:=
range
webhooks
{
hasRecognizedVersion
:=
false
for
_
,
version
:=
range
hook
.
AdmissionReviewVersions
{
if
isAcceptedAdmissionReviewVersion
(
version
)
{
hasRecognizedVersion
=
true
break
}
}
if
!
hasRecognizedVersion
&&
len
(
hook
.
AdmissionReviewVersions
)
>
0
{
return
false
}
}
return
true
}
// validatingHasAcceptedAdmissionReviewVersions returns true if all webhooks have at least one
// admission review version this apiserver accepts.
func
hasAcceptedAdmissionReviewVersions
(
webhooks
[]
admissionregistration
.
Webhook
)
bool
{
func
validatingHasAcceptedAdmissionReviewVersions
(
webhooks
[]
admissionregistration
.
Validating
Webhook
)
bool
{
for
_
,
hook
:=
range
webhooks
{
hasRecognizedVersion
:=
false
for
_
,
version
:=
range
hook
.
AdmissionReviewVersions
{
...
...
@@ -328,9 +383,9 @@ func hasAcceptedAdmissionReviewVersions(webhooks []admissionregistration.Webhook
}
func
ValidateValidatingWebhookConfigurationUpdate
(
newC
,
oldC
*
admissionregistration
.
ValidatingWebhookConfiguration
)
field
.
ErrorList
{
return
validateValidatingWebhookConfiguration
(
newC
,
h
asAcceptedAdmissionReviewVersions
(
oldC
.
Webhooks
))
return
validateValidatingWebhookConfiguration
(
newC
,
validatingH
asAcceptedAdmissionReviewVersions
(
oldC
.
Webhooks
))
}
func
ValidateMutatingWebhookConfigurationUpdate
(
newC
,
oldC
*
admissionregistration
.
MutatingWebhookConfiguration
)
field
.
ErrorList
{
return
validateMutatingWebhookConfiguration
(
newC
,
h
asAcceptedAdmissionReviewVersions
(
oldC
.
Webhooks
))
return
validateMutatingWebhookConfiguration
(
newC
,
mutatingH
asAcceptedAdmissionReviewVersions
(
oldC
.
Webhooks
))
}
pkg/apis/admissionregistration/validation/validation_test.go
View file @
55ecc454
This diff is collapsed.
Click to expand it.
staging/src/k8s.io/api/admissionregistration/v1beta1/types.go
View file @
55ecc454
...
...
@@ -124,7 +124,7 @@ type ValidatingWebhookConfiguration struct {
// +optional
// +patchMergeKey=name
// +patchStrategy=merge
Webhooks
[]
Webhook
`json:"webhooks,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,2,rep,name=Webhooks"`
Webhooks
[]
Validating
Webhook
`json:"webhooks,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,2,rep,name=Webhooks"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
...
...
@@ -154,7 +154,7 @@ type MutatingWebhookConfiguration struct {
// +optional
// +patchMergeKey=name
// +patchStrategy=merge
Webhooks
[]
Webhook
`json:"webhooks,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,2,rep,name=Webhooks"`
Webhooks
[]
Mutating
Webhook
`json:"webhooks,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,2,rep,name=Webhooks"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
...
...
@@ -170,8 +170,126 @@ type MutatingWebhookConfigurationList struct {
Items
[]
MutatingWebhookConfiguration
`json:"items" protobuf:"bytes,2,rep,name=items"`
}
// Webhook describes an admission webhook and the resources and operations it applies to.
type
Webhook
struct
{
// ValidatingWebhook describes an admission webhook and the resources and operations it applies to.
type
ValidatingWebhook
struct
{
// The name of the admission webhook.
// Name should be fully qualified, e.g., imagepolicy.kubernetes.io, where
// "imagepolicy" is the name of the webhook, and kubernetes.io is the name
// of the organization.
// Required.
Name
string
`json:"name" protobuf:"bytes,1,opt,name=name"`
// ClientConfig defines how to communicate with the hook.
// Required
ClientConfig
WebhookClientConfig
`json:"clientConfig" protobuf:"bytes,2,opt,name=clientConfig"`
// Rules describes what operations on what resources/subresources the webhook cares about.
// The webhook cares about an operation if it matches _any_ Rule.
// However, in order to prevent ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks
// from putting the cluster in a state which cannot be recovered from without completely
// disabling the plugin, ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks are never called
// on admission requests for ValidatingWebhookConfiguration and MutatingWebhookConfiguration objects.
Rules
[]
RuleWithOperations
`json:"rules,omitempty" protobuf:"bytes,3,rep,name=rules"`
// FailurePolicy defines how unrecognized errors from the admission endpoint are handled -
// allowed values are Ignore or Fail. Defaults to Ignore.
// +optional
FailurePolicy
*
FailurePolicyType
`json:"failurePolicy,omitempty" protobuf:"bytes,4,opt,name=failurePolicy,casttype=FailurePolicyType"`
// matchPolicy defines how the "rules" list is used to match incoming requests.
// Allowed values are "Exact" or "Equivalent".
//
// - Exact: match a request only if it exactly matches a specified rule.
// For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1,
// but "rules" only included `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]`,
// a request to apps/v1beta1 or extensions/v1beta1 would not be sent to the webhook.
//
// - Equivalent: match a request if modifies a resource listed in rules, even via another API group or version.
// For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1,
// and "rules" only included `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]`,
// a request to apps/v1beta1 or extensions/v1beta1 would be converted to apps/v1 and sent to the webhook.
//
// Defaults to "Exact"
// +optional
MatchPolicy
*
MatchPolicyType
`json:"matchPolicy,omitempty" protobuf:"bytes,9,opt,name=matchPolicy,casttype=MatchPolicyType"`
// NamespaceSelector decides whether to run the webhook on an object based
// on whether the namespace for that object matches the selector. If the
// object itself is a namespace, the matching is performed on
// object.metadata.labels. If the object is another cluster scoped resource,
// it never skips the webhook.
//
// For example, to run the webhook on any objects whose namespace is not
// associated with "runlevel" of "0" or "1"; you will set the selector as
// follows:
// "namespaceSelector": {
// "matchExpressions": [
// {
// "key": "runlevel",
// "operator": "NotIn",
// "values": [
// "0",
// "1"
// ]
// }
// ]
// }
//
// If instead you want to only run the webhook on any objects whose
// namespace is associated with the "environment" of "prod" or "staging";
// you will set the selector as follows:
// "namespaceSelector": {
// "matchExpressions": [
// {
// "key": "environment",
// "operator": "In",
// "values": [
// "prod",
// "staging"
// ]
// }
// ]
// }
//
// See
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
// for more examples of label selectors.
//
// Default to the empty LabelSelector, which matches everything.
// +optional
NamespaceSelector
*
metav1
.
LabelSelector
`json:"namespaceSelector,omitempty" protobuf:"bytes,5,opt,name=namespaceSelector"`
// SideEffects states whether this webhookk has side effects.
// Acceptable values are: Unknown, None, Some, NoneOnDryRun
// Webhooks with side effects MUST implement a reconciliation system, since a request may be
// rejected by a future step in the admission change and the side effects therefore need to be undone.
// Requests with the dryRun attribute will be auto-rejected if they match a webhook with
// sideEffects == Unknown or Some. Defaults to Unknown.
// +optional
SideEffects
*
SideEffectClass
`json:"sideEffects,omitempty" protobuf:"bytes,6,opt,name=sideEffects,casttype=SideEffectClass"`
// TimeoutSeconds specifies the timeout for this webhook. After the timeout passes,
// the webhook call will be ignored or the API call will fail based on the
// failure policy.
// The timeout value must be between 1 and 30 seconds.
// Default to 30 seconds.
// +optional
TimeoutSeconds
*
int32
`json:"timeoutSeconds,omitempty" protobuf:"varint,7,opt,name=timeoutSeconds"`
// AdmissionReviewVersions is an ordered list of preferred `AdmissionReview`
// versions the Webhook expects. API server will try to use first version in
// the list which it supports. If none of the versions specified in this list
// supported by API server, validation will fail for this object.
// If a persisted webhook configuration specifies allowed versions and does not
// include any versions known to the API Server, calls to the webhook will fail
// and be subject to the failure policy.
// Default to `['v1beta1']`.
// +optional
AdmissionReviewVersions
[]
string
`json:"admissionReviewVersions,omitempty" protobuf:"bytes,8,rep,name=admissionReviewVersions"`
}
// MutatingWebhook describes an admission webhook and the resources and operations it applies to.
type
MutatingWebhook
struct
{
// The name of the admission webhook.
// Name should be fully qualified, e.g., imagepolicy.kubernetes.io, where
// "imagepolicy" is the name of the webhook, and kubernetes.io is the name
...
...
staging/src/k8s.io/apiserver/pkg/admission/BUILD
View file @
55ecc454
...
...
@@ -80,18 +80,7 @@ filegroup(
"//staging/src/k8s.io/apiserver/pkg/admission/initializer:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/metrics:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/errors:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/initializer:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/request:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/rules:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testcerts:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testing:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/util:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/testing:all-srcs",
],
tags = ["automanaged"],
...
...
staging/src/k8s.io/apiserver/pkg/admission/configuration/BUILD
View file @
55ecc454
...
...
@@ -39,6 +39,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic:go_default_library",
"//staging/src/k8s.io/client-go/informers:go_default_library",
"//staging/src/k8s.io/client-go/listers/admissionregistration/v1beta1:go_default_library",
...
...
staging/src/k8s.io/apiserver/pkg/admission/configuration/mutating_webhook_manager.go
View file @
55ecc454
...
...
@@ -24,6 +24,7 @@ import (
"k8s.io/api/admissionregistration/v1beta1"
"k8s.io/apimachinery/pkg/labels"
utilruntime
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apiserver/pkg/admission/plugin/webhook"
"k8s.io/apiserver/pkg/admission/plugin/webhook/generic"
"k8s.io/client-go/informers"
admissionregistrationlisters
"k8s.io/client-go/listers/admissionregistration/v1beta1"
...
...
@@ -48,7 +49,7 @@ func NewMutatingWebhookConfigurationManager(f informers.SharedInformerFactory) g
}
// Start with an empty list
manager
.
configuration
.
Store
(
&
v1beta1
.
MutatingWebhookConfiguration
{})
manager
.
configuration
.
Store
(
[]
webhook
.
WebhookAccessor
{})
// On any change, rebuild the config
informer
.
Informer
()
.
AddEventHandler
(
cache
.
ResourceEventHandlerFuncs
{
...
...
@@ -61,8 +62,8 @@ func NewMutatingWebhookConfigurationManager(f informers.SharedInformerFactory) g
}
// Webhooks returns the merged MutatingWebhookConfiguration.
func
(
m
*
mutatingWebhookConfigurationManager
)
Webhooks
()
[]
v1beta1
.
Webhook
{
return
m
.
configuration
.
Load
()
.
(
*
v1beta1
.
MutatingWebhookConfiguration
)
.
Webhooks
func
(
m
*
mutatingWebhookConfigurationManager
)
Webhooks
()
[]
webhook
.
WebhookAccessor
{
return
m
.
configuration
.
Load
()
.
(
[]
webhook
.
WebhookAccessor
)
}
func
(
m
*
mutatingWebhookConfigurationManager
)
HasSynced
()
bool
{
...
...
@@ -78,16 +79,18 @@ func (m *mutatingWebhookConfigurationManager) updateConfiguration() {
m
.
configuration
.
Store
(
mergeMutatingWebhookConfigurations
(
configurations
))
}
func
mergeMutatingWebhookConfigurations
(
configurations
[]
*
v1beta1
.
MutatingWebhookConfiguration
)
*
v1beta1
.
MutatingWebhookConfiguration
{
var
ret
v1beta1
.
MutatingWebhookConfiguration
func
mergeMutatingWebhookConfigurations
(
configurations
[]
*
v1beta1
.
MutatingWebhookConfiguration
)
[]
webhook
.
WebhookAccessor
{
// The internal order of webhooks for each configuration is provided by the user
// but configurations themselves can be in any order. As we are going to run these
// webhooks in serial, they are sorted here to have a deterministic order.
sort
.
SliceStable
(
configurations
,
MutatingWebhookConfigurationSorter
(
configurations
)
.
ByName
)
accessors
:=
[]
webhook
.
WebhookAccessor
{}
for
_
,
c
:=
range
configurations
{
ret
.
Webhooks
=
append
(
ret
.
Webhooks
,
c
.
Webhooks
...
)
for
i
:=
range
c
.
Webhooks
{
accessors
=
append
(
accessors
,
webhook
.
NewMutatingWebhookAccessor
(
&
c
.
Webhooks
[
i
]))
}
}
return
&
ret
return
accessors
}
type
MutatingWebhookConfigurationSorter
[]
*
v1beta1
.
MutatingWebhookConfiguration
...
...
staging/src/k8s.io/apiserver/pkg/admission/configuration/mutating_webhook_manager_test.go
View file @
55ecc454
...
...
@@ -45,7 +45,7 @@ func TestGetMutatingWebhookConfig(t *testing.T) {
webhookConfiguration
:=
&
v1beta1
.
MutatingWebhookConfiguration
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"webhook1"
},
Webhooks
:
[]
v1beta1
.
Webhook
{{
Name
:
"webhook1.1"
}},
Webhooks
:
[]
v1beta1
.
Mutating
Webhook
{{
Name
:
"webhook1.1"
}},
}
mutatingInformer
:=
informerFactory
.
Admissionregistration
()
.
V1beta1
()
.
MutatingWebhookConfigurations
()
...
...
@@ -57,7 +57,14 @@ func TestGetMutatingWebhookConfig(t *testing.T) {
if
len
(
configurations
)
==
0
{
t
.
Errorf
(
"expected non empty webhooks"
)
}
if
!
reflect
.
DeepEqual
(
configurations
,
webhookConfiguration
.
Webhooks
)
{
t
.
Errorf
(
"Expected
\n
%#v
\n
got
\n
%#v"
,
webhookConfiguration
.
Webhooks
,
configurations
)
for
i
:=
range
configurations
{
h
,
ok
:=
configurations
[
i
]
.
GetMutatingWebhook
()
if
!
ok
{
t
.
Errorf
(
"Expected mutating webhook"
)
continue
}
if
!
reflect
.
DeepEqual
(
h
,
&
webhookConfiguration
.
Webhooks
[
i
])
{
t
.
Errorf
(
"Expected
\n
%#v
\n
got
\n
%#v"
,
&
webhookConfiguration
.
Webhooks
[
i
],
h
)
}
}
}
staging/src/k8s.io/apiserver/pkg/admission/configuration/validating_webhook_manager.go
View file @
55ecc454
...
...
@@ -24,6 +24,7 @@ import (
"k8s.io/api/admissionregistration/v1beta1"
"k8s.io/apimachinery/pkg/labels"
utilruntime
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apiserver/pkg/admission/plugin/webhook"
"k8s.io/apiserver/pkg/admission/plugin/webhook/generic"
"k8s.io/client-go/informers"
admissionregistrationlisters
"k8s.io/client-go/listers/admissionregistration/v1beta1"
...
...
@@ -48,7 +49,7 @@ func NewValidatingWebhookConfigurationManager(f informers.SharedInformerFactory)
}
// Start with an empty list
manager
.
configuration
.
Store
(
&
v1beta1
.
ValidatingWebhookConfiguration
{})
manager
.
configuration
.
Store
(
[]
webhook
.
WebhookAccessor
{})
// On any change, rebuild the config
informer
.
Informer
()
.
AddEventHandler
(
cache
.
ResourceEventHandlerFuncs
{
...
...
@@ -61,8 +62,8 @@ func NewValidatingWebhookConfigurationManager(f informers.SharedInformerFactory)
}
// Webhooks returns the merged ValidatingWebhookConfiguration.
func
(
v
*
validatingWebhookConfigurationManager
)
Webhooks
()
[]
v1beta1
.
Webhook
{
return
v
.
configuration
.
Load
()
.
(
*
v1beta1
.
ValidatingWebhookConfiguration
)
.
Webhooks
func
(
v
*
validatingWebhookConfigurationManager
)
Webhooks
()
[]
webhook
.
WebhookAccessor
{
return
v
.
configuration
.
Load
()
.
(
[]
webhook
.
WebhookAccessor
)
}
// HasSynced returns true if the shared informers have synced.
...
...
@@ -79,15 +80,15 @@ func (v *validatingWebhookConfigurationManager) updateConfiguration() {
v
.
configuration
.
Store
(
mergeValidatingWebhookConfigurations
(
configurations
))
}
func
mergeValidatingWebhookConfigurations
(
configurations
[]
*
v1beta1
.
ValidatingWebhookConfiguration
,
)
*
v1beta1
.
ValidatingWebhookConfiguration
{
func
mergeValidatingWebhookConfigurations
(
configurations
[]
*
v1beta1
.
ValidatingWebhookConfiguration
)
[]
webhook
.
WebhookAccessor
{
sort
.
SliceStable
(
configurations
,
ValidatingWebhookConfigurationSorter
(
configurations
)
.
ByName
)
var
ret
v1beta1
.
ValidatingWebhookConfiguration
accessors
:=
[]
webhook
.
WebhookAccessor
{}
for
_
,
c
:=
range
configurations
{
ret
.
Webhooks
=
append
(
ret
.
Webhooks
,
c
.
Webhooks
...
)
for
i
:=
range
c
.
Webhooks
{
accessors
=
append
(
accessors
,
webhook
.
NewValidatingWebhookAccessor
(
&
c
.
Webhooks
[
i
]))
}
}
return
&
ret
return
accessors
}
type
ValidatingWebhookConfigurationSorter
[]
*
v1beta1
.
ValidatingWebhookConfiguration
...
...
staging/src/k8s.io/apiserver/pkg/admission/configuration/validating_webhook_manager_test.go
View file @
55ecc454
...
...
@@ -46,7 +46,7 @@ func TestGetValidatingWebhookConfig(t *testing.T) {
webhookConfiguration
:=
&
v1beta1
.
ValidatingWebhookConfiguration
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"webhook1"
},
Webhooks
:
[]
v1beta1
.
Webhook
{{
Name
:
"webhook1.1"
}},
Webhooks
:
[]
v1beta1
.
Validating
Webhook
{{
Name
:
"webhook1.1"
}},
}
validatingInformer
:=
informerFactory
.
Admissionregistration
()
.
V1beta1
()
.
ValidatingWebhookConfigurations
()
...
...
@@ -59,7 +59,14 @@ func TestGetValidatingWebhookConfig(t *testing.T) {
if
len
(
configurations
)
==
0
{
t
.
Errorf
(
"expected non empty webhooks"
)
}
if
!
reflect
.
DeepEqual
(
configurations
,
webhookConfiguration
.
Webhooks
)
{
t
.
Errorf
(
"Expected
\n
%#v
\n
got
\n
%#v"
,
webhookConfiguration
.
Webhooks
,
configurations
)
for
i
:=
range
configurations
{
h
,
ok
:=
configurations
[
i
]
.
GetValidatingWebhook
()
if
!
ok
{
t
.
Errorf
(
"Expected validating webhook"
)
continue
}
if
!
reflect
.
DeepEqual
(
h
,
&
webhookConfiguration
.
Webhooks
[
i
])
{
t
.
Errorf
(
"Expected
\n
%#v
\n
got
\n
%#v"
,
&
webhookConfiguration
.
Webhooks
[
i
],
h
)
}
}
}
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/BUILD
0 → 100644
View file @
55ecc454
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["accessors.go"],
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook",
importpath = "k8s.io/apiserver/pkg/admission/plugin/webhook",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/api/admissionregistration/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/errors:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/initializer:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/request:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/rules:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testcerts:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testing:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/util:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/accessors.go
0 → 100644
View file @
55ecc454
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
webhook
import
(
"k8s.io/api/admissionregistration/v1beta1"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
)
// WebhookAccessor provides a common interface to both mutating and validating webhook types.
type
WebhookAccessor
interface
{
// GetName gets the webhook Name field.
GetName
()
string
// GetClientConfig gets the webhook ClientConfig field.
GetClientConfig
()
v1beta1
.
WebhookClientConfig
// GetRules gets the webhook Rules field.
GetRules
()
[]
v1beta1
.
RuleWithOperations
// GetFailurePolicy gets the webhook FailurePolicy field.
GetFailurePolicy
()
*
v1beta1
.
FailurePolicyType
// GetMatchPolicy gets the webhook MatchPolicy field.
GetMatchPolicy
()
*
v1beta1
.
MatchPolicyType
// GetNamespaceSelector gets the webhook NamespaceSelector field.
GetNamespaceSelector
()
*
metav1
.
LabelSelector
// GetSideEffects gets the webhook SideEffects field.
GetSideEffects
()
*
v1beta1
.
SideEffectClass
// GetTimeoutSeconds gets the webhook TimeoutSeconds field.
GetTimeoutSeconds
()
*
int32
// GetAdmissionReviewVersions gets the webhook AdmissionReviewVersions field.
GetAdmissionReviewVersions
()
[]
string
// GetMutatingWebhook if the accessor contains a MutatingWebhook, returns it and true, else returns false.
GetMutatingWebhook
()
(
*
v1beta1
.
MutatingWebhook
,
bool
)
// GetValidatingWebhook if the accessor contains a ValidatingWebhook, returns it and true, else returns false.
GetValidatingWebhook
()
(
*
v1beta1
.
ValidatingWebhook
,
bool
)
}
// NewMutatingWebhookAccessor creates an accessor for a MutatingWebhook.
func
NewMutatingWebhookAccessor
(
h
*
v1beta1
.
MutatingWebhook
)
WebhookAccessor
{
return
mutatingWebhookAccessor
{
h
}
}
type
mutatingWebhookAccessor
struct
{
*
v1beta1
.
MutatingWebhook
}
func
(
m
mutatingWebhookAccessor
)
GetName
()
string
{
return
m
.
Name
}
func
(
m
mutatingWebhookAccessor
)
GetClientConfig
()
v1beta1
.
WebhookClientConfig
{
return
m
.
ClientConfig
}
func
(
m
mutatingWebhookAccessor
)
GetRules
()
[]
v1beta1
.
RuleWithOperations
{
return
m
.
Rules
}
func
(
m
mutatingWebhookAccessor
)
GetFailurePolicy
()
*
v1beta1
.
FailurePolicyType
{
return
m
.
FailurePolicy
}
func
(
m
mutatingWebhookAccessor
)
GetMatchPolicy
()
*
v1beta1
.
MatchPolicyType
{
return
m
.
MatchPolicy
}
func
(
m
mutatingWebhookAccessor
)
GetNamespaceSelector
()
*
metav1
.
LabelSelector
{
return
m
.
NamespaceSelector
}
func
(
m
mutatingWebhookAccessor
)
GetSideEffects
()
*
v1beta1
.
SideEffectClass
{
return
m
.
SideEffects
}
func
(
m
mutatingWebhookAccessor
)
GetTimeoutSeconds
()
*
int32
{
return
m
.
TimeoutSeconds
}
func
(
m
mutatingWebhookAccessor
)
GetAdmissionReviewVersions
()
[]
string
{
return
m
.
AdmissionReviewVersions
}
func
(
m
mutatingWebhookAccessor
)
GetMutatingWebhook
()
(
*
v1beta1
.
MutatingWebhook
,
bool
)
{
return
m
.
MutatingWebhook
,
true
}
func
(
m
mutatingWebhookAccessor
)
GetValidatingWebhook
()
(
*
v1beta1
.
ValidatingWebhook
,
bool
)
{
return
nil
,
false
}
// NewValidatingWebhookAccessor creates an accessor for a ValidatingWebhook.
func
NewValidatingWebhookAccessor
(
h
*
v1beta1
.
ValidatingWebhook
)
WebhookAccessor
{
return
validatingWebhookAccessor
{
h
}
}
type
validatingWebhookAccessor
struct
{
*
v1beta1
.
ValidatingWebhook
}
func
(
v
validatingWebhookAccessor
)
GetName
()
string
{
return
v
.
Name
}
func
(
v
validatingWebhookAccessor
)
GetClientConfig
()
v1beta1
.
WebhookClientConfig
{
return
v
.
ClientConfig
}
func
(
v
validatingWebhookAccessor
)
GetRules
()
[]
v1beta1
.
RuleWithOperations
{
return
v
.
Rules
}
func
(
v
validatingWebhookAccessor
)
GetFailurePolicy
()
*
v1beta1
.
FailurePolicyType
{
return
v
.
FailurePolicy
}
func
(
v
validatingWebhookAccessor
)
GetMatchPolicy
()
*
v1beta1
.
MatchPolicyType
{
return
v
.
MatchPolicy
}
func
(
v
validatingWebhookAccessor
)
GetNamespaceSelector
()
*
metav1
.
LabelSelector
{
return
v
.
NamespaceSelector
}
func
(
v
validatingWebhookAccessor
)
GetSideEffects
()
*
v1beta1
.
SideEffectClass
{
return
v
.
SideEffects
}
func
(
v
validatingWebhookAccessor
)
GetTimeoutSeconds
()
*
int32
{
return
v
.
TimeoutSeconds
}
func
(
v
validatingWebhookAccessor
)
GetAdmissionReviewVersions
()
[]
string
{
return
v
.
AdmissionReviewVersions
}
func
(
v
validatingWebhookAccessor
)
GetMutatingWebhook
()
(
*
v1beta1
.
MutatingWebhook
,
bool
)
{
return
nil
,
false
}
func
(
v
validatingWebhookAccessor
)
GetValidatingWebhook
()
(
*
v1beta1
.
ValidatingWebhook
,
bool
)
{
return
v
.
ValidatingWebhook
,
true
}
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/BUILD
View file @
55ecc454
...
...
@@ -18,6 +18,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission/initializer:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/rules:go_default_library",
...
...
@@ -56,6 +57,7 @@ go_test(
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/apis/example:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/apis/example/v1:go_default_library",
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/interfaces.go
View file @
55ecc454
...
...
@@ -19,15 +19,15 @@ package generic
import
(
"context"
"k8s.io/api/admissionregistration/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/admission/plugin/webhook"
)
// Source can list dynamic webhook plugins.
type
Source
interface
{
Webhooks
()
[]
v1beta1
.
Webhook
Webhooks
()
[]
webhook
.
WebhookAccessor
HasSynced
()
bool
}
...
...
@@ -51,8 +51,7 @@ type VersionedAttributes struct {
// WebhookInvocation describes how to call a webhook, including the resource and subresource the webhook registered for,
// and the kind that should be sent to the webhook.
type
WebhookInvocation
struct
{
Webhook
*
v1beta1
.
Webhook
Webhook
webhook
.
WebhookAccessor
Resource
schema
.
GroupVersionResource
Subresource
string
Kind
schema
.
GroupVersionKind
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook.go
View file @
55ecc454
...
...
@@ -27,10 +27,11 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/admission"
genericadmissioninit
"k8s.io/apiserver/pkg/admission/initializer"
"k8s.io/apiserver/pkg/admission/plugin/webhook"
"k8s.io/apiserver/pkg/admission/plugin/webhook/config"
"k8s.io/apiserver/pkg/admission/plugin/webhook/namespace"
"k8s.io/apiserver/pkg/admission/plugin/webhook/rules"
"k8s.io/apiserver/pkg/util/webhook"
webhookutil
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/client-go/informers"
clientset
"k8s.io/client-go/kubernetes"
)
...
...
@@ -42,7 +43,7 @@ type Webhook struct {
sourceFactory
sourceFactory
hookSource
Source
clientManager
*
webhook
.
ClientManager
clientManager
*
webhook
util
.
ClientManager
namespaceMatcher
*
namespace
.
Matcher
dispatcher
Dispatcher
}
...
...
@@ -53,7 +54,7 @@ var (
)
type
sourceFactory
func
(
f
informers
.
SharedInformerFactory
)
Source
type
dispatcherFactory
func
(
cm
*
webhook
.
ClientManager
)
Dispatcher
type
dispatcherFactory
func
(
cm
*
webhook
util
.
ClientManager
)
Dispatcher
// NewWebhook creates a new generic admission webhook.
func
NewWebhook
(
handler
*
admission
.
Handler
,
configFile
io
.
Reader
,
sourceFactory
sourceFactory
,
dispatcherFactory
dispatcherFactory
)
(
*
Webhook
,
error
)
{
...
...
@@ -62,17 +63,17 @@ func NewWebhook(handler *admission.Handler, configFile io.Reader, sourceFactory
return
nil
,
err
}
cm
,
err
:=
webhook
.
NewClientManager
(
admissionv1beta1
.
SchemeGroupVersion
,
admissionv1beta1
.
AddToScheme
)
cm
,
err
:=
webhook
util
.
NewClientManager
(
admissionv1beta1
.
SchemeGroupVersion
,
admissionv1beta1
.
AddToScheme
)
if
err
!=
nil
{
return
nil
,
err
}
authInfoResolver
,
err
:=
webhook
.
NewDefaultAuthenticationInfoResolver
(
kubeconfigFile
)
authInfoResolver
,
err
:=
webhook
util
.
NewDefaultAuthenticationInfoResolver
(
kubeconfigFile
)
if
err
!=
nil
{
return
nil
,
err
}
// Set defaults which may be overridden later.
cm
.
SetAuthenticationInfoResolver
(
authInfoResolver
)
cm
.
SetServiceResolver
(
webhook
.
NewDefaultServiceResolver
())
cm
.
SetServiceResolver
(
webhook
util
.
NewDefaultServiceResolver
())
return
&
Webhook
{
Handler
:
handler
,
...
...
@@ -86,13 +87,13 @@ func NewWebhook(handler *admission.Handler, configFile io.Reader, sourceFactory
// SetAuthenticationInfoResolverWrapper sets the
// AuthenticationInfoResolverWrapper.
// TODO find a better way wire this, but keep this pull small for now.
func
(
a
*
Webhook
)
SetAuthenticationInfoResolverWrapper
(
wrapper
webhook
.
AuthenticationInfoResolverWrapper
)
{
func
(
a
*
Webhook
)
SetAuthenticationInfoResolverWrapper
(
wrapper
webhook
util
.
AuthenticationInfoResolverWrapper
)
{
a
.
clientManager
.
SetAuthenticationInfoResolverWrapper
(
wrapper
)
}
// SetServiceResolver sets a service resolver for the webhook admission plugin.
// Passing a nil resolver does not have an effect, instead a default one will be used.
func
(
a
*
Webhook
)
SetServiceResolver
(
sr
webhook
.
ServiceResolver
)
{
func
(
a
*
Webhook
)
SetServiceResolver
(
sr
webhook
util
.
ServiceResolver
)
{
a
.
clientManager
.
SetServiceResolver
(
sr
)
}
...
...
@@ -128,10 +129,10 @@ func (a *Webhook) ValidateInitialization() error {
// shouldCallHook returns invocation details if the webhook should be called, nil if the webhook should not be called,
// or an error if an error was encountered during evaluation.
func
(
a
*
Webhook
)
shouldCallHook
(
h
*
v1beta1
.
Webhook
,
attr
admission
.
Attributes
,
o
admission
.
ObjectInterfaces
)
(
*
WebhookInvocation
,
*
apierrors
.
StatusError
)
{
func
(
a
*
Webhook
)
shouldCallHook
(
h
webhook
.
WebhookAccessor
,
attr
admission
.
Attributes
,
o
admission
.
ObjectInterfaces
)
(
*
WebhookInvocation
,
*
apierrors
.
StatusError
)
{
var
err
*
apierrors
.
StatusError
var
invocation
*
WebhookInvocation
for
_
,
r
:=
range
h
.
Rules
{
for
_
,
r
:=
range
h
.
GetRules
()
{
m
:=
rules
.
Matcher
{
Rule
:
r
,
Attr
:
attr
}
if
m
.
Matches
()
{
invocation
=
&
WebhookInvocation
{
...
...
@@ -143,12 +144,12 @@ func (a *Webhook) shouldCallHook(h *v1beta1.Webhook, attr admission.Attributes,
break
}
}
if
invocation
==
nil
&&
h
.
MatchPolicy
!=
nil
&&
*
h
.
MatchPolicy
==
v1beta1
.
Equivalent
{
if
invocation
==
nil
&&
h
.
GetMatchPolicy
()
!=
nil
&&
*
h
.
GetMatchPolicy
()
==
v1beta1
.
Equivalent
{
attrWithOverride
:=
&
attrWithResourceOverride
{
Attributes
:
attr
}
equivalents
:=
o
.
GetEquivalentResourceMapper
()
.
EquivalentResourcesFor
(
attr
.
GetResource
(),
attr
.
GetSubresource
())
// honor earlier rules first
OuterLoop
:
for
_
,
r
:=
range
h
.
Rules
{
for
_
,
r
:=
range
h
.
GetRules
()
{
// see if the rule matches any of the equivalent resources
for
_
,
equivalent
:=
range
equivalents
{
if
equivalent
==
attr
.
GetResource
()
{
...
...
@@ -207,7 +208,7 @@ func (a *Webhook) Dispatch(attr admission.Attributes, o admission.ObjectInterfac
var
relevantHooks
[]
*
WebhookInvocation
for
i
:=
range
hooks
{
invocation
,
err
:=
a
.
shouldCallHook
(
&
hooks
[
i
],
attr
,
o
)
invocation
,
err
:=
a
.
shouldCallHook
(
hooks
[
i
],
attr
,
o
)
if
err
!=
nil
{
return
err
}
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook_test.go
View file @
55ecc454
...
...
@@ -25,6 +25,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/admission/plugin/webhook"
"k8s.io/apiserver/pkg/admission/plugin/webhook/namespace"
)
...
...
@@ -61,7 +62,7 @@ func TestShouldCallHook(t *testing.T) {
testcases
:=
[]
struct
{
name
string
webhook
*
v1beta1
.
Webhook
webhook
*
v1beta1
.
Validating
Webhook
attrs
admission
.
Attributes
expectCall
bool
...
...
@@ -72,13 +73,13 @@ func TestShouldCallHook(t *testing.T) {
}{
{
name
:
"no rules (just write)"
,
webhook
:
&
v1beta1
.
Webhook
{
Rules
:
[]
v1beta1
.
RuleWithOperations
{}},
webhook
:
&
v1beta1
.
Validating
Webhook
{
Rules
:
[]
v1beta1
.
RuleWithOperations
{}},
attrs
:
admission
.
NewAttributesRecord
(
nil
,
nil
,
schema
.
GroupVersionKind
{
"apps"
,
"v1"
,
"Deployment"
},
"ns"
,
"name"
,
schema
.
GroupVersionResource
{
"apps"
,
"v1"
,
"deployments"
},
""
,
admission
.
Create
,
&
metav1
.
CreateOptions
{},
false
,
nil
),
expectCall
:
false
,
},
{
name
:
"invalid kind lookup"
,
webhook
:
&
v1beta1
.
Webhook
{
webhook
:
&
v1beta1
.
Validating
Webhook
{
NamespaceSelector
:
&
metav1
.
LabelSelector
{},
MatchPolicy
:
&
equivalentMatch
,
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -91,7 +92,7 @@ func TestShouldCallHook(t *testing.T) {
},
{
name
:
"wildcard rule, match as requested"
,
webhook
:
&
v1beta1
.
Webhook
{
webhook
:
&
v1beta1
.
Validating
Webhook
{
NamespaceSelector
:
&
metav1
.
LabelSelector
{},
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
Operations
:
[]
v1beta1
.
OperationType
{
"*"
},
...
...
@@ -105,7 +106,7 @@ func TestShouldCallHook(t *testing.T) {
},
{
name
:
"specific rules, prefer exact match"
,
webhook
:
&
v1beta1
.
Webhook
{
webhook
:
&
v1beta1
.
Validating
Webhook
{
NamespaceSelector
:
&
metav1
.
LabelSelector
{},
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
Operations
:
[]
v1beta1
.
OperationType
{
"*"
},
...
...
@@ -125,7 +126,7 @@ func TestShouldCallHook(t *testing.T) {
},
{
name
:
"specific rules, match miss"
,
webhook
:
&
v1beta1
.
Webhook
{
webhook
:
&
v1beta1
.
Validating
Webhook
{
NamespaceSelector
:
&
metav1
.
LabelSelector
{},
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
Operations
:
[]
v1beta1
.
OperationType
{
"*"
},
...
...
@@ -139,7 +140,7 @@ func TestShouldCallHook(t *testing.T) {
},
{
name
:
"specific rules, exact match miss"
,
webhook
:
&
v1beta1
.
Webhook
{
webhook
:
&
v1beta1
.
Validating
Webhook
{
MatchPolicy
:
&
exactMatch
,
NamespaceSelector
:
&
metav1
.
LabelSelector
{},
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -154,7 +155,7 @@ func TestShouldCallHook(t *testing.T) {
},
{
name
:
"specific rules, equivalent match, prefer extensions"
,
webhook
:
&
v1beta1
.
Webhook
{
webhook
:
&
v1beta1
.
Validating
Webhook
{
MatchPolicy
:
&
equivalentMatch
,
NamespaceSelector
:
&
metav1
.
LabelSelector
{},
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -172,7 +173,7 @@ func TestShouldCallHook(t *testing.T) {
},
{
name
:
"specific rules, equivalent match, prefer apps"
,
webhook
:
&
v1beta1
.
Webhook
{
webhook
:
&
v1beta1
.
Validating
Webhook
{
MatchPolicy
:
&
equivalentMatch
,
NamespaceSelector
:
&
metav1
.
LabelSelector
{},
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -191,7 +192,7 @@ func TestShouldCallHook(t *testing.T) {
{
name
:
"specific rules, subresource prefer exact match"
,
webhook
:
&
v1beta1
.
Webhook
{
webhook
:
&
v1beta1
.
Validating
Webhook
{
NamespaceSelector
:
&
metav1
.
LabelSelector
{},
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
Operations
:
[]
v1beta1
.
OperationType
{
"*"
},
...
...
@@ -211,7 +212,7 @@ func TestShouldCallHook(t *testing.T) {
},
{
name
:
"specific rules, subresource match miss"
,
webhook
:
&
v1beta1
.
Webhook
{
webhook
:
&
v1beta1
.
Validating
Webhook
{
NamespaceSelector
:
&
metav1
.
LabelSelector
{},
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
Operations
:
[]
v1beta1
.
OperationType
{
"*"
},
...
...
@@ -225,7 +226,7 @@ func TestShouldCallHook(t *testing.T) {
},
{
name
:
"specific rules, subresource exact match miss"
,
webhook
:
&
v1beta1
.
Webhook
{
webhook
:
&
v1beta1
.
Validating
Webhook
{
MatchPolicy
:
&
exactMatch
,
NamespaceSelector
:
&
metav1
.
LabelSelector
{},
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -240,7 +241,7 @@ func TestShouldCallHook(t *testing.T) {
},
{
name
:
"specific rules, subresource equivalent match, prefer extensions"
,
webhook
:
&
v1beta1
.
Webhook
{
webhook
:
&
v1beta1
.
Validating
Webhook
{
MatchPolicy
:
&
equivalentMatch
,
NamespaceSelector
:
&
metav1
.
LabelSelector
{},
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -258,7 +259,7 @@ func TestShouldCallHook(t *testing.T) {
},
{
name
:
"specific rules, subresource equivalent match, prefer apps"
,
webhook
:
&
v1beta1
.
Webhook
{
webhook
:
&
v1beta1
.
Validating
Webhook
{
MatchPolicy
:
&
equivalentMatch
,
NamespaceSelector
:
&
metav1
.
LabelSelector
{},
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -278,7 +279,7 @@ func TestShouldCallHook(t *testing.T) {
for
_
,
testcase
:=
range
testcases
{
t
.
Run
(
testcase
.
name
,
func
(
t
*
testing
.
T
)
{
invocation
,
err
:=
a
.
shouldCallHook
(
testcase
.
webhook
,
testcase
.
attrs
,
interfaces
)
invocation
,
err
:=
a
.
shouldCallHook
(
webhook
.
NewValidatingWebhookAccessor
(
testcase
.
webhook
)
,
testcase
.
attrs
,
interfaces
)
if
err
!=
nil
{
if
len
(
testcase
.
expectErr
)
==
0
{
t
.
Fatal
(
err
)
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/dispatcher.go
View file @
55ecc454
...
...
@@ -39,16 +39,16 @@ import (
"k8s.io/apiserver/pkg/admission/plugin/webhook/generic"
"k8s.io/apiserver/pkg/admission/plugin/webhook/request"
"k8s.io/apiserver/pkg/admission/plugin/webhook/util"
"k8s.io/apiserver/pkg/util/webhook"
webhookutil
"k8s.io/apiserver/pkg/util/webhook"
)
type
mutatingDispatcher
struct
{
cm
*
webhook
.
ClientManager
cm
*
webhook
util
.
ClientManager
plugin
*
Plugin
}
func
newMutatingDispatcher
(
p
*
Plugin
)
func
(
cm
*
webhook
.
ClientManager
)
generic
.
Dispatcher
{
return
func
(
cm
*
webhook
.
ClientManager
)
generic
.
Dispatcher
{
func
newMutatingDispatcher
(
p
*
Plugin
)
func
(
cm
*
webhook
util
.
ClientManager
)
generic
.
Dispatcher
{
return
func
(
cm
*
webhook
util
.
ClientManager
)
generic
.
Dispatcher
{
return
&
mutatingDispatcher
{
cm
,
p
}
}
}
...
...
@@ -58,7 +58,10 @@ var _ generic.Dispatcher = &mutatingDispatcher{}
func
(
a
*
mutatingDispatcher
)
Dispatch
(
ctx
context
.
Context
,
attr
admission
.
Attributes
,
o
admission
.
ObjectInterfaces
,
relevantHooks
[]
*
generic
.
WebhookInvocation
)
error
{
var
versionedAttr
*
generic
.
VersionedAttributes
for
_
,
invocation
:=
range
relevantHooks
{
hook
:=
invocation
.
Webhook
hook
,
ok
:=
invocation
.
Webhook
.
GetMutatingWebhook
()
if
!
ok
{
return
fmt
.
Errorf
(
"mutating webhook dispatch requires v1beta1.MutatingWebhook, but got %T"
,
hook
)
}
if
versionedAttr
==
nil
{
// First webhook, create versioned attributes
var
err
error
...
...
@@ -73,14 +76,14 @@ func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr admission.Attrib
}
t
:=
time
.
Now
()
err
:=
a
.
callAttrMutatingHook
(
ctx
,
invocation
,
versionedAttr
,
o
)
err
:=
a
.
callAttrMutatingHook
(
ctx
,
hook
,
invocation
,
versionedAttr
,
o
)
admissionmetrics
.
Metrics
.
ObserveWebhook
(
time
.
Since
(
t
),
err
!=
nil
,
versionedAttr
.
Attributes
,
"admit"
,
hook
.
Name
)
if
err
==
nil
{
continue
}
ignoreClientCallFailures
:=
hook
.
FailurePolicy
!=
nil
&&
*
hook
.
FailurePolicy
==
v1beta1
.
Ignore
if
callErr
,
ok
:=
err
.
(
*
webhook
.
ErrCallingWebhook
);
ok
{
if
callErr
,
ok
:=
err
.
(
*
webhook
util
.
ErrCallingWebhook
);
ok
{
if
ignoreClientCallFailures
{
klog
.
Warningf
(
"Failed calling webhook, failing open %v: %v"
,
hook
.
Name
,
callErr
)
utilruntime
.
HandleError
(
callErr
)
...
...
@@ -100,11 +103,11 @@ func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr admission.Attrib
}
// note that callAttrMutatingHook updates attr
func
(
a
*
mutatingDispatcher
)
callAttrMutatingHook
(
ctx
context
.
Context
,
invocation
*
generic
.
WebhookInvocation
,
attr
*
generic
.
VersionedAttributes
,
o
admission
.
ObjectInterfaces
)
error
{
h
:=
invocation
.
Webhook
func
(
a
*
mutatingDispatcher
)
callAttrMutatingHook
(
ctx
context
.
Context
,
h
*
v1beta1
.
MutatingWebhook
,
invocation
*
generic
.
WebhookInvocation
,
attr
*
generic
.
VersionedAttributes
,
o
admission
.
ObjectInterfaces
)
error
{
if
attr
.
Attributes
.
IsDryRun
()
{
if
h
.
SideEffects
==
nil
{
return
&
webhook
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"Webhook SideEffects is nil"
)}
return
&
webhook
util
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"Webhook SideEffects is nil"
)}
}
if
!
(
*
h
.
SideEffects
==
v1beta1
.
SideEffectClassNone
||
*
h
.
SideEffects
==
v1beta1
.
SideEffectClassNoneOnDryRun
)
{
return
webhookerrors
.
NewDryRunUnsupportedErr
(
h
.
Name
)
...
...
@@ -113,15 +116,15 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, invocatio
// Currently dispatcher only supports `v1beta1` AdmissionReview
// TODO: Make the dispatcher capable of sending multiple AdmissionReview versions
if
!
util
.
HasAdmissionReviewVersion
(
v1beta1
.
SchemeGroupVersion
.
Version
,
h
)
{
return
&
webhook
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"webhook does not accept v1beta1 AdmissionReview"
)}
if
!
util
.
HasAdmissionReviewVersion
(
v1beta1
.
SchemeGroupVersion
.
Version
,
invocation
.
Webhook
)
{
return
&
webhook
util
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"webhook does not accept v1beta1 AdmissionReview"
)}
}
// Make the webhook request
request
:=
request
.
CreateAdmissionReview
(
attr
,
invocation
)
client
,
err
:=
a
.
cm
.
HookClient
(
util
.
HookClientConfigForWebhook
(
h
))
client
,
err
:=
a
.
cm
.
HookClient
(
util
.
HookClientConfigForWebhook
(
invocation
.
Webhook
))
if
err
!=
nil
{
return
&
webhook
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
return
&
webhook
util
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
}
response
:=
&
admissionv1beta1
.
AdmissionReview
{}
r
:=
client
.
Post
()
.
Context
(
ctx
)
.
Body
(
&
request
)
...
...
@@ -129,11 +132,11 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, invocatio
r
=
r
.
Timeout
(
time
.
Duration
(
*
h
.
TimeoutSeconds
)
*
time
.
Second
)
}
if
err
:=
r
.
Do
()
.
Into
(
response
);
err
!=
nil
{
return
&
webhook
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
return
&
webhook
util
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
}
if
response
.
Response
==
nil
{
return
&
webhook
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"Webhook response was absent"
)}
return
&
webhook
util
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"Webhook response was absent"
)}
}
for
k
,
v
:=
range
response
.
Response
.
AuditAnnotations
{
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/plugin_test.go
View file @
55ecc454
...
...
@@ -46,7 +46,7 @@ func TestAdmit(t *testing.T) {
defer
close
(
stopCh
)
testCases
:=
append
(
webhooktesting
.
NewMutatingTestCases
(
serverURL
),
webhooktesting
.
NewNonMutatingTestCases
(
serverURL
)
...
)
webhooktesting
.
ConvertToMutatingTestCases
(
webhooktesting
.
NewNonMutatingTestCases
(
serverURL
)
)
...
)
for
_
,
tt
:=
range
testCases
{
wh
,
err
:=
NewMutatingWebhook
(
nil
)
...
...
@@ -56,7 +56,7 @@ func TestAdmit(t *testing.T) {
}
ns
:=
"webhook-test"
client
,
informer
:=
webhooktesting
.
NewFake
DataSource
(
ns
,
tt
.
Webhooks
,
true
,
stopCh
)
client
,
informer
:=
webhooktesting
.
NewFake
MutatingDataSource
(
ns
,
tt
.
Webhooks
,
stopCh
)
wh
.
SetAuthenticationInfoResolverWrapper
(
webhooktesting
.
Wrapper
(
webhooktesting
.
NewAuthenticationInfoResolver
(
new
(
int32
))))
wh
.
SetServiceResolver
(
webhooktesting
.
NewServiceResolver
(
*
serverURL
))
...
...
@@ -136,7 +136,7 @@ func TestAdmitCachedClient(t *testing.T) {
for
_
,
tt
:=
range
webhooktesting
.
NewCachedClientTestcases
(
serverURL
)
{
ns
:=
"webhook-test"
client
,
informer
:=
webhooktesting
.
NewFake
DataSource
(
ns
,
tt
.
Webhooks
,
true
,
stopCh
)
client
,
informer
:=
webhooktesting
.
NewFake
MutatingDataSource
(
ns
,
webhooktesting
.
ConvertToMutatingWebhooks
(
tt
.
Webhooks
)
,
stopCh
)
// override the webhook source. The client cache will stay the same.
cacheMisses
:=
new
(
int32
)
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/BUILD
View file @
55ecc454
...
...
@@ -10,13 +10,13 @@ go_library(
importpath = "k8s.io/apiserver/pkg/admission/plugin/webhook/namespace",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/api/admissionregistration/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/listers/core/v1:go_default_library",
],
...
...
@@ -34,6 +34,7 @@ go_test(
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook:go_default_library",
],
)
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/matcher.go
View file @
55ecc454
...
...
@@ -19,13 +19,13 @@ package namespace
import
(
"fmt"
"k8s.io/api/admissionregistration/v1beta1"
apierrors
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
utilerrors
"k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/admission/plugin/webhook"
clientset
"k8s.io/client-go/kubernetes"
corelisters
"k8s.io/client-go/listers/core/v1"
)
...
...
@@ -86,7 +86,7 @@ func (m *Matcher) GetNamespaceLabels(attr admission.Attributes) (map[string]stri
// MatchNamespaceSelector decideds whether the request matches the
// namespaceSelctor of the webhook. Only when they match, the webhook is called.
func
(
m
*
Matcher
)
MatchNamespaceSelector
(
h
*
v1beta1
.
Webhook
,
attr
admission
.
Attributes
)
(
bool
,
*
apierrors
.
StatusError
)
{
func
(
m
*
Matcher
)
MatchNamespaceSelector
(
h
webhook
.
WebhookAccessor
,
attr
admission
.
Attributes
)
(
bool
,
*
apierrors
.
StatusError
)
{
namespaceName
:=
attr
.
GetNamespace
()
if
len
(
namespaceName
)
==
0
&&
attr
.
GetResource
()
.
Resource
!=
"namespaces"
{
// If the request is about a cluster scoped resource, and it is not a
...
...
@@ -96,7 +96,7 @@ func (m *Matcher) MatchNamespaceSelector(h *v1beta1.Webhook, attr admission.Attr
return
true
,
nil
}
// TODO: adding an LRU cache to cache the translation
selector
,
err
:=
metav1
.
LabelSelectorAsSelector
(
h
.
NamespaceSelector
)
selector
,
err
:=
metav1
.
LabelSelectorAsSelector
(
h
.
GetNamespaceSelector
()
)
if
err
!=
nil
{
return
false
,
apierrors
.
NewInternalError
(
err
)
}
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/matcher_test.go
View file @
55ecc454
...
...
@@ -27,6 +27,7 @@ import (
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/admission/plugin/webhook"
)
type
fakeNamespaceLister
struct
{
...
...
@@ -114,12 +115,12 @@ func TestGetNamespaceLabels(t *testing.T) {
}
func
TestNotExemptClusterScopedResource
(
t
*
testing
.
T
)
{
hook
:=
&
registrationv1beta1
.
Webhook
{
hook
:=
&
registrationv1beta1
.
Validating
Webhook
{
NamespaceSelector
:
&
metav1
.
LabelSelector
{},
}
attr
:=
admission
.
NewAttributesRecord
(
nil
,
nil
,
schema
.
GroupVersionKind
{},
""
,
"mock-name"
,
schema
.
GroupVersionResource
{
Version
:
"v1"
,
Resource
:
"nodes"
},
""
,
admission
.
Create
,
&
metav1
.
CreateOptions
{},
false
,
nil
)
matcher
:=
Matcher
{}
matches
,
err
:=
matcher
.
MatchNamespaceSelector
(
hook
,
attr
)
matches
,
err
:=
matcher
.
MatchNamespaceSelector
(
webhook
.
NewValidatingWebhookAccessor
(
hook
)
,
attr
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/testcase.go
View file @
55ecc454
This diff is collapsed.
Click to expand it.
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/util/BUILD
View file @
55ecc454
...
...
@@ -7,7 +7,7 @@ go_library(
importpath = "k8s.io/apiserver/pkg/admission/plugin/webhook/util",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/api
/admissionregistration/v1beta1
:go_default_library",
"//staging/src/k8s.io/api
server/pkg/admission/plugin/webhook
:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library",
],
)
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/util/client_config.go
View file @
55ecc454
...
...
@@ -17,38 +17,39 @@ limitations under the License.
package
util
import
(
"k8s.io/api
/admissionregistration/v1beta1
"
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/api
server/pkg/admission/plugin/webhook
"
webhookutil
"k8s.io/apiserver/pkg/util/webhook"
)
// HookClientConfigForWebhook construct a webhook.ClientConfig using a v1beta1.Webhook API object.
// webhook.ClientConfig is used to create a HookClient and the purpose of the config struct is to
// share that with other packages that need to create a HookClient.
func
HookClientConfigForWebhook
(
w
*
v1beta1
.
Webhook
)
webhook
.
ClientConfig
{
ret
:=
webhook
.
ClientConfig
{
Name
:
w
.
Name
,
CABundle
:
w
.
ClientConfig
.
CABundle
}
if
w
.
ClientConfig
.
URL
!=
nil
{
ret
.
URL
=
*
w
.
ClientConfig
.
URL
// HookClientConfigForWebhook construct a webhookutil.ClientConfig using a WebhookAccessor to access
// v1beta1.MutatingWebhook and v1beta1.ValidatingWebhook API objects. webhookutil.ClientConfig is used
// to create a HookClient and the purpose of the config struct is to share that with other packages
// that need to create a HookClient.
func
HookClientConfigForWebhook
(
w
webhook
.
WebhookAccessor
)
webhookutil
.
ClientConfig
{
ret
:=
webhookutil
.
ClientConfig
{
Name
:
w
.
GetName
(),
CABundle
:
w
.
GetClientConfig
()
.
CABundle
}
if
w
.
GetClientConfig
()
.
URL
!=
nil
{
ret
.
URL
=
*
w
.
GetClientConfig
()
.
URL
}
if
w
.
ClientConfig
.
Service
!=
nil
{
ret
.
Service
=
&
webhook
.
ClientConfigService
{
Name
:
w
.
ClientConfig
.
Service
.
Name
,
Namespace
:
w
.
ClientConfig
.
Service
.
Namespace
,
if
w
.
GetClientConfig
()
.
Service
!=
nil
{
ret
.
Service
=
&
webhook
util
.
ClientConfigService
{
Name
:
w
.
GetClientConfig
()
.
Service
.
Name
,
Namespace
:
w
.
GetClientConfig
()
.
Service
.
Namespace
,
}
if
w
.
ClientConfig
.
Service
.
Port
!=
nil
{
ret
.
Service
.
Port
=
*
w
.
ClientConfig
.
Service
.
Port
if
w
.
GetClientConfig
()
.
Service
.
Port
!=
nil
{
ret
.
Service
.
Port
=
*
w
.
GetClientConfig
()
.
Service
.
Port
}
else
{
ret
.
Service
.
Port
=
443
}
if
w
.
ClientConfig
.
Service
.
Path
!=
nil
{
ret
.
Service
.
Path
=
*
w
.
ClientConfig
.
Service
.
Path
if
w
.
GetClientConfig
()
.
Service
.
Path
!=
nil
{
ret
.
Service
.
Path
=
*
w
.
GetClientConfig
()
.
Service
.
Path
}
}
return
ret
}
// HasAdmissionReviewVersion check whether a version is accepted by a given webhook.
func
HasAdmissionReviewVersion
(
a
string
,
w
*
v1beta1
.
Webhook
)
bool
{
for
_
,
b
:=
range
w
.
AdmissionReviewVersions
{
func
HasAdmissionReviewVersion
(
a
string
,
w
webhook
.
WebhookAccessor
)
bool
{
for
_
,
b
:=
range
w
.
GetAdmissionReviewVersions
()
{
if
b
==
a
{
return
true
}
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/dispatcher.go
View file @
55ecc454
...
...
@@ -22,8 +22,6 @@ import (
"sync"
"time"
"k8s.io/klog"
admissionv1beta1
"k8s.io/api/admission/v1beta1"
"k8s.io/api/admissionregistration/v1beta1"
apierrors
"k8s.io/apimachinery/pkg/api/errors"
...
...
@@ -35,14 +33,15 @@ import (
"k8s.io/apiserver/pkg/admission/plugin/webhook/generic"
"k8s.io/apiserver/pkg/admission/plugin/webhook/request"
"k8s.io/apiserver/pkg/admission/plugin/webhook/util"
"k8s.io/apiserver/pkg/util/webhook"
webhookutil
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/klog"
)
type
validatingDispatcher
struct
{
cm
*
webhook
.
ClientManager
cm
*
webhook
util
.
ClientManager
}
func
newValidatingDispatcher
(
cm
*
webhook
.
ClientManager
)
generic
.
Dispatcher
{
func
newValidatingDispatcher
(
cm
*
webhook
util
.
ClientManager
)
generic
.
Dispatcher
{
return
&
validatingDispatcher
{
cm
}
}
...
...
@@ -69,18 +68,21 @@ func (d *validatingDispatcher) Dispatch(ctx context.Context, attr admission.Attr
for
i
:=
range
relevantHooks
{
go
func
(
invocation
*
generic
.
WebhookInvocation
)
{
defer
wg
.
Done
()
hook
:=
invocation
.
Webhook
hook
,
ok
:=
invocation
.
Webhook
.
GetValidatingWebhook
()
if
!
ok
{
utilruntime
.
HandleError
(
fmt
.
Errorf
(
"validating webhook dispatch requires v1beta1.ValidatingWebhook, but got %T"
,
hook
))
return
}
versionedAttr
:=
versionedAttrs
[
invocation
.
Kind
]
t
:=
time
.
Now
()
err
:=
d
.
callHook
(
ctx
,
invocation
,
versionedAttr
)
err
:=
d
.
callHook
(
ctx
,
hook
,
invocation
,
versionedAttr
)
admissionmetrics
.
Metrics
.
ObserveWebhook
(
time
.
Since
(
t
),
err
!=
nil
,
versionedAttr
.
Attributes
,
"validating"
,
hook
.
Name
)
if
err
==
nil
{
return
}
ignoreClientCallFailures
:=
hook
.
FailurePolicy
!=
nil
&&
*
hook
.
FailurePolicy
==
v1beta1
.
Ignore
if
callErr
,
ok
:=
err
.
(
*
webhook
.
ErrCallingWebhook
);
ok
{
if
callErr
,
ok
:=
err
.
(
*
webhook
util
.
ErrCallingWebhook
);
ok
{
if
ignoreClientCallFailures
{
klog
.
Warningf
(
"Failed calling webhook, failing open %v: %v"
,
hook
.
Name
,
callErr
)
utilruntime
.
HandleError
(
callErr
)
...
...
@@ -115,11 +117,10 @@ func (d *validatingDispatcher) Dispatch(ctx context.Context, attr admission.Attr
return
errs
[
0
]
}
func
(
d
*
validatingDispatcher
)
callHook
(
ctx
context
.
Context
,
invocation
*
generic
.
WebhookInvocation
,
attr
*
generic
.
VersionedAttributes
)
error
{
h
:=
invocation
.
Webhook
func
(
d
*
validatingDispatcher
)
callHook
(
ctx
context
.
Context
,
h
*
v1beta1
.
ValidatingWebhook
,
invocation
*
generic
.
WebhookInvocation
,
attr
*
generic
.
VersionedAttributes
)
error
{
if
attr
.
Attributes
.
IsDryRun
()
{
if
h
.
SideEffects
==
nil
{
return
&
webhook
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"Webhook SideEffects is nil"
)}
return
&
webhook
util
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"Webhook SideEffects is nil"
)}
}
if
!
(
*
h
.
SideEffects
==
v1beta1
.
SideEffectClassNone
||
*
h
.
SideEffects
==
v1beta1
.
SideEffectClassNoneOnDryRun
)
{
return
webhookerrors
.
NewDryRunUnsupportedErr
(
h
.
Name
)
...
...
@@ -128,15 +129,15 @@ func (d *validatingDispatcher) callHook(ctx context.Context, invocation *generic
// Currently dispatcher only supports `v1beta1` AdmissionReview
// TODO: Make the dispatcher capable of sending multiple AdmissionReview versions
if
!
util
.
HasAdmissionReviewVersion
(
v1beta1
.
SchemeGroupVersion
.
Version
,
h
)
{
return
&
webhook
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"webhook does not accept v1beta1 AdmissionReviewRequest"
)}
if
!
util
.
HasAdmissionReviewVersion
(
v1beta1
.
SchemeGroupVersion
.
Version
,
invocation
.
Webhook
)
{
return
&
webhook
util
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"webhook does not accept v1beta1 AdmissionReviewRequest"
)}
}
// Make the webhook request
request
:=
request
.
CreateAdmissionReview
(
attr
,
invocation
)
client
,
err
:=
d
.
cm
.
HookClient
(
util
.
HookClientConfigForWebhook
(
h
))
client
,
err
:=
d
.
cm
.
HookClient
(
util
.
HookClientConfigForWebhook
(
invocation
.
Webhook
))
if
err
!=
nil
{
return
&
webhook
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
return
&
webhook
util
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
}
response
:=
&
admissionv1beta1
.
AdmissionReview
{}
r
:=
client
.
Post
()
.
Context
(
ctx
)
.
Body
(
&
request
)
...
...
@@ -144,11 +145,11 @@ func (d *validatingDispatcher) callHook(ctx context.Context, invocation *generic
r
=
r
.
Timeout
(
time
.
Duration
(
*
h
.
TimeoutSeconds
)
*
time
.
Second
)
}
if
err
:=
r
.
Do
()
.
Into
(
response
);
err
!=
nil
{
return
&
webhook
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
return
&
webhook
util
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
}
if
response
.
Response
==
nil
{
return
&
webhook
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"Webhook response was absent"
)}
return
&
webhook
util
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"Webhook response was absent"
)}
}
for
k
,
v
:=
range
response
.
Response
.
AuditAnnotations
{
key
:=
h
.
Name
+
"/"
+
k
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/plugin_test.go
View file @
55ecc454
...
...
@@ -51,7 +51,7 @@ func TestValidate(t *testing.T) {
}
ns
:=
"webhook-test"
client
,
informer
:=
webhooktesting
.
NewFake
DataSource
(
ns
,
tt
.
Webhooks
,
false
,
stopCh
)
client
,
informer
:=
webhooktesting
.
NewFake
ValidatingDataSource
(
ns
,
tt
.
Webhooks
,
stopCh
)
wh
.
SetAuthenticationInfoResolverWrapper
(
webhooktesting
.
Wrapper
(
webhooktesting
.
NewAuthenticationInfoResolver
(
new
(
int32
))))
wh
.
SetServiceResolver
(
webhooktesting
.
NewServiceResolver
(
*
serverURL
))
...
...
@@ -116,7 +116,7 @@ func TestValidateCachedClient(t *testing.T) {
for
_
,
tt
:=
range
webhooktesting
.
NewCachedClientTestcases
(
serverURL
)
{
ns
:=
"webhook-test"
client
,
informer
:=
webhooktesting
.
NewFake
DataSource
(
ns
,
tt
.
Webhooks
,
false
,
stopCh
)
client
,
informer
:=
webhooktesting
.
NewFake
ValidatingDataSource
(
ns
,
tt
.
Webhooks
,
stopCh
)
// override the webhook source. The client cache will stay the same.
cacheMisses
:=
new
(
int32
)
...
...
test/e2e/apimachinery/webhook.go
View file @
55ecc454
...
...
@@ -436,7 +436,7 @@ func registerWebhook(f *framework.Framework, context *certContext) func() {
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
configName
,
},
Webhooks
:
[]
v1beta1
.
Webhook
{
Webhooks
:
[]
v1beta1
.
Validating
Webhook
{
{
Name
:
"deny-unwanted-pod-container-name-and-label.k8s.io"
,
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -517,7 +517,7 @@ func registerWebhookForAttachingPod(f *framework.Framework, context *certContext
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
configName
,
},
Webhooks
:
[]
v1beta1
.
Webhook
{
Webhooks
:
[]
v1beta1
.
Validating
Webhook
{
{
Name
:
"deny-attaching-pod.k8s.io"
,
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -561,7 +561,7 @@ func registerMutatingWebhookForConfigMap(f *framework.Framework, context *certCo
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
configName
,
},
Webhooks
:
[]
v1beta1
.
Webhook
{
Webhooks
:
[]
v1beta1
.
Mutating
Webhook
{
{
Name
:
"adding-configmap-data-stage-1.k8s.io"
,
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -638,7 +638,7 @@ func registerMutatingWebhookForPod(f *framework.Framework, context *certContext)
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
configName
,
},
Webhooks
:
[]
v1beta1
.
Webhook
{
Webhooks
:
[]
v1beta1
.
Mutating
Webhook
{
{
Name
:
"adding-init-container.k8s.io"
,
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -841,8 +841,8 @@ func testAttachingPodWebhook(f *framework.Framework) {
// failingWebhook returns a webhook with rule of create configmaps,
// but with an invalid client config so that server cannot communicate with it
func
failingWebhook
(
namespace
,
name
string
)
v1beta1
.
Webhook
{
return
v1beta1
.
Webhook
{
func
failingWebhook
(
namespace
,
name
string
)
v1beta1
.
Validating
Webhook
{
return
v1beta1
.
Validating
Webhook
{
Name
:
name
,
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
Operations
:
[]
v1beta1
.
OperationType
{
v1beta1
.
Create
},
...
...
@@ -889,7 +889,7 @@ func registerFailClosedWebhook(f *framework.Framework, context *certContext) fun
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
configName
,
},
Webhooks
:
[]
v1beta1
.
Webhook
{
Webhooks
:
[]
v1beta1
.
Validating
Webhook
{
// Server cannot talk to this webhook, so it always fails.
// Because this webhook is configured fail-closed, request should be rejected after the call fails.
hook
,
...
...
@@ -945,7 +945,7 @@ func registerValidatingWebhookForWebhookConfigurations(f *framework.Framework, c
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
configName
,
},
Webhooks
:
[]
v1beta1
.
Webhook
{
Webhooks
:
[]
v1beta1
.
Validating
Webhook
{
{
Name
:
"deny-webhook-configuration-deletions.k8s.io"
,
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -998,7 +998,7 @@ func registerMutatingWebhookForWebhookConfigurations(f *framework.Framework, con
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
configName
,
},
Webhooks
:
[]
v1beta1
.
Webhook
{
Webhooks
:
[]
v1beta1
.
Mutating
Webhook
{
{
Name
:
"add-label-to-webhook-configurations.k8s.io"
,
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -1050,7 +1050,7 @@ func testWebhooksForWebhookConfigurations(f *framework.Framework) {
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
dummyValidatingWebhookConfigName
,
},
Webhooks
:
[]
v1beta1
.
Webhook
{
Webhooks
:
[]
v1beta1
.
Validating
Webhook
{
{
Name
:
"dummy-validating-webhook.k8s.io"
,
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -1098,7 +1098,7 @@ func testWebhooksForWebhookConfigurations(f *framework.Framework) {
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
dummyMutatingWebhookConfigName
,
},
Webhooks
:
[]
v1beta1
.
Webhook
{
Webhooks
:
[]
v1beta1
.
Mutating
Webhook
{
{
Name
:
"dummy-mutating-webhook.k8s.io"
,
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -1306,7 +1306,7 @@ func registerWebhookForCustomResource(f *framework.Framework, context *certConte
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
configName
,
},
Webhooks
:
[]
v1beta1
.
Webhook
{
Webhooks
:
[]
v1beta1
.
Validating
Webhook
{
{
Name
:
"deny-unwanted-custom-resource-data.k8s.io"
,
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -1348,7 +1348,7 @@ func registerMutatingWebhookForCustomResource(f *framework.Framework, context *c
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
configName
,
},
Webhooks
:
[]
v1beta1
.
Webhook
{
Webhooks
:
[]
v1beta1
.
Mutating
Webhook
{
{
Name
:
"mutate-custom-resource-data-stage-1.k8s.io"
,
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -1543,7 +1543,7 @@ func registerValidatingWebhookForCRD(f *framework.Framework, context *certContex
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
configName
,
},
Webhooks
:
[]
v1beta1
.
Webhook
{
Webhooks
:
[]
v1beta1
.
Validating
Webhook
{
{
Name
:
"deny-crd-with-unwanted-label.k8s.io"
,
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
@@ -1649,7 +1649,7 @@ func registerSlowWebhook(f *framework.Framework, context *certContext, policy *v
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
configName
,
},
Webhooks
:
[]
v1beta1
.
Webhook
{
Webhooks
:
[]
v1beta1
.
Validating
Webhook
{
{
Name
:
"allow-configmap-with-delay-webhook.k8s.io"
,
Rules
:
[]
v1beta1
.
RuleWithOperations
{{
...
...
test/integration/apiserver/admissionwebhook/admission_test.go
View file @
55ecc454
...
...
@@ -283,6 +283,9 @@ func (h *holder) record(phase string, converted bool, request *v1beta1.Admission
return
}
if
debug
{
h
.
t
.
Logf
(
"recording: %#v = %s %#v %v"
,
webhookOptions
{
phase
:
phase
,
converted
:
converted
},
request
.
Operation
,
request
.
Resource
,
request
.
SubResource
)
}
h
.
recorded
[
webhookOptions
{
phase
:
phase
,
converted
:
converted
}]
=
request
}
...
...
@@ -1287,7 +1290,7 @@ func createV1beta1ValidationWebhook(client clientset.Interface, endpoint, conver
// Attaching Admission webhook to API server
_
,
err
:=
client
.
AdmissionregistrationV1beta1
()
.
ValidatingWebhookConfigurations
()
.
Create
(
&
admissionv1beta1
.
ValidatingWebhookConfiguration
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"admission.integration.test"
},
Webhooks
:
[]
admissionv1beta1
.
Webhook
{
Webhooks
:
[]
admissionv1beta1
.
Validating
Webhook
{
{
Name
:
"admission.integration.test"
,
ClientConfig
:
admissionv1beta1
.
WebhookClientConfig
{
...
...
@@ -1323,7 +1326,7 @@ func createV1beta1MutationWebhook(client clientset.Interface, endpoint, converte
// Attaching Mutation webhook to API server
_
,
err
:=
client
.
AdmissionregistrationV1beta1
()
.
MutatingWebhookConfigurations
()
.
Create
(
&
admissionv1beta1
.
MutatingWebhookConfiguration
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"mutation.integration.test"
},
Webhooks
:
[]
admissionv1beta1
.
Webhook
{
Webhooks
:
[]
admissionv1beta1
.
Mutating
Webhook
{
{
Name
:
"mutation.integration.test"
,
ClientConfig
:
admissionv1beta1
.
WebhookClientConfig
{
...
...
test/integration/apiserver/admissionwebhook/broken_webhook_test.go
View file @
55ecc454
...
...
@@ -155,7 +155,7 @@ func brokenWebhookConfig(name string) *admissionregistrationv1beta1.ValidatingWe
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
name
,
},
Webhooks
:
[]
admissionregistrationv1beta1
.
Webhook
{
Webhooks
:
[]
admissionregistrationv1beta1
.
Validating
Webhook
{
{
Name
:
"broken-webhook.k8s.io"
,
Rules
:
[]
admissionregistrationv1beta1
.
RuleWithOperations
{{
...
...
test/integration/examples/webhook_test.go
View file @
55ecc454
...
...
@@ -22,7 +22,7 @@ import (
"time"
admissionv1beta1
"k8s.io/api/admissionregistration/v1beta1"
"k8s.io/api/core/v1"
v1
"k8s.io/api/core/v1"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
auditinternal
"k8s.io/apiserver/pkg/apis/audit"
...
...
@@ -65,7 +65,7 @@ func TestWebhookLoopback(t *testing.T) {
fail
:=
admissionv1beta1
.
Fail
_
,
err
:=
client
.
AdmissionregistrationV1beta1
()
.
MutatingWebhookConfigurations
()
.
Create
(
&
admissionv1beta1
.
MutatingWebhookConfiguration
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"webhooktest.example.com"
},
Webhooks
:
[]
admissionv1beta1
.
Webhook
{{
Webhooks
:
[]
admissionv1beta1
.
Mutating
Webhook
{{
Name
:
"webhooktest.example.com"
,
ClientConfig
:
admissionv1beta1
.
WebhookClientConfig
{
Service
:
&
admissionv1beta1
.
ServiceReference
{
Namespace
:
"default"
,
Name
:
"kubernetes"
,
Path
:
&
webhookPath
},
...
...
vendor/modules.txt
View file @
55ecc454
...
...
@@ -1184,6 +1184,7 @@ k8s.io/apiserver/pkg/admission/configuration
k8s.io/apiserver/pkg/admission/initializer
k8s.io/apiserver/pkg/admission/metrics
k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle
k8s.io/apiserver/pkg/admission/plugin/webhook
k8s.io/apiserver/pkg/admission/plugin/webhook/config
k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission
k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1alpha1
...
...
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