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

Use cache.Store instead of custom stores

This commit is contained in:
Simon Pasquier 2020-08-28 11:27:08 +02:00
parent caf6b9f3ce
commit a0a1816f4c

View file

@ -1207,13 +1207,13 @@ func (c *Operator) sync(key string) error {
return err
}
assetCacher := newAssetCache(newSecretIndexer(c.kclient.CoreV1()), newConfigMapIndexer(c.kclient.CoreV1()))
assetStore := newAssetStore(c.kclient.CoreV1(), c.kclient.CoreV1())
if err := c.createOrUpdateConfigurationSecret(p, ruleConfigMapNames, assetCacher); err != nil {
if err := c.createOrUpdateConfigurationSecret(p, ruleConfigMapNames, assetStore); err != nil {
return errors.Wrap(err, "creating config failed")
}
if err := c.createOrUpdateTLSAssetSecret(p, assetCacher); err != nil {
if err := c.createOrUpdateTLSAssetSecret(p, assetStore); err != nil {
return errors.Wrap(err, "creating tls asset secret failed")
}
@ -1416,74 +1416,6 @@ func (c *Operator) loadAdditionalScrapeConfigsSecret(additionalScrapeConfigs *v1
return nil, nil
}
type secretIndexer struct {
client corev1client.SecretsGetter
cache map[string]*v1.Secret
}
func newSecretIndexer(c corev1client.SecretsGetter) *secretIndexer {
return &secretIndexer{
client: c,
cache: make(map[string]*v1.Secret),
}
}
func (i *secretIndexer) getKey(namespace string, sel v1.SecretKeySelector) (string, error) {
var (
err error
cacheKey = fmt.Sprintf("%s/%s", namespace, sel.Name)
)
s, found := i.cache[cacheKey]
if !found {
s, err = i.client.Secrets(namespace).Get(context.TODO(), sel.Name, metav1.GetOptions{})
if err != nil {
return "", errors.Wrapf(err, "unable to get secret %q", cacheKey)
}
i.cache[cacheKey] = s
}
if _, found := s.Data[sel.Key]; !found {
return "", fmt.Errorf("key %q in secret %q not found", sel.Key, cacheKey)
}
return string(s.Data[sel.Key]), nil
}
type configMapIndexer struct {
client corev1client.ConfigMapsGetter
cache map[string]*v1.ConfigMap
}
func newConfigMapIndexer(c corev1client.ConfigMapsGetter) *configMapIndexer {
return &configMapIndexer{
client: c,
cache: make(map[string]*v1.ConfigMap),
}
}
func (i *configMapIndexer) getKey(namespace string, sel v1.ConfigMapKeySelector) (string, error) {
var (
err error
cacheKey = fmt.Sprintf("%s/%s", namespace, sel.Name)
)
cm, found := i.cache[cacheKey]
if !found {
cm, err = i.client.ConfigMaps(namespace).Get(context.TODO(), sel.Name, metav1.GetOptions{})
if err != nil {
return "", errors.Wrapf(err, "unable to get configmap %q", sel.Name)
}
i.cache[cacheKey] = cm
}
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 gzipConfig(buf *bytes.Buffer, conf []byte) error {
w := gzip.NewWriter(buf)
defer w.Close()
@ -1493,7 +1425,7 @@ func gzipConfig(buf *bytes.Buffer, conf []byte) error {
return nil
}
func (c *Operator) createOrUpdateConfigurationSecret(p *monitoringv1.Prometheus, ruleConfigMapNames []string, cacher *assetCache) error {
func (c *Operator) createOrUpdateConfigurationSecret(p *monitoringv1.Prometheus, ruleConfigMapNames []string, store *assetStore) error {
// If no service or pod monitor selectors are configured, the user wants to
// manage configuration themselves. Do create an empty Secret if it doesn't
// exist.
@ -1519,7 +1451,7 @@ func (c *Operator) createOrUpdateConfigurationSecret(p *monitoringv1.Prometheus,
return nil
}
smons, err := c.selectServiceMonitors(p, cacher)
smons, err := c.selectServiceMonitors(p, store)
if err != nil {
return errors.Wrap(err, "selecting ServiceMonitors failed")
}
@ -1541,19 +1473,19 @@ func (c *Operator) createOrUpdateConfigurationSecret(p *monitoringv1.Prometheus,
}
for i, remote := range p.Spec.RemoteRead {
if err := cacher.processBasicAuth(p.GetNamespace(), remote.BasicAuth, fmt.Sprintf("remoteRead/%d", i)); err != nil {
if err := store.addBasicAuth(p.GetNamespace(), remote.BasicAuth, fmt.Sprintf("remoteRead/%d", i)); err != nil {
return errors.Wrapf(err, "remote read %d", i)
}
}
for i, remote := range p.Spec.RemoteWrite {
if err := cacher.processBasicAuth(p.GetNamespace(), remote.BasicAuth, fmt.Sprintf("remoteWrite/%d", i)); err != nil {
if err := store.addBasicAuth(p.GetNamespace(), remote.BasicAuth, fmt.Sprintf("remoteWrite/%d", i)); err != nil {
return errors.Wrapf(err, "remote write %d", i)
}
}
if p.Spec.APIServerConfig != nil {
if err := cacher.processBasicAuth(p.GetNamespace(), p.Spec.APIServerConfig.BasicAuth, "apiserver"); err != nil {
if err := store.addBasicAuth(p.GetNamespace(), p.Spec.APIServerConfig.BasicAuth, "apiserver"); err != nil {
return errors.Wrap(err, "apiserver config")
}
}
@ -1577,8 +1509,8 @@ func (c *Operator) createOrUpdateConfigurationSecret(p *monitoringv1.Prometheus,
smons,
pmons,
bmons,
cacher.basicAuthAssets,
cacher.bearerTokenAssets,
store.basicAuthAssets,
store.bearerTokenAssets,
additionalScrapeConfigs,
additionalAlertRelabelConfigs,
additionalAlertManagerConfigs,
@ -1626,7 +1558,7 @@ func (c *Operator) createOrUpdateConfigurationSecret(p *monitoringv1.Prometheus,
return err
}
func (c *Operator) createOrUpdateTLSAssetSecret(p *monitoringv1.Prometheus, cacher *assetCache) error {
func (c *Operator) createOrUpdateTLSAssetSecret(p *monitoringv1.Prometheus, store *assetStore) error {
boolTrue := true
sClient := c.kclient.CoreV1().Secrets(p.Namespace)
@ -1649,12 +1581,12 @@ func (c *Operator) createOrUpdateTLSAssetSecret(p *monitoringv1.Prometheus, cach
}
for i, rw := range p.Spec.RemoteWrite {
if err := cacher.processTLSConfig(p.GetNamespace(), rw.TLSConfig); err != nil {
if err := store.addTLSConfig(p.GetNamespace(), rw.TLSConfig); err != nil {
return errors.Wrapf(err, "remote write %d", i)
}
}
for key, asset := range cacher.tlsAssets {
for key, asset := range store.tlsAssets {
tlsAssetsSecret.Data[key.String()] = []byte(asset)
}
@ -1683,7 +1615,7 @@ func (c *Operator) createOrUpdateTLSAssetSecret(p *monitoringv1.Prometheus, cach
return nil
}
func (c *Operator) selectServiceMonitors(p *monitoringv1.Prometheus, cacher *assetCache) (map[string]*monitoringv1.ServiceMonitor, error) {
func (c *Operator) selectServiceMonitors(p *monitoringv1.Prometheus, store *assetStore) (map[string]*monitoringv1.ServiceMonitor, error) {
namespaces := []string{}
// Selectors (<namespace>/<name>) might overlap. Deduplicate them along the keyFunc.
serviceMonitors := make(map[string]*monitoringv1.ServiceMonitor)
@ -1734,15 +1666,15 @@ func (c *Operator) selectServiceMonitors(p *monitoringv1.Prometheus, cacher *ass
smKey := fmt.Sprintf("serviceMonitor/%s/%s/%d", sm.GetNamespace(), sm.GetName(), i)
if err = cacher.processBearerToken(sm.GetNamespace(), endpoint.BearerTokenSecret, smKey); err != nil {
if err = store.addBearerToken(sm.GetNamespace(), endpoint.BearerTokenSecret, smKey); err != nil {
break
}
if err = cacher.processBasicAuth(sm.GetNamespace(), endpoint.BasicAuth, smKey); err != nil {
if err = store.addBasicAuth(sm.GetNamespace(), endpoint.BasicAuth, smKey); err != nil {
break
}
if err = cacher.processTLSConfig(sm.GetNamespace(), endpoint.TLSConfig); err != nil {
if err = store.addTLSConfig(sm.GetNamespace(), endpoint.TLSConfig); err != nil {
break
}
}
@ -1770,144 +1702,6 @@ func (c *Operator) selectServiceMonitors(p *monitoringv1.Prometheus, cacher *ass
return res, nil
}
type assetCache struct {
sIndexer *secretIndexer
cmIndexer *configMapIndexer
tlsAssets map[tlsAssetKey]TLSAsset
bearerTokenAssets map[string]BearerToken
basicAuthAssets map[string]BasicAuthCredentials
}
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)
}
func newAssetCache(sIndexer *secretIndexer, cmIndexer *configMapIndexer) *assetCache {
return &assetCache{
sIndexer: sIndexer,
cmIndexer: cmIndexer,
tlsAssets: make(map[tlsAssetKey]TLSAsset),
bearerTokenAssets: make(map[string]BearerToken),
basicAuthAssets: make(map[string]BasicAuthCredentials),
}
}
func (a *assetCache) processTLSConfig(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.sIndexer.getKey(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.cmIndexer.getKey(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.sIndexer.getKey(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.cmIndexer.getKey(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.sIndexer.getKey(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 *assetCache) processBasicAuth(ns string, ba *monitoringv1.BasicAuth, key string) error {
if ba == nil {
return nil
}
username, err := a.sIndexer.getKey(ns, ba.Username)
if err != nil {
return errors.Wrap(err, "failed to get basic auth username")
}
password, err := a.sIndexer.getKey(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 *assetCache) processBearerToken(ns string, sel v1.SecretKeySelector, key string) error {
if sel.Name == "" {
return nil
}
bearerToken, err := a.sIndexer.getKey(ns, sel)
if err != nil {
return errors.Wrap(err, "failed to get bearer token")
}
a.bearerTokenAssets[key] = BearerToken(bearerToken)
return nil
}
func (c *Operator) selectPodMonitors(p *monitoringv1.Prometheus) (map[string]*monitoringv1.PodMonitor, error) {
namespaces := []string{}
// Selectors might overlap. Deduplicate them along the keyFunc.
@ -2026,3 +1820,216 @@ 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
}