github.com/verrazzano/verrazzano@v1.7.0/application-operator/controllers/webhooks/metrics-binding-updater-workload_test.go (about)

     1  // Copyright (c) 2021, 2022, 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 webhooks
     5  
     6  import (
     7  	"context"
     8  	"encoding/json"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	vzapp "github.com/verrazzano/verrazzano/application-operator/apis/app/v1alpha1"
    13  	"github.com/verrazzano/verrazzano/application-operator/constants"
    14  	vzconst "github.com/verrazzano/verrazzano/pkg/constants"
    15  	admissionv1 "k8s.io/api/admission/v1"
    16  	appsv1 "k8s.io/api/apps/v1"
    17  	corev1 "k8s.io/api/core/v1"
    18  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    19  	"k8s.io/apimachinery/pkg/runtime"
    20  	"k8s.io/apimachinery/pkg/runtime/schema"
    21  	"k8s.io/apimachinery/pkg/types"
    22  	"k8s.io/client-go/kubernetes/fake"
    23  	ctrlfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
    24  	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
    25  )
    26  
    27  const testNS = "test"
    28  const testConfigMapName = "testPromConfigMap"
    29  const testTemplateWorkloadNamespace = "testTemplateWorkloadNamespace"
    30  const appsv1APIVersion = "apps/v1"
    31  const testDeploymentName = "testDeployment"
    32  
    33  // newGeneratorWorkloadWebhook creates a new WorkloadWebhook
    34  func newGeneratorWorkloadWebhook() WorkloadWebhook {
    35  	scheme := newScheme()
    36  	scheme.AddKnownTypes(schema.GroupVersion{
    37  		Version: "v1",
    38  	}, &corev1.Pod{}, &appsv1.Deployment{}, &appsv1.ReplicaSet{}, &appsv1.StatefulSet{}, &corev1.Namespace{})
    39  	_ = vzapp.AddToScheme(scheme)
    40  	decoder, _ := admission.NewDecoder(scheme)
    41  	cli := ctrlfake.NewClientBuilder().WithScheme(scheme).Build()
    42  	v := WorkloadWebhook{
    43  		Client:     cli,
    44  		Decoder:    decoder,
    45  		KubeClient: fake.NewSimpleClientset(),
    46  	}
    47  	return v
    48  }
    49  
    50  // newGeneratorWorkloadRequest creates a new admissionRequest with the provided operation and object.
    51  func newGeneratorWorkloadRequest(op admissionv1.Operation, kind string, obj interface{}) admission.Request {
    52  	raw := runtime.RawExtension{}
    53  	bytes, _ := json.Marshal(obj)
    54  	raw.Raw = bytes
    55  	req := admission.Request{
    56  		AdmissionRequest: admissionv1.AdmissionRequest{
    57  			Kind: metav1.GroupVersionKind{
    58  				Kind: kind,
    59  			},
    60  			Operation: op, Object: raw}}
    61  	return req
    62  }
    63  
    64  // TestHandlePod tests the handling of a Pod resource
    65  // GIVEN a call validate Pod on create or update
    66  // WHEN the Pod is properly formed
    67  // THEN the validation should succeed
    68  func TestHandlePod(t *testing.T) {
    69  
    70  	v := newGeneratorWorkloadWebhook()
    71  
    72  	// Test data
    73  	v.createNamespace(t, "test", nil, nil)
    74  	testPod := corev1.Pod{
    75  		ObjectMeta: metav1.ObjectMeta{
    76  			Name:      "test",
    77  			Namespace: "test",
    78  		},
    79  	}
    80  	assert.NoError(t, v.Client.Create(context.TODO(), &testPod))
    81  
    82  	req := newGeneratorWorkloadRequest(admissionv1.Create, "Pod", testPod)
    83  	res := v.Handle(context.TODO(), req)
    84  	assert.True(t, res.Allowed, "Expected validation to succeed.")
    85  }
    86  
    87  // TestHandleDeployment tests the handling of a Deployment resource
    88  // GIVEN a call validate Deployment on create or update
    89  // WHEN the Deployment is properly formed
    90  // THEN the validation should succeed
    91  func TestHandleDeployment(t *testing.T) {
    92  
    93  	v := newGeneratorWorkloadWebhook()
    94  
    95  	// Test data
    96  	v.createNamespace(t, "test", nil, nil)
    97  	testDeployment := appsv1.Deployment{
    98  		ObjectMeta: metav1.ObjectMeta{
    99  			Name:      testDeploymentName,
   100  			Namespace: "test",
   101  		},
   102  	}
   103  	assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
   104  
   105  	req := newGeneratorWorkloadRequest(admissionv1.Create, "Deployment", testDeployment)
   106  	res := v.Handle(context.TODO(), req)
   107  	assert.True(t, res.Allowed, "Expected validation to succeed.")
   108  }
   109  
   110  // TestHandleReplicaSet tests the handling of a ReplicaSet resource
   111  // GIVEN a call validate ReplicaSet on create or update
   112  // WHEN the ReplicaSet is properly formed
   113  // THEN the validation should succeed
   114  func TestHandleReplicaSet(t *testing.T) {
   115  
   116  	v := newGeneratorWorkloadWebhook()
   117  
   118  	// Test data
   119  	v.createNamespace(t, "test", nil, nil)
   120  	testReplicaSet := appsv1.ReplicaSet{
   121  		ObjectMeta: metav1.ObjectMeta{
   122  			Name:      "testReplicaSet",
   123  			Namespace: "test",
   124  		},
   125  	}
   126  	assert.NoError(t, v.Client.Create(context.TODO(), &testReplicaSet))
   127  
   128  	req := newGeneratorWorkloadRequest(admissionv1.Create, "ReplicaSet", testReplicaSet)
   129  	res := v.Handle(context.TODO(), req)
   130  	assert.True(t, res.Allowed, "Expected validation to succeed.")
   131  }
   132  
   133  // TestHandleStatefulSet tests the handling of a StatefulSet resource
   134  // GIVEN a call validate StatefulSet on create or update
   135  // WHEN the StatefulSet is properly formed
   136  // THEN the validation should succeed
   137  func TestHandleStatefulSet(t *testing.T) {
   138  
   139  	v := newGeneratorWorkloadWebhook()
   140  
   141  	// Test data
   142  	v.createNamespace(t, "test", nil, nil)
   143  	testStatefulSet := appsv1.StatefulSet{
   144  		ObjectMeta: metav1.ObjectMeta{
   145  			Name:      "testStatefulSet",
   146  			Namespace: "test",
   147  		},
   148  	}
   149  	assert.NoError(t, v.Client.Create(context.TODO(), &testStatefulSet))
   150  
   151  	req := newGeneratorWorkloadRequest(admissionv1.Create, "StatefulSet", testStatefulSet)
   152  	res := v.Handle(context.TODO(), req)
   153  	assert.True(t, res.Allowed, "Expected validation to succeed.")
   154  }
   155  
   156  // TestHandleOwnerRefs tests the handling of a workload resource with owner references
   157  // GIVEN a call to the webhook Handle function
   158  // WHEN the workload resource has owner references
   159  // THEN the Handle function should succeed and no metricsBinding is not created
   160  func TestHandleOwnerRefs(t *testing.T) {
   161  
   162  	v := newGeneratorWorkloadWebhook()
   163  
   164  	// Test data
   165  	v.createNamespace(t, "test", nil, nil)
   166  	testDeployment := appsv1.Deployment{
   167  		ObjectMeta: metav1.ObjectMeta{
   168  			Name:      testDeploymentName,
   169  			Namespace: "test",
   170  			OwnerReferences: []metav1.OwnerReference{
   171  				{
   172  					Name: "foo",
   173  				},
   174  			},
   175  		},
   176  	}
   177  	assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
   178  
   179  	req := newGeneratorWorkloadRequest(admissionv1.Create, "Deployment", testDeployment)
   180  	res := v.Handle(context.TODO(), req)
   181  	assert.True(t, res.Allowed)
   182  	assert.Nil(t, res.Patches, "expected no changes to workload resource")
   183  
   184  	// validate that metrics binding was not created as expected
   185  	v.validateNoMetricsBinding(t)
   186  }
   187  
   188  // TestHandleMetricsNone tests the handling of a workload resource with "app.verrazzano.io/metrics": "none"
   189  // GIVEN a call to the webhook Handle function
   190  // WHEN the workload resource has  "app.verrazzano.io/metrics": "none"
   191  // THEN the Handle function should succeed and the metricsBinding is not created
   192  func TestHandleMetricsNone(t *testing.T) {
   193  
   194  	v := newGeneratorWorkloadWebhook()
   195  
   196  	// Test data
   197  	v.createNamespace(t, "test", map[string]string{vzconst.VerrazzanoManagedLabelKey: "true"}, nil)
   198  	testDeployment := appsv1.Deployment{
   199  		ObjectMeta: metav1.ObjectMeta{
   200  			Name:      testDeploymentName,
   201  			Namespace: "test",
   202  			Annotations: map[string]string{
   203  				MetricsAnnotation: "none",
   204  			},
   205  		},
   206  	}
   207  	assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
   208  
   209  	req := newGeneratorWorkloadRequest(admissionv1.Create, "Deployment", testDeployment)
   210  	res := v.Handle(context.TODO(), req)
   211  	assert.True(t, res.Allowed)
   212  	assert.Nil(t, res.Patches, "expected no changes to workload resource")
   213  
   214  	// validate that metrics binding was not created as expected
   215  	v.validateNoMetricsBinding(t)
   216  }
   217  
   218  // TestHandleMetricsNoneNamespace tests the handling of a namespace with "app.verrazzano.io/metrics": "none"
   219  // GIVEN a call to the webhook Handle function
   220  // WHEN the workload resource has  "app.verrazzano.io/metrics": "none"
   221  // THEN the Handle function should succeed and the metricsBinding is not created
   222  func TestHandleMetricsNoneNamespace(t *testing.T) {
   223  
   224  	v := newGeneratorWorkloadWebhook()
   225  
   226  	// Test data
   227  	v.createNamespace(t, "test", map[string]string{vzconst.VerrazzanoManagedLabelKey: "true"}, map[string]string{MetricsAnnotation: "none"})
   228  	testDeployment := appsv1.Deployment{
   229  		ObjectMeta: metav1.ObjectMeta{
   230  			Name:      testDeploymentName,
   231  			Namespace: "test",
   232  		},
   233  	}
   234  	assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
   235  
   236  	req := newGeneratorWorkloadRequest(admissionv1.Create, "Deployment", testDeployment)
   237  	res := v.Handle(context.TODO(), req)
   238  	assert.True(t, res.Allowed)
   239  	assert.Nil(t, res.Patches, "expected no changes to workload resource")
   240  
   241  	// validate that metrics binding was not created as expected
   242  	v.validateNoMetricsBinding(t)
   243  }
   244  
   245  // TestHandleInvalidMetricsTemplate tests the handling of a workload resource with references a metrics template
   246  // that does not exist
   247  // GIVEN a call to the webhook Handle function
   248  // WHEN the workload resource has  "app.verrazzano.io/metrics": "badTemplate"
   249  // THEN the Handle function should
   250  // Generate an error for a pre-VZ 1.4 app with existing metrics binding
   251  // Allow the workload for an app with no existing metrics binding
   252  func TestHandleInvalidMetricsTemplate(t *testing.T) {
   253  
   254  	tests := []struct {
   255  		name                 string
   256  		metricsBindingExists bool
   257  		expectAllowed        bool
   258  		expectedError        string
   259  	}{
   260  		{"legacy app with existing MetricsBinding", true, false, "metricstemplates.app.verrazzano.io \"badTemplate\" not found"},
   261  		{"new app with no MetricsBinding present", false, true, ""},
   262  	}
   263  	for _, tt := range tests {
   264  		t.Run(tt.name, func(t *testing.T) {
   265  			v := newGeneratorWorkloadWebhook()
   266  
   267  			// Test data
   268  			v.createNamespace(t, "test", map[string]string{vzconst.VerrazzanoManagedLabelKey: "true"}, nil)
   269  			testDeployment := appsv1.Deployment{
   270  				TypeMeta: metav1.TypeMeta{
   271  					Kind:       "Deployment",
   272  					APIVersion: appsv1APIVersion,
   273  				},
   274  				ObjectMeta: metav1.ObjectMeta{
   275  					Name:      testDeploymentName,
   276  					Namespace: "test",
   277  					Annotations: map[string]string{
   278  						MetricsAnnotation: "badTemplate",
   279  					},
   280  				},
   281  			}
   282  			assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
   283  
   284  			if tt.metricsBindingExists {
   285  				existingMetricsBinding := vzapp.MetricsBinding{
   286  					ObjectMeta: metav1.ObjectMeta{
   287  						Namespace: "test",
   288  						Name:      generateMetricsBindingName(testDeployment.Name, testDeployment.APIVersion, testDeployment.Kind),
   289  					},
   290  				}
   291  				assert.NoError(t, v.Client.Create(context.TODO(), &existingMetricsBinding))
   292  			}
   293  
   294  			req := newGeneratorWorkloadRequest(admissionv1.Create, vzconst.DeploymentWorkloadKind, testDeployment)
   295  			res := v.Handle(context.TODO(), req)
   296  			assert.Equal(t, tt.expectAllowed, res.Allowed)
   297  			if !tt.expectAllowed {
   298  				assert.Equal(t, tt.expectedError, res.Result.Message)
   299  			}
   300  		})
   301  	}
   302  }
   303  
   304  // TestHandleMetricsTemplateWorkloadNamespace tests the handling of a workload resource which references a metrics
   305  // template found in the namespace of the workload resource that already has a MetricsBinding
   306  // GIVEN a call to the webhook Handle function
   307  // WHEN the workload resource has a valid metrics template reference
   308  // THEN the Handle function should succeed and the existing MetricsBinding is updated
   309  func TestHandleMetricsTemplateWorkloadNamespace(t *testing.T) {
   310  
   311  	tests := []struct {
   312  		name                       string
   313  		metricsBindingExists       bool
   314  		expectAllowed              bool
   315  		expectMetricsBindingUpdate bool
   316  		expectServiceMonitor       bool
   317  	}{
   318  		{"legacy app with existing MetricsBinding", true, true, true, false},
   319  		{"new app with no MetricsBinding present", false, true, false, false},
   320  	}
   321  	for _, tt := range tests {
   322  		t.Run(tt.name, func(t *testing.T) {
   323  			v := newGeneratorWorkloadWebhook()
   324  
   325  			// Test data
   326  			v.createNamespace(t, "test", map[string]string{vzconst.VerrazzanoManagedLabelKey: "true"}, nil)
   327  			v.createConfigMap(t, "test", testConfigMapName)
   328  			testDeployment := appsv1.Deployment{
   329  				TypeMeta: metav1.TypeMeta{
   330  					Kind:       vzconst.DeploymentWorkloadKind,
   331  					APIVersion: appsv1APIVersion,
   332  				},
   333  				ObjectMeta: metav1.ObjectMeta{
   334  					Name:      testDeploymentName,
   335  					Namespace: "test",
   336  					UID:       "11",
   337  					Annotations: map[string]string{
   338  						MetricsAnnotation: testTemplateWorkloadNamespace,
   339  					},
   340  				},
   341  			}
   342  			assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
   343  
   344  			if tt.metricsBindingExists {
   345  				existingMetricsBinding := vzapp.MetricsBinding{
   346  					ObjectMeta: metav1.ObjectMeta{
   347  						Name:      generateMetricsBindingName(testDeployment.Name, testDeployment.APIVersion, testDeployment.Kind),
   348  						Namespace: "test",
   349  					},
   350  				}
   351  				assert.NoError(t, v.Client.Create(context.TODO(), &existingMetricsBinding))
   352  			}
   353  
   354  			testTemplate := vzapp.MetricsTemplate{
   355  				ObjectMeta: metav1.ObjectMeta{
   356  					Namespace: "test",
   357  					Name:      testTemplateWorkloadNamespace,
   358  				},
   359  				Spec: vzapp.MetricsTemplateSpec{
   360  					WorkloadSelector: vzapp.WorkloadSelector{},
   361  					PrometheusConfig: vzapp.PrometheusConfig{
   362  						TargetConfigMap: vzapp.TargetConfigMap{
   363  							Namespace: "test",
   364  							Name:      testConfigMapName,
   365  						},
   366  					},
   367  				},
   368  			}
   369  			assert.NoError(t, v.Client.Create(context.TODO(), &testTemplate))
   370  
   371  			req := newGeneratorWorkloadRequest(admissionv1.Create, vzconst.DeploymentWorkloadKind, testDeployment)
   372  			res := v.Handle(context.TODO(), req)
   373  
   374  			assert.Equal(t, tt.expectAllowed, res.Allowed)
   375  
   376  			if tt.expectMetricsBindingUpdate {
   377  				assert.Len(t, res.Patches, 1)
   378  				assert.Equal(t, "add", res.Patches[0].Operation)
   379  				assert.Equal(t, "/metadata/labels", res.Patches[0].Path)
   380  				assert.Contains(t, res.Patches[0].Value, constants.MetricsWorkloadLabel)
   381  
   382  				// validate that metrics binding was updated as expected
   383  				v.validateMetricsBinding(t, testNS, testTemplateWorkloadNamespace, testNS, testConfigMapName, false)
   384  			} else {
   385  				assert.Len(t, res.Patches, 0)
   386  				v.validateNoMetricsBinding(t)
   387  			}
   388  		})
   389  	}
   390  }
   391  
   392  // TestHandleMetricsTemplateSystemNamespace tests the handling of a workload resource which references a metrics
   393  // template found in the verrazzano-system namespace
   394  // GIVEN a call to the webhook Handle function
   395  // WHEN the workload resource has a valid metrics template reference
   396  // THEN the Handle function should succeed
   397  // AND for a pre-VZ 1.4 app with existing MetricsBinding, the metricsBinding is updated
   398  // BUT for an app with no existing MetricsBinding, no action is taken
   399  func TestHandleMetricsTemplateSystemNamespace(t *testing.T) {
   400  
   401  	tests := []struct {
   402  		name                       string
   403  		metricsBindingExists       bool
   404  		expectAllowed              bool
   405  		expectMetricsBindingUpdate bool
   406  		expectServiceMonitor       bool
   407  	}{
   408  		{"legacy app with existing MetricsBinding", true, true, true, false},
   409  		{"new app with no MetricsBinding present", false, true, false, false},
   410  	}
   411  	for _, tt := range tests {
   412  		t.Run(tt.name, func(t *testing.T) {
   413  			v := newGeneratorWorkloadWebhook()
   414  			// Test data
   415  			v.createNamespace(t, testNS, map[string]string{vzconst.VerrazzanoManagedLabelKey: "true"}, nil)
   416  			v.createNamespace(t, vzconst.VerrazzanoSystemNamespace, nil, nil)
   417  			v.createConfigMap(t, testNS, testConfigMapName)
   418  			testDeployment := appsv1.Deployment{
   419  				TypeMeta: metav1.TypeMeta{
   420  					Kind:       vzconst.DeploymentWorkloadKind,
   421  					APIVersion: appsv1APIVersion,
   422  				},
   423  				ObjectMeta: metav1.ObjectMeta{
   424  					Name:      testDeploymentName,
   425  					Namespace: testNS,
   426  					UID:       "11",
   427  					Annotations: map[string]string{
   428  						MetricsAnnotation: "testTemplateSameNamespace",
   429  					},
   430  				},
   431  			}
   432  			assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
   433  
   434  			if tt.metricsBindingExists {
   435  				existingMetricsBinding := vzapp.MetricsBinding{
   436  					ObjectMeta: metav1.ObjectMeta{
   437  						Name:      generateMetricsBindingName(testDeployment.Name, testDeployment.APIVersion, testDeployment.Kind),
   438  						Namespace: testNS,
   439  					},
   440  				}
   441  				assert.NoError(t, v.Client.Create(context.TODO(), &existingMetricsBinding))
   442  			}
   443  
   444  			testTemplate := vzapp.MetricsTemplate{
   445  				ObjectMeta: metav1.ObjectMeta{
   446  					Namespace: vzconst.VerrazzanoSystemNamespace,
   447  					Name:      "testTemplateSameNamespace",
   448  				},
   449  				Spec: vzapp.MetricsTemplateSpec{
   450  					WorkloadSelector: vzapp.WorkloadSelector{},
   451  					PrometheusConfig: vzapp.PrometheusConfig{
   452  						TargetConfigMap: vzapp.TargetConfigMap{
   453  							Namespace: testNS,
   454  							Name:      testConfigMapName,
   455  						},
   456  					},
   457  				},
   458  			}
   459  			assert.NoError(t, v.Client.Create(context.TODO(), &testTemplate))
   460  
   461  			req := newGeneratorWorkloadRequest(admissionv1.Create, vzconst.DeploymentWorkloadKind, testDeployment)
   462  			res := v.Handle(context.TODO(), req)
   463  			assert.Equal(t, tt.expectAllowed, res.Allowed)
   464  			if tt.expectMetricsBindingUpdate {
   465  				assert.Len(t, res.Patches, 1)
   466  				assert.Equal(t, "add", res.Patches[0].Operation)
   467  				assert.Equal(t, "/metadata/labels", res.Patches[0].Path)
   468  				assert.Contains(t, res.Patches[0].Value, constants.MetricsWorkloadLabel)
   469  
   470  				// validate that metrics binding was updated as expected
   471  				v.validateMetricsBinding(t, vzconst.VerrazzanoSystemNamespace, "testTemplateSameNamespace", testNS, testConfigMapName, false)
   472  			} else {
   473  				assert.Len(t, res.Patches, 0)
   474  				v.validateNoMetricsBinding(t)
   475  			}
   476  		})
   477  	}
   478  }
   479  
   480  // TestHandleMetricsTemplateConfigMapNotFound tests the handling of a workload resource which references a metrics
   481  // template found with Prometheus config map that does not exist
   482  // GIVEN a call to the webhook Handle function
   483  // WHEN the workload resource has an invalid Prometheus config map reference
   484  // THEN the Handle function should
   485  // fail and return an error for a pre-VZ 1.4 app with existing metrics binding
   486  // Allow the workload for an app with no existing metrics binding
   487  
   488  func TestHandleMetricsTemplateConfigMapNotFound(t *testing.T) {
   489  
   490  	tests := []struct {
   491  		name                      string
   492  		metricsBindingExists      bool
   493  		expectAllowed             bool
   494  		expectMetricsBindingError bool
   495  	}{
   496  		{"legacy app with existing MetricsBinding", true, false, true},
   497  		{"new app with no MetricsBinding present", false, true, false},
   498  	}
   499  	for _, tt := range tests {
   500  		t.Run(tt.name, func(t *testing.T) {
   501  
   502  			v := newGeneratorWorkloadWebhook()
   503  
   504  			// Test data
   505  			v.createNamespace(t, testNS, map[string]string{vzconst.VerrazzanoManagedLabelKey: "true"}, nil)
   506  			testDeployment := appsv1.Deployment{
   507  				ObjectMeta: metav1.ObjectMeta{
   508  					Name:      "test",
   509  					Namespace: testNS,
   510  					UID:       "11",
   511  					Annotations: map[string]string{
   512  						MetricsAnnotation: testTemplateWorkloadNamespace,
   513  					},
   514  				},
   515  				TypeMeta: metav1.TypeMeta{
   516  					Kind:       vzconst.DeploymentWorkloadKind,
   517  					APIVersion: appsv1APIVersion,
   518  				},
   519  			}
   520  			assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
   521  
   522  			if tt.metricsBindingExists {
   523  				existingMetricsBinding := vzapp.MetricsBinding{
   524  					ObjectMeta: metav1.ObjectMeta{
   525  						Name:      generateMetricsBindingName(testDeployment.Name, testDeployment.APIVersion, testDeployment.Kind),
   526  						Namespace: testNS,
   527  					},
   528  				}
   529  				assert.NoError(t, v.Client.Create(context.TODO(), &existingMetricsBinding))
   530  			}
   531  
   532  			testTemplate := vzapp.MetricsTemplate{
   533  				ObjectMeta: metav1.ObjectMeta{
   534  					Namespace: testNS,
   535  					Name:      testTemplateWorkloadNamespace,
   536  				},
   537  				Spec: vzapp.MetricsTemplateSpec{
   538  					WorkloadSelector: vzapp.WorkloadSelector{},
   539  					PrometheusConfig: vzapp.PrometheusConfig{
   540  						TargetConfigMap: vzapp.TargetConfigMap{
   541  							Namespace: testNS,
   542  							Name:      testConfigMapName,
   543  						},
   544  					},
   545  				},
   546  			}
   547  			assert.NoError(t, v.Client.Create(context.TODO(), &testTemplate))
   548  
   549  			req := newGeneratorWorkloadRequest(admissionv1.Create, vzconst.DeploymentWorkloadKind, testDeployment)
   550  			res := v.Handle(context.TODO(), req)
   551  			assert.Equal(t, tt.expectAllowed, res.Allowed)
   552  			if tt.expectMetricsBindingError {
   553  				assert.Equal(t, "configmaps \"testPromConfigMap\" not found", res.Result.Message)
   554  			}
   555  		})
   556  	}
   557  }
   558  
   559  // TestHandleMatchWorkloadNamespace tests the handling of a workload resource with no metrics template specified
   560  // but matches a template found in the workload resources namespace
   561  // GIVEN a call to the webhook Handle function
   562  // WHEN the workload resource has no metrics template reference
   563  // THEN the Handle function should succeed
   564  // AND for a pre-VZ 1.4 app, the existing legacy MetricsBinding is updated
   565  // BUT for an app with no existing MetricsBinding, no action is taken. It's up to user to create a monitor resource.
   566  func TestHandleMatchWorkloadNamespace(t *testing.T) {
   567  
   568  	tests := []struct {
   569  		name                       string
   570  		metricsBindingExists       bool
   571  		expectAllowed              bool
   572  		expectMetricsBindingUpdate bool
   573  	}{
   574  		{"legacy app with existing MetricsBinding", true, true, true},
   575  		{"new app with no MetricsBinding present", false, true, false},
   576  	}
   577  	for _, tt := range tests {
   578  		t.Run(tt.name, func(t *testing.T) {
   579  			v := newGeneratorWorkloadWebhook()
   580  			// Test data
   581  			v.createNamespace(t, testNS, map[string]string{vzconst.VerrazzanoManagedLabelKey: "true"}, nil)
   582  			v.createNamespace(t, vzconst.VerrazzanoSystemNamespace, nil, nil)
   583  			v.createConfigMap(t, testNS, testConfigMapName)
   584  			testDeployment := appsv1.Deployment{
   585  				TypeMeta: metav1.TypeMeta{
   586  					Kind:       vzconst.DeploymentWorkloadKind,
   587  					APIVersion: appsv1APIVersion,
   588  				},
   589  				ObjectMeta: metav1.ObjectMeta{
   590  					Name:      testDeploymentName,
   591  					Namespace: testNS,
   592  					UID:       "11",
   593  				},
   594  			}
   595  			assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
   596  
   597  			if tt.metricsBindingExists {
   598  				existingMetricsBinding := vzapp.MetricsBinding{
   599  					ObjectMeta: metav1.ObjectMeta{
   600  						Name:      generateMetricsBindingName(testDeployment.Name, testDeployment.APIVersion, testDeployment.Kind),
   601  						Namespace: testNS,
   602  					},
   603  				}
   604  				assert.NoError(t, v.Client.Create(context.TODO(), &existingMetricsBinding))
   605  			}
   606  
   607  			testTemplate := vzapp.MetricsTemplate{
   608  				ObjectMeta: metav1.ObjectMeta{
   609  					Namespace: testNS,
   610  					Name:      testTemplateWorkloadNamespace,
   611  				},
   612  				Spec: vzapp.MetricsTemplateSpec{
   613  					WorkloadSelector: vzapp.WorkloadSelector{
   614  						APIGroups: []string{
   615  							"apps",
   616  						},
   617  						APIVersions: []string{
   618  							"v1",
   619  						},
   620  						Resources: []string{
   621  							"deployment",
   622  						},
   623  					},
   624  					PrometheusConfig: vzapp.PrometheusConfig{
   625  						TargetConfigMap: vzapp.TargetConfigMap{
   626  							Namespace: testNS,
   627  							Name:      testConfigMapName,
   628  						},
   629  					},
   630  				},
   631  			}
   632  			assert.NoError(t, v.Client.Create(context.TODO(), &testTemplate))
   633  
   634  			req := newGeneratorWorkloadRequest(admissionv1.Create, vzconst.DeploymentWorkloadKind, testDeployment)
   635  			res := v.Handle(context.TODO(), req)
   636  			assert.Equal(t, tt.expectAllowed, res.Allowed)
   637  			if tt.expectMetricsBindingUpdate {
   638  				assert.Len(t, res.Patches, 1)
   639  				assert.Equal(t, "add", res.Patches[0].Operation)
   640  				assert.Equal(t, "/metadata/labels", res.Patches[0].Path)
   641  				assert.Contains(t, res.Patches[0].Value, constants.MetricsWorkloadLabel)
   642  				// validate that metrics binding was updated as expected
   643  				v.validateMetricsBinding(t, testNS, testTemplateWorkloadNamespace, testNS, testConfigMapName, false)
   644  			} else {
   645  				assert.Len(t, res.Patches, 0)
   646  				v.validateNoMetricsBinding(t)
   647  			}
   648  		})
   649  	}
   650  
   651  }
   652  
   653  // TestHandleMatchSystemNamespace tests the handling of a workload resource with no metrics template specified
   654  // but matches a template found in the verrazzano-system namespace
   655  // GIVEN a call to the webhook Handle function
   656  // WHEN the workload resource has no metrics template reference
   657  // THEN the Handle function should succeed
   658  // AND for a pre-VZ 1.4 app, the existing legacy MetricsBinding is updated
   659  // BUT for an app with no existing MetricsBinding, no action is taken. It's up to user to create a monitor resource.
   660  func TestHandleMatchSystemNamespace(t *testing.T) {
   661  
   662  	tests := []struct {
   663  		name                       string
   664  		metricsBindingExists       bool
   665  		expectAllowed              bool
   666  		expectMetricsBindingUpdate bool
   667  	}{
   668  		{"legacy app with existing MetricsBinding", true, true, true},
   669  		{"new app with no MetricsBinding present", false, true, false},
   670  	}
   671  	for _, tt := range tests {
   672  		t.Run(tt.name, func(t *testing.T) {
   673  
   674  			v := newGeneratorWorkloadWebhook()
   675  
   676  			// Test data
   677  			v.createNamespace(t, testNS, map[string]string{vzconst.VerrazzanoManagedLabelKey: "true"}, nil)
   678  			v.createNamespace(t, vzconst.VerrazzanoSystemNamespace, nil, nil)
   679  			v.createConfigMap(t, testNS, testConfigMapName)
   680  			testDeployment := appsv1.Deployment{
   681  				TypeMeta: metav1.TypeMeta{
   682  					Kind:       vzconst.DeploymentWorkloadKind,
   683  					APIVersion: appsv1APIVersion,
   684  				},
   685  				ObjectMeta: metav1.ObjectMeta{
   686  					Name:      testDeploymentName,
   687  					Namespace: testNS,
   688  					UID:       "11",
   689  				},
   690  			}
   691  			assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
   692  
   693  			if tt.metricsBindingExists {
   694  				existingMetricsBinding := vzapp.MetricsBinding{
   695  					ObjectMeta: metav1.ObjectMeta{
   696  						Name:      generateMetricsBindingName(testDeployment.Name, testDeployment.APIVersion, testDeployment.Kind),
   697  						Namespace: testNS,
   698  					},
   699  				}
   700  				assert.NoError(t, v.Client.Create(context.TODO(), &existingMetricsBinding))
   701  			}
   702  
   703  			testTemplate := vzapp.MetricsTemplate{
   704  				ObjectMeta: metav1.ObjectMeta{
   705  					Namespace: vzconst.VerrazzanoSystemNamespace,
   706  					Name:      "testTemplateSystemNamespace",
   707  				},
   708  				Spec: vzapp.MetricsTemplateSpec{
   709  					WorkloadSelector: vzapp.WorkloadSelector{
   710  						APIGroups: []string{
   711  							"apps",
   712  						},
   713  						APIVersions: []string{
   714  							"v1",
   715  						},
   716  						Resources: []string{
   717  							"deployment",
   718  						},
   719  					},
   720  					PrometheusConfig: vzapp.PrometheusConfig{
   721  						TargetConfigMap: vzapp.TargetConfigMap{
   722  							Namespace: testNS,
   723  							Name:      testConfigMapName,
   724  						},
   725  					},
   726  				},
   727  			}
   728  			assert.NoError(t, v.Client.Create(context.TODO(), &testTemplate))
   729  
   730  			req := newGeneratorWorkloadRequest(admissionv1.Create, vzconst.DeploymentWorkloadKind, testDeployment)
   731  			res := v.Handle(context.TODO(), req)
   732  			assert.Equal(t, tt.expectAllowed, res.Allowed)
   733  			if tt.expectMetricsBindingUpdate {
   734  				assert.Len(t, res.Patches, 1)
   735  				assert.Equal(t, "add", res.Patches[0].Operation)
   736  				assert.Equal(t, "/metadata/labels", res.Patches[0].Path)
   737  				assert.Contains(t, res.Patches[0].Value, constants.MetricsWorkloadLabel)
   738  
   739  				// validate that metrics binding was updated as expected
   740  				v.validateMetricsBinding(t, vzconst.VerrazzanoSystemNamespace, "testTemplateSystemNamespace", testNS, testConfigMapName, false)
   741  			} else {
   742  				assert.Len(t, res.Patches, 0)
   743  				v.validateNoMetricsBinding(t)
   744  			}
   745  		})
   746  	}
   747  }
   748  
   749  // TestHandleMatchNotFound tests the handling of a workload resource with no metrics template specified
   750  // and a matching template not found
   751  // GIVEN a call to the webhook Handle function
   752  // WHEN the workload resource has no metrics template reference
   753  // THEN the Handle function should succeed and no metricsBinding is created
   754  func TestHandleMatchNotFound(t *testing.T) {
   755  
   756  	v := newGeneratorWorkloadWebhook()
   757  
   758  	// Test data
   759  	v.createNamespace(t, testNS, map[string]string{vzconst.VerrazzanoManagedLabelKey: "true"}, nil)
   760  	v.createNamespace(t, vzconst.VerrazzanoSystemNamespace, nil, nil)
   761  	v.createConfigMap(t, testNS, testConfigMapName)
   762  	testDeployment := appsv1.Deployment{
   763  		TypeMeta: metav1.TypeMeta{
   764  			Kind:       vzconst.DeploymentWorkloadKind,
   765  			APIVersion: appsv1APIVersion,
   766  		},
   767  		ObjectMeta: metav1.ObjectMeta{
   768  			Name:      testDeploymentName,
   769  			Namespace: testNS,
   770  			UID:       "11",
   771  		},
   772  	}
   773  	assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
   774  	testTemplate := vzapp.MetricsTemplate{
   775  		ObjectMeta: metav1.ObjectMeta{
   776  			Namespace: vzconst.VerrazzanoSystemNamespace,
   777  			Name:      "testTemplateSystemNamespace",
   778  		},
   779  		Spec: vzapp.MetricsTemplateSpec{
   780  			WorkloadSelector: vzapp.WorkloadSelector{
   781  				APIGroups: []string{
   782  					"apps",
   783  				},
   784  				APIVersions: []string{
   785  					"*",
   786  				},
   787  				Resources: []string{
   788  					"foo",
   789  				},
   790  			},
   791  			PrometheusConfig: vzapp.PrometheusConfig{
   792  				TargetConfigMap: vzapp.TargetConfigMap{
   793  					Namespace: testNS,
   794  					Name:      testConfigMapName,
   795  				},
   796  			},
   797  		},
   798  	}
   799  	assert.NoError(t, v.Client.Create(context.TODO(), &testTemplate))
   800  
   801  	req := newGeneratorWorkloadRequest(admissionv1.Create, vzconst.DeploymentWorkloadKind, testDeployment)
   802  	res := v.Handle(context.TODO(), req)
   803  	assert.True(t, res.Allowed)
   804  	assert.Empty(t, res.Patches)
   805  
   806  	// validate that metrics binding was not created as expected
   807  	v.validateNoMetricsBinding(t)
   808  }
   809  
   810  // TestHandleMatchTemplateNoWorkloadSelector tests the handling of a workload resource with no metrics template specified
   811  // and a metrics template that doesn't have a workload selector specified
   812  // GIVEN a call to the webhook Handle function
   813  // WHEN the workload resource has no metrics template reference
   814  // THEN the Handle function should succeed and no metricsBinding is created
   815  func TestHandleMatchTemplateNoWorkloadSelector(t *testing.T) {
   816  
   817  	v := newGeneratorWorkloadWebhook()
   818  
   819  	// Test data
   820  	v.createNamespace(t, testNS, map[string]string{vzconst.VerrazzanoManagedLabelKey: "true"}, nil)
   821  	v.createNamespace(t, vzconst.VerrazzanoSystemNamespace, nil, nil)
   822  	v.createConfigMap(t, testNS, testConfigMapName)
   823  	testDeployment := appsv1.Deployment{
   824  		TypeMeta: metav1.TypeMeta{
   825  			Kind:       vzconst.DeploymentWorkloadKind,
   826  			APIVersion: appsv1APIVersion,
   827  		},
   828  		ObjectMeta: metav1.ObjectMeta{
   829  			Name:      testDeploymentName,
   830  			Namespace: testNS,
   831  			UID:       "11",
   832  		},
   833  	}
   834  	assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
   835  	testTemplate := vzapp.MetricsTemplate{
   836  		ObjectMeta: metav1.ObjectMeta{
   837  			Namespace: vzconst.VerrazzanoSystemNamespace,
   838  			Name:      "testTemplateSystemNamespace",
   839  		},
   840  		Spec: vzapp.MetricsTemplateSpec{
   841  			PrometheusConfig: vzapp.PrometheusConfig{
   842  				TargetConfigMap: vzapp.TargetConfigMap{
   843  					Namespace: testNS,
   844  					Name:      testConfigMapName,
   845  				},
   846  			},
   847  		},
   848  	}
   849  	assert.NoError(t, v.Client.Create(context.TODO(), &testTemplate))
   850  
   851  	req := newGeneratorWorkloadRequest(admissionv1.Create, vzconst.DeploymentWorkloadKind, testDeployment)
   852  	res := v.Handle(context.TODO(), req)
   853  	assert.True(t, res.Allowed)
   854  	assert.Empty(t, res.Patches)
   855  
   856  	// validate that metrics binding was not created as expected
   857  	v.validateNoMetricsBinding(t)
   858  }
   859  
   860  // TestHandleNoConfigMap tests the handling of a workload resource that doesn't have a Prometheus target
   861  // config map specified in the metrics template
   862  // GIVEN a call to the webhook Handle function
   863  // WHEN the workload resource has a metrics template reference
   864  // THEN the Handle function should succeed and no metricsBinding is created
   865  func TestHandleNoConfigMap(t *testing.T) {
   866  
   867  	v := newGeneratorWorkloadWebhook()
   868  
   869  	// Test data
   870  	v.createNamespace(t, testNS, map[string]string{vzconst.VerrazzanoManagedLabelKey: "true"}, nil)
   871  	v.createNamespace(t, vzconst.VerrazzanoSystemNamespace, nil, nil)
   872  	testDeployment := appsv1.Deployment{
   873  		TypeMeta: metav1.TypeMeta{
   874  			Kind:       vzconst.DeploymentWorkloadKind,
   875  			APIVersion: appsv1APIVersion,
   876  		},
   877  		ObjectMeta: metav1.ObjectMeta{
   878  			Name:      testDeploymentName,
   879  			Namespace: testNS,
   880  			Annotations: map[string]string{
   881  				MetricsAnnotation: testTemplateWorkloadNamespace,
   882  			},
   883  			UID: "11",
   884  		},
   885  	}
   886  	assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
   887  	testTemplate := vzapp.MetricsTemplate{
   888  		ObjectMeta: metav1.ObjectMeta{
   889  			Namespace: testNS,
   890  			Name:      testTemplateWorkloadNamespace,
   891  		},
   892  		Spec: vzapp.MetricsTemplateSpec{},
   893  	}
   894  	assert.NoError(t, v.Client.Create(context.TODO(), &testTemplate))
   895  
   896  	req := newGeneratorWorkloadRequest(admissionv1.Create, vzconst.DeploymentWorkloadKind, testDeployment)
   897  	res := v.Handle(context.TODO(), req)
   898  	assert.True(t, res.Allowed)
   899  	assert.Empty(t, res.Patches)
   900  
   901  	// validate that metrics binding was not created as expected
   902  	v.validateNoMetricsBinding(t)
   903  }
   904  
   905  // TestHandleNamespaceAnnotation tests the handling of a namespace that specifies a template
   906  // GIVEN a call to the webhook Handle function
   907  // WHEN the namespace has a metrics template reference
   908  // THEN the Handle function should succeed and a metricsBinding is created
   909  func TestHandleNamespaceAnnotation(t *testing.T) {
   910  
   911  	tests := []struct {
   912  		name                       string
   913  		metricsBindingExists       bool
   914  		expectAllowed              bool
   915  		expectMetricsBindingUpdate bool
   916  	}{
   917  		{"legacy app with existing MetricsBinding", true, true, true},
   918  		{"new app with no MetricsBinding present", false, true, false},
   919  	}
   920  	for _, tt := range tests {
   921  		t.Run(tt.name, func(t *testing.T) {
   922  			v := newGeneratorWorkloadWebhook()
   923  
   924  			// Test data
   925  			v.createNamespace(t, testNS, map[string]string{vzconst.VerrazzanoManagedLabelKey: "true"}, map[string]string{MetricsAnnotation: "testTemplateDifferentNamespace"})
   926  			v.createNamespace(t, constants.VerrazzanoSystemNamespace, nil, nil)
   927  			v.createConfigMap(t, testNS, testConfigMapName)
   928  			testDeployment := appsv1.Deployment{
   929  				TypeMeta: metav1.TypeMeta{
   930  					Kind:       vzconst.DeploymentWorkloadKind,
   931  					APIVersion: appsv1APIVersion,
   932  				},
   933  				ObjectMeta: metav1.ObjectMeta{
   934  					Name:      testDeploymentName,
   935  					Namespace: testNS,
   936  				},
   937  			}
   938  			assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
   939  
   940  			if tt.metricsBindingExists {
   941  				existingMetricsBinding := vzapp.MetricsBinding{
   942  					ObjectMeta: metav1.ObjectMeta{
   943  						Name:      generateMetricsBindingName(testDeployment.Name, testDeployment.APIVersion, testDeployment.Kind),
   944  						Namespace: testNS,
   945  					},
   946  				}
   947  				assert.NoError(t, v.Client.Create(context.TODO(), &existingMetricsBinding))
   948  			}
   949  
   950  			testTemplate := vzapp.MetricsTemplate{
   951  				ObjectMeta: metav1.ObjectMeta{
   952  					Namespace: constants.VerrazzanoSystemNamespace,
   953  					Name:      "testTemplateDifferentNamespace",
   954  				},
   955  				Spec: vzapp.MetricsTemplateSpec{
   956  					WorkloadSelector: vzapp.WorkloadSelector{},
   957  					PrometheusConfig: vzapp.PrometheusConfig{
   958  						TargetConfigMap: vzapp.TargetConfigMap{
   959  							Namespace: testNS,
   960  							Name:      testConfigMapName,
   961  						},
   962  					},
   963  				},
   964  			}
   965  			extraTemplate := vzapp.MetricsTemplate{
   966  				ObjectMeta: metav1.ObjectMeta{
   967  					Namespace: constants.VerrazzanoSystemNamespace,
   968  					Name:      "testWrongTemplate",
   969  				},
   970  				Spec: vzapp.MetricsTemplateSpec{
   971  					WorkloadSelector: vzapp.WorkloadSelector{},
   972  					PrometheusConfig: vzapp.PrometheusConfig{
   973  						TargetConfigMap: vzapp.TargetConfigMap{
   974  							Namespace: testNS,
   975  							Name:      testConfigMapName,
   976  						},
   977  					},
   978  				},
   979  			}
   980  			assert.NoError(t, v.Client.Create(context.TODO(), &testTemplate))
   981  			assert.NoError(t, v.Client.Create(context.TODO(), &extraTemplate))
   982  
   983  			req := newGeneratorWorkloadRequest(admissionv1.Create, vzconst.DeploymentWorkloadKind, testDeployment)
   984  			res := v.Handle(context.TODO(), req)
   985  			assert.Equal(t, tt.expectAllowed, res.Allowed)
   986  			if tt.expectMetricsBindingUpdate {
   987  				assert.Len(t, res.Patches, 1)
   988  				assert.Equal(t, "add", res.Patches[0].Operation)
   989  				assert.Equal(t, "/metadata/labels", res.Patches[0].Path)
   990  				assert.Contains(t, res.Patches[0].Value, constants.MetricsWorkloadLabel)
   991  
   992  				// validate that metrics binding was created as expected
   993  				v.validateMetricsBinding(t, vzconst.VerrazzanoSystemNamespace, "testTemplateDifferentNamespace", testNS, testConfigMapName, false)
   994  			} else {
   995  				assert.Len(t, res.Patches, 0)
   996  				v.validateNoMetricsBinding(t)
   997  			}
   998  		})
   999  	}
  1000  }
  1001  
  1002  // TestExistingMetricsBindingVmiConfigMap tests the handling of an existing metrics binding which
  1003  // uses the legacy VMI Prometheus ConfigMap
  1004  // GIVEN an existing metrics binding which uses the legacy VMI Prometheus ConfigMap
  1005  // WHEN the webhook Handle is called
  1006  // THEN the metrics binding should be modified to use the Prometheus Operator additionalScrapeConfigs secret instead
  1007  func TestExistingMetricsBindingVmiConfigMap(t *testing.T) {
  1008  
  1009  	v := newGeneratorWorkloadWebhook()
  1010  
  1011  	// Test data
  1012  	v.createNamespace(t, testNS, map[string]string{vzconst.VerrazzanoManagedLabelKey: "true"}, map[string]string{MetricsAnnotation: "testTemplateDifferentNamespace"})
  1013  	v.createNamespace(t, constants.VerrazzanoSystemNamespace, nil, nil)
  1014  
  1015  	testTemplate := vzapp.MetricsTemplate{
  1016  		ObjectMeta: metav1.ObjectMeta{
  1017  			Namespace: testNS,
  1018  			Name:      "testTemplate",
  1019  		},
  1020  		Spec: vzapp.MetricsTemplateSpec{
  1021  			WorkloadSelector: vzapp.WorkloadSelector{},
  1022  			PrometheusConfig: vzapp.PrometheusConfig{
  1023  				TargetConfigMap: vzapp.TargetConfigMap{
  1024  					Namespace: vzconst.VerrazzanoSystemNamespace,
  1025  					Name:      vzconst.VmiPromConfigName,
  1026  				},
  1027  			},
  1028  		},
  1029  	}
  1030  	assert.NoError(t, v.Client.Create(context.TODO(), &testTemplate))
  1031  
  1032  	testDeployment := appsv1.Deployment{
  1033  		TypeMeta: metav1.TypeMeta{
  1034  			Kind:       vzconst.DeploymentWorkloadKind,
  1035  			APIVersion: appsv1APIVersion,
  1036  		},
  1037  		ObjectMeta: metav1.ObjectMeta{
  1038  			Name:      testDeploymentName,
  1039  			Namespace: testNS,
  1040  			Annotations: map[string]string{
  1041  				MetricsAnnotation: testTemplate.Name,
  1042  			},
  1043  		},
  1044  	}
  1045  	assert.NoError(t, v.Client.Create(context.TODO(), &testDeployment))
  1046  
  1047  	existingMetricsBinding := vzapp.MetricsBinding{
  1048  		ObjectMeta: metav1.ObjectMeta{
  1049  			Name:      generateMetricsBindingName(testDeployment.Name, testDeployment.APIVersion, testDeployment.Kind),
  1050  			Namespace: testNS,
  1051  		},
  1052  		Spec: vzapp.MetricsBindingSpec{
  1053  			PrometheusConfigMap: vzapp.NamespaceName{
  1054  				Namespace: vzconst.VerrazzanoSystemNamespace,
  1055  				Name:      vzconst.VmiPromConfigName,
  1056  			},
  1057  		},
  1058  	}
  1059  	assert.NoError(t, v.Client.Create(context.TODO(), &existingMetricsBinding))
  1060  
  1061  	req := newGeneratorWorkloadRequest(admissionv1.Update, vzconst.DeploymentWorkloadKind, testDeployment)
  1062  	res := v.Handle(context.TODO(), req)
  1063  	assert.True(t, res.Allowed, "Expected validation to succeed.")
  1064  	v.validateMetricsBinding(t, testNS, "testTemplate", "", "", true)
  1065  }
  1066  
  1067  func (v *WorkloadWebhook) createNamespace(t *testing.T, name string, labels map[string]string, annotations map[string]string) {
  1068  	ns := &corev1.Namespace{
  1069  		ObjectMeta: metav1.ObjectMeta{
  1070  			Name:        name,
  1071  			Labels:      labels,
  1072  			Annotations: annotations,
  1073  		},
  1074  	}
  1075  	err := v.Client.Create(context.TODO(), ns)
  1076  	assert.NoError(t, err, "unexpected error creating namespace")
  1077  	_, err = v.KubeClient.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{})
  1078  	assert.NoError(t, err, "unexpected error creating namespace")
  1079  }
  1080  
  1081  func (v *WorkloadWebhook) createConfigMap(t *testing.T, namespace string, name string) {
  1082  	cm := &corev1.ConfigMap{
  1083  		ObjectMeta: metav1.ObjectMeta{
  1084  			Namespace: namespace,
  1085  			Name:      name,
  1086  		},
  1087  	}
  1088  	_, err := v.KubeClient.CoreV1().ConfigMaps(namespace).Create(context.TODO(), cm, metav1.CreateOptions{})
  1089  	assert.NoError(t, err, "unexpected error creating namespace")
  1090  }
  1091  
  1092  func (v *WorkloadWebhook) validateNoMetricsBinding(t *testing.T) {
  1093  	namespacedName := types.NamespacedName{Namespace: testNS, Name: "testDeployment-deployment"}
  1094  	metricsBinding := &vzapp.MetricsBinding{}
  1095  	assert.EqualError(t, v.Client.Get(context.TODO(), namespacedName, metricsBinding), "metricsbindings.app.verrazzano.io \"testDeployment-deployment\" not found")
  1096  }
  1097  
  1098  func (v *WorkloadWebhook) validateMetricsBinding(
  1099  	t *testing.T, templateNamespace string, templateName string, configMapNamespace string,
  1100  	configMapName string, hasAdditionalScrapeConfigsSecret bool) {
  1101  	namespacedName := types.NamespacedName{Namespace: testNS, Name: "testDeployment-apps-v1-deployment"}
  1102  	metricsBinding := &vzapp.MetricsBinding{}
  1103  	assert.NoError(t, v.Client.Get(context.TODO(), namespacedName, metricsBinding))
  1104  	assert.Equal(t, appsv1APIVersion, metricsBinding.Spec.Workload.TypeMeta.APIVersion)
  1105  	assert.Equal(t, vzconst.DeploymentWorkloadKind, metricsBinding.Spec.Workload.TypeMeta.Kind)
  1106  	assert.Equal(t, testDeploymentName, metricsBinding.Spec.Workload.Name)
  1107  	assert.Equal(t, templateNamespace, metricsBinding.Spec.MetricsTemplate.Namespace)
  1108  	assert.Equal(t, templateName, metricsBinding.Spec.MetricsTemplate.Name)
  1109  	assert.Equal(t, configMapNamespace, metricsBinding.Spec.PrometheusConfigMap.Namespace)
  1110  	assert.Equal(t, configMapName, metricsBinding.Spec.PrometheusConfigMap.Name)
  1111  	if hasAdditionalScrapeConfigsSecret {
  1112  		assert.Equal(t, vzconst.PrometheusOperatorNamespace, metricsBinding.Spec.PrometheusConfigSecret.Namespace)
  1113  		assert.Equal(t, vzconst.PromAdditionalScrapeConfigsSecretName, metricsBinding.Spec.PrometheusConfigSecret.Name)
  1114  		assert.Equal(t, vzconst.PromAdditionalScrapeConfigsSecretKey, metricsBinding.Spec.PrometheusConfigSecret.Key)
  1115  	}
  1116  }