Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:dirkmueller:acdc:as_python3_module
kubevirt
0014-ServiceMonitor-and-PrometheusRule-API-dete...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0014-ServiceMonitor-and-PrometheusRule-API-detection-and-.patch of Package kubevirt
From 8d4af84fd0674dd88564bd82e88fcd3c3eb2504e Mon Sep 17 00:00:00 2001 From: Chris Ho <chris.he@suse.com> Date: Wed, 18 Jan 2023 21:16:57 +0800 Subject: [PATCH] ServiceMonitor and PrometheusRule API detection and uint test Signed-off-by: Chris Ho <chris.he@suse.com> --- pkg/testutils/mock_config.go | 34 +++++++++++ pkg/virt-config/configuration.go | 41 ++++++++++++- pkg/virt-operator/BUILD.bazel | 1 + pkg/virt-operator/application.go | 57 ++++++++++++++++-- pkg/virt-operator/application_test.go | 86 +++++++++++++++++++++++++++ 5 files changed, 212 insertions(+), 7 deletions(-) create mode 100644 pkg/virt-operator/application_test.go diff --git a/pkg/testutils/mock_config.go b/pkg/testutils/mock_config.go index f5c2cdd79..990e3ebde 100644 --- a/pkg/testutils/mock_config.go +++ b/pkg/testutils/mock_config.go @@ -93,3 +93,37 @@ func UpdateFakeKubeVirtClusterConfig(kubeVirtInformer cache.SharedIndexInformer, kubeVirtInformer.GetStore().Update(clone) } + +func AddServiceMonitorAPI(crdInformer cache.SharedIndexInformer) { + crdInformer.GetStore().Add(&extv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "service-monitors.monitoring.coreos.com", + }, + Spec: extv1.CustomResourceDefinitionSpec{ + Names: extv1.CustomResourceDefinitionNames{ + Kind: "ServiceMonitor", + }, + }, + }) +} + +func RemoveServiceMonitorAPI(crdInformer cache.SharedIndexInformer) { + crdInformer.GetStore().Replace(nil, "") +} + +func AddPrometheusRuleAPI(crdInformer cache.SharedIndexInformer) { + crdInformer.GetStore().Add(&extv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "prometheusrules.monitoring.coreos.com", + }, + Spec: extv1.CustomResourceDefinitionSpec{ + Names: extv1.CustomResourceDefinitionNames{ + Kind: "PrometheusRule", + }, + }, + }) +} + +func RemovePrometheusRuleAPI(crdInformer cache.SharedIndexInformer) { + crdInformer.GetStore().Replace(nil, "") +} diff --git a/pkg/virt-config/configuration.go b/pkg/virt-config/configuration.go index 06ddcd1a7..127c16172 100644 --- a/pkg/virt-config/configuration.go +++ b/pkg/virt-config/configuration.go @@ -119,10 +119,19 @@ func isDataSourceCrd(crd *extv1.CustomResourceDefinition) bool { return crd.Spec.Names.Kind == "DataSource" } +func isServiceMonitor(crd *extv1.CustomResourceDefinition) bool { + return crd.Spec.Names.Kind == "ServiceMonitor" +} + +func isPrometheusRules(crd *extv1.CustomResourceDefinition) bool { + return crd.Spec.Names.Kind == "PrometheusRule" +} + func (c *ClusterConfig) crdAddedDeleted(obj interface{}) { go c.GetConfig() crd := obj.(*extv1.CustomResourceDefinition) - if !isDataVolumeCrd(crd) && !isDataSourceCrd(crd) { + if !isDataVolumeCrd(crd) && !isDataSourceCrd(crd) && + !isServiceMonitor(crd) && !isPrometheusRules(crd) { return } @@ -379,6 +388,36 @@ func (c *ClusterConfig) HasDataVolumeAPI() bool { return false } +func (c *ClusterConfig) HasServiceMonitorAPI() bool { + c.lock.Lock() + defer c.lock.Unlock() + + objects := c.crdInformer.GetStore().List() + for _, obj := range objects { + if crd, ok := obj.(*extv1.CustomResourceDefinition); ok && crd.DeletionTimestamp == nil { + if isServiceMonitor(crd) { + return true + } + } + } + return false +} + +func (c *ClusterConfig) HasPrometheusRuleAPI() bool { + c.lock.Lock() + defer c.lock.Unlock() + + objects := c.crdInformer.GetStore().List() + for _, obj := range objects { + if crd, ok := obj.(*extv1.CustomResourceDefinition); ok && crd.DeletionTimestamp == nil { + if isPrometheusRules(crd) { + return true + } + } + } + return false +} + func parseNodeSelectors(str string) (map[string]string, error) { nodeSelectors := make(map[string]string) for _, s := range strings.Split(strings.TrimSpace(str), "\n") { diff --git a/pkg/virt-operator/BUILD.bazel b/pkg/virt-operator/BUILD.bazel index c6058e4a2..6b441c782 100644 --- a/pkg/virt-operator/BUILD.bazel +++ b/pkg/virt-operator/BUILD.bazel @@ -59,6 +59,7 @@ go_test( name = "go_default_test", timeout = "long", srcs = [ + "application_test.go", "kubevirt_test.go", "virt_operator_suite_test.go", ], diff --git a/pkg/virt-operator/application.go b/pkg/virt-operator/application.go index e9076921e..df2e42d54 100644 --- a/pkg/virt-operator/application.go +++ b/pkg/virt-operator/application.go @@ -91,6 +91,8 @@ type VirtOperatorApp struct { kubeVirtInformer cache.SharedIndexInformer kubeVirtCache cache.Store + crdInformer cache.SharedIndexInformer + stores util.Stores informers util.Informers @@ -99,6 +101,10 @@ type VirtOperatorApp struct { operatorCertManager certificate.Manager clusterConfig *virtconfig.ClusterConfig + + ctx context.Context + + reInitChan chan string } var ( @@ -223,6 +229,8 @@ func Execute() { ConfigMapCache: app.informerFactory.OperatorConfigMap().GetStore(), } + app.crdInformer = app.informerFactory.CRD() + onOpenShift, err := clusterutil.IsOnOpenShift(app.clientSet) if err != nil { golog.Fatalf("Error determining cluster type: %v", err) @@ -284,7 +292,14 @@ func Execute() { app.informerFactory.KubeVirt(), app.operatorNamespace) - app.Run() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + app.ctx = ctx + + app.reInitChan = make(chan string, 0) + + go app.Run() + <-app.reInitChan } func (app *VirtOperatorApp) Run() { @@ -317,9 +332,6 @@ func (app *VirtOperatorApp) Run() { } }() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - endpointName := VirtOperator recorder := app.getNewRecorder(k8sv1.NamespaceAll, endpointName) @@ -344,8 +356,13 @@ func (app *VirtOperatorApp) Run() { apiAuthConfig := app.informerFactory.ApiAuthConfigMap() - stop := ctx.Done() + stop := app.ctx.Done() app.informerFactory.Start(stop) + + stopChan := app.ctx.Done() + cache.WaitForCacheSync(stopChan, app.crdInformer.HasSynced, app.kubeVirtInformer.HasSynced) + app.clusterConfig.SetConfigModifiedCallback(app.configModificationCallback) + cache.WaitForCacheSync(stop, apiAuthConfig.HasSynced) go app.operatorCertManager.Start() @@ -404,11 +421,39 @@ func (app *VirtOperatorApp) Run() { readyGauge.Set(1) log.Log.Infof("Attempting to acquire leader status") - leaderElector.Run(ctx) + leaderElector.Run(app.ctx) + panic("unreachable") } +// Detects if ServiceMonitor or PrometheusRule crd has been applied or deleted that +// re-initializing virt-operator. +func (app *VirtOperatorApp) configModificationCallback() { + msgf := "Reinitialize virt-operator, %s has been %s" + + smEnabled := app.clusterConfig.HasServiceMonitorAPI() + if app.stores.ServiceMonitorEnabled != smEnabled { + if !app.stores.ServiceMonitorEnabled && smEnabled { + log.Log.Infof(msgf, "ServiceMonitor", "introduced") + } else { + log.Log.Infof(msgf, "ServiceMonitor", "removed") + } + app.reInitChan <- "reinit" + return + } + + prEnabled := app.clusterConfig.HasPrometheusRuleAPI() + if app.stores.PrometheusRulesEnabled != prEnabled { + if !app.stores.PrometheusRulesEnabled && prEnabled { + log.Log.Infof(msgf, "PrometheusRule", "introduced") + } else { + log.Log.Infof(msgf, "PrometheusRule", "removed") + } + app.reInitChan <- "reinit" + } +} + func (app *VirtOperatorApp) getNewRecorder(namespace string, componentName string) record.EventRecorder { eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartRecordingToSink(&k8coresv1.EventSinkImpl{Interface: app.clientSet.CoreV1().Events(namespace)}) diff --git a/pkg/virt-operator/application_test.go b/pkg/virt-operator/application_test.go new file mode 100644 index 000000000..e62ed9f77 --- /dev/null +++ b/pkg/virt-operator/application_test.go @@ -0,0 +1,86 @@ +/* + * This file is part of the KubeVirt project + * + * 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. + * + * Copyright 2017 Red Hat, Inc. + * + */ + +package virt_operator + +import ( + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + v1 "kubevirt.io/api/core/v1" + + "kubevirt.io/kubevirt/pkg/testutils" +) + +var _ = Describe("Reinitialization conditions", func() { + DescribeTable("Re-trigger initialization", func( + hasServiceMonitor bool, hasPrometheusRules bool, + addServiceMonitorCrd bool, removeServiceMonitorCrd bool, + addPrometheusRuleCrd bool, removePrometheusRuleCrd bool, + expectReInit bool) { + var reInitTriggered bool + + app := VirtOperatorApp{} + + clusterConfig, crdInformer, _ := testutils.NewFakeClusterConfigUsingKVConfig(&v1.KubeVirtConfiguration{}) + app.clusterConfig = clusterConfig + app.reInitChan = make(chan string, 10) + app.stores.ServiceMonitorEnabled = hasServiceMonitor + app.stores.PrometheusRulesEnabled = hasPrometheusRules + + if addServiceMonitorCrd { + testutils.AddServiceMonitorAPI(crdInformer) + } else if removeServiceMonitorCrd { + testutils.RemoveServiceMonitorAPI(crdInformer) + } + + if addPrometheusRuleCrd { + testutils.AddPrometheusRuleAPI(crdInformer) + } else if removePrometheusRuleCrd { + testutils.RemovePrometheusRuleAPI(crdInformer) + } + + app.clusterConfig.SetConfigModifiedCallback(app.configModificationCallback) + + select { + case <-app.reInitChan: + reInitTriggered = true + case <-time.After(1 * time.Second): + reInitTriggered = false + } + + Expect(reInitTriggered).To(Equal(expectReInit)) + }, + Entry("when ServiceMonitor is introduced", false, false, true, false, false, false, true), + Entry("when ServiceMonitor is removed", true, false, false, true, false, false, true), + Entry("when PrometheusRule is introduced", false, false, false, false, true, false, true), + Entry("when PrometheusRule is removed", false, true, false, false, false, true, true), + + Entry("when ServiceMonitor and PrometheusRule are introduced", false, false, true, false, true, false, true), + Entry("when ServiceMonitor and PrometheusRule are removed", true, true, false, true, false, true, true), + + Entry("not when nothing changed and ServiceMonitor and PrometheusRule exists", true, true, true, false, true, false, false), + Entry("not when nothing changed and ServiceMonitor and PrometheusRule does not exists", false, false, false, true, false, true, false), + + Entry("when ServiceMonitor is introduced and PrometheusRule is removed", false, true, true, false, false, true, true), + Entry("when ServiceMonitor is removed and PrometheusRule is introduced", true, false, false, true, true, false, true), + ) +}) -- 2.40.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor