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
5652d5cf
Commit
5652d5cf
authored
Aug 26, 2018
by
Mehdy Bohlool
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor addmission webhook hook client to a util package
parent
5b2a7c73
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
136 additions
and
79 deletions
+136
-79
server.go
cmd/kube-apiserver/app/server.go
+4
-4
.golint_failures
hack/.golint_failures
+0
-1
initializer.go
pkg/kubeapiserver/admission/initializer.go
+3
-3
webhook.go
...apiserver/pkg/admission/plugin/webhook/generic/webhook.go
+9
-7
initializer.go
...r/pkg/admission/plugin/webhook/initializer/initializer.go
+7
-7
initializer_test.go
.../admission/plugin/webhook/initializer/initializer_test.go
+2
-2
dispatcher.go
...erver/pkg/admission/plugin/webhook/mutating/dispatcher.go
+11
-10
authentication_info_resolver.go
...on/plugin/webhook/testing/authentication_info_resolver.go
+4
-4
service_resolver.go
.../pkg/admission/plugin/webhook/testing/service_resolver.go
+2
-2
client_config.go
...server/pkg/admission/plugin/webhook/util/client_config.go
+42
-0
dispatcher.go
...ver/pkg/admission/plugin/webhook/validating/dispatcher.go
+10
-9
authentication.go
...g/src/k8s.io/apiserver/pkg/util/webhook/authentication.go
+3
-1
authentication_test.go
.../k8s.io/apiserver/pkg/util/webhook/authentication_test.go
+1
-1
client.go
staging/src/k8s.io/apiserver/pkg/util/webhook/client.go
+34
-25
error.go
staging/src/k8s.io/apiserver/pkg/util/webhook/error.go
+1
-1
serviceresolver.go
.../src/k8s.io/apiserver/pkg/util/webhook/serviceresolver.go
+2
-1
serviceresolver_test.go
...k8s.io/apiserver/pkg/util/webhook/serviceresolver_test.go
+1
-1
No files found.
cmd/kube-apiserver/app/server.go
View file @
5652d5cf
...
...
@@ -42,7 +42,6 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
utilwait
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/admission"
webhookconfig
"k8s.io/apiserver/pkg/admission/plugin/webhook/config"
webhookinit
"k8s.io/apiserver/pkg/admission/plugin/webhook/initializer"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authorization/authorizer"
...
...
@@ -54,6 +53,7 @@ import (
"k8s.io/apiserver/pkg/storage/etcd3/preflight"
utilfeature
"k8s.io/apiserver/pkg/util/feature"
apiserverflag
"k8s.io/apiserver/pkg/util/flag"
"k8s.io/apiserver/pkg/util/webhook"
cacheddiscovery
"k8s.io/client-go/discovery/cached"
clientgoinformers
"k8s.io/client-go/informers"
clientgoclientset
"k8s.io/client-go/kubernetes"
...
...
@@ -539,8 +539,8 @@ func buildGenericConfig(
genericConfig
.
DisabledPostStartHooks
.
Insert
(
rbacrest
.
PostStartHookName
)
}
webhookAuthResolverWrapper
:=
func
(
delegate
webhook
config
.
AuthenticationInfoResolver
)
webhookconfig
.
AuthenticationInfoResolver
{
return
&
webhook
config
.
AuthenticationInfoResolverDelegator
{
webhookAuthResolverWrapper
:=
func
(
delegate
webhook
.
AuthenticationInfoResolver
)
webhook
.
AuthenticationInfoResolver
{
return
&
webhook
.
AuthenticationInfoResolverDelegator
{
ClientConfigForFunc
:
func
(
server
string
)
(
*
rest
.
Config
,
error
)
{
if
server
==
"kubernetes.default.svc"
{
return
genericConfig
.
LoopbackClientConfig
,
nil
...
...
@@ -593,7 +593,7 @@ func BuildAdmissionPluginInitializers(
client
internalclientset
.
Interface
,
sharedInformers
informers
.
SharedInformerFactory
,
serviceResolver
aggregatorapiserver
.
ServiceResolver
,
webhookAuthWrapper
webhook
config
.
AuthenticationInfoResolverWrapper
,
webhookAuthWrapper
webhook
.
AuthenticationInfoResolverWrapper
,
)
([]
admission
.
PluginInitializer
,
genericapiserver
.
PostStartHookFunc
,
error
)
{
var
cloudConfig
[]
byte
...
...
hack/.golint_failures
View file @
5652d5cf
...
...
@@ -548,7 +548,6 @@ staging/src/k8s.io/apiserver/pkg/admission/configuration
staging/src/k8s.io/apiserver/pkg/admission/initializer
staging/src/k8s.io/apiserver/pkg/admission/plugin/initialization
staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/config
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/mutating
...
...
pkg/kubeapiserver/admission/initializer.go
View file @
5652d5cf
...
...
@@ -19,8 +19,8 @@ package admission
import
(
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apiserver/pkg/admission"
webhookconfig
"k8s.io/apiserver/pkg/admission/plugin/webhook/config"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
informers
"k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
"k8s.io/kubernetes/pkg/quota"
...
...
@@ -64,8 +64,8 @@ type PluginInitializer struct {
cloudConfig
[]
byte
restMapper
meta
.
RESTMapper
quotaConfiguration
quota
.
Configuration
serviceResolver
webhook
config
.
ServiceResolver
authenticationInfoResolverWrapper
webhook
config
.
AuthenticationInfoResolverWrapper
serviceResolver
webhook
.
ServiceResolver
authenticationInfoResolverWrapper
webhook
.
AuthenticationInfoResolverWrapper
}
var
_
admission
.
PluginInitializer
=
&
PluginInitializer
{}
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook.go
View file @
5652d5cf
...
...
@@ -21,6 +21,7 @@ import (
"fmt"
"io"
admissionv1beta1
"k8s.io/api/admission/v1beta1"
"k8s.io/api/admissionregistration/v1beta1"
apierrors
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
...
...
@@ -29,6 +30,7 @@ import (
"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"
"k8s.io/client-go/informers"
clientset
"k8s.io/client-go/kubernetes"
)
...
...
@@ -40,7 +42,7 @@ type Webhook struct {
sourceFactory
sourceFactory
hookSource
Source
clientManager
*
config
.
ClientManager
clientManager
*
webhook
.
ClientManager
convertor
*
convertor
namespaceMatcher
*
namespace
.
Matcher
dispatcher
Dispatcher
...
...
@@ -52,7 +54,7 @@ var (
)
type
sourceFactory
func
(
f
informers
.
SharedInformerFactory
)
Source
type
dispatcherFactory
func
(
cm
*
config
.
ClientManager
)
Dispatcher
type
dispatcherFactory
func
(
cm
*
webhook
.
ClientManager
)
Dispatcher
// NewWebhook creates a new generic admission webhook.
func
NewWebhook
(
handler
*
admission
.
Handler
,
configFile
io
.
Reader
,
sourceFactory
sourceFactory
,
dispatcherFactory
dispatcherFactory
)
(
*
Webhook
,
error
)
{
...
...
@@ -61,17 +63,17 @@ func NewWebhook(handler *admission.Handler, configFile io.Reader, sourceFactory
return
nil
,
err
}
cm
,
err
:=
config
.
NewClientManager
(
)
cm
,
err
:=
webhook
.
NewClientManager
(
admissionv1beta1
.
SchemeGroupVersion
,
admissionv1beta1
.
AddToScheme
)
if
err
!=
nil
{
return
nil
,
err
}
authInfoResolver
,
err
:=
config
.
NewDefaultAuthenticationInfoResolver
(
kubeconfigFile
)
authInfoResolver
,
err
:=
webhook
.
NewDefaultAuthenticationInfoResolver
(
kubeconfigFile
)
if
err
!=
nil
{
return
nil
,
err
}
// Set defaults which may be overridden later.
cm
.
SetAuthenticationInfoResolver
(
authInfoResolver
)
cm
.
SetServiceResolver
(
config
.
NewDefaultServiceResolver
())
cm
.
SetServiceResolver
(
webhook
.
NewDefaultServiceResolver
())
return
&
Webhook
{
Handler
:
handler
,
...
...
@@ -86,13 +88,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
config
.
AuthenticationInfoResolverWrapper
)
{
func
(
a
*
Webhook
)
SetAuthenticationInfoResolverWrapper
(
wrapper
webhook
.
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
config
.
ServiceResolver
)
{
func
(
a
*
Webhook
)
SetServiceResolver
(
sr
webhook
.
ServiceResolver
)
{
a
.
clientManager
.
SetServiceResolver
(
sr
)
}
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/initializer/initializer.go
View file @
5652d5cf
...
...
@@ -20,13 +20,13 @@ import (
"net/url"
"k8s.io/apiserver/pkg/admission"
webhookconfig
"k8s.io/apiserver/pkg/admission/plugin/webhook/config
"
"k8s.io/apiserver/pkg/util/webhook
"
)
// WantsServiceResolver defines a function that accepts a ServiceResolver for
// admission plugins that need to make calls to services.
type
WantsServiceResolver
interface
{
SetServiceResolver
(
webhook
config
.
ServiceResolver
)
SetServiceResolver
(
webhook
.
ServiceResolver
)
}
// ServiceResolver knows how to convert a service reference into an actual
...
...
@@ -38,22 +38,22 @@ type ServiceResolver interface {
// WantsAuthenticationInfoResolverWrapper defines a function that wraps the standard AuthenticationInfoResolver
// to allow the apiserver to control what is returned as auth info
type
WantsAuthenticationInfoResolverWrapper
interface
{
SetAuthenticationInfoResolverWrapper
(
w
ebhookconfig
.
AuthenticationInfoResolverWrapper
)
SetAuthenticationInfoResolverWrapper
(
w
rapper
webhook
.
AuthenticationInfoResolverWrapper
)
admission
.
InitializationValidator
}
// PluginInitializer is used for initialization of the webhook admission plugin.
type
PluginInitializer
struct
{
serviceResolver
webhook
config
.
ServiceResolver
authenticationInfoResolverWrapper
webhook
config
.
AuthenticationInfoResolverWrapper
serviceResolver
webhook
.
ServiceResolver
authenticationInfoResolverWrapper
webhook
.
AuthenticationInfoResolverWrapper
}
var
_
admission
.
PluginInitializer
=
&
PluginInitializer
{}
// NewPluginInitializer constructs new instance of PluginInitializer
func
NewPluginInitializer
(
authenticationInfoResolverWrapper
webhook
config
.
AuthenticationInfoResolverWrapper
,
serviceResolver
webhook
config
.
ServiceResolver
,
authenticationInfoResolverWrapper
webhook
.
AuthenticationInfoResolverWrapper
,
serviceResolver
webhook
.
ServiceResolver
,
)
*
PluginInitializer
{
return
&
PluginInitializer
{
authenticationInfoResolverWrapper
:
authenticationInfoResolverWrapper
,
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/initializer/initializer_test.go
View file @
5652d5cf
...
...
@@ -21,7 +21,7 @@ import (
"testing"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/
admission/plugin/webhook/config
"
"k8s.io/apiserver/pkg/
util/webhook
"
)
type
doNothingAdmission
struct
{}
...
...
@@ -39,7 +39,7 @@ type serviceWanter struct {
got
ServiceResolver
}
func
(
s
*
serviceWanter
)
SetServiceResolver
(
sr
config
.
ServiceResolver
)
{
s
.
got
=
sr
}
func
(
s
*
serviceWanter
)
SetServiceResolver
(
sr
webhook
.
ServiceResolver
)
{
s
.
got
=
sr
}
func
TestWantsServiceResolver
(
t
*
testing
.
T
)
{
sw
:=
&
serviceWanter
{}
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/dispatcher.go
View file @
5652d5cf
...
...
@@ -33,19 +33,20 @@ import (
"k8s.io/apimachinery/pkg/runtime"
utilruntime
"k8s.io/apimachinery/pkg/util/runtime"
admissionmetrics
"k8s.io/apiserver/pkg/admission/metrics"
"k8s.io/apiserver/pkg/admission/plugin/webhook/config"
webhookerrors
"k8s.io/apiserver/pkg/admission/plugin/webhook/errors"
"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"
)
type
mutatingDispatcher
struct
{
cm
*
config
.
ClientManager
cm
*
webhook
.
ClientManager
plugin
*
Plugin
}
func
newMutatingDispatcher
(
p
*
Plugin
)
func
(
cm
*
config
.
ClientManager
)
generic
.
Dispatcher
{
return
func
(
cm
*
config
.
ClientManager
)
generic
.
Dispatcher
{
func
newMutatingDispatcher
(
p
*
Plugin
)
func
(
cm
*
webhook
.
ClientManager
)
generic
.
Dispatcher
{
return
func
(
cm
*
webhook
.
ClientManager
)
generic
.
Dispatcher
{
return
&
mutatingDispatcher
{
cm
,
p
}
}
}
...
...
@@ -62,7 +63,7 @@ func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr *generic.Version
}
ignoreClientCallFailures
:=
hook
.
FailurePolicy
!=
nil
&&
*
hook
.
FailurePolicy
==
v1beta1
.
Ignore
if
callErr
,
ok
:=
err
.
(
*
webhook
errors
.
ErrCallingWebhook
);
ok
{
if
callErr
,
ok
:=
err
.
(
*
webhook
.
ErrCallingWebhook
);
ok
{
if
ignoreClientCallFailures
{
glog
.
Warningf
(
"Failed calling webhook, failing open %v: %v"
,
hook
.
Name
,
callErr
)
utilruntime
.
HandleError
(
callErr
)
...
...
@@ -84,7 +85,7 @@ func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr *generic.Version
func
(
a
*
mutatingDispatcher
)
callAttrMutatingHook
(
ctx
context
.
Context
,
h
*
v1beta1
.
Webhook
,
attr
*
generic
.
VersionedAttributes
)
error
{
if
attr
.
IsDryRun
()
{
if
h
.
SideEffects
==
nil
{
return
&
webhook
errors
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"Webhook SideEffects is nil"
)}
return
&
webhook
.
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
)
...
...
@@ -93,17 +94,17 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta
// Make the webhook request
request
:=
request
.
CreateAdmissionReview
(
attr
)
client
,
err
:=
a
.
cm
.
HookClient
(
h
)
client
,
err
:=
a
.
cm
.
HookClient
(
util
.
HookClientConfigForWebhook
(
h
)
)
if
err
!=
nil
{
return
&
webhook
errors
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
return
&
webhook
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
}
response
:=
&
admissionv1beta1
.
AdmissionReview
{}
if
err
:=
client
.
Post
()
.
Context
(
ctx
)
.
Body
(
&
request
)
.
Do
()
.
Into
(
response
);
err
!=
nil
{
return
&
webhook
errors
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
return
&
webhook
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
}
if
response
.
Response
==
nil
{
return
&
webhook
errors
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"Webhook response was absent"
)}
return
&
webhook
.
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/testing/authentication_info_resolver.go
View file @
5652d5cf
...
...
@@ -19,22 +19,22 @@ package testing
import
(
"sync/atomic"
"k8s.io/apiserver/pkg/admission/plugin/webhook/config"
"k8s.io/apiserver/pkg/admission/plugin/webhook/testcerts"
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/client-go/rest"
)
// Wrapper turns an AuthenticationInfoResolver into a AuthenticationInfoResolverWrapper that unconditionally
// returns the given AuthenticationInfoResolver.
func
Wrapper
(
r
config
.
AuthenticationInfoResolver
)
func
(
config
.
AuthenticationInfoResolver
)
config
.
AuthenticationInfoResolver
{
return
func
(
config
.
AuthenticationInfoResolver
)
config
.
AuthenticationInfoResolver
{
func
Wrapper
(
r
webhook
.
AuthenticationInfoResolver
)
func
(
webhook
.
AuthenticationInfoResolver
)
webhook
.
AuthenticationInfoResolver
{
return
func
(
webhook
.
AuthenticationInfoResolver
)
webhook
.
AuthenticationInfoResolver
{
return
r
}
}
// NewAuthenticationInfoResolver creates a fake AuthenticationInfoResolver that counts cache misses on
// every call to its methods.
func
NewAuthenticationInfoResolver
(
cacheMisses
*
int32
)
config
.
AuthenticationInfoResolver
{
func
NewAuthenticationInfoResolver
(
cacheMisses
*
int32
)
webhook
.
AuthenticationInfoResolver
{
return
&
authenticationInfoResolver
{
restConfig
:
&
rest
.
Config
{
TLSClientConfig
:
rest
.
TLSClientConfig
{
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/service_resolver.go
View file @
5652d5cf
...
...
@@ -20,7 +20,7 @@ import (
"fmt"
"net/url"
"k8s.io/apiserver/pkg/
admission/plugin/webhook/config
"
"k8s.io/apiserver/pkg/
util/webhook
"
)
type
serviceResolver
struct
{
...
...
@@ -29,7 +29,7 @@ type serviceResolver struct {
// NewServiceResolver returns a static service resolve that return the given URL or
// an error for the failResolve namespace.
func
NewServiceResolver
(
base
url
.
URL
)
config
.
ServiceResolver
{
func
NewServiceResolver
(
base
url
.
URL
)
webhook
.
ServiceResolver
{
return
&
serviceResolver
{
base
}
}
...
...
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/util/client_config.go
0 → 100644
View file @
5652d5cf
/*
Copyright 2018 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
util
import
(
"k8s.io/api/admissionregistration/v1beta1"
"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
}
if
w
.
ClientConfig
.
Service
!=
nil
{
ret
.
Service
=
&
webhook
.
ClientConfigService
{
Name
:
w
.
ClientConfig
.
Service
.
Name
,
Namespace
:
w
.
ClientConfig
.
Service
.
Namespace
,
}
if
w
.
ClientConfig
.
Service
.
Path
!=
nil
{
ret
.
Service
.
Path
=
*
w
.
ClientConfig
.
Service
.
Path
}
}
return
ret
}
staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/dispatcher.go
View file @
5652d5cf
...
...
@@ -29,17 +29,18 @@ import (
apierrors
"k8s.io/apimachinery/pkg/api/errors"
utilruntime
"k8s.io/apimachinery/pkg/util/runtime"
admissionmetrics
"k8s.io/apiserver/pkg/admission/metrics"
"k8s.io/apiserver/pkg/admission/plugin/webhook/config"
webhookerrors
"k8s.io/apiserver/pkg/admission/plugin/webhook/errors"
"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"
)
type
validatingDispatcher
struct
{
cm
*
config
.
ClientManager
cm
*
webhook
.
ClientManager
}
func
newValidatingDispatcher
(
cm
*
config
.
ClientManager
)
generic
.
Dispatcher
{
func
newValidatingDispatcher
(
cm
*
webhook
.
ClientManager
)
generic
.
Dispatcher
{
return
&
validatingDispatcher
{
cm
}
}
...
...
@@ -61,7 +62,7 @@ func (d *validatingDispatcher) Dispatch(ctx context.Context, attr *generic.Versi
}
ignoreClientCallFailures
:=
hook
.
FailurePolicy
!=
nil
&&
*
hook
.
FailurePolicy
==
v1beta1
.
Ignore
if
callErr
,
ok
:=
err
.
(
*
webhook
errors
.
ErrCallingWebhook
);
ok
{
if
callErr
,
ok
:=
err
.
(
*
webhook
.
ErrCallingWebhook
);
ok
{
if
ignoreClientCallFailures
{
glog
.
Warningf
(
"Failed calling webhook, failing open %v: %v"
,
hook
.
Name
,
callErr
)
utilruntime
.
HandleError
(
callErr
)
...
...
@@ -99,7 +100,7 @@ func (d *validatingDispatcher) Dispatch(ctx context.Context, attr *generic.Versi
func
(
d
*
validatingDispatcher
)
callHook
(
ctx
context
.
Context
,
h
*
v1beta1
.
Webhook
,
attr
*
generic
.
VersionedAttributes
)
error
{
if
attr
.
IsDryRun
()
{
if
h
.
SideEffects
==
nil
{
return
&
webhook
errors
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"Webhook SideEffects is nil"
)}
return
&
webhook
.
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
)
...
...
@@ -108,17 +109,17 @@ func (d *validatingDispatcher) callHook(ctx context.Context, h *v1beta1.Webhook,
// Make the webhook request
request
:=
request
.
CreateAdmissionReview
(
attr
)
client
,
err
:=
d
.
cm
.
HookClient
(
h
)
client
,
err
:=
d
.
cm
.
HookClient
(
util
.
HookClientConfigForWebhook
(
h
)
)
if
err
!=
nil
{
return
&
webhook
errors
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
return
&
webhook
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
}
response
:=
&
admissionv1beta1
.
AdmissionReview
{}
if
err
:=
client
.
Post
()
.
Context
(
ctx
)
.
Body
(
&
request
)
.
Do
()
.
Into
(
response
);
err
!=
nil
{
return
&
webhook
errors
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
return
&
webhook
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
err
}
}
if
response
.
Response
==
nil
{
return
&
webhook
errors
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"Webhook response was absent"
)}
return
&
webhook
.
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/config
/authentication.go
→
staging/src/k8s.io/apiserver/pkg/
util/webhook
/authentication.go
View file @
5652d5cf
...
...
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package
config
package
webhook
import
(
"fmt"
...
...
@@ -47,10 +47,12 @@ type AuthenticationInfoResolverDelegator struct {
ClientConfigForServiceFunc
func
(
serviceName
,
serviceNamespace
string
)
(
*
rest
.
Config
,
error
)
}
// ClientConfigFor returns client config for given server.
func
(
a
*
AuthenticationInfoResolverDelegator
)
ClientConfigFor
(
server
string
)
(
*
rest
.
Config
,
error
)
{
return
a
.
ClientConfigForFunc
(
server
)
}
// ClientConfigForService returns client config for given service.
func
(
a
*
AuthenticationInfoResolverDelegator
)
ClientConfigForService
(
serviceName
,
serviceNamespace
string
)
(
*
rest
.
Config
,
error
)
{
return
a
.
ClientConfigForServiceFunc
(
serviceName
,
serviceNamespace
)
}
...
...
staging/src/k8s.io/apiserver/pkg/
admission/plugin/webhook/config
/authentication_test.go
→
staging/src/k8s.io/apiserver/pkg/
util/webhook
/authentication_test.go
View file @
5652d5cf
...
...
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package
config
package
webhook
import
(
"testing"
...
...
staging/src/k8s.io/apiserver/pkg/
admission/plugin/webhook/config
/client.go
→
staging/src/k8s.io/apiserver/pkg/
util/webhook
/client.go
View file @
5652d5cf
...
...
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package
config
package
webhook
import
(
"context"
...
...
@@ -24,13 +24,11 @@ import (
"net"
"net/url"
lru
"github.com/hashicorp/golang-lru"
admissionv1beta1
"k8s.io/api/admission/v1beta1"
"k8s.io/api/admissionregistration/v1beta1"
"github.com/hashicorp/golang-lru"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
utilerrors
"k8s.io/apimachinery/pkg/util/errors"
webhookerrors
"k8s.io/apiserver/pkg/admission/plugin/webhook/errors"
"k8s.io/client-go/rest"
)
...
...
@@ -38,9 +36,20 @@ const (
defaultCacheSize
=
200
)
var
(
ErrNeedServiceOrURL
=
errors
.
New
(
"webhook configuration must have either service or URL"
)
)
// ClientConfig defines parameters required for creating a hook client.
type
ClientConfig
struct
{
Name
string
URL
string
CABundle
[]
byte
Service
*
ClientConfigService
}
// ClientConfigService defines service discovery parameters of the webhook.
type
ClientConfigService
struct
{
Name
string
Namespace
string
Path
string
}
// ClientManager builds REST clients to talk to webhooks. It caches the clients
// to avoid duplicate creation.
...
...
@@ -52,19 +61,19 @@ type ClientManager struct {
}
// NewClientManager creates a clientManager.
func
NewClientManager
()
(
ClientManager
,
error
)
{
func
NewClientManager
(
gv
schema
.
GroupVersion
,
addToSchemaFunc
func
(
s
*
runtime
.
Scheme
)
error
)
(
ClientManager
,
error
)
{
cache
,
err
:=
lru
.
New
(
defaultCacheSize
)
if
err
!=
nil
{
return
ClientManager
{},
err
}
admissionScheme
:=
runtime
.
NewScheme
()
if
err
:=
ad
missionv1beta1
.
AddToScheme
(
admissionScheme
);
err
!=
nil
{
if
err
:=
ad
dToSchemaFunc
(
admissionScheme
);
err
!=
nil
{
return
ClientManager
{},
err
}
return
ClientManager
{
cache
:
cache
,
negotiatedSerializer
:
serializer
.
NegotiatedSerializerWrapper
(
runtime
.
SerializerInfo
{
Serializer
:
serializer
.
NewCodecFactory
(
admissionScheme
)
.
LegacyCodec
(
admissionv1beta1
.
SchemeGroupVersion
),
Serializer
:
serializer
.
NewCodecFactory
(
admissionScheme
)
.
LegacyCodec
(
gv
),
}),
},
nil
}
...
...
@@ -106,8 +115,10 @@ func (cm *ClientManager) Validate() error {
// HookClient get a RESTClient from the cache, or constructs one based on the
// webhook configuration.
func
(
cm
*
ClientManager
)
HookClient
(
h
*
v1beta1
.
Webhook
)
(
*
rest
.
RESTClient
,
error
)
{
cacheKey
,
err
:=
json
.
Marshal
(
h
.
ClientConfig
)
func
(
cm
*
ClientManager
)
HookClient
(
cc
ClientConfig
)
(
*
rest
.
RESTClient
,
error
)
{
ccWithNoName
:=
cc
ccWithNoName
.
Name
=
""
cacheKey
,
err
:=
json
.
Marshal
(
ccWithNoName
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -120,7 +131,7 @@ func (cm *ClientManager) HookClient(h *v1beta1.Webhook) (*rest.RESTClient, error
if
len
(
cfg
.
TLSClientConfig
.
CAData
)
>
0
{
cfg
.
TLSClientConfig
.
CAData
=
append
(
cfg
.
TLSClientConfig
.
CAData
,
'\n'
)
}
cfg
.
TLSClientConfig
.
CAData
=
append
(
cfg
.
TLSClientConfig
.
CAData
,
h
.
ClientConfig
.
CABundle
...
)
cfg
.
TLSClientConfig
.
CAData
=
append
(
cfg
.
TLSClientConfig
.
CAData
,
cc
.
CABundle
...
)
cfg
.
ContentConfig
.
NegotiatedSerializer
=
cm
.
negotiatedSerializer
cfg
.
ContentConfig
.
ContentType
=
runtime
.
ContentTypeJSON
...
...
@@ -131,18 +142,16 @@ func (cm *ClientManager) HookClient(h *v1beta1.Webhook) (*rest.RESTClient, error
return
client
,
err
}
if
svc
:=
h
.
ClientConfig
.
Service
;
svc
!=
nil
{
restConfig
,
err
:=
cm
.
authInfoResolver
.
ClientConfigForService
(
svc
.
Name
,
svc
.
Namespace
)
if
cc
.
Service
!=
nil
{
restConfig
,
err
:=
cm
.
authInfoResolver
.
ClientConfigForService
(
cc
.
Service
.
Name
,
cc
.
Service
.
Namespace
)
if
err
!=
nil
{
return
nil
,
err
}
cfg
:=
rest
.
CopyConfig
(
restConfig
)
serverName
:=
svc
.
Name
+
"."
+
svc
.
Namespace
+
".svc"
serverName
:=
cc
.
Service
.
Name
+
"."
+
cc
.
Service
.
Namespace
+
".svc"
host
:=
serverName
+
":443"
cfg
.
Host
=
"https://"
+
host
if
svc
.
Path
!=
nil
{
cfg
.
APIPath
=
*
svc
.
Path
}
cfg
.
APIPath
=
cc
.
Service
.
Path
// Set the server name if not already set
if
len
(
cfg
.
TLSClientConfig
.
ServerName
)
==
0
{
cfg
.
TLSClientConfig
.
ServerName
=
serverName
...
...
@@ -155,7 +164,7 @@ func (cm *ClientManager) HookClient(h *v1beta1.Webhook) (*rest.RESTClient, error
}
cfg
.
Dial
=
func
(
ctx
context
.
Context
,
network
,
addr
string
)
(
net
.
Conn
,
error
)
{
if
addr
==
host
{
u
,
err
:=
cm
.
serviceResolver
.
ResolveEndpoint
(
svc
.
Namespace
,
svc
.
Name
)
u
,
err
:=
cm
.
serviceResolver
.
ResolveEndpoint
(
cc
.
Service
.
Namespace
,
cc
.
Service
.
Name
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -167,13 +176,13 @@ func (cm *ClientManager) HookClient(h *v1beta1.Webhook) (*rest.RESTClient, error
return
complete
(
cfg
)
}
if
h
.
ClientConfig
.
URL
==
nil
{
return
nil
,
&
webhookerrors
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
ErrNeedServiceOrURL
}
if
cc
.
URL
==
""
{
return
nil
,
&
ErrCallingWebhook
{
WebhookName
:
cc
.
Name
,
Reason
:
errors
.
New
(
"webhook configuration must have either service or URL"
)
}
}
u
,
err
:=
url
.
Parse
(
*
h
.
ClientConfig
.
URL
)
u
,
err
:=
url
.
Parse
(
cc
.
URL
)
if
err
!=
nil
{
return
nil
,
&
webhookerrors
.
ErrCallingWebhook
{
WebhookName
:
h
.
Name
,
Reason
:
fmt
.
Errorf
(
"Unparsable URL: %v"
,
err
)}
return
nil
,
&
ErrCallingWebhook
{
WebhookName
:
cc
.
Name
,
Reason
:
fmt
.
Errorf
(
"Unparsable URL: %v"
,
err
)}
}
restConfig
,
err
:=
cm
.
authInfoResolver
.
ClientConfigFor
(
u
.
Host
)
...
...
staging/src/k8s.io/apiserver/pkg/
admission/plugin/webhook/errors/errors
.go
→
staging/src/k8s.io/apiserver/pkg/
util/webhook/error
.go
View file @
5652d5cf
...
...
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package
errors
package
webhook
import
"fmt"
...
...
staging/src/k8s.io/apiserver/pkg/
admission/plugin/webhook/config
/serviceresolver.go
→
staging/src/k8s.io/apiserver/pkg/
util/webhook
/serviceresolver.go
View file @
5652d5cf
...
...
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package
config
package
webhook
import
(
"errors"
...
...
@@ -29,6 +29,7 @@ type ServiceResolver interface {
type
defaultServiceResolver
struct
{}
// NewDefaultServiceResolver creates a new default server resolver.
func
NewDefaultServiceResolver
()
ServiceResolver
{
return
&
defaultServiceResolver
{}
}
...
...
staging/src/k8s.io/apiserver/pkg/
admission/plugin/webhook/config
/serviceresolver_test.go
→
staging/src/k8s.io/apiserver/pkg/
util/webhook
/serviceresolver_test.go
View file @
5652d5cf
...
...
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package
config
package
webhook
import
(
"fmt"
...
...
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