diff --git a/go.mod b/go.mod index d65c959c7..1ec7281eb 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,9 @@ require ( github.com/google/go-cmp v0.5.6 github.com/imdario/mergo v0.3.7 github.com/openshift/api v0.0.0-20211209173311-a19f3b9052a6 - github.com/openshift/build-machinery-go v0.0.0-20210922160744-a9caf93aef90 + github.com/openshift/build-machinery-go v0.0.0-20211213093930-7e33a7eb4ce3 github.com/openshift/client-go v0.0.0-20211209144617-7385dd6338e3 - github.com/openshift/library-go v0.0.0-20211209153216-ed9bc958bd8a + github.com/openshift/library-go v0.0.0-20220117141918-17ce0045e35e github.com/prometheus/client_golang v1.11.0 github.com/spf13/cobra v1.2.1 k8s.io/api v0.23.0 diff --git a/go.sum b/go.sum index 70b5c223d..072dbb407 100644 --- a/go.sum +++ b/go.sum @@ -74,6 +74,7 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/RangelReale/osincli v0.0.0-20160924135400-fababb0555f2/go.mod h1:XyjUkMA8GN+tOOPXvnbi3XuRxWFvTJntqvTFnjmhzbk= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -521,13 +522,12 @@ github.com/openshift/api v0.0.0-20211209135129-c58d9f695577/go.mod h1:DoslCwtqUp github.com/openshift/api v0.0.0-20211209173311-a19f3b9052a6 h1:34Ff+I2ZVJWVRwHY1hLnRyN3lcjqw+9kG2qSKfmxk2A= github.com/openshift/api v0.0.0-20211209173311-a19f3b9052a6/go.mod h1:DoslCwtqUpr3d/gsbq4ZlkaMEdYqKxuypsDjorcHhME= github.com/openshift/build-machinery-go v0.0.0-20210712174854-1bb7fd1518d3/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= -github.com/openshift/build-machinery-go v0.0.0-20210806203541-4ea9b6da3a37/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= -github.com/openshift/build-machinery-go v0.0.0-20210922160744-a9caf93aef90 h1:UUq18A+3oxNPCLvgSbhwKfMhVX3SQWOeJKcXkMkumek= -github.com/openshift/build-machinery-go v0.0.0-20210922160744-a9caf93aef90/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= +github.com/openshift/build-machinery-go v0.0.0-20211213093930-7e33a7eb4ce3 h1:65oBhJYHzYK5VL0gF1eiYY37lLzyLZ47b9y5Kib1nf8= +github.com/openshift/build-machinery-go v0.0.0-20211213093930-7e33a7eb4ce3/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= github.com/openshift/client-go v0.0.0-20211209144617-7385dd6338e3 h1:SG1aqwleU6bGD0X4mhkTNupjVnByMYYuW4XbnCPavQU= github.com/openshift/client-go v0.0.0-20211209144617-7385dd6338e3/go.mod h1:cwhyki5lqBmrT0m8Im+9I7PGFaraOzcYPtEz93RcsGY= -github.com/openshift/library-go v0.0.0-20211209153216-ed9bc958bd8a h1:MoAaYFrzB5QlYzO7phyjx/JBxghUrLitwb69RaulRAs= -github.com/openshift/library-go v0.0.0-20211209153216-ed9bc958bd8a/go.mod h1:M/Gi/GUUrMdSS07nrYtTiK43J6/VUAyk/+IfN4ZqUY4= +github.com/openshift/library-go v0.0.0-20220117141918-17ce0045e35e h1:O3M+vt90vglXRKyb9At4S9Z8MpKHwlRJlc1HbokZlt4= +github.com/openshift/library-go v0.0.0-20220117141918-17ce0045e35e/go.mod h1:4UQ9snU1vg53fyTpHQw3vLPiAxI8ub5xrc+y8KPQQFs= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= diff --git a/vendor/github.com/openshift/build-machinery-go/make/targets/openshift/yaml-patch.mk b/vendor/github.com/openshift/build-machinery-go/make/targets/openshift/yaml-patch.mk index 1e62348a1..4a65f7b90 100644 --- a/vendor/github.com/openshift/build-machinery-go/make/targets/openshift/yaml-patch.mk +++ b/vendor/github.com/openshift/build-machinery-go/make/targets/openshift/yaml-patch.mk @@ -6,7 +6,7 @@ include $(addprefix $(dir $(lastword $(MAKEFILE_LIST))), \ ../../lib/tmp.mk \ ) -YAML_PATCH_VERSION ?=v0.0.10 +YAML_PATCH_VERSION ?=v0.0.11 YAML_PATCH ?=$(PERMANENT_TMP_GOPATH)/bin/yaml-patch-$(YAML_PATCH_VERSION) yaml_patch_dir :=$(dir $(YAML_PATCH)) @@ -15,7 +15,7 @@ ensure-yaml-patch: ifeq "" "$(wildcard $(YAML_PATCH))" $(info Installing yaml-patch into '$(YAML_PATCH)') mkdir -p '$(yaml_patch_dir)' - curl -s -f -L https://github.com/krishicks/yaml-patch/releases/download/$(YAML_PATCH_VERSION)/yaml_patch_$(GOHOSTOS) -o '$(YAML_PATCH)' + curl -s -f -L https://github.com/pivotal-cf/yaml-patch/releases/download/$(YAML_PATCH_VERSION)/yaml_patch_$(GOHOSTOS) -o '$(YAML_PATCH)' chmod +x '$(YAML_PATCH)'; else $(info Using existing yaml-patch from "$(YAML_PATCH)") diff --git a/vendor/github.com/openshift/library-go/pkg/config/leaderelection/leaderelection.go b/vendor/github.com/openshift/library-go/pkg/config/leaderelection/leaderelection.go index 5cec68257..edbd10fb1 100644 --- a/vendor/github.com/openshift/library-go/pkg/config/leaderelection/leaderelection.go +++ b/vendor/github.com/openshift/library-go/pkg/config/leaderelection/leaderelection.go @@ -22,8 +22,15 @@ import ( configv1 "github.com/openshift/api/config/v1" ) -// ToConfigMapLeaderElection returns a leader election config that you just need to fill in the Callback for. Don't forget the callbacks! -func ToConfigMapLeaderElection(clientConfig *rest.Config, config configv1.LeaderElection, component, identity string) (leaderelection.LeaderElectionConfig, error) { +// ToLeaderElectionWithConfigmapLease returns a "configmapsleases" based leader +// election config that you just need to fill in the Callback for. +// It is compatible with a "configmaps" based leader election and +// paves the way toward using "leases" based leader election. +// See https://github.com/kubernetes/kubernetes/issues/107454 for +// details on how to migrate to "leases" leader election. +// Don't forget the callbacks! +// TODO: In the next version we should switch to using "leases" +func ToLeaderElectionWithConfigmapLease(clientConfig *rest.Config, config configv1.LeaderElection, component, identity string) (leaderelection.LeaderElectionConfig, error) { kubeClient, err := kubernetes.NewForConfig(clientConfig) if err != nil { return leaderelection.LeaderElectionConfig{}, err @@ -50,7 +57,7 @@ func ToConfigMapLeaderElection(clientConfig *rest.Config, config configv1.Leader eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: v1core.New(kubeClient.CoreV1().RESTClient()).Events("")}) eventRecorder := eventBroadcaster.NewRecorder(clientgoscheme.Scheme, corev1.EventSource{Component: component}) rl, err := resourcelock.New( - resourcelock.ConfigMapsResourceLock, + resourcelock.ConfigMapsLeasesResourceLock, config.Namespace, config.Name, kubeClient.CoreV1(), diff --git a/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/builder.go b/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/builder.go index f98b86f3d..820892a17 100644 --- a/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/builder.go +++ b/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/builder.go @@ -329,7 +329,7 @@ func (b *ControllerBuilder) Run(ctx context.Context, config *unstructured.Unstru leaderConfig := rest.CopyConfig(protoConfig) leaderConfig.Timeout = b.leaderElection.RenewDeadline.Duration - leaderElection, err := leaderelectionconverter.ToConfigMapLeaderElection(leaderConfig, *b.leaderElection, b.componentName, b.instanceIdentity) + leaderElection, err := leaderelectionconverter.ToLeaderElectionWithConfigmapLease(leaderConfig, *b.leaderElection, b.componentName, b.instanceIdentity) if err != nil { return err } diff --git a/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/cmd.go b/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/cmd.go index 5196e350a..fb5bd2afb 100644 --- a/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/cmd.go +++ b/vendor/github.com/openshift/library-go/pkg/controller/controllercmd/cmd.go @@ -28,8 +28,8 @@ import ( "github.com/openshift/library-go/pkg/operator/events" "github.com/openshift/library-go/pkg/serviceability" - // for metrics - _ "github.com/openshift/library-go/pkg/controller/metrics" + // load all the prometheus client-go metrics + _ "k8s.io/component-base/metrics/prometheus/clientgo" ) // ControllerCommandConfig holds values required to construct a command to run. diff --git a/vendor/github.com/openshift/library-go/pkg/controller/metrics/client_metrics.go b/vendor/github.com/openshift/library-go/pkg/controller/metrics/client_metrics.go deleted file mode 100644 index c36e2d3c8..000000000 --- a/vendor/github.com/openshift/library-go/pkg/controller/metrics/client_metrics.go +++ /dev/null @@ -1,97 +0,0 @@ -package metrics - -import ( - "net/url" - "time" - - "github.com/blang/semver" - k8smetrics "k8s.io/component-base/metrics" - "k8s.io/component-base/metrics/legacyregistry" - - "github.com/prometheus/client_golang/prometheus" -) - -var ( - // requestLatency is a Prometheus Summary metric type partitioned by - // "verb" and "url" labels. It is used for the rest client latency metrics. - requestLatency = k8smetrics.NewHistogramVec( - &k8smetrics.HistogramOpts{ - Name: "rest_client_request_latency_seconds", - Help: "Request latency in seconds. Broken down by verb and URL.", - Buckets: prometheus.ExponentialBuckets(0.001, 2, 10), - }, - []string{"verb", "url"}, - ) - - requestResult = k8smetrics.NewCounterVec( - &k8smetrics.CounterOpts{ - Name: "rest_client_requests_total", - Help: "Number of HTTP requests, partitioned by status code, method, and host.", - }, - []string{"code", "method", "host"}, - ) -) - -func init() { - legacyregistry.MustRegister(requestLatency) - legacyregistry.MustRegister(requestResult) - - legacyregistry.Register(&latencyAdapter{requestLatency}) - legacyregistry.Register(&resultAdapter{requestResult}) -} - -type latencyAdapter struct { - m *k8smetrics.HistogramVec -} - -func (l *latencyAdapter) Describe(c chan<- *prometheus.Desc) { - l.m.Describe(c) -} - -func (l *latencyAdapter) Collect(c chan<- prometheus.Metric) { - l.m.Collect(c) -} - -func (l *latencyAdapter) Create(version *semver.Version) bool { - return l.m.Create(version) -} - -func (l *latencyAdapter) Observe(verb string, u url.URL, latency time.Duration) { - l.m.WithLabelValues(verb, u.String()).Observe(latency.Seconds()) -} - -func (l *latencyAdapter) ClearState() { - l.m.Reset() -} - -func (l *latencyAdapter) FQName() string { - return l.m.FQName() -} - -type resultAdapter struct { - m *k8smetrics.CounterVec -} - -func (r *resultAdapter) Describe(c chan<- *prometheus.Desc) { - r.m.Describe(c) -} - -func (r *resultAdapter) Collect(c chan<- prometheus.Metric) { - r.m.Collect(c) -} - -func (r *resultAdapter) Create(version *semver.Version) bool { - return r.m.Create(version) -} - -func (r *resultAdapter) Increment(code, method, host string) { - r.m.WithLabelValues(code, method, host).Inc() -} - -func (r *resultAdapter) ClearState() { - r.m.Reset() -} - -func (r *resultAdapter) FQName() string { - return r.m.FQName() -} diff --git a/vendor/github.com/openshift/library-go/pkg/controller/metrics/workqueue_metrics.go b/vendor/github.com/openshift/library-go/pkg/controller/metrics/workqueue_metrics.go deleted file mode 100644 index 47002e74d..000000000 --- a/vendor/github.com/openshift/library-go/pkg/controller/metrics/workqueue_metrics.go +++ /dev/null @@ -1,210 +0,0 @@ -package metrics - -import ( - "k8s.io/client-go/util/workqueue" - k8smetrics "k8s.io/component-base/metrics" - "k8s.io/component-base/metrics/legacyregistry" - "k8s.io/klog/v2" - - "github.com/prometheus/client_golang/prometheus" -) - -// Package prometheus sets the workqueue DefaultMetricsFactory to produce -// prometheus metrics. To use this package, you just have to import it. - -func init() { - workqueue.SetProvider(prometheusMetricsProvider{}) -} - -// Package prometheus sets the workqueue DefaultMetricsFactory to produce -// prometheus metrics. To use this package, you just have to import it. - -// Metrics subsystem and keys used by the workqueue. -const ( - WorkQueueSubsystem = "workqueue" - DepthKey = "depth" - AddsKey = "adds_total" - QueueLatencyKey = "queue_duration_seconds" - WorkDurationKey = "work_duration_seconds" - UnfinishedWorkKey = "unfinished_work_seconds" - LongestRunningProcessorKey = "longest_running_processor_seconds" - RetriesKey = "retries_total" -) - -func init() { - workqueue.SetProvider(prometheusMetricsProvider{}) -} - -type prometheusMetricsProvider struct{} - -func (prometheusMetricsProvider) NewDepthMetric(name string) workqueue.GaugeMetric { - depth := k8smetrics.NewGauge(&k8smetrics.GaugeOpts{ - Subsystem: WorkQueueSubsystem, - Name: DepthKey, - Help: "Current depth of workqueue", - ConstLabels: prometheus.Labels{"name": name}, - }) - legacyregistry.Register(depth) - return depth -} - -func (prometheusMetricsProvider) NewAddsMetric(name string) workqueue.CounterMetric { - adds := k8smetrics.NewCounter(&k8smetrics.CounterOpts{ - Subsystem: WorkQueueSubsystem, - Name: AddsKey, - Help: "Total number of adds handled by workqueue", - ConstLabels: prometheus.Labels{"name": name}, - }) - legacyregistry.Register(adds) - return adds -} - -func (prometheusMetricsProvider) NewLatencyMetric(name string) workqueue.HistogramMetric { - latency := k8smetrics.NewHistogram(&k8smetrics.HistogramOpts{ - Subsystem: WorkQueueSubsystem, - Name: QueueLatencyKey, - Help: "How long in seconds an item stays in workqueue before being requested.", - ConstLabels: prometheus.Labels{"name": name}, - Buckets: prometheus.ExponentialBuckets(10e-9, 10, 10), - }) - legacyregistry.Register(latency) - return latency -} - -func (prometheusMetricsProvider) NewWorkDurationMetric(name string) workqueue.HistogramMetric { - workDuration := k8smetrics.NewHistogram(&k8smetrics.HistogramOpts{ - Subsystem: WorkQueueSubsystem, - Name: WorkDurationKey, - Help: "How long in seconds processing an item from workqueue takes.", - ConstLabels: prometheus.Labels{"name": name}, - Buckets: prometheus.ExponentialBuckets(10e-9, 10, 10), - }) - legacyregistry.Register(workDuration) - return workDuration -} - -func (prometheusMetricsProvider) NewUnfinishedWorkSecondsMetric(name string) workqueue.SettableGaugeMetric { - unfinished := k8smetrics.NewGauge(&k8smetrics.GaugeOpts{ - Subsystem: WorkQueueSubsystem, - Name: UnfinishedWorkKey, - Help: "How many seconds of work has done that " + - "is in progress and hasn't been observed by work_duration. Large " + - "values indicate stuck threads. One can deduce the number of stuck " + - "threads by observing the rate at which this increases.", - ConstLabels: prometheus.Labels{"name": name}, - }) - legacyregistry.Register(unfinished) - return unfinished -} - -func (prometheusMetricsProvider) NewLongestRunningProcessorSecondsMetric(name string) workqueue.SettableGaugeMetric { - unfinished := k8smetrics.NewGauge(&k8smetrics.GaugeOpts{ - Subsystem: WorkQueueSubsystem, - Name: LongestRunningProcessorKey, - Help: "How many seconds has the longest running " + - "processor for workqueue been running.", - ConstLabels: prometheus.Labels{"name": name}, - }) - legacyregistry.Register(unfinished) - return unfinished -} - -func (prometheusMetricsProvider) NewRetriesMetric(name string) workqueue.CounterMetric { - retries := k8smetrics.NewCounter(&k8smetrics.CounterOpts{ - Subsystem: WorkQueueSubsystem, - Name: RetriesKey, - Help: "Total number of retries handled by workqueue", - ConstLabels: prometheus.Labels{"name": name}, - }) - legacyregistry.Register(retries) - return retries -} - -// TODO(danielqsj): Remove the following metrics, they are deprecated -func (prometheusMetricsProvider) NewDeprecatedDepthMetric(name string) workqueue.GaugeMetric { - depth := k8smetrics.NewGauge(&k8smetrics.GaugeOpts{ - Subsystem: name, - Name: "depth", - Help: "(Deprecated) Current depth of workqueue: " + name, - }) - if err := legacyregistry.Register(depth); err != nil { - klog.Errorf("failed to register depth metric %v: %v", name, err) - } - return depth -} - -func (prometheusMetricsProvider) NewDeprecatedAddsMetric(name string) workqueue.CounterMetric { - adds := k8smetrics.NewCounter(&k8smetrics.CounterOpts{ - Subsystem: name, - Name: "adds", - Help: "(Deprecated) Total number of adds handled by workqueue: " + name, - }) - if err := legacyregistry.Register(adds); err != nil { - klog.Errorf("failed to register adds metric %v: %v", name, err) - } - return adds -} - -func (prometheusMetricsProvider) NewDeprecatedLatencyMetric(name string) workqueue.SummaryMetric { - latency := k8smetrics.NewSummary(&k8smetrics.SummaryOpts{ - Subsystem: name, - Name: "queue_latency", - Help: "(Deprecated) How long an item stays in workqueue" + name + " before being requested.", - }) - if err := legacyregistry.Register(latency); err != nil { - klog.Errorf("failed to register latency metric %v: %v", name, err) - } - return latency -} - -func (prometheusMetricsProvider) NewDeprecatedWorkDurationMetric(name string) workqueue.SummaryMetric { - workDuration := k8smetrics.NewSummary(&k8smetrics.SummaryOpts{ - Subsystem: name, - Name: "work_duration", - Help: "(Deprecated) How long processing an item from workqueue" + name + " takes.", - }) - if err := legacyregistry.Register(workDuration); err != nil { - klog.Errorf("failed to register work_duration metric %v: %v", name, err) - } - return workDuration -} - -func (prometheusMetricsProvider) NewDeprecatedUnfinishedWorkSecondsMetric(name string) workqueue.SettableGaugeMetric { - unfinished := k8smetrics.NewGauge(&k8smetrics.GaugeOpts{ - Subsystem: name, - Name: "unfinished_work_seconds", - Help: "(Deprecated) How many seconds of work " + name + " has done that " + - "is in progress and hasn't been observed by work_duration. Large " + - "values indicate stuck threads. One can deduce the number of stuck " + - "threads by observing the rate at which this increases.", - }) - if err := legacyregistry.Register(unfinished); err != nil { - klog.Errorf("failed to register unfinished_work_seconds metric %v: %v", name, err) - } - return unfinished -} - -func (prometheusMetricsProvider) NewDeprecatedLongestRunningProcessorMicrosecondsMetric(name string) workqueue.SettableGaugeMetric { - unfinished := k8smetrics.NewGauge(&k8smetrics.GaugeOpts{ - Subsystem: name, - Name: "longest_running_processor_microseconds", - Help: "(Deprecated) How many microseconds has the longest running " + - "processor for " + name + " been running.", - }) - if err := legacyregistry.Register(unfinished); err != nil { - klog.Errorf("failed to register longest_running_processor_microseconds metric %v: %v", name, err) - } - return unfinished -} - -func (prometheusMetricsProvider) NewDeprecatedRetriesMetric(name string) workqueue.CounterMetric { - retries := k8smetrics.NewCounter(&k8smetrics.CounterOpts{ - Subsystem: name, - Name: "retries", - Help: "(Deprecated) Total number of retries handled by workqueue: " + name, - }) - if err := legacyregistry.Register(retries); err != nil { - klog.Errorf("failed to register retries metric %v: %v", name, err) - } - return retries -} diff --git a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/core.go b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/core.go index 9e78612a9..1ffee4f80 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/core.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/core.go @@ -7,38 +7,110 @@ import ( "sort" "strings" - "k8s.io/klog/v2" - + "github.com/openshift/library-go/pkg/operator/events" + "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/sets" coreclientv1 "k8s.io/client-go/kubernetes/typed/core/v1" - - "github.com/openshift/library-go/pkg/operator/events" - "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" + "k8s.io/klog/v2" ) +// TODO find way to create a registry of these based on struct mapping or some such that forces users to get this right +// for creating an ApplyGeneric +// Perhaps a struct containing the apply function and the getKind +func getCoreGroupKind(obj runtime.Object) *schema.GroupKind { + switch obj.(type) { + case *corev1.Namespace: + return &schema.GroupKind{ + Kind: "Namespace", + } + case *corev1.Service: + return &schema.GroupKind{ + Kind: "Service", + } + case *corev1.Pod: + return &schema.GroupKind{ + Kind: "Pod", + } + case *corev1.ServiceAccount: + return &schema.GroupKind{ + Kind: "ServiceAccount", + } + case *corev1.ConfigMap: + return &schema.GroupKind{ + Kind: "ConfigMap", + } + case *corev1.Secret: + return &schema.GroupKind{ + Kind: "Secret", + } + default: + return nil + } +} + // ApplyNamespace merges objectmeta, does not worry about anything else func ApplyNamespace(ctx context.Context, client coreclientv1.NamespacesGetter, recorder events.Recorder, required *corev1.Namespace) (*corev1.Namespace, bool, error) { + return ApplyNamespaceImproved(ctx, client, recorder, required, noCache) +} + +// ApplyService merges objectmeta and requires +// TODO, since this cannot determine whether changes are due to legitimate actors (api server) or illegitimate ones (users), we cannot update +// TODO I've special cased the selector for now +func ApplyService(ctx context.Context, client coreclientv1.ServicesGetter, recorder events.Recorder, required *corev1.Service) (*corev1.Service, bool, error) { + return ApplyServiceImproved(ctx, client, recorder, required, noCache) +} + +// ApplyPod merges objectmeta, does not worry about anything else +func ApplyPod(ctx context.Context, client coreclientv1.PodsGetter, recorder events.Recorder, required *corev1.Pod) (*corev1.Pod, bool, error) { + return ApplyPodImproved(ctx, client, recorder, required, noCache) +} + +// ApplyServiceAccount merges objectmeta, does not worry about anything else +func ApplyServiceAccount(ctx context.Context, client coreclientv1.ServiceAccountsGetter, recorder events.Recorder, required *corev1.ServiceAccount) (*corev1.ServiceAccount, bool, error) { + return ApplyServiceAccountImproved(ctx, client, recorder, required, noCache) +} + +// ApplyConfigMap merges objectmeta, requires data +func ApplyConfigMap(ctx context.Context, client coreclientv1.ConfigMapsGetter, recorder events.Recorder, required *corev1.ConfigMap) (*corev1.ConfigMap, bool, error) { + return ApplyConfigMapImproved(ctx, client, recorder, required, noCache) +} + +// ApplySecret merges objectmeta, requires data +func ApplySecret(ctx context.Context, client coreclientv1.SecretsGetter, recorder events.Recorder, required *corev1.Secret) (*corev1.Secret, bool, error) { + return ApplySecretImproved(ctx, client, recorder, required, noCache) +} + +// ApplyNamespace merges objectmeta, does not worry about anything else +func ApplyNamespaceImproved(ctx context.Context, client coreclientv1.NamespacesGetter, recorder events.Recorder, required *corev1.Namespace, cache ResourceCache) (*corev1.Namespace, bool, error) { existing, err := client.Namespaces().Get(ctx, required.Name, metav1.GetOptions{}) if apierrors.IsNotFound(err) { requiredCopy := required.DeepCopy() actual, err := client.Namespaces(). Create(ctx, resourcemerge.WithCleanLabelsAndAnnotations(requiredCopy).(*corev1.Namespace), metav1.CreateOptions{}) reportCreateEvent(recorder, requiredCopy, err) + cache.UpdateCachedResourceMetadata(required, actual) return actual, true, err } if err != nil { return nil, false, err } + if cache.SafeToSkipApply(required, existing) { + return existing, false, nil + } + modified := resourcemerge.BoolPtr(false) existingCopy := existing.DeepCopy() resourcemerge.EnsureObjectMeta(modified, &existingCopy.ObjectMeta, required.ObjectMeta) if !*modified { + cache.UpdateCachedResourceMetadata(required, existingCopy) return existingCopy, false, nil } @@ -48,25 +120,31 @@ func ApplyNamespace(ctx context.Context, client coreclientv1.NamespacesGetter, r actual, err := client.Namespaces().Update(ctx, existingCopy, metav1.UpdateOptions{}) reportUpdateEvent(recorder, required, err) + cache.UpdateCachedResourceMetadata(required, actual) return actual, true, err } // ApplyService merges objectmeta and requires // TODO, since this cannot determine whether changes are due to legitimate actors (api server) or illegitimate ones (users), we cannot update // TODO I've special cased the selector for now -func ApplyService(ctx context.Context, client coreclientv1.ServicesGetter, recorder events.Recorder, required *corev1.Service) (*corev1.Service, bool, error) { +func ApplyServiceImproved(ctx context.Context, client coreclientv1.ServicesGetter, recorder events.Recorder, required *corev1.Service, cache ResourceCache) (*corev1.Service, bool, error) { existing, err := client.Services(required.Namespace).Get(ctx, required.Name, metav1.GetOptions{}) if apierrors.IsNotFound(err) { requiredCopy := required.DeepCopy() actual, err := client.Services(requiredCopy.Namespace). Create(ctx, resourcemerge.WithCleanLabelsAndAnnotations(requiredCopy).(*corev1.Service), metav1.CreateOptions{}) reportCreateEvent(recorder, requiredCopy, err) + cache.UpdateCachedResourceMetadata(required, actual) return actual, true, err } if err != nil { return nil, false, err } + if cache.SafeToSkipApply(required, existing) { + return existing, false, nil + } + modified := resourcemerge.BoolPtr(false) existingCopy := existing.DeepCopy() @@ -81,6 +159,7 @@ func ApplyService(ctx context.Context, client coreclientv1.ServicesGetter, recor } if selectorSame && typeSame && !*modified { + cache.UpdateCachedResourceMetadata(required, existingCopy) return existingCopy, false, nil } @@ -93,28 +172,35 @@ func ApplyService(ctx context.Context, client coreclientv1.ServicesGetter, recor actual, err := client.Services(required.Namespace).Update(ctx, existingCopy, metav1.UpdateOptions{}) reportUpdateEvent(recorder, required, err) + cache.UpdateCachedResourceMetadata(required, actual) return actual, true, err } // ApplyPod merges objectmeta, does not worry about anything else -func ApplyPod(ctx context.Context, client coreclientv1.PodsGetter, recorder events.Recorder, required *corev1.Pod) (*corev1.Pod, bool, error) { +func ApplyPodImproved(ctx context.Context, client coreclientv1.PodsGetter, recorder events.Recorder, required *corev1.Pod, cache ResourceCache) (*corev1.Pod, bool, error) { existing, err := client.Pods(required.Namespace).Get(ctx, required.Name, metav1.GetOptions{}) if apierrors.IsNotFound(err) { requiredCopy := required.DeepCopy() actual, err := client.Pods(requiredCopy.Namespace). Create(ctx, resourcemerge.WithCleanLabelsAndAnnotations(requiredCopy).(*corev1.Pod), metav1.CreateOptions{}) reportCreateEvent(recorder, requiredCopy, err) + cache.UpdateCachedResourceMetadata(required, actual) return actual, true, err } if err != nil { return nil, false, err } + if cache.SafeToSkipApply(required, existing) { + return existing, false, nil + } + modified := resourcemerge.BoolPtr(false) existingCopy := existing.DeepCopy() resourcemerge.EnsureObjectMeta(modified, &existingCopy.ObjectMeta, required.ObjectMeta) if !*modified { + cache.UpdateCachedResourceMetadata(required, existingCopy) return existingCopy, false, nil } @@ -124,28 +210,35 @@ func ApplyPod(ctx context.Context, client coreclientv1.PodsGetter, recorder even actual, err := client.Pods(required.Namespace).Update(ctx, existingCopy, metav1.UpdateOptions{}) reportUpdateEvent(recorder, required, err) + cache.UpdateCachedResourceMetadata(required, actual) return actual, true, err } // ApplyServiceAccount merges objectmeta, does not worry about anything else -func ApplyServiceAccount(ctx context.Context, client coreclientv1.ServiceAccountsGetter, recorder events.Recorder, required *corev1.ServiceAccount) (*corev1.ServiceAccount, bool, error) { +func ApplyServiceAccountImproved(ctx context.Context, client coreclientv1.ServiceAccountsGetter, recorder events.Recorder, required *corev1.ServiceAccount, cache ResourceCache) (*corev1.ServiceAccount, bool, error) { existing, err := client.ServiceAccounts(required.Namespace).Get(ctx, required.Name, metav1.GetOptions{}) if apierrors.IsNotFound(err) { requiredCopy := required.DeepCopy() actual, err := client.ServiceAccounts(requiredCopy.Namespace). Create(ctx, resourcemerge.WithCleanLabelsAndAnnotations(requiredCopy).(*corev1.ServiceAccount), metav1.CreateOptions{}) reportCreateEvent(recorder, requiredCopy, err) + cache.UpdateCachedResourceMetadata(required, actual) return actual, true, err } if err != nil { return nil, false, err } + if cache.SafeToSkipApply(required, existing) { + return existing, false, nil + } + modified := resourcemerge.BoolPtr(false) existingCopy := existing.DeepCopy() resourcemerge.EnsureObjectMeta(modified, &existingCopy.ObjectMeta, required.ObjectMeta) if !*modified { + cache.UpdateCachedResourceMetadata(required, existingCopy) return existingCopy, false, nil } if klog.V(4).Enabled() { @@ -153,23 +246,29 @@ func ApplyServiceAccount(ctx context.Context, client coreclientv1.ServiceAccount } actual, err := client.ServiceAccounts(required.Namespace).Update(ctx, existingCopy, metav1.UpdateOptions{}) reportUpdateEvent(recorder, required, err) + cache.UpdateCachedResourceMetadata(required, actual) return actual, true, err } // ApplyConfigMap merges objectmeta, requires data -func ApplyConfigMap(ctx context.Context, client coreclientv1.ConfigMapsGetter, recorder events.Recorder, required *corev1.ConfigMap) (*corev1.ConfigMap, bool, error) { +func ApplyConfigMapImproved(ctx context.Context, client coreclientv1.ConfigMapsGetter, recorder events.Recorder, required *corev1.ConfigMap, cache ResourceCache) (*corev1.ConfigMap, bool, error) { existing, err := client.ConfigMaps(required.Namespace).Get(ctx, required.Name, metav1.GetOptions{}) if apierrors.IsNotFound(err) { requiredCopy := required.DeepCopy() actual, err := client.ConfigMaps(requiredCopy.Namespace). Create(ctx, resourcemerge.WithCleanLabelsAndAnnotations(requiredCopy).(*corev1.ConfigMap), metav1.CreateOptions{}) reportCreateEvent(recorder, requiredCopy, err) + cache.UpdateCachedResourceMetadata(required, actual) return actual, true, err } if err != nil { return nil, false, err } + if cache.SafeToSkipApply(required, existing) { + return existing, false, nil + } + modified := resourcemerge.BoolPtr(false) existingCopy := existing.DeepCopy() @@ -208,6 +307,7 @@ func ApplyConfigMap(ctx context.Context, client coreclientv1.ConfigMapsGetter, r dataSame := len(modifiedKeys) == 0 if dataSame && !*modified { + cache.UpdateCachedResourceMetadata(required, existingCopy) return existingCopy, false, nil } existingCopy.Data = required.Data @@ -231,12 +331,23 @@ func ApplyConfigMap(ctx context.Context, client coreclientv1.ConfigMapsGetter, r klog.Infof("ConfigMap %q changes: %v", required.Namespace+"/"+required.Name, JSONPatchNoError(existing, required)) } reportUpdateEvent(recorder, required, err, details) + cache.UpdateCachedResourceMetadata(required, actual) return actual, true, err } // ApplySecret merges objectmeta, requires data -func ApplySecret(ctx context.Context, client coreclientv1.SecretsGetter, recorder events.Recorder, requiredInput *corev1.Secret) (*corev1.Secret, bool, error) { +func ApplySecretImproved(ctx context.Context, client coreclientv1.SecretsGetter, recorder events.Recorder, requiredInput *corev1.Secret, cache ResourceCache) (*corev1.Secret, bool, error) { // copy the stringData to data. Error on a data content conflict inside required. This is usually a bug. + + existing, err := client.Secrets(requiredInput.Namespace).Get(ctx, requiredInput.Name, metav1.GetOptions{}) + if err != nil && !apierrors.IsNotFound(err) { + return nil, false, err + } + + if cache.SafeToSkipApply(requiredInput, existing) { + return existing, false, nil + } + required := requiredInput.DeepCopy() if required.Data == nil { required.Data = map[string][]byte{} @@ -251,12 +362,12 @@ func ApplySecret(ctx context.Context, client coreclientv1.SecretsGetter, recorde } required.StringData = nil - existing, err := client.Secrets(required.Namespace).Get(ctx, required.Name, metav1.GetOptions{}) if apierrors.IsNotFound(err) { requiredCopy := required.DeepCopy() actual, err := client.Secrets(requiredCopy.Namespace). Create(ctx, resourcemerge.WithCleanLabelsAndAnnotations(requiredCopy).(*corev1.Secret), metav1.CreateOptions{}) reportCreateEvent(recorder, requiredCopy, err) + cache.UpdateCachedResourceMetadata(requiredInput, actual) return actual, true, err } if err != nil { @@ -291,6 +402,7 @@ func ApplySecret(ctx context.Context, client coreclientv1.SecretsGetter, recorde } if equality.Semantic.DeepEqual(existingCopy, existing) { + cache.UpdateCachedResourceMetadata(requiredInput, existingCopy) return existing, false, nil } @@ -324,7 +436,7 @@ func ApplySecret(ctx context.Context, client coreclientv1.SecretsGetter, recorde existingCopy.ResourceVersion = "" actual, err = client.Secrets(required.Namespace).Create(ctx, existingCopy, metav1.CreateOptions{}) reportCreateEvent(recorder, existingCopy, err) - + cache.UpdateCachedResourceMetadata(requiredInput, actual) return actual, true, err } diff --git a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/generic.go b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/generic.go index d1df4e3db..c0a9fc8f4 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/generic.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/generic.go @@ -101,7 +101,7 @@ func (c *ClientHolder) WithMigrationClient(client migrationclient.Interface) *Cl } // ApplyDirectly applies the given manifest files to API server. -func ApplyDirectly(ctx context.Context, clients *ClientHolder, recorder events.Recorder, manifests AssetFunc, files ...string) []ApplyResult { +func ApplyDirectly(ctx context.Context, clients *ClientHolder, recorder events.Recorder, cache ResourceCache, manifests AssetFunc, files ...string) []ApplyResult { ret := []ApplyResult{} for _, file := range files { @@ -126,39 +126,39 @@ func ApplyDirectly(ctx context.Context, clients *ClientHolder, recorder events.R if clients.kubeClient == nil { result.Error = fmt.Errorf("missing kubeClient") } else { - result.Result, result.Changed, result.Error = ApplyNamespace(ctx, clients.kubeClient.CoreV1(), recorder, t) + result.Result, result.Changed, result.Error = ApplyNamespaceImproved(ctx, clients.kubeClient.CoreV1(), recorder, t, cache) } case *corev1.Service: if clients.kubeClient == nil { result.Error = fmt.Errorf("missing kubeClient") } else { - result.Result, result.Changed, result.Error = ApplyService(ctx, clients.kubeClient.CoreV1(), recorder, t) + result.Result, result.Changed, result.Error = ApplyServiceImproved(ctx, clients.kubeClient.CoreV1(), recorder, t, cache) } case *corev1.Pod: if clients.kubeClient == nil { result.Error = fmt.Errorf("missing kubeClient") } else { - result.Result, result.Changed, result.Error = ApplyPod(ctx, clients.kubeClient.CoreV1(), recorder, t) + result.Result, result.Changed, result.Error = ApplyPodImproved(ctx, clients.kubeClient.CoreV1(), recorder, t, cache) } case *corev1.ServiceAccount: if clients.kubeClient == nil { result.Error = fmt.Errorf("missing kubeClient") } else { - result.Result, result.Changed, result.Error = ApplyServiceAccount(ctx, clients.kubeClient.CoreV1(), recorder, t) + result.Result, result.Changed, result.Error = ApplyServiceAccountImproved(ctx, clients.kubeClient.CoreV1(), recorder, t, cache) } case *corev1.ConfigMap: client := clients.configMapsGetter() if client == nil { result.Error = fmt.Errorf("missing kubeClient") } else { - result.Result, result.Changed, result.Error = ApplyConfigMap(ctx, client, recorder, t) + result.Result, result.Changed, result.Error = ApplyConfigMapImproved(ctx, client, recorder, t, cache) } case *corev1.Secret: client := clients.secretsGetter() if client == nil { result.Error = fmt.Errorf("missing kubeClient") } else { - result.Result, result.Changed, result.Error = ApplySecret(ctx, client, recorder, t) + result.Result, result.Changed, result.Error = ApplySecretImproved(ctx, client, recorder, t, cache) } case *rbacv1.ClusterRole: if clients.kubeClient == nil { diff --git a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/resource_cache.go b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/resource_cache.go new file mode 100644 index 000000000..daa1a5e15 --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/resource_cache.go @@ -0,0 +1,168 @@ +package resourceapply + +import ( + "crypto/md5" + "fmt" + "io" + "reflect" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog/v2" +) + +type cachedVersionKey struct { + name string + namespace string + kind schema.GroupKind +} + +// record of resource metadata used to determine if its safe to return early from an ApplyFoo +// resourceHash is an ms5 hash of the required in an ApplyFoo that is computed in case the input changes +// resourceVersion is the received resourceVersion from the apiserver in response to an update that is comparable to the GET +type cachedResource struct { + resourceHash, resourceVersion string +} + +type resourceCache struct { + cache map[cachedVersionKey]cachedResource +} + +type ResourceCache interface { + UpdateCachedResourceMetadata(required runtime.Object, actual runtime.Object) + SafeToSkipApply(required runtime.Object, existing runtime.Object) bool +} + +func NewResourceCache() *resourceCache { + return &resourceCache{ + cache: map[cachedVersionKey]cachedResource{}, + } +} + +var noCache *resourceCache + +func getResourceMetadata(obj runtime.Object) (schema.GroupKind, string, string, string, error) { + if obj == nil { + return schema.GroupKind{}, "", "", "", fmt.Errorf("nil object has no metadata") + } + metadata, err := meta.Accessor(obj) + if err != nil { + return schema.GroupKind{}, "", "", "", err + } + if metadata == nil || reflect.ValueOf(metadata).IsNil() { + return schema.GroupKind{}, "", "", "", fmt.Errorf("object has no metadata") + } + resourceHash := hashOfResourceStruct(obj) + + // retrieve kind, sometimes this can be done via the accesor, sometimes not (depends on the type) + kind := schema.GroupKind{} + gvk := obj.GetObjectKind().GroupVersionKind() + if len(gvk.Kind) > 0 { + kind = gvk.GroupKind() + } else { + if currKind := getCoreGroupKind(obj); currKind != nil { + kind = *currKind + } + } + if len(kind.Kind) == 0 { + return schema.GroupKind{}, "", "", "", fmt.Errorf("unable to determine GroupKind of %T", obj) + } + + return kind, metadata.GetName(), metadata.GetNamespace(), resourceHash, nil +} + +func getResourceVersion(obj runtime.Object) (string, error) { + if obj == nil { + return "", fmt.Errorf("nil object has no resourceVersion") + } + metadata, err := meta.Accessor(obj) + if err != nil { + return "", err + } + if metadata == nil || reflect.ValueOf(metadata).IsNil() { + return "", fmt.Errorf("object has no metadata") + } + rv := metadata.GetResourceVersion() + if len(rv) == 0 { + return "", fmt.Errorf("missing resourceVersion") + } + + return rv, nil +} + +func (c *resourceCache) UpdateCachedResourceMetadata(required runtime.Object, actual runtime.Object) { + if c == nil || c.cache == nil { + return + } + if required == nil || actual == nil { + return + } + kind, name, namespace, resourceHash, err := getResourceMetadata(required) + if err != nil { + return + } + cacheKey := cachedVersionKey{ + name: name, + namespace: namespace, + kind: kind, + } + + resourceVersion, err := getResourceVersion(actual) + if err != nil { + klog.V(4).Infof("error reading resourceVersion %s:%s:%s %s", name, kind, namespace, err) + return + } + + c.cache[cacheKey] = cachedResource{resourceHash, resourceVersion} + klog.V(7).Infof("updated resourceVersion of %s:%s:%s %s", name, kind, namespace, resourceVersion) +} + +// in the circumstance that an ApplyFoo's 'required' is the same one which was previously +// applied for a given (name, kind, namespace) and the existing resource (if any), +// hasn't been modified since the ApplyFoo last updated that resource, then return true (we don't +// need to reapply the resource). Otherwise return false. +func (c *resourceCache) SafeToSkipApply(required runtime.Object, existing runtime.Object) bool { + if c == nil || c.cache == nil { + return false + } + if required == nil || existing == nil { + return false + } + kind, name, namespace, resourceHash, err := getResourceMetadata(required) + if err != nil { + return false + } + cacheKey := cachedVersionKey{ + name: name, + namespace: namespace, + kind: kind, + } + + resourceVersion, err := getResourceVersion(existing) + if err != nil { + return false + } + + var versionMatch, hashMatch bool + if cached, exists := c.cache[cacheKey]; exists { + versionMatch = cached.resourceVersion == resourceVersion + hashMatch = cached.resourceHash == resourceHash + if versionMatch && hashMatch { + klog.V(4).Infof("found matching resourceVersion & manifest hash") + return true + } + } + + return false +} + +// detect changes in a resource by caching a hash of the string representation of the resource +// note: some changes in a resource e.g. nil vs empty, will not be detected this way +func hashOfResourceStruct(o interface{}) string { + oString := fmt.Sprintf("%v", o) + h := md5.New() + io.WriteString(h, oString) + rval := fmt.Sprintf("%x", h.Sum(nil)) + return rval +} diff --git a/vendor/github.com/openshift/library-go/pkg/operator/v1helpers/helpers.go b/vendor/github.com/openshift/library-go/pkg/operator/v1helpers/helpers.go index 46d5c13b0..de48550f6 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/v1helpers/helpers.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/v1helpers/helpers.go @@ -383,3 +383,42 @@ func InjectObservedProxyIntoContainers(podSpec *corev1.PodSpec, containerNames [ return nil } + +func InjectTrustedCAIntoContainers(podSpec *corev1.PodSpec, configMapName string, containerNames []string) error { + podSpec.Volumes = append(podSpec.Volumes, corev1.Volume{ + Name: "non-standard-root-system-trust-ca-bundle", + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: configMapName, + }, + Items: []corev1.KeyToPath{ + {Key: "ca-bundle.crt", Path: "tls-ca-bundle.pem"}, + }, + }, + }, + }) + + for _, containerName := range containerNames { + for i := range podSpec.InitContainers { + if podSpec.InitContainers[i].Name == containerName { + podSpec.InitContainers[i].VolumeMounts = append(podSpec.InitContainers[i].VolumeMounts, corev1.VolumeMount{ + Name: "non-standard-root-system-trust-ca-bundle", + MountPath: "/etc/pki/ca-trust/extracted/pem", + ReadOnly: true, + }) + } + } + for i := range podSpec.Containers { + if podSpec.Containers[i].Name == containerName { + podSpec.Containers[i].VolumeMounts = append(podSpec.Containers[i].VolumeMounts, corev1.VolumeMount{ + Name: "non-standard-root-system-trust-ca-bundle", + MountPath: "/etc/pki/ca-trust/extracted/pem", + ReadOnly: true, + }) + } + } + } + + return nil +} diff --git a/vendor/k8s.io/component-base/metrics/prometheus/clientgo/leaderelection/metrics.go b/vendor/k8s.io/component-base/metrics/prometheus/clientgo/leaderelection/metrics.go new file mode 100644 index 000000000..6592c755b --- /dev/null +++ b/vendor/k8s.io/component-base/metrics/prometheus/clientgo/leaderelection/metrics.go @@ -0,0 +1,53 @@ +/* +Copyright 2018 The Kubernetes 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 leaderelection + +import ( + "k8s.io/client-go/tools/leaderelection" + k8smetrics "k8s.io/component-base/metrics" + "k8s.io/component-base/metrics/legacyregistry" +) + +var ( + leaderGauge = k8smetrics.NewGaugeVec(&k8smetrics.GaugeOpts{ + Name: "leader_election_master_status", + Help: "Gauge of if the reporting system is master of the relevant lease, 0 indicates backup, 1 indicates master. 'name' is the string used to identify the lease. Please make sure to group by name.", + }, []string{"name"}) +) + +func init() { + legacyregistry.MustRegister(leaderGauge) + leaderelection.SetProvider(prometheusMetricsProvider{}) +} + +type prometheusMetricsProvider struct{} + +func (prometheusMetricsProvider) NewLeaderMetric() leaderelection.SwitchMetric { + return &switchAdapter{gauge: leaderGauge} +} + +type switchAdapter struct { + gauge *k8smetrics.GaugeVec +} + +func (s *switchAdapter) On(name string) { + s.gauge.WithLabelValues(name).Set(1.0) +} + +func (s *switchAdapter) Off(name string) { + s.gauge.WithLabelValues(name).Set(0.0) +} diff --git a/vendor/k8s.io/component-base/metrics/prometheus/clientgo/metrics.go b/vendor/k8s.io/component-base/metrics/prometheus/clientgo/metrics.go new file mode 100644 index 000000000..43574ca9a --- /dev/null +++ b/vendor/k8s.io/component-base/metrics/prometheus/clientgo/metrics.go @@ -0,0 +1,23 @@ +/* +Copyright 2019 The Kubernetes 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 clientgo + +import ( + _ "k8s.io/component-base/metrics/prometheus/clientgo/leaderelection" // load leaderelection metrics + _ "k8s.io/component-base/metrics/prometheus/restclient" // load restclient metrics + _ "k8s.io/component-base/metrics/prometheus/workqueue" // load the workqueue metrics +) diff --git a/vendor/k8s.io/component-base/metrics/prometheus/restclient/metrics.go b/vendor/k8s.io/component-base/metrics/prometheus/restclient/metrics.go new file mode 100644 index 000000000..21e4bb359 --- /dev/null +++ b/vendor/k8s.io/component-base/metrics/prometheus/restclient/metrics.go @@ -0,0 +1,176 @@ +/* +Copyright 2016 The Kubernetes 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 restclient + +import ( + "context" + "fmt" + "math" + "net/url" + "time" + + "k8s.io/client-go/tools/metrics" + k8smetrics "k8s.io/component-base/metrics" + "k8s.io/component-base/metrics/legacyregistry" +) + +var ( + // requestLatency is a Prometheus Summary metric type partitioned by + // "verb" and "url" labels. It is used for the rest client latency metrics. + requestLatency = k8smetrics.NewHistogramVec( + &k8smetrics.HistogramOpts{ + Name: "rest_client_request_duration_seconds", + Help: "Request latency in seconds. Broken down by verb and URL.", + Buckets: k8smetrics.ExponentialBuckets(0.001, 2, 10), + }, + []string{"verb", "url"}, + ) + + rateLimiterLatency = k8smetrics.NewHistogramVec( + &k8smetrics.HistogramOpts{ + Name: "rest_client_rate_limiter_duration_seconds", + Help: "Client side rate limiter latency in seconds. Broken down by verb and URL.", + Buckets: k8smetrics.ExponentialBuckets(0.001, 2, 10), + }, + []string{"verb", "url"}, + ) + + requestResult = k8smetrics.NewCounterVec( + &k8smetrics.CounterOpts{ + Name: "rest_client_requests_total", + Help: "Number of HTTP requests, partitioned by status code, method, and host.", + }, + []string{"code", "method", "host"}, + ) + + execPluginCertTTLAdapter = &expiryToTTLAdapter{} + + execPluginCertTTL = k8smetrics.NewGaugeFunc( + k8smetrics.GaugeOpts{ + Name: "rest_client_exec_plugin_ttl_seconds", + Help: "Gauge of the shortest TTL (time-to-live) of the client " + + "certificate(s) managed by the auth exec plugin. The value " + + "is in seconds until certificate expiry (negative if " + + "already expired). If auth exec plugins are unused or manage no " + + "TLS certificates, the value will be +INF.", + StabilityLevel: k8smetrics.ALPHA, + }, + func() float64 { + if execPluginCertTTLAdapter.e == nil { + return math.Inf(1) + } + return execPluginCertTTLAdapter.e.Sub(time.Now()).Seconds() + }, + ) + + execPluginCertRotation = k8smetrics.NewHistogram( + &k8smetrics.HistogramOpts{ + Name: "rest_client_exec_plugin_certificate_rotation_age", + Help: "Histogram of the number of seconds the last auth exec " + + "plugin client certificate lived before being rotated. " + + "If auth exec plugin client certificates are unused, " + + "histogram will contain no data.", + // There are three sets of ranges these buckets intend to capture: + // - 10-60 minutes: captures a rotation cadence which is + // happening too quickly. + // - 4 hours - 1 month: captures an ideal rotation cadence. + // - 3 months - 4 years: captures a rotation cadence which is + // is probably too slow or much too slow. + Buckets: []float64{ + 600, // 10 minutes + 1800, // 30 minutes + 3600, // 1 hour + 14400, // 4 hours + 86400, // 1 day + 604800, // 1 week + 2592000, // 1 month + 7776000, // 3 months + 15552000, // 6 months + 31104000, // 1 year + 124416000, // 4 years + }, + }, + ) + + execPluginCalls = k8smetrics.NewCounterVec( + &k8smetrics.CounterOpts{ + Name: "rest_client_exec_plugin_call_total", + Help: "Number of calls to an exec plugin, partitioned by the type of " + + "event encountered (no_error, plugin_execution_error, plugin_not_found_error, " + + "client_internal_error) and an optional exit code. The exit code will " + + "be set to 0 if and only if the plugin call was successful.", + }, + []string{"code", "call_status"}, + ) +) + +func init() { + + legacyregistry.MustRegister(requestLatency) + legacyregistry.MustRegister(rateLimiterLatency) + legacyregistry.MustRegister(requestResult) + legacyregistry.RawMustRegister(execPluginCertTTL) + legacyregistry.MustRegister(execPluginCertRotation) + metrics.Register(metrics.RegisterOpts{ + ClientCertExpiry: execPluginCertTTLAdapter, + ClientCertRotationAge: &rotationAdapter{m: execPluginCertRotation}, + RequestLatency: &latencyAdapter{m: requestLatency}, + RateLimiterLatency: &latencyAdapter{m: rateLimiterLatency}, + RequestResult: &resultAdapter{requestResult}, + ExecPluginCalls: &callsAdapter{m: execPluginCalls}, + }) +} + +type latencyAdapter struct { + m *k8smetrics.HistogramVec +} + +func (l *latencyAdapter) Observe(ctx context.Context, verb string, u url.URL, latency time.Duration) { + l.m.WithContext(ctx).WithLabelValues(verb, u.String()).Observe(latency.Seconds()) +} + +type resultAdapter struct { + m *k8smetrics.CounterVec +} + +func (r *resultAdapter) Increment(ctx context.Context, code, method, host string) { + r.m.WithContext(ctx).WithLabelValues(code, method, host).Inc() +} + +type expiryToTTLAdapter struct { + e *time.Time +} + +func (e *expiryToTTLAdapter) Set(expiry *time.Time) { + e.e = expiry +} + +type rotationAdapter struct { + m *k8smetrics.Histogram +} + +func (r *rotationAdapter) Observe(d time.Duration) { + r.m.Observe(d.Seconds()) +} + +type callsAdapter struct { + m *k8smetrics.CounterVec +} + +func (r *callsAdapter) Increment(code int, callStatus string) { + r.m.WithLabelValues(fmt.Sprintf("%d", code), callStatus).Inc() +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 4131c0619..375488f26 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -206,7 +206,7 @@ github.com/openshift/api/template github.com/openshift/api/template/v1 github.com/openshift/api/user github.com/openshift/api/user/v1 -# github.com/openshift/build-machinery-go v0.0.0-20210922160744-a9caf93aef90 +# github.com/openshift/build-machinery-go v0.0.0-20211213093930-7e33a7eb4ce3 ## explicit; go 1.13 github.com/openshift/build-machinery-go github.com/openshift/build-machinery-go/make @@ -226,7 +226,7 @@ github.com/openshift/client-go/config/informers/externalversions/config github.com/openshift/client-go/config/informers/externalversions/config/v1 github.com/openshift/client-go/config/informers/externalversions/internalinterfaces github.com/openshift/client-go/config/listers/config/v1 -# github.com/openshift/library-go v0.0.0-20211209153216-ed9bc958bd8a +# github.com/openshift/library-go v0.0.0-20220117141918-17ce0045e35e ## explicit; go 1.17 github.com/openshift/library-go/pkg/authorization/hardcodedauthorizer github.com/openshift/library-go/pkg/config/client @@ -237,7 +237,6 @@ github.com/openshift/library-go/pkg/config/serving github.com/openshift/library-go/pkg/controller/controllercmd github.com/openshift/library-go/pkg/controller/factory github.com/openshift/library-go/pkg/controller/fileobserver -github.com/openshift/library-go/pkg/controller/metrics github.com/openshift/library-go/pkg/crypto github.com/openshift/library-go/pkg/network github.com/openshift/library-go/pkg/operator/events @@ -1145,6 +1144,9 @@ k8s.io/component-base/logs/registry k8s.io/component-base/logs/sanitization k8s.io/component-base/metrics k8s.io/component-base/metrics/legacyregistry +k8s.io/component-base/metrics/prometheus/clientgo +k8s.io/component-base/metrics/prometheus/clientgo/leaderelection +k8s.io/component-base/metrics/prometheus/restclient k8s.io/component-base/metrics/prometheus/workqueue k8s.io/component-base/metrics/testutil k8s.io/component-base/traces