Split ClientConfigFor()

pull/6/head
Yang Guo 2018-01-25 21:31:02 -08:00
parent 454276c23c
commit 05fbc22064
6 changed files with 69 additions and 39 deletions

View File

@ -459,29 +459,35 @@ func BuildGenericConfig(s *options.ServerRunOptions, proxyTransport *http.Transp
genericConfig.DisabledPostStartHooks.Insert(rbacrest.PostStartHookName) genericConfig.DisabledPostStartHooks.Insert(rbacrest.PostStartHookName)
} }
webhookAuthResolver := func(delegate webhookconfig.AuthenticationInfoResolver) webhookconfig.AuthenticationInfoResolver { webhookAuthResolverWrapper := func(delegate webhookconfig.AuthenticationInfoResolver) webhookconfig.AuthenticationInfoResolver {
return webhookconfig.AuthenticationInfoResolverFunc(func(server string, directRouting bool) (*rest.Config, error) { return &webhookconfig.AuthenticationInfoResolverDelegator{
if server == "kubernetes.default.svc" { ClientConfigForFunc: func(server string) (*rest.Config, error) {
return genericConfig.LoopbackClientConfig, nil if server == "kubernetes.default.svc" {
} return genericConfig.LoopbackClientConfig, nil
ret, err := delegate.ClientConfigFor(server, directRouting) }
if err != nil { return delegate.ClientConfigFor(server)
return nil, err },
} ClientConfigForServiceFunc: func(serviceName, serviceNamespace string) (*rest.Config, error) {
if !directRouting && proxyTransport != nil && proxyTransport.Dial != nil { if serviceName == "kubernetes" && serviceNamespace == "default" {
// Use the SSH tunnels iff the webhook server is not directly return genericConfig.LoopbackClientConfig, nil
// routable from apiserver's network environment. }
ret.Dial = proxyTransport.Dial ret, err := delegate.ClientConfigForService(serviceName, serviceNamespace)
} if err != nil {
return ret, err return nil, err
}) }
if proxyTransport != nil && proxyTransport.Dial != nil {
ret.Dial = proxyTransport.Dial
}
return ret, err
},
}
} }
pluginInitializers, err := BuildAdmissionPluginInitializers( pluginInitializers, err := BuildAdmissionPluginInitializers(
s, s,
client, client,
sharedInformers, sharedInformers,
serviceResolver, serviceResolver,
webhookAuthResolver, webhookAuthResolverWrapper,
) )
if err != nil { if err != nil {
return nil, nil, nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %v", err) return nil, nil, nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %v", err)

View File

@ -31,22 +31,28 @@ import (
// rest.Config generated by the resolver. // rest.Config generated by the resolver.
type AuthenticationInfoResolverWrapper func(AuthenticationInfoResolver) AuthenticationInfoResolver type AuthenticationInfoResolverWrapper func(AuthenticationInfoResolver) AuthenticationInfoResolver
// AuthenticationInfoResolver builds rest.Config base on the server name and // AuthenticationInfoResolver builds rest.Config base on the server or service
// the directRouting flag indicating whether the webhook server is routable // name and service namespace.
// directly from apiserver's network environment.
//
// TODO(yguo0905): Remove the directRouting flag once the SSH tunnels that is
// used for the communication from master to nodes get removed.
type AuthenticationInfoResolver interface { type AuthenticationInfoResolver interface {
ClientConfigFor(server string, directRouting bool) (*rest.Config, error) // ClientConfigFor builds rest.Config based on the server.
ClientConfigFor(server string) (*rest.Config, error)
// ClientConfigForService builds rest.Config based on the serviceName and
// serviceNamespace.
ClientConfigForService(serviceName, serviceNamespace string) (*rest.Config, error)
} }
// AuthenticationInfoResolverFunc implements AuthenticationInfoResolver. // AuthenticationInfoResolverDelegator implements AuthenticationInfoResolver.
type AuthenticationInfoResolverFunc func(server string, directRouting bool) (*rest.Config, error) type AuthenticationInfoResolverDelegator struct {
ClientConfigForFunc func(server string) (*rest.Config, error)
ClientConfigForServiceFunc func(serviceName, serviceNamespace string) (*rest.Config, error)
}
//ClientConfigFor implements AuthenticationInfoResolver. func (a *AuthenticationInfoResolverDelegator) ClientConfigFor(server string) (*rest.Config, error) {
func (a AuthenticationInfoResolverFunc) ClientConfigFor(server string, directRouting bool) (*rest.Config, error) { return a.ClientConfigForFunc(server)
return a(server, directRouting) }
func (a *AuthenticationInfoResolverDelegator) ClientConfigForService(serviceName, serviceNamespace string) (*rest.Config, error) {
return a.ClientConfigForServiceFunc(serviceName, serviceNamespace)
} }
type defaultAuthenticationInfoResolver struct { type defaultAuthenticationInfoResolver struct {
@ -72,14 +78,22 @@ func NewDefaultAuthenticationInfoResolver(kubeconfigFile string) (Authentication
return &defaultAuthenticationInfoResolver{kubeconfig: clientConfig}, nil return &defaultAuthenticationInfoResolver{kubeconfig: clientConfig}, nil
} }
func (c *defaultAuthenticationInfoResolver) ClientConfigFor(server string, directRouting bool) (*rest.Config, error) { func (c *defaultAuthenticationInfoResolver) ClientConfigFor(server string) (*rest.Config, error) {
return c.clientConfig(server)
}
func (c *defaultAuthenticationInfoResolver) ClientConfigForService(serviceName, serviceNamespace string) (*rest.Config, error) {
return c.clientConfig(serviceName + "." + serviceNamespace + ".svc")
}
func (c *defaultAuthenticationInfoResolver) clientConfig(target string) (*rest.Config, error) {
// exact match // exact match
if authConfig, ok := c.kubeconfig.AuthInfos[server]; ok { if authConfig, ok := c.kubeconfig.AuthInfos[target]; ok {
return restConfigFromKubeconfig(authConfig) return restConfigFromKubeconfig(authConfig)
} }
// star prefixed match // star prefixed match
serverSteps := strings.Split(server, ".") serverSteps := strings.Split(target, ".")
for i := 1; i < len(serverSteps); i++ { for i := 1; i < len(serverSteps); i++ {
nickName := "*." + strings.Join(serverSteps[i:], ".") nickName := "*." + strings.Join(serverSteps[i:], ".")
if authConfig, ok := c.kubeconfig.AuthInfos[nickName]; ok { if authConfig, ok := c.kubeconfig.AuthInfos[nickName]; ok {
@ -88,7 +102,7 @@ func (c *defaultAuthenticationInfoResolver) ClientConfigFor(server string, direc
} }
// if we're trying to hit the kube-apiserver and there wasn't an explicit config, use the in-cluster config // if we're trying to hit the kube-apiserver and there wasn't an explicit config, use the in-cluster config
if server == "kubernetes.default.svc" { if target == "kubernetes.default.svc" {
// if we can find an in-cluster-config use that. If we can't, fall through. // if we can find an in-cluster-config use that. If we can't, fall through.
inClusterConfig, err := rest.InClusterConfig() inClusterConfig, err := rest.InClusterConfig()
if err == nil { if err == nil {

View File

@ -114,7 +114,7 @@ func TestAuthenticationDetection(t *testing.T) {
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
resolver := defaultAuthenticationInfoResolver{kubeconfig: tc.kubeconfig} resolver := defaultAuthenticationInfoResolver{kubeconfig: tc.kubeconfig}
actual, err := resolver.ClientConfigFor(tc.serverName, false) actual, err := resolver.ClientConfigFor(tc.serverName)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -122,12 +122,12 @@ func (cm *ClientManager) HookClient(h *v1beta1.Webhook) (*rest.RESTClient, error
} }
if svc := h.ClientConfig.Service; svc != nil { if svc := h.ClientConfig.Service; svc != nil {
serverName := svc.Name + "." + svc.Namespace + ".svc" restConfig, err := cm.authInfoResolver.ClientConfigForService(svc.Name, svc.Namespace)
restConfig, err := cm.authInfoResolver.ClientConfigFor(serverName, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
cfg := rest.CopyConfig(restConfig) cfg := rest.CopyConfig(restConfig)
serverName := svc.Name + "." + svc.Namespace + ".svc"
host := serverName + ":443" host := serverName + ":443"
cfg.Host = "https://" + host cfg.Host = "https://" + host
if svc.Path != nil { if svc.Path != nil {
@ -162,7 +162,7 @@ func (cm *ClientManager) HookClient(h *v1beta1.Webhook) (*rest.RESTClient, error
return nil, &webhookerrors.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Unparsable URL: %v", err)} return nil, &webhookerrors.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Unparsable URL: %v", err)}
} }
restConfig, err := cm.authInfoResolver.ClientConfigFor(u.Host, true) restConfig, err := cm.authInfoResolver.ClientConfigFor(u.Host)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -631,7 +631,12 @@ type fakeAuthenticationInfoResolver struct {
cachedCount *int32 cachedCount *int32
} }
func (c *fakeAuthenticationInfoResolver) ClientConfigFor(server string, directRouting bool) (*rest.Config, error) { func (c *fakeAuthenticationInfoResolver) ClientConfigFor(server string) (*rest.Config, error) {
atomic.AddInt32(c.cachedCount, 1)
return c.restConfig, nil
}
func (c *fakeAuthenticationInfoResolver) ClientConfigForService(serviceName, serviceNamespace string) (*rest.Config, error) {
atomic.AddInt32(c.cachedCount, 1) atomic.AddInt32(c.cachedCount, 1)
return c.restConfig, nil return c.restConfig, nil
} }

View File

@ -656,7 +656,12 @@ type fakeAuthenticationInfoResolver struct {
cachedCount *int32 cachedCount *int32
} }
func (c *fakeAuthenticationInfoResolver) ClientConfigFor(server string, directRouting bool) (*rest.Config, error) { func (c *fakeAuthenticationInfoResolver) ClientConfigFor(server string) (*rest.Config, error) {
atomic.AddInt32(c.cachedCount, 1)
return c.restConfig, nil
}
func (c *fakeAuthenticationInfoResolver) ClientConfigForService(serviceName, serviceNamespace string) (*rest.Config, error) {
atomic.AddInt32(c.cachedCount, 1) atomic.AddInt32(c.cachedCount, 1)
return c.restConfig, nil return c.restConfig, nil
} }