2020-07-30 00:22:25 +00:00
|
|
|
/*
|
|
|
|
Copyright 2020 VMware, Inc.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
package logindiscovery
|
|
|
|
|
|
|
|
import (
|
2020-07-30 14:39:15 +00:00
|
|
|
"context"
|
2020-07-30 00:22:25 +00:00
|
|
|
"encoding/base64"
|
2020-07-30 14:39:15 +00:00
|
|
|
"fmt"
|
2020-07-30 00:22:25 +00:00
|
|
|
|
2020-07-30 14:39:15 +00:00
|
|
|
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
2020-07-30 00:22:25 +00:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
2020-07-30 21:34:13 +00:00
|
|
|
corev1informers "k8s.io/client-go/informers/core/v1"
|
2020-07-30 00:22:25 +00:00
|
|
|
"k8s.io/client-go/tools/clientcmd"
|
2020-07-30 14:39:15 +00:00
|
|
|
"k8s.io/klog/v2"
|
2020-07-30 00:22:25 +00:00
|
|
|
|
|
|
|
"github.com/suzerain-io/controller-go"
|
2020-08-05 20:58:03 +00:00
|
|
|
crdsplaceholderv1alpha1 "github.com/suzerain-io/placeholder-name/kubernetes/1.19/api/apis/crdsplaceholder/v1alpha1"
|
2020-08-05 14:54:51 +00:00
|
|
|
placeholderclientset "github.com/suzerain-io/placeholder-name/kubernetes/1.19/client-go/clientset/versioned"
|
|
|
|
crdsplaceholderv1alpha1informers "github.com/suzerain-io/placeholder-name/kubernetes/1.19/client-go/informers/externalversions/crdsplaceholder/v1alpha1"
|
2020-07-30 00:22:25 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2020-07-31 16:08:07 +00:00
|
|
|
ClusterInfoNamespace = "kube-public"
|
|
|
|
|
2020-07-30 00:22:25 +00:00
|
|
|
clusterInfoName = "cluster-info"
|
|
|
|
clusterInfoConfigMapKey = "kubeconfig"
|
|
|
|
|
|
|
|
configName = "placeholder-name-config"
|
|
|
|
)
|
|
|
|
|
2020-07-31 00:16:09 +00:00
|
|
|
func nameAndNamespaceExactMatchFilterFactory(name, namespace string) controller.FilterFuncs {
|
|
|
|
objMatchesFunc := func(obj metav1.Object) bool {
|
|
|
|
return obj.GetName() == name && obj.GetNamespace() == namespace
|
|
|
|
}
|
|
|
|
return controller.FilterFuncs{
|
|
|
|
AddFunc: objMatchesFunc,
|
|
|
|
UpdateFunc: func(oldObj, newObj metav1.Object) bool {
|
|
|
|
return objMatchesFunc(oldObj) || objMatchesFunc(newObj)
|
|
|
|
},
|
|
|
|
DeleteFunc: objMatchesFunc,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Same signature as controller.WithInformer().
|
|
|
|
type withInformerOptionFunc func(
|
|
|
|
getter controller.InformerGetter,
|
|
|
|
filter controller.Filter,
|
|
|
|
opt controller.InformerOption) controller.Option
|
|
|
|
|
2020-07-30 00:22:25 +00:00
|
|
|
type publisherController struct {
|
2020-07-30 21:34:13 +00:00
|
|
|
namespace string
|
2020-08-03 14:17:11 +00:00
|
|
|
serverOverride *string
|
2020-07-30 21:34:13 +00:00
|
|
|
placeholderClient placeholderclientset.Interface
|
|
|
|
configMapInformer corev1informers.ConfigMapInformer
|
2020-08-01 00:22:12 +00:00
|
|
|
loginDiscoveryConfigInformer crdsplaceholderv1alpha1informers.LoginDiscoveryConfigInformer
|
2020-07-30 00:22:25 +00:00
|
|
|
}
|
|
|
|
|
2020-07-30 21:34:13 +00:00
|
|
|
func NewPublisherController(
|
|
|
|
namespace string,
|
2020-08-03 14:17:11 +00:00
|
|
|
serverOverride *string,
|
2020-07-30 21:34:13 +00:00
|
|
|
placeholderClient placeholderclientset.Interface,
|
|
|
|
configMapInformer corev1informers.ConfigMapInformer,
|
2020-08-01 00:22:12 +00:00
|
|
|
loginDiscoveryConfigInformer crdsplaceholderv1alpha1informers.LoginDiscoveryConfigInformer,
|
2020-07-31 00:16:09 +00:00
|
|
|
withInformer withInformerOptionFunc,
|
2020-07-30 21:34:13 +00:00
|
|
|
) controller.Controller {
|
2020-07-30 00:22:25 +00:00
|
|
|
return controller.New(
|
|
|
|
controller.Config{
|
|
|
|
Name: "publisher-controller",
|
|
|
|
Syncer: &publisherController{
|
2020-07-30 21:34:13 +00:00
|
|
|
namespace: namespace,
|
2020-08-03 14:17:11 +00:00
|
|
|
serverOverride: serverOverride,
|
2020-07-30 21:34:13 +00:00
|
|
|
placeholderClient: placeholderClient,
|
|
|
|
configMapInformer: configMapInformer,
|
|
|
|
loginDiscoveryConfigInformer: loginDiscoveryConfigInformer,
|
2020-07-30 00:22:25 +00:00
|
|
|
},
|
|
|
|
},
|
2020-07-31 00:16:09 +00:00
|
|
|
withInformer(
|
2020-07-30 21:34:13 +00:00
|
|
|
configMapInformer,
|
2020-07-31 16:08:07 +00:00
|
|
|
nameAndNamespaceExactMatchFilterFactory(clusterInfoName, ClusterInfoNamespace),
|
2020-07-30 21:34:13 +00:00
|
|
|
controller.InformerOption{},
|
|
|
|
),
|
2020-07-31 00:16:09 +00:00
|
|
|
withInformer(
|
2020-07-30 21:34:13 +00:00
|
|
|
loginDiscoveryConfigInformer,
|
2020-07-31 00:16:09 +00:00
|
|
|
nameAndNamespaceExactMatchFilterFactory(configName, namespace),
|
2020-07-30 21:34:13 +00:00
|
|
|
controller.InformerOption{},
|
|
|
|
),
|
2020-07-30 00:22:25 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *publisherController) Sync(ctx controller.Context) error {
|
2020-07-30 21:34:13 +00:00
|
|
|
configMap, err := c.configMapInformer.
|
|
|
|
Lister().
|
2020-07-31 16:08:07 +00:00
|
|
|
ConfigMaps(ClusterInfoNamespace).
|
2020-07-30 21:34:13 +00:00
|
|
|
Get(clusterInfoName)
|
2020-07-30 14:39:15 +00:00
|
|
|
notFound := k8serrors.IsNotFound(err)
|
|
|
|
if err != nil && !notFound {
|
|
|
|
return fmt.Errorf("failed to get %s configmap: %w", clusterInfoName, err)
|
2020-07-30 01:18:42 +00:00
|
|
|
}
|
2020-07-30 14:39:15 +00:00
|
|
|
if notFound {
|
|
|
|
klog.InfoS(
|
|
|
|
"could not find config map",
|
|
|
|
"configmap",
|
2020-07-31 16:08:07 +00:00
|
|
|
klog.KRef(ClusterInfoNamespace, clusterInfoName),
|
2020-07-30 14:39:15 +00:00
|
|
|
)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-07-30 01:18:42 +00:00
|
|
|
kubeConfig, kubeConfigPresent := configMap.Data[clusterInfoConfigMapKey]
|
|
|
|
if !kubeConfigPresent {
|
2020-07-30 14:39:15 +00:00
|
|
|
klog.InfoS("could not find kubeconfig configmap key")
|
|
|
|
return nil
|
2020-07-30 01:18:42 +00:00
|
|
|
}
|
2020-07-30 00:22:25 +00:00
|
|
|
|
|
|
|
config, _ := clientcmd.Load([]byte(kubeConfig))
|
|
|
|
|
|
|
|
var certificateAuthorityData, server string
|
|
|
|
for _, v := range config.Clusters {
|
|
|
|
certificateAuthorityData = base64.StdEncoding.EncodeToString(v.CertificateAuthorityData)
|
|
|
|
server = v.Server
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2020-08-03 14:17:11 +00:00
|
|
|
if c.serverOverride != nil {
|
|
|
|
server = *c.serverOverride
|
|
|
|
}
|
|
|
|
|
2020-08-01 00:22:12 +00:00
|
|
|
discoveryConfig := crdsplaceholderv1alpha1.LoginDiscoveryConfig{
|
2020-07-30 00:22:25 +00:00
|
|
|
TypeMeta: metav1.TypeMeta{},
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: configName,
|
|
|
|
Namespace: c.namespace,
|
|
|
|
},
|
2020-08-01 00:22:12 +00:00
|
|
|
Spec: crdsplaceholderv1alpha1.LoginDiscoveryConfigSpec{
|
2020-07-30 00:22:25 +00:00
|
|
|
Server: server,
|
|
|
|
CertificateAuthorityData: certificateAuthorityData,
|
|
|
|
},
|
|
|
|
}
|
2020-07-30 14:39:15 +00:00
|
|
|
if err := c.createOrUpdateLoginDiscoveryConfig(ctx.Context, &discoveryConfig); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *publisherController) createOrUpdateLoginDiscoveryConfig(
|
|
|
|
ctx context.Context,
|
2020-08-01 00:22:12 +00:00
|
|
|
discoveryConfig *crdsplaceholderv1alpha1.LoginDiscoveryConfig,
|
2020-07-30 14:39:15 +00:00
|
|
|
) error {
|
2020-07-30 21:34:13 +00:00
|
|
|
existingDiscoveryConfig, err := c.loginDiscoveryConfigInformer.
|
|
|
|
Lister().
|
|
|
|
LoginDiscoveryConfigs(c.namespace).
|
|
|
|
Get(discoveryConfig.Name)
|
2020-07-30 14:39:15 +00:00
|
|
|
notFound := k8serrors.IsNotFound(err)
|
|
|
|
if err != nil && !notFound {
|
|
|
|
return fmt.Errorf("could not get logindiscoveryconfig: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-07-30 21:34:13 +00:00
|
|
|
loginDiscoveryConfigs := c.placeholderClient.
|
2020-08-01 00:22:12 +00:00
|
|
|
CrdsV1alpha1().
|
2020-07-30 21:34:13 +00:00
|
|
|
LoginDiscoveryConfigs(c.namespace)
|
2020-07-30 14:39:15 +00:00
|
|
|
if notFound {
|
|
|
|
if _, err := loginDiscoveryConfigs.Create(
|
|
|
|
ctx,
|
|
|
|
discoveryConfig,
|
|
|
|
metav1.CreateOptions{},
|
|
|
|
); err != nil {
|
|
|
|
return fmt.Errorf("could not create logindiscoveryconfig: %w", err)
|
|
|
|
}
|
|
|
|
} else if !equal(existingDiscoveryConfig, discoveryConfig) {
|
|
|
|
// Update just the fields we care about.
|
|
|
|
existingDiscoveryConfig.Spec.Server = discoveryConfig.Spec.Server
|
|
|
|
existingDiscoveryConfig.Spec.CertificateAuthorityData = discoveryConfig.Spec.CertificateAuthorityData
|
|
|
|
|
|
|
|
if _, err := loginDiscoveryConfigs.Update(
|
|
|
|
ctx,
|
|
|
|
existingDiscoveryConfig,
|
|
|
|
metav1.UpdateOptions{},
|
|
|
|
); err != nil {
|
|
|
|
return fmt.Errorf("could not update logindiscoveryconfig: %w", err)
|
|
|
|
}
|
|
|
|
}
|
2020-07-30 00:22:25 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2020-07-30 14:39:15 +00:00
|
|
|
|
2020-08-01 00:22:12 +00:00
|
|
|
func equal(a, b *crdsplaceholderv1alpha1.LoginDiscoveryConfig) bool {
|
2020-07-30 14:39:15 +00:00
|
|
|
return a.Spec.Server == b.Spec.Server &&
|
|
|
|
a.Spec.CertificateAuthorityData == b.Spec.CertificateAuthorityData
|
|
|
|
}
|