1
0
Fork 0
mirror of https://github.com/prometheus-operator/prometheus-operator.git synced 2025-04-16 01:06:27 +00:00
prometheus-operator/pkg/prometheus/rules.go
2018-06-05 13:34:13 +02:00

212 lines
5.6 KiB
Go

// Copyright 2016 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 (
"crypto/sha256"
"fmt"
"sort"
"strings"
monitoringv1 "github.com/coreos/prometheus-operator/pkg/client/monitoring/v1"
"k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/cache"
"github.com/ghodss/yaml"
"github.com/go-kit/kit/log/level"
"github.com/pkg/errors"
)
func (c *Operator) createOrUpdateRuleConfigMap(p *monitoringv1.Prometheus) error {
cClient := c.kclient.CoreV1().ConfigMaps(p.Namespace)
namespaces, err := c.selectRuleNamespaces(p)
if err != nil {
return err
}
rules, err := c.selectRules(p, namespaces)
if err != nil {
return err
}
newConfigMap := c.makeRulesConfigMap(p, rules)
currentConfigMap, err := cClient.Get(prometheusRuleConfigMapName(p.Name), metav1.GetOptions{})
if err != nil && !apierrors.IsNotFound(err) {
return err
}
isNotFound := false
if apierrors.IsNotFound(err) {
level.Debug(c.logger).Log(
"msg", "no PrometheusRule configmap created yet",
"namespace", p.Namespace,
"prometheus", p.Name,
)
isNotFound = true
}
newChecksum := checksumRules(rules)
currentChecksum := checksumRules(currentConfigMap.Data)
if newChecksum == currentChecksum && !isNotFound {
level.Debug(c.logger).Log(
"msg", "no PrometheusRule changes",
"namespace", p.Namespace,
"prometheus", p.Name,
)
return nil
}
if isNotFound {
level.Debug(c.logger).Log(
"msg", "no PrometheusRule found, creating new one",
"namespace", p.Namespace,
"prometheus", p.Name,
)
_, err = cClient.Create(newConfigMap)
} else {
level.Debug(c.logger).Log(
"msg", "updating PrometheusRule",
"namespace", p.Namespace,
"prometheus", p.Name,
)
_, err = cClient.Update(newConfigMap)
}
if err != nil {
return err
}
return nil
}
func (c *Operator) selectRuleNamespaces(p *monitoringv1.Prometheus) ([]string, error) {
namespaces := []string{}
// If 'RuleNamespaceSelector' is nil, only check own namespace.
if p.Spec.RuleNamespaceSelector == nil {
namespaces = append(namespaces, p.Namespace)
} else {
ruleNamespaceSelector, err := metav1.LabelSelectorAsSelector(p.Spec.RuleNamespaceSelector)
if err != nil {
return namespaces, errors.Wrap(err, "convert rule namespace label selector to selector")
}
cache.ListAll(c.nsInf.GetStore(), ruleNamespaceSelector, func(obj interface{}) {
namespaces = append(namespaces, obj.(*v1.Namespace).Name)
})
}
level.Debug(c.logger).Log(
"msg", "selected RuleNamespaces",
"namespaces", strings.Join(namespaces, ","),
"namespace", p.Namespace,
"prometheus", p.Name,
)
return namespaces, nil
}
func (c *Operator) selectRules(p *monitoringv1.Prometheus, namespaces []string) (map[string]string, error) {
rules := map[string]string{}
// With Prometheus Operator v0.20.0 the 'RuleSelector' field in the Prometheus
// CRD Spec is deprecated. Any value in 'RuleSelector' is just copied to the new
// field 'PrometheusRuleSelector'.
if p.Spec.PrometheusRuleSelector == nil && p.Spec.RuleSelector != nil {
p.Spec.PrometheusRuleSelector = p.Spec.RuleSelector
}
ruleSelector, err := metav1.LabelSelectorAsSelector(p.Spec.PrometheusRuleSelector)
if err != nil {
return rules, errors.Wrap(err, "convert rule label selector to selector")
}
for _, ns := range namespaces {
var marshalErr error
err := cache.ListAllByNamespace(c.ruleInf.GetIndexer(), ns, ruleSelector, func(obj interface{}) {
rule := obj.(*monitoringv1.PrometheusRule)
content, err := yaml.Marshal(rule.Spec)
if err != nil {
marshalErr = err
return
}
rules[fmt.Sprintf("%v-%v.yaml", rule.Namespace, rule.Name)] = string(content)
})
if err != nil {
return nil, err
}
if marshalErr != nil {
return nil, marshalErr
}
}
// sort rules map
rulenames := []string{}
for k := range rules {
rulenames = append(rulenames, k)
}
sort.Strings(rulenames)
sortedRules := map[string]string{}
for _, name := range rulenames {
sortedRules[name] = rules[name]
}
level.Debug(c.logger).Log(
"msg", "selected Rules",
"rules", strings.Join(rulenames, ","),
"namespace", p.Namespace,
"prometheus", p.Name,
)
return sortedRules, nil
}
func (c *Operator) makeRulesConfigMap(p *monitoringv1.Prometheus, ruleFiles map[string]string) *v1.ConfigMap {
boolTrue := true
return &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: prometheusRuleConfigMapName(p.Name),
Labels: managedByOperatorLabels,
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: p.APIVersion,
BlockOwnerDeletion: &boolTrue,
Controller: &boolTrue,
Kind: p.Kind,
Name: p.Name,
UID: p.UID,
},
},
},
Data: ruleFiles,
}
}
func checksumRules(files map[string]string) string {
var sum string
for name, value := range files {
sum = sum + name + value
}
return fmt.Sprintf("%x", sha256.Sum256([]byte(sum)))
}
func prometheusRuleConfigMapName(prometheusName string) string {
return "prometheus-" + prometheusName + "-rulefiles"
}