mirror of
https://github.com/coreos/prometheus-operator.git
synced 2026-02-05 06:45:27 +01:00
* Share parsing for the logging flags across all binaries. * Refactor and share the web server implementation between the operator and the admission webhook. * Refactor controller configuration structs to include only the required parameters. * Parse label and field selector arguments early instead of doing it in each controller. Signed-off-by: Simon Pasquier <spasquie@redhat.com>
338 lines
7.9 KiB
Go
338 lines
7.9 KiB
Go
// 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 operator
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"sort"
|
|
"strings"
|
|
|
|
"golang.org/x/exp/maps"
|
|
v1 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/api/resource"
|
|
"k8s.io/apimachinery/pkg/fields"
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
"k8s.io/apimachinery/pkg/version"
|
|
)
|
|
|
|
// Config defines configuration parameters for the Operator.
|
|
type Config struct {
|
|
// Version reported by the Kubernetes API.
|
|
KubernetesVersion version.Info
|
|
|
|
// Parameters for the kubelet endpoint controller.
|
|
KubeletObject string
|
|
KubeletSelector LabelSelector
|
|
|
|
// Cluster domain for Kubernetes services managed by the operator.
|
|
ClusterDomain string
|
|
|
|
// Global configuration for the reloader config sidecar.
|
|
ReloaderConfig ContainerConfig
|
|
|
|
// Base container images for operands.
|
|
AlertmanagerDefaultBaseImage string
|
|
PrometheusDefaultBaseImage string
|
|
ThanosDefaultBaseImage string
|
|
|
|
// Allow and deny lists for namespace watchers.
|
|
Namespaces Namespaces
|
|
|
|
// Metadata applied to all resources managed by the operator.
|
|
Annotations Map
|
|
Labels Map
|
|
|
|
// Custom name to use for "localhost".
|
|
LocalHost string
|
|
|
|
// Label and field selectors for resource watchers.
|
|
PromSelector LabelSelector
|
|
AlertmanagerSelector LabelSelector
|
|
ThanosRulerSelector LabelSelector
|
|
SecretListWatchSelector FieldSelector
|
|
}
|
|
|
|
// DefaultConfig returns a default operator configuration.
|
|
func DefaultConfig(cpu, memory string) Config {
|
|
return Config{
|
|
ReloaderConfig: ContainerConfig{
|
|
CPURequests: Quantity{q: resource.MustParse(cpu)},
|
|
CPULimits: Quantity{q: resource.MustParse(cpu)},
|
|
MemoryRequests: Quantity{q: resource.MustParse(memory)},
|
|
MemoryLimits: Quantity{q: resource.MustParse(memory)},
|
|
},
|
|
Namespaces: Namespaces{
|
|
AllowList: StringSet{},
|
|
DenyList: StringSet{},
|
|
PrometheusAllowList: StringSet{},
|
|
AlertmanagerAllowList: StringSet{},
|
|
AlertmanagerConfigAllowList: StringSet{},
|
|
ThanosRulerAllowList: StringSet{},
|
|
},
|
|
}
|
|
}
|
|
|
|
// ContainerConfig holds some configuration for the ConfigReloader sidecar
|
|
// that can be set through prometheus-operator command line arguments
|
|
type ContainerConfig struct {
|
|
// The struct tag are needed for github.com/mitchellh/hashstructure to take
|
|
// the field values into account when generating the statefulset hash.
|
|
CPURequests Quantity `hash:"string"`
|
|
CPULimits Quantity `hash:"string"`
|
|
MemoryRequests Quantity `hash:"string"`
|
|
MemoryLimits Quantity `hash:"string"`
|
|
Image string
|
|
EnableProbes bool
|
|
}
|
|
|
|
func (cc ContainerConfig) ResourceRequirements() v1.ResourceRequirements {
|
|
resources := v1.ResourceRequirements{
|
|
Limits: v1.ResourceList{},
|
|
Requests: v1.ResourceList{},
|
|
}
|
|
|
|
if cc.CPURequests.String() != "0" {
|
|
resources.Requests[v1.ResourceCPU] = cc.CPURequests.q
|
|
}
|
|
if cc.CPULimits.String() != "0" {
|
|
resources.Limits[v1.ResourceCPU] = cc.CPULimits.q
|
|
}
|
|
if cc.MemoryRequests.String() != "0" {
|
|
resources.Requests[v1.ResourceMemory] = cc.MemoryRequests.q
|
|
}
|
|
if cc.MemoryLimits.String() != "0" {
|
|
resources.Limits[v1.ResourceMemory] = cc.MemoryLimits.q
|
|
}
|
|
|
|
return resources
|
|
}
|
|
|
|
type Quantity struct {
|
|
q resource.Quantity
|
|
}
|
|
|
|
var _ = fmt.Stringer(Quantity{})
|
|
|
|
// String implements the flag.Value and fmt.Stringer interfaces.
|
|
func (q Quantity) String() string {
|
|
return q.q.String()
|
|
}
|
|
|
|
// Set implements the flag.Value interface.
|
|
func (q *Quantity) Set(value string) error {
|
|
if value == "" {
|
|
return nil
|
|
}
|
|
|
|
quantity, err := resource.ParseQuantity(value)
|
|
if err == nil {
|
|
q.q = quantity
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
type Map map[string]string
|
|
|
|
// String implements the flag.Value interface
|
|
func (m *Map) String() string {
|
|
if m == nil {
|
|
return ""
|
|
}
|
|
|
|
kv := make([]string, 0, len(*m))
|
|
for _, k := range m.SortedKeys() {
|
|
kv = append(kv, fmt.Sprintf("%s=%s", k, (*m)[k]))
|
|
}
|
|
|
|
return strings.Join(kv, ",")
|
|
}
|
|
|
|
// Merge returns a map which is a merge of the original map and the other parameter.
|
|
// The keys of the original map take precedence over other.
|
|
func (m *Map) Merge(other map[string]string) map[string]string {
|
|
merged := map[string]string{}
|
|
|
|
for key, value := range other {
|
|
merged[key] = value
|
|
}
|
|
|
|
if m == nil {
|
|
return merged
|
|
}
|
|
|
|
for key, value := range *m {
|
|
merged[key] = value
|
|
}
|
|
|
|
return merged
|
|
}
|
|
|
|
// Set implements the flag.Value interface.
|
|
func (m *Map) Set(value string) error {
|
|
if value == "" {
|
|
return nil
|
|
}
|
|
|
|
if *m == nil {
|
|
*m = map[string]string{}
|
|
}
|
|
|
|
for _, pair := range strings.Split(value, ",") {
|
|
pair := strings.Split(pair, "=")
|
|
(*m)[pair[0]] = pair[1]
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// SortedKeys returns a slice of the keys in increasing order.
|
|
func (m *Map) SortedKeys() []string {
|
|
if m == nil {
|
|
return nil
|
|
}
|
|
|
|
keys := maps.Keys(*m)
|
|
sort.Strings(keys)
|
|
|
|
return keys
|
|
}
|
|
|
|
type Namespaces struct {
|
|
// Allow list for common custom resources.
|
|
AllowList StringSet
|
|
// Deny list for common custom resources.
|
|
DenyList StringSet
|
|
// Allow list for Prometheus custom resources.
|
|
PrometheusAllowList StringSet
|
|
// Allow list for Alertmanager custom resources.
|
|
AlertmanagerAllowList StringSet
|
|
// Allow list for AlertmanagerConfig custom resources.
|
|
AlertmanagerConfigAllowList StringSet
|
|
// Allow list for ThanosRuler custom resources.
|
|
ThanosRulerAllowList StringSet
|
|
}
|
|
|
|
func (n *Namespaces) String() string {
|
|
return fmt.Sprintf("{allow_list=%q,deny_list=%q,prometheus_allow_list=%q,alertmanager_allow_list=%q,alertmanagerconfig_allow_list=%q,thanosruler_allow_list=%q}",
|
|
n.AllowList,
|
|
n.DenyList,
|
|
n.PrometheusAllowList,
|
|
n.AlertmanagerAllowList,
|
|
n.AlertmanagerConfigAllowList,
|
|
n.ThanosRulerAllowList,
|
|
)
|
|
}
|
|
|
|
func (n *Namespaces) Finalize() {
|
|
if len(n.AllowList) == 0 {
|
|
n.AllowList.Insert(v1.NamespaceAll)
|
|
}
|
|
|
|
if len(n.PrometheusAllowList) == 0 {
|
|
n.PrometheusAllowList = n.AllowList
|
|
}
|
|
|
|
if len(n.AlertmanagerAllowList) == 0 {
|
|
n.AlertmanagerAllowList = n.AllowList
|
|
}
|
|
|
|
if len(n.AlertmanagerConfigAllowList) == 0 {
|
|
n.AlertmanagerConfigAllowList = n.AllowList
|
|
}
|
|
|
|
if len(n.ThanosRulerAllowList) == 0 {
|
|
n.ThanosRulerAllowList = n.AllowList
|
|
}
|
|
}
|
|
|
|
type LabelSelector string
|
|
|
|
// String implements the flag.Value interface
|
|
func (ls *LabelSelector) String() string {
|
|
if ls == nil {
|
|
return ""
|
|
}
|
|
|
|
return string(*ls)
|
|
}
|
|
|
|
// Set implements the flag.Value interface.
|
|
func (ls *LabelSelector) Set(value string) error {
|
|
if _, err := labels.Parse(value); err != nil {
|
|
return err
|
|
}
|
|
|
|
*ls = LabelSelector(value)
|
|
return nil
|
|
}
|
|
|
|
type FieldSelector string
|
|
|
|
// String implements the flag.Value interface
|
|
func (fs *FieldSelector) String() string {
|
|
if fs == nil {
|
|
return ""
|
|
}
|
|
|
|
return string(*fs)
|
|
}
|
|
|
|
// Set implements the flag.Value interface.
|
|
func (fs *FieldSelector) Set(value string) error {
|
|
if _, err := fields.ParseSelector(value); err != nil {
|
|
return err
|
|
}
|
|
|
|
*fs = FieldSelector(value)
|
|
return nil
|
|
}
|
|
|
|
// StringSet represents a list of comma-separated strings.
|
|
type StringSet map[string]struct{}
|
|
|
|
// Set implements the flag.Value interface.
|
|
func (s StringSet) Set(value string) error {
|
|
if s == nil {
|
|
return fmt.Errorf("expected StringSet variable to be initialized")
|
|
}
|
|
|
|
for _, v := range strings.Split(value, ",") {
|
|
s[v] = struct{}{}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// String implements the flag.Value interface.
|
|
func (s StringSet) String() string {
|
|
return strings.Join(s.Slice(), ",")
|
|
}
|
|
|
|
func (s StringSet) Insert(value string) {
|
|
s[value] = struct{}{}
|
|
}
|
|
|
|
func (s StringSet) Slice() []string {
|
|
ss := make([]string, 0, len(s))
|
|
for k := range s {
|
|
ss = append(ss, k)
|
|
}
|
|
|
|
slices.Sort(ss)
|
|
return ss
|
|
}
|