ContainerImage.Pinniped/internal/controller/supervisorconfig/dynamic_config_watcher.go
Andrew Keesler 019f44982c
supervisor-oidc: checkpoint: controller watches OIDCProviderConfig
Signed-off-by: Andrew Keesler <akeesler@vmware.com>
2020-10-07 10:54:56 -04:00

113 lines
3.1 KiB
Go

// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package supervisorconfig
import (
"fmt"
"net/url"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/klog/v2"
configinformers "go.pinniped.dev/generated/1.19/client/informers/externalversions/config/v1alpha1"
pinnipedcontroller "go.pinniped.dev/internal/controller"
"go.pinniped.dev/internal/controllerlib"
)
const (
issuerConfigMapKey = "issuer"
)
// IssuerSetter can be notified of a valid issuer with its SetIssuer function. If there is no
// longer any valid issuer, then nil can be passed to this interface.
//
// If the IssuerSetter doesn't like the provided issuer, it can return an error.
//
// Implementations of this type should be thread-safe to support calls from multiple goroutines.
type IssuerSetter interface {
SetIssuer(issuer *url.URL) error
}
type dynamicConfigWatcherController struct {
issuerSetter IssuerSetter
opcInformer configinformers.OIDCProviderConfigInformer
}
// NewDynamicConfigWatcherController creates a controllerlib.Controller that watches
// OIDCProviderConfig objects and notifies a callback object of their creation or deletion.
func NewDynamicConfigWatcherController(
issuerObserver IssuerSetter,
opcInformer configinformers.OIDCProviderConfigInformer,
withInformer pinnipedcontroller.WithInformerOptionFunc,
) controllerlib.Controller {
return controllerlib.New(
controllerlib.Config{
Name: "DynamicConfigWatcherController",
Syncer: &dynamicConfigWatcherController{
issuerSetter: issuerObserver,
opcInformer: opcInformer,
},
},
withInformer(
opcInformer,
pinnipedcontroller.NoOpFilter(),
controllerlib.InformerOption{},
),
)
}
// Sync implements controllerlib.Syncer.
func (c *dynamicConfigWatcherController) Sync(ctx controllerlib.Context) error {
// TODO Watch the configmap to find the issuer name, ingress url, etc.
// TODO Update some kind of in-memory representation of the configuration so the discovery endpoint can use it.
// TODO The discovery endpoint would return an error until all missing configuration options are
// filled in.
opc, err := c.opcInformer.
Lister().
OIDCProviderConfigs(ctx.Key.Namespace).
Get(ctx.Key.Name)
notFound := k8serrors.IsNotFound(err)
if err != nil && !notFound {
return fmt.Errorf("failed to get %s/%s oidcproviderconfig: %w", ctx.Key.Namespace, ctx.Key.Name, err)
}
if notFound {
klog.InfoS(
"dynamicConfigWatcherController Sync found no oidcproviderconfig",
"oidcproviderconfig",
klog.KRef(ctx.Key.Namespace, ctx.Key.Name),
)
c.issuerSetter.SetIssuer(nil)
return nil
}
url, err := url.Parse(opc.Spec.Issuer)
if err != nil {
klog.InfoS(
"dynamicConfigWatcherController Sync failed to parse issuer",
"err",
err,
)
return nil
}
klog.InfoS(
"dynamicConfigWatcherController Sync issuer",
"oidcproviderconfig",
klog.KObj(opc),
"issuer",
url,
)
if err := c.issuerSetter.SetIssuer(url); err != nil {
klog.InfoS(
"dynamicConfigWatcherController Sync failed to set issuer",
"err",
err,
)
}
return nil
}