expose RunOnce method on RequestHeaderAuthRequest controller

This commit is contained in:
Lukasz Szaszkiewicz 2020-04-28 15:35:17 +02:00
parent cb4b4cb5a6
commit f3a7f057c4
4 changed files with 52 additions and 30 deletions

View File

@ -69,6 +69,7 @@ type RequestHeaderAuthRequestController struct {
configmapName string
configmapNamespace string
client kubernetes.Interface
configmapLister corev1listers.ConfigMapNamespaceLister
configmapInformer cache.SharedIndexInformer
configmapInformerSynced cache.InformerSynced
@ -89,10 +90,12 @@ func NewRequestHeaderAuthRequestController(
cmName string,
cmNamespace string,
client kubernetes.Interface,
usernameHeadersKey, groupHeadersKey, extraHeaderPrefixesKey, allowedClientNamesKey string) (*RequestHeaderAuthRequestController, error) {
usernameHeadersKey, groupHeadersKey, extraHeaderPrefixesKey, allowedClientNamesKey string) *RequestHeaderAuthRequestController {
c := &RequestHeaderAuthRequestController{
name: "RequestHeaderAuthRequestController",
client: client,
configmapName: cmName,
configmapNamespace: cmNamespace,
@ -104,11 +107,6 @@ func NewRequestHeaderAuthRequestController(
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "RequestHeaderAuthRequestController"),
}
// use the live client to prime the controller
if err := c.syncOnce(client); err != nil {
return nil, err
}
// we construct our own informer because we need such a small subset of the information available. Just one namespace.
c.configmapInformer = coreinformers.NewFilteredConfigMapInformer(client, c.configmapNamespace, 12*time.Hour, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, func(listOptions *metav1.ListOptions) {
listOptions.FieldSelector = fields.OneTermEqualSelector("metadata.name", c.configmapName).String()
@ -144,7 +142,7 @@ func NewRequestHeaderAuthRequestController(
c.configmapLister = corev1listers.NewConfigMapLister(c.configmapInformer.GetIndexer()).ConfigMaps(c.configmapNamespace)
c.configmapInformerSynced = c.configmapInformer.HasSynced
return c, nil
return c
}
func (c *RequestHeaderAuthRequestController) UsernameHeaders() []string {
@ -184,6 +182,24 @@ func (c *RequestHeaderAuthRequestController) Run(workers int, stopCh <-chan stru
<-stopCh
}
// // RunOnce runs a single sync loop
func (c *RequestHeaderAuthRequestController) RunOnce() error {
configMap, err := c.client.CoreV1().ConfigMaps(c.configmapNamespace).Get(context.TODO(), c.configmapName, metav1.GetOptions{})
switch {
case errors.IsNotFound(err):
// ignore, authConfigMap is nil now
return nil
case errors.IsForbidden(err):
klog.Warningf("Unable to get configmap/%s in %s. Usually fixed by "+
"'kubectl create rolebinding -n %s ROLEBINDING_NAME --role=%s --serviceaccount=YOUR_NS:YOUR_SA'",
c.configmapName, c.configmapNamespace, c.configmapNamespace, authenticationRoleName)
return err
case err != nil:
return err
}
return c.syncConfigMap(configMap)
}
func (c *RequestHeaderAuthRequestController) runWorker() {
for c.processNextWorkItem() {
}
@ -208,23 +224,6 @@ func (c *RequestHeaderAuthRequestController) processNextWorkItem() bool {
return true
}
func (c *RequestHeaderAuthRequestController) syncOnce(client kubernetes.Interface) error {
configMap, err := client.CoreV1().ConfigMaps(c.configmapNamespace).Get(context.TODO(), c.configmapName, metav1.GetOptions{})
switch {
case errors.IsNotFound(err):
// ignore, authConfigMap is nil now
return nil
case errors.IsForbidden(err):
klog.Warningf("Unable to get configmap/%s in %s. Usually fixed by "+
"'kubectl create rolebinding -n %s ROLEBINDING_NAME --role=%s --serviceaccount=YOUR_NS:YOUR_SA'",
c.configmapName, c.configmapNamespace, c.configmapNamespace, authenticationRoleName)
return err
case err != nil:
return err
}
return c.syncConfigMap(configMap)
}
// sync reads the config and propagates the changes to exportedRequestHeaderBundle
// which is exposed by the set of methods that are used to fill RequestHeaderConfig struct
func (c *RequestHeaderAuthRequestController) sync() error {

View File

@ -218,9 +218,10 @@ func TestRequestHeaderAuthRequestControllerSyncOnce(t *testing.T) {
// test data
target := newDefaultTarget()
fakeKubeClient := fake.NewSimpleClientset(scenario.cm)
target.client = fakeKubeClient
// act
err := target.syncOnce(fakeKubeClient)
err := target.RunOnce()
if err != nil && !scenario.expectErr {
t.Errorf("got unexpected error %v", err)

View File

@ -335,6 +335,11 @@ func (s *DelegatingAuthenticationOptions) createRequestHeaderConfig(client kuber
return nil, fmt.Errorf("unable to create request header authentication config: %v", err)
}
// look up authentication configuration in the cluster and in case of an err defer to authentication-tolerate-lookup-failure flag
if err := dynamicRequestHeaderProvider.RunOnce(); err != nil {
return nil, err
}
return &authenticatorfactory.RequestHeaderConfig{
CAContentProvider: dynamicRequestHeaderProvider,
UsernameHeaders: headerrequest.StringSliceProvider(headerrequest.StringSliceProviderFunc(dynamicRequestHeaderProvider.UsernameHeaders)),

View File

@ -1,8 +1,25 @@
/*
Copyright 2020 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 options
import (
"fmt"
"k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apiserver/pkg/authentication/request/headerrequest"
"k8s.io/apiserver/pkg/server/dynamiccertificates"
"k8s.io/client-go/kubernetes"
@ -33,7 +50,7 @@ func newDynamicRequestHeaderController(client kubernetes.Interface) (*DynamicReq
return nil, fmt.Errorf("unable to create DynamicCAFromConfigMap controller: %v", err)
}
requestHeaderAuthRequestController, err := headerrequest.NewRequestHeaderAuthRequestController(
requestHeaderAuthRequestController := headerrequest.NewRequestHeaderAuthRequestController(
authenticationConfigMapName,
authenticationConfigMapNamespace,
client,
@ -42,9 +59,6 @@ func newDynamicRequestHeaderController(client kubernetes.Interface) (*DynamicReq
"requestheader-extra-headers-prefix",
"requestheader-allowed-names",
)
if err != nil {
return nil, fmt.Errorf("unable to create RequestHeaderAuthRequest controller: %v", err)
}
return &DynamicRequestHeaderController{
ConfigMapCAController: requestHeaderCAController,
RequestHeaderAuthRequestController: requestHeaderAuthRequestController,
@ -52,7 +66,10 @@ func newDynamicRequestHeaderController(client kubernetes.Interface) (*DynamicReq
}
func (c *DynamicRequestHeaderController) RunOnce() error {
return c.ConfigMapCAController.RunOnce()
errs := []error{}
errs = append(errs, c.ConfigMapCAController.RunOnce())
errs = append(errs, c.RequestHeaderAuthRequestController.RunOnce())
return errors.NewAggregate(errs)
}
func (c *DynamicRequestHeaderController) Run(workers int, stopCh <-chan struct{}) {