github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/verify-install/promstack/promstack_test.go (about) 1 // Copyright (c) 2022, 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package promstack 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/Jeffail/gabs/v2" 11 "github.com/verrazzano/verrazzano/pkg/vzcr" 12 vzbeta1 "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1beta1" 13 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/appoper" 14 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/authproxy" 15 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/clusteroperator" 16 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/istio" 17 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/nginx" 18 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/opensearch" 19 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/prometheus/adapter" 20 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/prometheus/kubestatemetrics" 21 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/prometheus/nodeexporter" 22 prometheusOperator "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/prometheus/operator" 23 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/prometheus/pushgateway" 24 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/thanos" 25 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/vmo" 26 27 . "github.com/onsi/ginkgo/v2" 28 . "github.com/onsi/gomega" 29 "github.com/verrazzano/verrazzano/pkg/k8sutil" 30 "github.com/verrazzano/verrazzano/platform-operator/constants" 31 "github.com/verrazzano/verrazzano/tests/e2e/pkg" 32 "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework" 33 corev1 "k8s.io/api/core/v1" 34 k8serrors "k8s.io/apimachinery/pkg/api/errors" 35 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 36 ) 37 38 const ( 39 waitTimeout = 15 * time.Minute 40 pollingInterval = 10 * time.Second 41 prometheusTLSSecret = "prometheus-operator-kube-p-admission" 42 prometheusOperatorDeployment = "prometheus-operator-kube-p-operator" 43 prometheusOperatorContainerName = "kube-prometheus-stack" 44 thanosSidecarContainerName = "thanos-sidecar" 45 overrideConfigMapSecretName = "test-overrides" 46 overrideKey = "override" 47 overrideValue = "true" 48 ) 49 50 type enabledComponents struct { 51 podName string 52 componentName string 53 target string 54 } 55 56 var ( 57 vz *vzbeta1.Verrazzano 58 59 promStackEnabledComponents = []enabledComponents{ 60 {podName: "prometheus-adapter", componentName: adapter.ComponentName}, 61 {podName: "prometheus-operator-kube-p-operator", componentName: prometheusOperator.ComponentName}, 62 {podName: "kube-state-metrics", componentName: kubestatemetrics.ComponentName}, 63 {podName: "prometheus-pushgateway", componentName: pushgateway.ComponentName}, 64 {podName: "prometheus-node-exporter", componentName: nodeexporter.ComponentName}, 65 {podName: "prometheus-prometheus-operator-kube-p-prometheus", componentName: prometheusOperator.ComponentName}, 66 } 67 promOperatorCrds = []string{ 68 "alertmanagerconfigs.monitoring.coreos.com", 69 "alertmanagers.monitoring.coreos.com", 70 "podmonitors.monitoring.coreos.com", 71 "probes.monitoring.coreos.com", 72 "prometheuses.monitoring.coreos.com", 73 "prometheusrules.monitoring.coreos.com", 74 "servicemonitors.monitoring.coreos.com", 75 "thanosrulers.monitoring.coreos.com", 76 } 77 imagePrefix = pkg.GetImagePrefix() 78 expectedPromOperatorArgs = []string{ 79 "--prometheus-default-base-image=" + imagePrefix + "/verrazzano/prometheus", 80 "--alertmanager-default-base-image=" + imagePrefix + "/verrazzano/alertmanager", 81 } 82 labelMatch = map[string]string{overrideKey: overrideValue} 83 isMinVersion140 bool 84 85 scrapeTargets = []enabledComponents{ 86 {target: "serviceMonitor/verrazzano-monitoring/prometheus-node-exporter", componentName: nodeexporter.ComponentName}, 87 {target: "serviceMonitor/verrazzano-monitoring/prometheus-operator-kube-p-apiserver", componentName: prometheusOperator.ComponentName}, 88 {target: "serviceMonitor/verrazzano-monitoring/prometheus-operator-kube-p-coredns", componentName: prometheusOperator.ComponentName}, 89 {target: "serviceMonitor/verrazzano-monitoring/prometheus-operator-kube-p-kubelet", componentName: prometheusOperator.ComponentName}, 90 {target: "serviceMonitor/verrazzano-monitoring/prometheus-operator-kube-p-operator", componentName: prometheusOperator.ComponentName}, 91 //{target: "serviceMonitor/verrazzano-monitoring/prometheus-operator-kube-p-prometheus", componentName: prometheusOperator.ComponentName}, 92 {target: "serviceMonitor/verrazzano-monitoring/authproxy", componentName: authproxy.ComponentName}, 93 //{target: "serviceMonitor/verrazzano-monitoring/fluentd", componentName: fluentd.ComponentName}, 94 {target: "serviceMonitor/verrazzano-monitoring/kube-state-metrics", componentName: kubestatemetrics.ComponentName}, 95 {target: "serviceMonitor/verrazzano-monitoring/opensearch", componentName: opensearch.ComponentName}, 96 {target: "serviceMonitor/verrazzano-monitoring/pilot", componentName: istio.ComponentName}, 97 {target: "serviceMonitor/verrazzano-monitoring/verrazzano-application-operator", componentName: appoper.ComponentName}, 98 {target: "serviceMonitor/verrazzano-monitoring/verrazzano-cluster-operator", componentName: clusteroperator.ComponentName}, 99 {target: "serviceMonitor/verrazzano-monitoring/verrazzano-monitoring-operator", componentName: vmo.ComponentName}, 100 {target: "serviceMonitor/verrazzano-monitoring/thanos-query-frontend", componentName: thanos.ComponentName}, 101 {target: "serviceMonitor/verrazzano-monitoring/thanos-query", componentName: thanos.ComponentName}, 102 } 103 ) 104 105 var t = framework.NewTestFramework("promstack") 106 107 func listEnabledComponents() []string { 108 var enabledPods []string 109 for _, component := range promStackEnabledComponents { 110 if vzcr.IsComponentStatusEnabled(vz, component.componentName) { 111 enabledPods = append(enabledPods, component.podName) 112 } 113 } 114 return enabledPods 115 } 116 117 func listDisabledComponents() []string { 118 var disabledPods []string 119 for _, component := range promStackEnabledComponents { 120 if !vzcr.IsComponentStatusEnabled(vz, component.componentName) { 121 disabledPods = append(disabledPods, component.podName) 122 } 123 } 124 return disabledPods 125 } 126 127 // areOverridesEnabled - return true if the override value prometheusOperator.podAnnotations.override 128 // is present and set to "true" 129 func areOverridesEnabled() bool { 130 kubeconfigPath := getKubeConfigOrAbort() 131 vz, err := pkg.GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath) 132 if err != nil { 133 AbortSuite(fmt.Sprintf("Failed to get vz resource in cluster: %s", err.Error())) 134 return false 135 } 136 137 promOper := vz.Spec.Components.PrometheusOperator 138 if promOper == nil || len(promOper.ValueOverrides) == 0 { 139 return false 140 } 141 142 // The overrides are enabled if the override value prometheusOperator.podAnnotations.override = "true" 143 for _, override := range promOper.ValueOverrides { 144 if override.Values != nil { 145 jsonString, err := gabs.ParseJSON(override.Values.Raw) 146 if err != nil { 147 return false 148 } 149 if container := jsonString.Path("prometheusOperator.podAnnotations.override"); container != nil { 150 if val, ok := container.Data().(string); ok { 151 return "true" == string(val) 152 } 153 } 154 } 155 } 156 157 return false 158 } 159 160 // isThanosSidecarEnabled returns true if the Helm override for enabling the Thanos sidecar is found 161 func isThanosSidecarEnabled() (bool, error) { 162 kubeconfigPath := getKubeConfigOrAbort() 163 vz, err := pkg.GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath) 164 if err != nil { 165 t.Logs.Errorf("Failed to get installed Verrazzano resource in the cluster: %v", err) 166 return false, err 167 } 168 169 if vz.Spec.Components.PrometheusOperator == nil { 170 return false, nil 171 } 172 overrides := vz.Spec.Components.PrometheusOperator.ValueOverrides 173 174 for _, override := range overrides { 175 if override.Values == nil { 176 continue 177 } 178 vals, err := gabs.ParseJSON(override.Values.Raw) 179 if err != nil { 180 t.Logs.Errorf("Failed to parse the Values Override JSON: %v", err) 181 return false, err 182 } 183 184 integration, ok := vals.Path("prometheus.thanos.integration").Data().(string) 185 t.Logs.Debugf("Integration Override: %s", integration) 186 if ok && integration == "sidecar" { 187 return true, nil 188 } 189 } 190 t.Logs.Infof("Thanos Sidecar override not found in the Prometheus Operator overrides.") 191 return false, nil 192 } 193 194 // isThanosSidecarInstalledIfEnabled returns true if Thanos is disabled, or if Thanos is enabled and the sidecar container is found 195 func isThanosSidecarInstalledIfEnabled() (bool, error) { 196 enabled, err := isThanosSidecarEnabled() 197 if err != nil { 198 return false, err 199 } 200 if !enabled { 201 return true, nil 202 } 203 204 promPod, err := pkg.GetPodsFromSelector(&metav1.LabelSelector{ 205 MatchLabels: map[string]string{"app.kubernetes.io/name": "prometheus"}, 206 }, constants.VerrazzanoMonitoringNamespace) 207 if err != nil { 208 t.Logs.Errorf("Failed to get the Prometheus pod from the cluster: %v", err) 209 return false, err 210 } 211 212 for _, pod := range promPod { 213 for _, container := range pod.Spec.Containers { 214 if container.Name == thanosSidecarContainerName { 215 return true, nil 216 } 217 } 218 } 219 return false, nil 220 } 221 222 // 'It' Wrapper to only run spec if the Prometheus Stack is supported on the current Verrazzano version 223 func WhenPromStackInstalledIt(description string, f func()) { 224 kubeconfigPath := getKubeConfigOrAbort() 225 supported, err := pkg.IsVerrazzanoMinVersion("1.3.0", kubeconfigPath) 226 if err != nil { 227 t.It(description, func() { 228 Fail(fmt.Sprintf("Failed to check Verrazzano version 1.3.0: %s", err.Error())) 229 }) 230 } 231 if supported { 232 t.It(description, f) 233 } else { 234 t.Logs.Infof("Skipping check '%v', the Prometheus stack is not supported", description) 235 } 236 } 237 238 func getKubeConfigOrAbort() string { 239 kubeconfigPath, err := k8sutil.GetKubeConfigLocation() 240 if err != nil { 241 AbortSuite(fmt.Sprintf("Failed to get default kubeconfig path: %s", err.Error())) 242 } 243 return kubeconfigPath 244 } 245 246 var beforeSuite = t.BeforeSuiteFunc(func() { 247 var err error 248 kubeconfigPath := getKubeConfigOrAbort() 249 isMinVersion140, err = pkg.IsVerrazzanoMinVersion("1.4.0", kubeconfigPath) 250 if err != nil { 251 Fail(err.Error()) 252 } 253 254 vz, err = pkg.GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath) 255 if err != nil { 256 AbortSuite(fmt.Sprintf("Failed to get installed Verrazzano resource in the cluster: %v", err)) 257 } 258 }) 259 260 var _ = BeforeSuite(beforeSuite) 261 262 var _ = t.Describe("Prometheus Stack", Label("f:platform-lcm.install"), func() { 263 t.Context("after successful installation", func() { 264 // GIVEN the Prometheus stack is installed 265 // WHEN we check to make sure the namespace exists 266 // THEN we successfully find the namespace 267 WhenPromStackInstalledIt("should have a verrazzano-monitoring namespace", func() { 268 Eventually(func() (bool, error) { 269 if len(listEnabledComponents()) == 0 { 270 return true, nil 271 } 272 return pkg.DoesNamespaceExist(constants.VerrazzanoMonitoringNamespace) 273 }, waitTimeout, pollingInterval).Should(BeTrue()) 274 }) 275 276 // GIVEN the Prometheus stack is installed 277 // WHEN we check to make sure the pods are running 278 // THEN we successfully find the running pods 279 WhenPromStackInstalledIt("should have running pods", func() { 280 promStackPodsRunning := func() (bool, error) { 281 enabledPods := listEnabledComponents() 282 result, err := pkg.PodsRunning(constants.VerrazzanoMonitoringNamespace, enabledPods) 283 if err != nil { 284 t.Logs.Errorf("Pods %v is not running in the namespace: %v, error: %v", enabledPods, constants.VerrazzanoMonitoringNamespace, err) 285 } 286 return result, err 287 } 288 Eventually(promStackPodsRunning, waitTimeout, pollingInterval).Should(BeTrue()) 289 }) 290 291 // GIVEN the Prometheus stack is installed 292 // WHEN we check to make sure any disabled pods are NOT running 293 // THEN we successfully find the running pods 294 WhenPromStackInstalledIt("Disabled pods not running", func() { 295 promStackPodsRunning := func() bool { 296 disabledPods := listDisabledComponents() 297 t.Logs.Debugf("Checking disabled component pods %v", disabledPods) 298 result, err := pkg.PodsNotRunning(constants.VerrazzanoMonitoringNamespace, disabledPods) 299 if err != nil { 300 AbortSuite(fmt.Sprintf("Unexpected error occurred checking for pods %v in namespace: %v, error: %v", disabledPods, constants.VerrazzanoMonitoringNamespace, err)) 301 } 302 return result 303 } 304 Eventually(promStackPodsRunning, waitTimeout, pollingInterval).Should(BeTrue()) 305 }) 306 307 // GIVEN the Prometheus stack is installed 308 // WHEN we check to make sure the operator overrides get applied 309 // THEN we see that the correct pod labels and annotations exist 310 WhenPromStackInstalledIt("should have Prometheus Operator pod labeled and annotated", func() { 311 promStackPodsRunning := func() bool { 312 if vzcr.IsComponentStatusEnabled(vz, prometheusOperator.ComponentName) && areOverridesEnabled() { 313 _, err := pkg.GetConfigMap(overrideConfigMapSecretName, constants.DefaultNamespace) 314 if err == nil { 315 pods, err := pkg.GetPodsFromSelector(&metav1.LabelSelector{ 316 MatchLabels: labelMatch, 317 }, constants.VerrazzanoMonitoringNamespace) 318 if err != nil { 319 AbortSuite(fmt.Sprintf("Label override not found for the Prometheus Operator pod in namespace %s: %v", constants.VerrazzanoMonitoringNamespace, err)) 320 } 321 foundAnnotation := false 322 for _, pod := range pods { 323 if val, ok := pod.Annotations[overrideKey]; ok && val == overrideValue { 324 foundAnnotation = true 325 } 326 } 327 return len(pods) == 1 && foundAnnotation 328 } else if !k8serrors.IsNotFound(err) { 329 AbortSuite(fmt.Sprintf("Error retrieving the override ConfigMap: %v", err)) 330 } 331 } 332 return true 333 } 334 Eventually(promStackPodsRunning, waitTimeout, pollingInterval).Should(BeTrue()) 335 }) 336 337 // GIVEN the Prometheus stack is installed 338 // WHEN we check to make sure the default images are from Verrazzano 339 // THEN we see that the arguments are correctly populated 340 WhenPromStackInstalledIt(fmt.Sprintf("should have the correct default image arguments: %s, %s", expectedPromOperatorArgs[0], expectedPromOperatorArgs[1]), func() { 341 promStackPodsRunning := func() (bool, error) { 342 if vzcr.IsComponentStatusEnabled(vz, prometheusOperator.ComponentName) { 343 return pkg.ContainerHasExpectedArgs(constants.VerrazzanoMonitoringNamespace, prometheusOperatorDeployment, prometheusOperatorContainerName, expectedPromOperatorArgs) 344 } 345 return true, nil 346 } 347 Eventually(promStackPodsRunning, waitTimeout, pollingInterval).Should(BeTrue()) 348 }) 349 350 WhenPromStackInstalledIt("should have the correct Prometheus Operator CRDs", func() { 351 verifyCRDList := func() (bool, error) { 352 if vzcr.IsComponentStatusEnabled(vz, prometheusOperator.ComponentName) { 353 for _, crd := range promOperatorCrds { 354 exists, err := pkg.DoesCRDExist(crd) 355 if err != nil || !exists { 356 return exists, err 357 } 358 } 359 return true, nil 360 } 361 return true, nil 362 } 363 Eventually(verifyCRDList, waitTimeout, pollingInterval).Should(BeTrue()) 364 }) 365 366 // GIVEN the Prometheus stack is installed 367 // WHEN the Prometheus Instance has Thanos enabled 368 // THEN we see that the Thanos sidecar exists 369 WhenPromStackInstalledIt("should have the Thanos sidecar if enabled", func() { 370 Eventually(func() (bool, error) { 371 return isThanosSidecarInstalledIfEnabled() 372 }, waitTimeout, pollingInterval).Should(BeTrue()) 373 }) 374 375 WhenPromStackInstalledIt("should have the TLS secret", func() { 376 Eventually(func() bool { 377 if vzcr.IsComponentStatusEnabled(vz, prometheusOperator.ComponentName) { 378 return pkg.SecretsCreated(constants.VerrazzanoMonitoringNamespace, prometheusTLSSecret) 379 } 380 return true 381 }, waitTimeout, pollingInterval).Should(BeTrue()) 382 }) 383 384 WhenPromStackInstalledIt("has affinity configured on prometheus pods", func() { 385 if isMinVersion140 { 386 var pods []corev1.Pod 387 Eventually(func() error { 388 var err error 389 selector := map[string]string{ 390 "prometheus": "prometheus-operator-kube-p-prometheus", 391 "app.kubernetes.io/name": "prometheus", 392 } 393 pods, err = pkg.GetPodsFromSelector(&metav1.LabelSelector{MatchLabels: selector}, constants.VerrazzanoMonitoringNamespace) 394 return err 395 }, waitTimeout, pollingInterval).ShouldNot(HaveOccurred()) 396 397 // Check the affinity configuration. Verify only a pod anti-affinity definition exists. 398 for _, pod := range pods { 399 affinity := pod.Spec.Affinity 400 Expect(affinity).ToNot(BeNil()) 401 Expect(affinity.PodAffinity).To(BeNil()) 402 Expect(affinity.NodeAffinity).To(BeNil()) 403 Expect(affinity.PodAntiAffinity).ToNot(BeNil()) 404 Expect(len(affinity.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution)).To(Equal(1)) 405 } 406 } else { 407 t.Logs.Info("Skipping check, Verrazzano minimum version is not v1.4.0") 408 } 409 }) 410 411 WhenPromStackInstalledIt("should have scrape targets healthy for installed components", func() { 412 if isMinVersion140 && !pkg.IsManagedClusterProfile() { 413 verifyScrapeTargets := func() (bool, error) { 414 var targets []string 415 for _, scrapeTarget := range scrapeTargets { 416 if vzcr.IsComponentStatusEnabled(vz, scrapeTarget.componentName) { 417 targets = append(targets, scrapeTarget.target) 418 } 419 } 420 if vzcr.IsComponentStatusEnabled(vz, prometheusOperator.ComponentName) { 421 if !vzcr.IsComponentStatusEnabled(vz, nginx.ComponentName) { 422 return pkg.ScrapeTargetsHealthyFromExec(targets) 423 } 424 return pkg.ScrapeTargetsHealthy(targets) 425 } 426 return true, nil 427 } 428 Eventually(verifyScrapeTargets, waitTimeout, pollingInterval).Should(BeTrue()) 429 } else { 430 t.Logs.Info("Skipping check, Verrazzano minimum version is not v1.4.0 or is managed cluster") 431 } 432 }) 433 }) 434 })