github.com/verrazzano/verrazzano@v1.7.0/application-operator/internal/operatorinit/update_webhook_test.go (about)

     1  // Copyright (c) 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 operatorinit
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/verrazzano/verrazzano/application-operator/internal/certificates"
    13  	adminv1 "k8s.io/api/admissionregistration/v1"
    14  	v1 "k8s.io/api/core/v1"
    15  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    16  	"k8s.io/client-go/kubernetes/fake"
    17  )
    18  
    19  // TestUpdateValidatingnWebhookConfiguration tests that the CA Bundle is updated in the verrazzano-application-operator
    20  // validatingWebhookConfiguration resource.
    21  // GIVEN a validatingWebhookConfiguration resource with the CA Bundle set
    22  //
    23  //	WHEN I call updateValidatingWebhookConfiguration
    24  //	THEN the validatingWebhookConfiguration resource set the CA Bundle as expected
    25  func TestUpdateValidatingnWebhookConfiguration(t *testing.T) {
    26  	asserts := assert.New(t)
    27  
    28  	kubeClient := fake.NewSimpleClientset()
    29  
    30  	_, caCert, err := createExpectedCASecret(kubeClient)
    31  	asserts.Nilf(err, "Unexpected error creating expected CA secret", err)
    32  
    33  	wh, err := createExpectedValidatingWebhook(kubeClient)
    34  	asserts.Nilf(err, "error should not be returned creating validation webhook configuration: %v", err)
    35  	asserts.NotEmpty(wh)
    36  
    37  	err = updateValidatingWebhookConfiguration(kubeClient, certificates.VerrazzanoProjectValidatingWebhookName)
    38  	asserts.Nilf(err, "error should not be returned updating validation webhook configuration: %v", err)
    39  
    40  	updatedWebhook, _ := kubeClient.AdmissionregistrationV1().ValidatingWebhookConfigurations().Get(context.TODO(), certificates.VerrazzanoProjectValidatingWebhookName, metav1.GetOptions{})
    41  	asserts.Equal(caCert.Bytes(), updatedWebhook.Webhooks[0].ClientConfig.CABundle, "Expected CA bundle name did not match")
    42  }
    43  
    44  // TestUpdateValidatingnWebhookConfigurationFail tests that the CA Bundle is not updated in the
    45  // verrazzano-application-operator validatingWebhookConfiguration resource.
    46  // GIVEN an invalid validatingWebhookConfiguration resource with the CA Bundle set
    47  //
    48  //	WHEN I call updateValidatingWebhookConfiguration
    49  //	THEN the validatingWebhookConfiguration resource will fail to be updated
    50  func TestUpdateValidatingnWebhookConfigurationFail(t *testing.T) {
    51  	asserts := assert.New(t)
    52  
    53  	kubeClient := fake.NewSimpleClientset()
    54  
    55  	_, _, err := createExpectedCASecret(kubeClient)
    56  	asserts.Nilf(err, "Unexpected error creating expected CA secret", err)
    57  
    58  	_, err = createInvalidExpectedValidatingWebhook(kubeClient, certificates.VerrazzanoProjectValidatingWebhookName)
    59  	asserts.Nil(err, "error should not be returned creating validation webhook configuration")
    60  
    61  	err = updateValidatingWebhookConfiguration(kubeClient, certificates.VerrazzanoProjectValidatingWebhookName)
    62  	asserts.Error(err, "error should be returned updating validation webhook configuration")
    63  }
    64  
    65  // TestUpdateMutatingWebhookConfiguration tests that the CA Bundle is updated the specified MutatingWebhook configuration
    66  // GIVEN a call to updateMutatingWebhookConfiguration
    67  //
    68  //	WHEN with the webhook CA bundle secret exists
    69  //	THEN the MutatingWebhook configuration sets the CA bundle on all webhook client configurations
    70  func TestUpdateMutatingWebhookConfiguration(t *testing.T) {
    71  	asserts := assert.New(t)
    72  
    73  	kubeClient := fake.NewSimpleClientset()
    74  
    75  	_, caCert, err := createExpectedCASecret(kubeClient)
    76  	asserts.Nilf(err, "Unexpected error creating expected CA secret", err)
    77  
    78  	_, err = createExpectedMutatingWebhook(kubeClient)
    79  	asserts.Nilf(err, "Unexpected error creating expected webhook configuration")
    80  
    81  	err = updateMutatingWebhookConfiguration(kubeClient, certificates.IstioMutatingWebhookName)
    82  	asserts.Nilf(err, "Unexpected error returned from updateMutatingWebhookConfiguration: %v", err)
    83  
    84  	updatedWebhook, _ := kubeClient.AdmissionregistrationV1().MutatingWebhookConfigurations().Get(context.TODO(), certificates.IstioMutatingWebhookName, metav1.GetOptions{})
    85  	asserts.Equal(caCert.Bytes(), updatedWebhook.Webhooks[0].ClientConfig.CABundle, "Expected CA bundle name did not match")
    86  	asserts.Equal(caCert.Bytes(), updatedWebhook.Webhooks[1].ClientConfig.CABundle, "Expected CA bundle name did not match")
    87  }
    88  
    89  // TestUpdateMutatingWebhookConfigurationNoCASecret tests that
    90  // GIVEN a call to updateMutatingWebhookConfiguration
    91  //
    92  //	WHEN with the webhook CA bundle secret does not exist but the webhook does
    93  //	THEN an error is returned
    94  func TestUpdateMutatingWebhookConfigurationNoCASecret(t *testing.T) {
    95  	asserts := assert.New(t)
    96  
    97  	kubeClient := fake.NewSimpleClientset()
    98  
    99  	_, err := createExpectedMutatingWebhook(kubeClient)
   100  	asserts.Nilf(err, "Unexpected error creating expected webhook configuration", err)
   101  
   102  	err = updateMutatingWebhookConfiguration(kubeClient, certificates.IstioMutatingWebhookName)
   103  	asserts.NotNil(err, "No error returned when webhook doesn't exist")
   104  }
   105  
   106  // TestUpdateMutatingWebhookConfigurationNoWebhook tests that
   107  // GIVEN a call to updateMutatingWebhookConfiguration
   108  //
   109  //	WHEN with the webhook CA bundle secret exists but the webhook does not
   110  //	THEN an error is returned
   111  func TestUpdateMutatingWebhookConfigurationNoWebhook(t *testing.T) {
   112  	asserts := assert.New(t)
   113  
   114  	kubeClient := fake.NewSimpleClientset()
   115  
   116  	_, _, err := createExpectedCASecret(kubeClient)
   117  	asserts.Nilf(err, "Unexpected error creating expected CA secret", err)
   118  
   119  	err = updateMutatingWebhookConfiguration(kubeClient, certificates.IstioMutatingWebhookName)
   120  	asserts.NotNil(err, "No error returned when webhook doesn't exist")
   121  }
   122  
   123  func createExpectedCASecret(kubeClient *fake.Clientset) (*v1.Secret, bytes.Buffer, error) {
   124  	var caCert bytes.Buffer
   125  	caCert.WriteString("Fake CABundle")
   126  
   127  	caSecret := v1.Secret{}
   128  	caSecret.Name = certificates.OperatorCA
   129  	caSecret.Type = v1.SecretTypeTLS
   130  	caSecret.Namespace = certificates.OperatorNamespace
   131  	caSecret.Data = make(map[string][]byte)
   132  	caSecret.Data[certificates.CertKey] = caCert.Bytes()
   133  	caSecret.Data[certificates.PrivKey] = caCert.Bytes()
   134  
   135  	newSecret, err := kubeClient.CoreV1().Secrets(certificates.OperatorNamespace).Create(context.TODO(), &caSecret, metav1.CreateOptions{})
   136  	return newSecret, caCert, err
   137  }
   138  
   139  func createExpectedMutatingWebhook(kubeClient *fake.Clientset) (*adminv1.MutatingWebhookConfiguration, error) {
   140  	webhook := adminv1.MutatingWebhookConfiguration{
   141  		TypeMeta: metav1.TypeMeta{},
   142  		ObjectMeta: metav1.ObjectMeta{
   143  			Name: certificates.IstioMutatingWebhookName,
   144  		},
   145  		Webhooks: []adminv1.MutatingWebhook{
   146  			{Name: "webhook1"},
   147  			{Name: "webhook2"},
   148  		},
   149  	}
   150  	return kubeClient.AdmissionregistrationV1().MutatingWebhookConfigurations().Create(context.TODO(), &webhook, metav1.CreateOptions{})
   151  }
   152  
   153  func createExpectedValidatingWebhook(kubeClient *fake.Clientset) (*adminv1.ValidatingWebhookConfiguration, error) {
   154  	path := "/validate-clusters-verrazzano-io-v1alpha1-verrazzanoproject"
   155  	service := adminv1.ServiceReference{
   156  		Name:      certificates.VerrazzanoProjectValidatingWebhookName,
   157  		Namespace: certificates.OperatorNamespace,
   158  		Path:      &path,
   159  	}
   160  	webhook := adminv1.ValidatingWebhookConfiguration{
   161  		TypeMeta: metav1.TypeMeta{},
   162  		ObjectMeta: metav1.ObjectMeta{
   163  			Name: certificates.VerrazzanoProjectValidatingWebhookName,
   164  		},
   165  		Webhooks: []adminv1.ValidatingWebhook{
   166  			{
   167  				Name: "verrazzano-clusters-verrazzanoproject-validator.verrazzano.io",
   168  				ClientConfig: adminv1.WebhookClientConfig{
   169  					Service: &service,
   170  				},
   171  			},
   172  		},
   173  	}
   174  	return kubeClient.AdmissionregistrationV1().ValidatingWebhookConfigurations().Create(context.TODO(), &webhook, metav1.CreateOptions{})
   175  }
   176  
   177  func createInvalidExpectedValidatingWebhook(kubeClient *fake.Clientset, whName string) (*adminv1.ValidatingWebhookConfiguration, error) {
   178  	path := "/validate-clusters-verrazzano-io-v1alpha1-verrazzanoproject"
   179  	service := adminv1.ServiceReference{
   180  		Name:      certificates.VerrazzanoProjectValidatingWebhookName,
   181  		Namespace: certificates.OperatorNamespace,
   182  		Path:      &path,
   183  	}
   184  	webhook := adminv1.ValidatingWebhookConfiguration{
   185  		TypeMeta: metav1.TypeMeta{},
   186  		ObjectMeta: metav1.ObjectMeta{
   187  			Name: "InvalidName",
   188  		},
   189  		Webhooks: []adminv1.ValidatingWebhook{
   190  			{
   191  				Name: "verrazzano-clusters-verrazzanoproject-validator.verrazzano.io",
   192  				ClientConfig: adminv1.WebhookClientConfig{
   193  					Service: &service,
   194  				},
   195  			},
   196  		},
   197  	}
   198  	return kubeClient.AdmissionregistrationV1().ValidatingWebhookConfigurations().Create(context.TODO(), &webhook, metav1.CreateOptions{})
   199  }