1
0
Fork 0
mirror of https://github.com/prometheus-operator/prometheus-operator.git synced 2025-04-21 11:48:53 +00:00

Add tests for assetStore

Signed-off-by: Simon Pasquier <spasquie@redhat.com>
This commit is contained in:
Simon Pasquier 2020-08-31 13:33:26 +02:00
parent a0a1816f4c
commit 7ed47043ce
4 changed files with 885 additions and 231 deletions

View file

@ -0,0 +1,267 @@
// Copyright 2020 The prometheus-operator 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 prometheus
import (
"context"
"fmt"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/tools/cache"
)
// tlsAssetKey is a key for a TLS asset.
type tlsAssetKey struct {
from string
ns string
name string
key string
}
// tlsAssetKeyFromSecretSelector returns a tlsAssetKey struct from a secret key selector.
func tlsAssetKeyFromSecretSelector(ns string, sel *v1.SecretKeySelector) tlsAssetKey {
return tlsAssetKeyFromSelector(
ns,
monitoringv1.SecretOrConfigMap{
Secret: sel,
},
)
}
// tlsAssetKeyFromSelector returns a tlsAssetKey struct from a secret or configmap key selector.
func tlsAssetKeyFromSelector(ns string, sel monitoringv1.SecretOrConfigMap) tlsAssetKey {
if sel.Secret != nil {
return tlsAssetKey{
from: "secret",
ns: ns,
name: sel.Secret.Name,
key: sel.Secret.Key,
}
}
return tlsAssetKey{
from: "configmap",
ns: ns,
name: sel.ConfigMap.Name,
key: sel.ConfigMap.Key,
}
}
// String implements the fmt.Stringer interface.
func (k tlsAssetKey) String() string {
return fmt.Sprintf("%s_%s_%s_%s", k.from, k.ns, k.name, k.key)
}
// assetStore is a store that fetches and caches TLS materials, bearer tokens
// and auth credentials from configmaps and secrets.
// Data can be referenced directly from a Prometheus object or indirectly (for
// instance via ServiceMonitor). In practice a new store is created and used by
// each reconciliation loop.
//
// assetStore doesn't support concurrent access.
type assetStore struct {
cmClient corev1client.ConfigMapsGetter
sClient corev1client.SecretsGetter
objStore cache.Store
tlsAssets map[tlsAssetKey]TLSAsset
bearerTokenAssets map[string]BearerToken
basicAuthAssets map[string]BasicAuthCredentials
}
// newAssetStore returns an empty assetStore.
func newAssetStore(cmClient corev1client.ConfigMapsGetter, sClient corev1client.SecretsGetter) *assetStore {
return &assetStore{
cmClient: cmClient,
sClient: sClient,
tlsAssets: make(map[tlsAssetKey]TLSAsset),
bearerTokenAssets: make(map[string]BearerToken),
basicAuthAssets: make(map[string]BasicAuthCredentials),
objStore: cache.NewStore(assetKeyFunc),
}
}
func assetKeyFunc(obj interface{}) (string, error) {
switch v := obj.(type) {
case *v1.ConfigMap:
return fmt.Sprintf("0/%s/%s", v.GetNamespace(), v.GetName()), nil
case *v1.Secret:
return fmt.Sprintf("1/%s/%s", v.GetNamespace(), v.GetName()), nil
}
return "", errors.Errorf("unsupported type: %T", obj)
}
// addTLSConfig processes the given *TLSConfig and adds the referenced CA, certifcate and key to the store.
func (a *assetStore) addTLSConfig(ns string, tlsConfig *monitoringv1.TLSConfig) error {
if tlsConfig == nil {
return nil
}
if tlsConfig.CA != (monitoringv1.SecretOrConfigMap{}) {
var (
ca string
err error
)
switch {
case tlsConfig.CA.Secret != nil:
ca, err = a.getSecretKey(ns, *tlsConfig.CA.Secret)
case tlsConfig.CA.ConfigMap != nil:
ca, err = a.getConfigMapKey(ns, *tlsConfig.CA.ConfigMap)
}
if err != nil {
return errors.Wrap(err, "failed to get CA")
}
a.tlsAssets[tlsAssetKeyFromSelector(ns, tlsConfig.CA)] = TLSAsset(ca)
}
if tlsConfig.Cert != (monitoringv1.SecretOrConfigMap{}) {
var (
cert string
err error
)
switch {
case tlsConfig.Cert.Secret != nil:
cert, err = a.getSecretKey(ns, *tlsConfig.Cert.Secret)
case tlsConfig.Cert.ConfigMap != nil:
cert, err = a.getConfigMapKey(ns, *tlsConfig.Cert.ConfigMap)
}
if err != nil {
return errors.Wrap(err, "failed to get cert")
}
a.tlsAssets[tlsAssetKeyFromSelector(ns, tlsConfig.Cert)] = TLSAsset(cert)
}
if tlsConfig.KeySecret != nil {
key, err := a.getSecretKey(ns, *tlsConfig.KeySecret)
if err != nil {
return errors.Wrap(err, "failed to get key")
}
a.tlsAssets[tlsAssetKeyFromSelector(ns, monitoringv1.SecretOrConfigMap{Secret: tlsConfig.KeySecret})] = TLSAsset(key)
}
return nil
}
// addTLSConfig processes the given *BasicAuth and adds the referenced credentials to the store.
func (a *assetStore) addBasicAuth(ns string, ba *monitoringv1.BasicAuth, key string) error {
if ba == nil {
return nil
}
username, err := a.getSecretKey(ns, ba.Username)
if err != nil {
return errors.Wrap(err, "failed to get basic auth username")
}
password, err := a.getSecretKey(ns, ba.Password)
if err != nil {
return errors.Wrap(err, "failed to get basic auth password")
}
a.basicAuthAssets[key] = BasicAuthCredentials{
username: username,
password: password,
}
return nil
}
// addTLSConfig processes the given SecretKeySelector and adds the referenced data to the store.
func (a *assetStore) addBearerToken(ns string, sel v1.SecretKeySelector, key string) error {
if sel.Name == "" {
return nil
}
bearerToken, err := a.getSecretKey(ns, sel)
if err != nil {
return errors.Wrap(err, "failed to get bearer token")
}
a.bearerTokenAssets[key] = BearerToken(bearerToken)
return nil
}
func (a *assetStore) getConfigMapKey(namespace string, sel v1.ConfigMapKeySelector) (string, error) {
obj, exists, err := a.objStore.Get(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: sel.Name,
Namespace: namespace,
},
})
if err != nil {
return "", errors.Wrapf(err, "unexpected store error when getting configmap %q", sel.Name)
}
if !exists {
cm, err := a.cmClient.ConfigMaps(namespace).Get(context.TODO(), sel.Name, metav1.GetOptions{})
if err != nil {
return "", errors.Wrapf(err, "unable to get configmap %q", sel.Name)
}
if err = a.objStore.Add(cm); err != nil {
return "", errors.Wrapf(err, "unexpected store error when adding configmap %q", sel.Name)
}
obj = cm
}
cm := obj.(*v1.ConfigMap)
if _, found := cm.Data[sel.Key]; !found {
return "", errors.Errorf("key %q in configmap %q not found", sel.Key, sel.Name)
}
return cm.Data[sel.Key], nil
}
func (a *assetStore) getSecretKey(namespace string, sel v1.SecretKeySelector) (string, error) {
obj, exists, err := a.objStore.Get(&v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: sel.Name,
Namespace: namespace,
},
})
if err != nil {
return "", errors.Wrapf(err, "unexpected store error when getting secret %q", sel.Name)
}
if !exists {
secret, err := a.sClient.Secrets(namespace).Get(context.TODO(), sel.Name, metav1.GetOptions{})
if err != nil {
return "", errors.Wrapf(err, "unable to get secret %q", sel.Name)
}
if err = a.objStore.Add(secret); err != nil {
return "", errors.Wrapf(err, "unexpected store error when adding secret %q", sel.Name)
}
obj = secret
}
secret := obj.(*v1.Secret)
if _, found := secret.Data[sel.Key]; !found {
return "", errors.Errorf("key %q in secret %q not found", sel.Key, sel.Name)
}
return string(secret.Data[sel.Key]), nil
}

View file

@ -0,0 +1,611 @@
// Copyright 2020 The prometheus-operator 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 prometheus
import (
"fmt"
"testing"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
func TestAddBearerToken(t *testing.T) {
c := fake.NewSimpleClientset(
&v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "secret",
Namespace: "ns1",
},
Data: map[string][]byte{
"key1": []byte("val1"),
},
},
)
for i, tc := range []struct {
ns string
selectedName string
selectedKey string
err bool
expected string
}{
{
ns: "ns1",
selectedName: "secret",
selectedKey: "key1",
expected: "val1",
},
// Wrong namespace.
{
ns: "ns2",
selectedName: "secret",
selectedKey: "key1",
err: true,
},
// Wrong name.
{
ns: "ns1",
selectedName: "secreet",
selectedKey: "key1",
err: true,
},
// Wrong key.
{
ns: "ns1",
selectedName: "secret",
selectedKey: "key2",
err: true,
},
} {
t.Run("", func(t *testing.T) {
store := newAssetStore(c.CoreV1(), c.CoreV1())
sel := v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: tc.selectedName,
},
Key: tc.selectedKey,
}
key := fmt.Sprintf("basicauth/%d", i)
err := store.addBearerToken(tc.ns, sel, key)
if tc.err {
if err == nil {
t.Fatal("expecting error, got no error")
}
return
}
if err != nil {
t.Fatalf("expecting no error, got %q", err)
}
s, found := store.bearerTokenAssets[key]
if !found {
t.Fatalf("expecting to find key %q but got nothing", key)
}
if string(s) != tc.expected {
t.Fatalf("expecting %q, got %q", tc.expected, s)
}
})
}
}
func TestAddBasicAuth(t *testing.T) {
c := fake.NewSimpleClientset(
&v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "secret",
Namespace: "ns1",
},
Data: map[string][]byte{
"key1": []byte("val1"),
"key2": []byte("val2"),
},
},
)
for i, tc := range []struct {
ns string
selectedUserName string
selectedUserKey string
selectedPasswordName string
selectedPasswordKey string
err bool
expectedUser string
expectedPassword string
}{
{
ns: "ns1",
selectedUserName: "secret",
selectedUserKey: "key1",
selectedPasswordName: "secret",
selectedPasswordKey: "key2",
expectedUser: "val1",
expectedPassword: "val2",
},
// Wrong namespace.
{
ns: "ns2",
selectedUserName: "secret",
selectedUserKey: "key1",
selectedPasswordName: "secret",
selectedPasswordKey: "key2",
err: true,
},
// Wrong name for username selector.
{
ns: "ns1",
selectedUserName: "secreet",
selectedUserKey: "key1",
selectedPasswordName: "secret",
selectedPasswordKey: "key2",
err: true,
},
// Wrong key for username selector.
{
ns: "ns1",
selectedUserName: "secret",
selectedUserKey: "key3",
selectedPasswordName: "secret",
selectedPasswordKey: "key2",
err: true,
},
// Wrong name for password selector.
{
ns: "ns1",
selectedUserName: "secret",
selectedUserKey: "key1",
selectedPasswordName: "secreet",
selectedPasswordKey: "key2",
err: true,
},
// Wrong key for password selector.
{
ns: "ns1",
selectedUserName: "secret",
selectedUserKey: "key1",
selectedPasswordName: "secret",
selectedPasswordKey: "key3",
err: true,
},
} {
t.Run("", func(t *testing.T) {
store := newAssetStore(c.CoreV1(), c.CoreV1())
basicAuth := &monitoringv1.BasicAuth{
Username: v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: tc.selectedUserName,
},
Key: tc.selectedUserKey,
},
Password: v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: tc.selectedPasswordName,
},
Key: tc.selectedPasswordKey,
},
}
key := fmt.Sprintf("basicauth/%d", i)
err := store.addBasicAuth(tc.ns, basicAuth, key)
if tc.err {
if err == nil {
t.Fatal("expecting error, got no error")
}
return
}
if err != nil {
t.Fatalf("expecting no error, got %q", err)
}
s, found := store.basicAuthAssets[key]
if !found {
t.Fatalf("expecting to find key %q but got nothing", key)
}
if s.username != tc.expectedUser {
t.Fatalf("expecting username %q, got %q", tc.expectedUser, s)
}
if s.password != tc.expectedPassword {
t.Fatalf("expecting password %q, got %q", tc.expectedPassword, s)
}
})
}
}
func TestAddTLSConfig(t *testing.T) {
c := fake.NewSimpleClientset(
&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "cm",
Namespace: "ns1",
},
Data: map[string]string{
"key1": "val1",
"key2": "val2",
"key3": "val3",
},
},
&v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "secret",
Namespace: "ns1",
},
Data: map[string][]byte{
"key4": []byte("val4"),
"key5": []byte("val5"),
"key6": []byte("val6"),
},
},
)
for _, tc := range []struct {
ns string
tlsConfig *monitoringv1.TLSConfig
err bool
expectedCA string
expectedCert string
expectedKey string
}{
{
// CA, cert and key in secret.
ns: "ns1",
tlsConfig: &monitoringv1.TLSConfig{
CA: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key4",
},
},
Cert: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key5",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key6",
},
},
expectedCA: "val4",
expectedCert: "val5",
expectedKey: "val6",
},
{
// CA in configmap, cert and key in secret.
ns: "ns1",
tlsConfig: &monitoringv1.TLSConfig{
CA: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "cm",
},
Key: "key1",
},
},
Cert: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key5",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key6",
},
},
expectedCA: "val1",
expectedCert: "val5",
expectedKey: "val6",
},
{
// CA and cert in configmap, key in secret.
ns: "ns1",
tlsConfig: &monitoringv1.TLSConfig{
CA: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "cm",
},
Key: "key1",
},
},
Cert: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "cm",
},
Key: "key2",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key6",
},
},
expectedCA: "val1",
expectedCert: "val2",
expectedKey: "val6",
},
{
// Wrong namespace.
ns: "ns2",
tlsConfig: &monitoringv1.TLSConfig{
CA: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "cm",
},
Key: "key1",
},
},
Cert: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "cm",
},
Key: "key2",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key6",
},
},
err: true,
},
{
// Wrong configmap selector for CA.
ns: "ns1",
tlsConfig: &monitoringv1.TLSConfig{
CA: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "cm",
},
Key: "key4",
},
},
Cert: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "cm",
},
Key: "key2",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key6",
},
},
err: true,
},
{
// Wrong secret selector for CA.
ns: "ns1",
tlsConfig: &monitoringv1.TLSConfig{
CA: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key1",
},
},
Cert: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "cm",
},
Key: "key2",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key6",
},
},
err: true,
},
{
// Wrong configmap selector for cert.
ns: "ns1",
tlsConfig: &monitoringv1.TLSConfig{
CA: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "cm",
},
Key: "key1",
},
},
Cert: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "cm",
},
Key: "key4",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key6",
},
},
err: true,
},
{
// Wrong secret selector for cert.
ns: "ns1",
tlsConfig: &monitoringv1.TLSConfig{
CA: monitoringv1.SecretOrConfigMap{
ConfigMap: &v1.ConfigMapKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "cm",
},
Key: "key1",
},
},
Cert: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key2",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key6",
},
},
err: true,
},
{
// Wrong key selector.
ns: "ns1",
tlsConfig: &monitoringv1.TLSConfig{
CA: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key4",
},
},
Cert: monitoringv1.SecretOrConfigMap{
Secret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key5",
},
},
KeySecret: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: "secret",
},
Key: "key7",
},
},
err: true,
},
} {
t.Run("", func(t *testing.T) {
store := newAssetStore(c.CoreV1(), c.CoreV1())
err := store.addTLSConfig(tc.ns, tc.tlsConfig)
if tc.err {
if err == nil {
t.Fatal("expecting error, got no error")
}
return
}
if err != nil {
t.Fatalf("expecting no error, got %q", err)
}
key := tlsAssetKeyFromSelector(tc.ns, tc.tlsConfig.CA)
ca, found := store.tlsAssets[key]
if !found {
t.Fatalf("expecting to find key %q but got nothing", key)
}
if string(ca) != tc.expectedCA {
t.Fatalf("expecting CA %q, got %q", tc.expectedCA, ca)
}
key = tlsAssetKeyFromSelector(tc.ns, tc.tlsConfig.Cert)
cert, found := store.tlsAssets[key]
if !found {
t.Fatalf("expecting to find key %q but got nothing", key)
}
if string(cert) != tc.expectedCert {
t.Fatalf("expecting cert %q, got %q", tc.expectedCert, ca)
}
key = tlsAssetKeyFromSecretSelector(tc.ns, tc.tlsConfig.KeySecret)
k, found := store.tlsAssets[key]
if !found {
t.Fatalf("expecting to find key %q but got nothing", key)
}
if string(k) != tc.expectedKey {
t.Fatalf("expecting cert key %q, got %q", tc.expectedCert, ca)
}
})
}
}

View file

@ -45,7 +45,6 @@ import (
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
@ -1820,216 +1819,3 @@ func (c *Operator) listMatchingNamespaces(selector labels.Selector) ([]string, e
}
return ns, nil
}
type tlsAssetKey struct {
from string
ns string
name string
key string
}
func tlsAssetKeyFromSecretSelector(ns string, sel *v1.SecretKeySelector) tlsAssetKey {
return tlsAssetKey{
from: "configmap",
ns: ns,
name: sel.Name,
key: sel.Key,
}
}
func tlsAssetKeyFromConfigMapSelector(ns string, sel *v1.ConfigMapKeySelector) tlsAssetKey {
return tlsAssetKey{
from: "secret",
ns: ns,
name: sel.Name,
key: sel.Key,
}
}
func (k tlsAssetKey) String() string {
return fmt.Sprintf("%s_%s_%s_%s", k.from, k.ns, k.name, k.key)
}
type assetStore struct {
cmClient corev1client.ConfigMapsGetter
sClient corev1client.SecretsGetter
objStore cache.Store
tlsAssets map[tlsAssetKey]TLSAsset
bearerTokenAssets map[string]BearerToken
basicAuthAssets map[string]BasicAuthCredentials
}
func newAssetStore(cmClient corev1client.ConfigMapsGetter, sClient corev1client.SecretsGetter) *assetStore {
assetStore := &assetStore{
cmClient: cmClient,
sClient: sClient,
tlsAssets: make(map[tlsAssetKey]TLSAsset),
bearerTokenAssets: make(map[string]BearerToken),
basicAuthAssets: make(map[string]BasicAuthCredentials),
}
assetStore.objStore = cache.NewStore(assetStore.keyFunc)
return assetStore
}
func (a *assetStore) keyFunc(obj interface{}) (string, error) {
switch v := obj.(type) {
case *v1.ConfigMap:
return fmt.Sprintf("0/%s/%s", v.GetNamespace(), v.GetName()), nil
case *v1.Secret:
return fmt.Sprintf("1/%s/%s", v.GetNamespace(), v.GetName()), nil
}
return "", errors.Errorf("unsupported type: %T", obj)
}
func (a *assetStore) addTLSConfig(ns string, tlsConfig *monitoringv1.TLSConfig) error {
if tlsConfig == nil {
return nil
}
if tlsConfig.CA != (monitoringv1.SecretOrConfigMap{}) {
switch {
case tlsConfig.CA.Secret != nil:
ca, err := a.getSecretKey(ns, *tlsConfig.CA.Secret)
if err != nil {
return errors.Wrap(err, "failed to get CA")
}
a.tlsAssets[tlsAssetKeyFromSecretSelector(ns, tlsConfig.CA.Secret)] = TLSAsset(ca)
case tlsConfig.CA.ConfigMap != nil:
ca, err := a.getConfigMapKey(ns, *tlsConfig.CA.ConfigMap)
if err != nil {
return errors.Wrap(err, "failed to get CA")
}
a.tlsAssets[tlsAssetKeyFromConfigMapSelector(ns, tlsConfig.CA.ConfigMap)] = TLSAsset(ca)
}
}
if tlsConfig.Cert != (monitoringv1.SecretOrConfigMap{}) {
switch {
case tlsConfig.Cert.Secret != nil:
cert, err := a.getSecretKey(ns, *tlsConfig.Cert.Secret)
if err != nil {
return errors.Wrap(err, "failed to get cert")
}
a.tlsAssets[tlsAssetKeyFromSecretSelector(ns, tlsConfig.Cert.Secret)] = TLSAsset(cert)
case tlsConfig.Cert.ConfigMap != nil:
cert, err := a.getConfigMapKey(ns, *tlsConfig.Cert.ConfigMap)
if err != nil {
return errors.Wrap(err, "failed to get cert")
}
a.tlsAssets[tlsAssetKeyFromConfigMapSelector(ns, tlsConfig.Cert.ConfigMap)] = TLSAsset(cert)
}
}
if tlsConfig.KeySecret != nil {
key, err := a.getSecretKey(ns, *tlsConfig.KeySecret)
if err != nil {
return errors.Wrap(err, "failed to get key")
}
a.tlsAssets[tlsAssetKeyFromSecretSelector(ns, tlsConfig.KeySecret)] = TLSAsset(key)
}
return nil
}
func (a *assetStore) addBasicAuth(ns string, ba *monitoringv1.BasicAuth, key string) error {
if ba == nil {
return nil
}
username, err := a.getSecretKey(ns, ba.Username)
if err != nil {
return errors.Wrap(err, "failed to get basic auth username")
}
password, err := a.getSecretKey(ns, ba.Password)
if err != nil {
return errors.Wrap(err, "failed to get basic auth password")
}
a.basicAuthAssets[key] = BasicAuthCredentials{
username: username,
password: password,
}
return nil
}
func (a *assetStore) addBearerToken(ns string, sel v1.SecretKeySelector, key string) error {
if sel.Name == "" {
return nil
}
bearerToken, err := a.getSecretKey(ns, sel)
if err != nil {
return errors.Wrap(err, "failed to get bearer token")
}
a.bearerTokenAssets[key] = BearerToken(bearerToken)
return nil
}
func (a *assetStore) getConfigMapKey(namespace string, sel v1.ConfigMapKeySelector) (string, error) {
obj, exists, err := a.objStore.Get(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: sel.Name,
Namespace: namespace,
},
})
if err != nil {
return "", errors.Wrapf(err, "unexpected store error when getting configmap %q", sel.Name)
}
if !exists {
cm, err := a.cmClient.ConfigMaps(namespace).Get(context.TODO(), sel.Name, metav1.GetOptions{})
if err != nil {
return "", errors.Wrapf(err, "unable to get configmap %q", sel.Name)
}
if err = a.objStore.Add(cm); err != nil {
return "", errors.Wrapf(err, "unexpected store error when adding configmap %q", sel.Name)
}
obj = cm
}
cm := obj.(*v1.ConfigMap)
if _, found := cm.Data[sel.Key]; !found {
return "", errors.Errorf("key %q in configmap %q not found", sel.Key, sel.Name)
}
return cm.Data[sel.Key], nil
}
func (a *assetStore) getSecretKey(namespace string, sel v1.SecretKeySelector) (string, error) {
obj, exists, err := a.objStore.Get(&v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: sel.Name,
Namespace: namespace,
},
})
if err != nil {
return "", errors.Wrapf(err, "unexpected store error when getting secret %q", sel.Name)
}
if !exists {
secret, err := a.sClient.Secrets(namespace).Get(context.TODO(), sel.Name, metav1.GetOptions{})
if err != nil {
return "", errors.Wrapf(err, "unable to get secret %q", sel.Name)
}
if err = a.objStore.Add(secret); err != nil {
return "", errors.Wrapf(err, "unexpected store error when adding secret %q", sel.Name)
}
obj = secret
}
secret := obj.(*v1.Secret)
if _, found := secret.Data[sel.Key]; !found {
return "", errors.Errorf("key %q in secret %q not found", sel.Key, sel.Name)
}
return string(secret.Data[sel.Key]), nil
}

View file

@ -26,7 +26,6 @@ import (
"github.com/go-kit/kit/log/level"
"github.com/pkg/errors"
yaml "gopkg.in/yaml.v2"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
@ -75,11 +74,8 @@ func stringMapToMapSlice(m map[string]string) yaml.MapSlice {
}
func addTLStoYaml(cfg yaml.MapSlice, namespace string, tls *v1.TLSConfig) yaml.MapSlice {
pathForSecretSelector := func(sel *corev1.SecretKeySelector) string {
return path.Join(tlsAssetsDir, tlsAssetKeyFromSecretSelector(namespace, sel).String())
}
pathForConfigMapSelector := func(sel *corev1.ConfigMapKeySelector) string {
return path.Join(tlsAssetsDir, tlsAssetKeyFromConfigMapSelector(namespace, sel).String())
pathForSelector := func(sel v1.SecretOrConfigMap) string {
return path.Join(tlsAssetsDir, tlsAssetKeyFromSelector(namespace, sel).String())
}
if tls != nil {
tlsConfig := yaml.MapSlice{
@ -88,26 +84,20 @@ func addTLStoYaml(cfg yaml.MapSlice, namespace string, tls *v1.TLSConfig) yaml.M
if tls.CAFile != "" {
tlsConfig = append(tlsConfig, yaml.MapItem{Key: "ca_file", Value: tls.CAFile})
}
if tls.CA.Secret != nil {
tlsConfig = append(tlsConfig, yaml.MapItem{Key: "ca_file", Value: pathForSecretSelector(tls.CA.Secret)})
}
if tls.CA.ConfigMap != nil {
tlsConfig = append(tlsConfig, yaml.MapItem{Key: "ca_file", Value: pathForConfigMapSelector(tls.CA.ConfigMap)})
if tls.CA.Secret != nil || tls.CA.ConfigMap != nil {
tlsConfig = append(tlsConfig, yaml.MapItem{Key: "ca_file", Value: pathForSelector(tls.CA)})
}
if tls.CertFile != "" {
tlsConfig = append(tlsConfig, yaml.MapItem{Key: "cert_file", Value: tls.CertFile})
}
if tls.Cert.Secret != nil {
tlsConfig = append(tlsConfig, yaml.MapItem{Key: "cert_file", Value: pathForSecretSelector(tls.Cert.Secret)})
}
if tls.Cert.ConfigMap != nil {
tlsConfig = append(tlsConfig, yaml.MapItem{Key: "cert_file", Value: pathForConfigMapSelector(tls.Cert.ConfigMap)})
if tls.Cert.Secret != nil || tls.Cert.ConfigMap != nil {
tlsConfig = append(tlsConfig, yaml.MapItem{Key: "cert_file", Value: pathForSelector(tls.Cert)})
}
if tls.KeyFile != "" {
tlsConfig = append(tlsConfig, yaml.MapItem{Key: "key_file", Value: tls.KeyFile})
}
if tls.KeySecret != nil {
tlsConfig = append(tlsConfig, yaml.MapItem{Key: "key_file", Value: pathForSecretSelector(tls.KeySecret)})
tlsConfig = append(tlsConfig, yaml.MapItem{Key: "key_file", Value: pathForSelector(v1.SecretOrConfigMap{Secret: tls.KeySecret})})
}
if tls.ServerName != "" {
tlsConfig = append(tlsConfig, yaml.MapItem{Key: "server_name", Value: tls.ServerName})