github.com/argoproj-labs/argocd-operator@v0.10.0/controllers/argocd/prometheus_test.go (about)

     1  package argocd
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	monitoringv1 "github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1"
     9  	"github.com/stretchr/testify/assert"
    10  	"k8s.io/apimachinery/pkg/runtime"
    11  	"k8s.io/apimachinery/pkg/types"
    12  	"k8s.io/apimachinery/pkg/util/intstr"
    13  	"sigs.k8s.io/controller-runtime/pkg/client"
    14  
    15  	argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1"
    16  )
    17  
    18  func TestReconcileWorkloadStatusAlertRule(t *testing.T) {
    19  	tests := []struct {
    20  		name              string
    21  		argocd            *argoproj.ArgoCD
    22  		wantPromRuleFound bool
    23  		existingPromRule  bool
    24  	}{
    25  		{
    26  			name: "monitoring enabled, no existing prom rule",
    27  			argocd: makeTestArgoCD(func(cr *argoproj.ArgoCD) {
    28  				cr.Spec.Monitoring.Enabled = true
    29  			}),
    30  			existingPromRule:  false,
    31  			wantPromRuleFound: true,
    32  		},
    33  		{
    34  			name: "monitoring disabled, no existing prom rule",
    35  			argocd: makeTestArgoCD(func(cr *argoproj.ArgoCD) {
    36  				cr.Spec.Monitoring.Enabled = false
    37  			}),
    38  			existingPromRule:  false,
    39  			wantPromRuleFound: false,
    40  		},
    41  		{
    42  			name: "monitoring enabled, existing prom rule",
    43  			argocd: makeTestArgoCD(func(cr *argoproj.ArgoCD) {
    44  				cr.Spec.Monitoring.Enabled = true
    45  			}),
    46  			existingPromRule:  true,
    47  			wantPromRuleFound: true,
    48  		},
    49  		{
    50  			name: "monitoring disabled, existing prom rule",
    51  			argocd: makeTestArgoCD(func(cr *argoproj.ArgoCD) {
    52  				cr.Spec.Monitoring.Enabled = false
    53  			}),
    54  			existingPromRule:  true,
    55  			wantPromRuleFound: false,
    56  		},
    57  	}
    58  
    59  	for _, test := range tests {
    60  		t.Run(test.name, func(t *testing.T) {
    61  
    62  			desiredRuleGroup := []monitoringv1.RuleGroup{
    63  				{
    64  					Name: "ArgoCDComponentStatus",
    65  					Rules: []monitoringv1.Rule{
    66  						{
    67  							Alert: "ApplicationControllerNotReady",
    68  							Annotations: map[string]string{
    69  								"message": fmt.Sprintf("application controller deployment for Argo CD instance in namespace %s is not running", test.argocd.Namespace),
    70  							},
    71  							Expr: intstr.IntOrString{
    72  								Type:   intstr.String,
    73  								StrVal: fmt.Sprintf("kube_statefulset_status_replicas{statefulset=\"%s\", namespace=\"%s\"} != kube_statefulset_status_replicas_ready{statefulset=\"%s\", namespace=\"%s\"} ", fmt.Sprintf(test.argocd.Name+"-application-controller"), test.argocd.Namespace, fmt.Sprintf(test.argocd.Name+"-application-controller"), test.argocd.Namespace),
    74  							},
    75  							For: "1m",
    76  							Labels: map[string]string{
    77  								"severity": "critical",
    78  							},
    79  						},
    80  						{
    81  							Alert: "ServerNotReady",
    82  							Annotations: map[string]string{
    83  								"message": fmt.Sprintf("server deployment for Argo CD instance in namespace %s is not running", test.argocd.Namespace),
    84  							},
    85  							Expr: intstr.IntOrString{
    86  								Type:   intstr.String,
    87  								StrVal: fmt.Sprintf("kube_deployment_status_replicas{deployment=\"%s\", namespace=\"%s\"} != kube_deployment_status_replicas_ready{deployment=\"%s\", namespace=\"%s\"} ", fmt.Sprintf(test.argocd.Name+"-server"), test.argocd.Namespace, fmt.Sprintf(test.argocd.Name+"-server"), test.argocd.Namespace),
    88  							},
    89  							For: "1m",
    90  							Labels: map[string]string{
    91  								"severity": "critical",
    92  							},
    93  						},
    94  						{
    95  							Alert: "RepoServerNotReady",
    96  							Annotations: map[string]string{
    97  								"message": fmt.Sprintf("repo server deployment for Argo CD instance in namespace %s is not running", test.argocd.Namespace),
    98  							},
    99  							Expr: intstr.IntOrString{
   100  								Type:   intstr.String,
   101  								StrVal: fmt.Sprintf("kube_deployment_status_replicas{deployment=\"%s\", namespace=\"%s\"} != kube_deployment_status_replicas_ready{deployment=\"%s\", namespace=\"%s\"} ", fmt.Sprintf(test.argocd.Name+"-repo-server"), test.argocd.Namespace, fmt.Sprintf(test.argocd.Name+"-repo-server"), test.argocd.Namespace),
   102  							},
   103  							For: "1m",
   104  							Labels: map[string]string{
   105  								"severity": "critical",
   106  							},
   107  						},
   108  						{
   109  							Alert: "ApplicationSetControllerNotReady",
   110  							Annotations: map[string]string{
   111  								"message": fmt.Sprintf("applicationSet controller deployment for Argo CD instance in namespace %s is not running", test.argocd.Namespace),
   112  							},
   113  							Expr: intstr.IntOrString{
   114  								Type:   intstr.String,
   115  								StrVal: fmt.Sprintf("kube_deployment_status_replicas{deployment=\"%s\", namespace=\"%s\"} != kube_deployment_status_replicas_ready{deployment=\"%s\", namespace=\"%s\"} ", fmt.Sprintf(test.argocd.Name+"-applicationset-controller"), test.argocd.Namespace, fmt.Sprintf(test.argocd.Name+"-applicationset-controller"), test.argocd.Namespace),
   116  							},
   117  							For: "5m",
   118  							Labels: map[string]string{
   119  								"severity": "warning",
   120  							},
   121  						},
   122  						{
   123  							Alert: "DexNotReady",
   124  							Annotations: map[string]string{
   125  								"message": fmt.Sprintf("dex deployment for Argo CD instance in namespace %s is not running", test.argocd.Namespace),
   126  							},
   127  							Expr: intstr.IntOrString{
   128  								Type:   intstr.String,
   129  								StrVal: fmt.Sprintf("kube_deployment_status_replicas{deployment=\"%s\", namespace=\"%s\"} != kube_deployment_status_replicas_ready{deployment=\"%s\", namespace=\"%s\"} ", fmt.Sprintf(test.argocd.Name+"-dex-server"), test.argocd.Namespace, fmt.Sprintf(test.argocd.Name+"-dex-server"), test.argocd.Namespace),
   130  							},
   131  							For: "5m",
   132  							Labels: map[string]string{
   133  								"severity": "warning",
   134  							},
   135  						},
   136  						{
   137  							Alert: "NotificationsControllerNotReady",
   138  							Annotations: map[string]string{
   139  								"message": fmt.Sprintf("notifications controller deployment for Argo CD instance in namespace %s is not running", test.argocd.Namespace),
   140  							},
   141  							Expr: intstr.IntOrString{
   142  								Type:   intstr.String,
   143  								StrVal: fmt.Sprintf("kube_deployment_status_replicas{deployment=\"%s\", namespace=\"%s\"} != kube_deployment_status_replicas_ready{deployment=\"%s\", namespace=\"%s\"} ", fmt.Sprintf(test.argocd.Name+"-notifications-controller"), test.argocd.Namespace, fmt.Sprintf(test.argocd.Name+"-notifications-controller"), test.argocd.Namespace),
   144  							},
   145  							For: "5m",
   146  							Labels: map[string]string{
   147  								"severity": "warning",
   148  							},
   149  						},
   150  						{
   151  							Alert: "RedisNotReady",
   152  							Annotations: map[string]string{
   153  								"message": fmt.Sprintf("redis deployment for Argo CD instance in namespace %s is not running", test.argocd.Namespace),
   154  							},
   155  							Expr: intstr.IntOrString{
   156  								Type:   intstr.String,
   157  								StrVal: fmt.Sprintf("kube_deployment_status_replicas{deployment=\"%s\", namespace=\"%s\"} != kube_deployment_status_replicas_ready{deployment=\"%s\", namespace=\"%s\"} ", fmt.Sprintf(test.argocd.Name+"-redis"), test.argocd.Namespace, fmt.Sprintf(test.argocd.Name+"-redis"), test.argocd.Namespace),
   158  							},
   159  							For: "5m",
   160  							Labels: map[string]string{
   161  								"severity": "warning",
   162  							},
   163  						},
   164  					},
   165  				},
   166  			}
   167  
   168  			resObjs := []client.Object{test.argocd}
   169  			subresObjs := []client.Object{test.argocd}
   170  			runtimeObjs := []runtime.Object{}
   171  			sch := makeTestReconcilerScheme(argoproj.AddToScheme)
   172  			cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
   173  			r := makeTestReconciler(cl, sch)
   174  
   175  			err := monitoringv1.AddToScheme(r.Scheme)
   176  			assert.NoError(t, err)
   177  
   178  			if test.existingPromRule {
   179  				r.Client.Create(context.TODO(), newPrometheusRule(test.argocd.Namespace, "argocd-component-status-alert"))
   180  			}
   181  
   182  			err = r.reconcilePrometheusRule(test.argocd)
   183  
   184  			// reconciler doesn't need to do anything and should return nil
   185  			if (test.existingPromRule && test.wantPromRuleFound) || (!test.existingPromRule && !test.wantPromRuleFound) {
   186  				if err != nil {
   187  					t.Fatal("expected nil response but got non-nil response")
   188  				}
   189  			} else {
   190  				// reconciler either needs to create rule or delete it
   191  				testRule := &monitoringv1.PrometheusRule{}
   192  				err = r.Client.Get(context.TODO(), types.NamespacedName{
   193  					Name:      "argocd-component-status-alert",
   194  					Namespace: test.argocd.Namespace,
   195  				}, testRule)
   196  
   197  				if test.wantPromRuleFound && err != nil {
   198  					t.Fatal("unexpected error - prometheusRule not found")
   199  				} else if !test.wantPromRuleFound && err == nil {
   200  					t.Fatal("expected error but did not get one - prometheusRule not deleted")
   201  				}
   202  
   203  				if !test.existingPromRule {
   204  					assert.Equal(t, desiredRuleGroup, testRule.Spec.Groups)
   205  				}
   206  
   207  			}
   208  		})
   209  	}
   210  }