github.com/nmstate/kubernetes-nmstate@v0.82.0/test/e2e/handler/webhook_test.go (about)

     1  /*
     2  Copyright The Kubernetes NMState Authors.
     3  
     4  
     5  Licensed under the Apache License, Version 2.0 (the "License");
     6  you may not use this file except in compliance with the License.
     7  You may obtain a copy of the License at
     8  
     9      http://www.apache.org/licenses/LICENSE-2.0
    10  
    11  Unless required by applicable law or agreed to in writing, software
    12  distributed under the License is distributed on an "AS IS" BASIS,
    13  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  See the License for the specific language governing permissions and
    15  limitations under the License.
    16  */
    17  
    18  package handler
    19  
    20  import (
    21  	"context"
    22  	"strconv"
    23  
    24  	. "github.com/onsi/ginkgo/v2"
    25  	. "github.com/onsi/gomega"
    26  
    27  	"k8s.io/client-go/util/retry"
    28  
    29  	nmstatev1 "github.com/nmstate/kubernetes-nmstate/api/v1"
    30  	nncpwebhook "github.com/nmstate/kubernetes-nmstate/pkg/webhook/nodenetworkconfigurationpolicy"
    31  	"github.com/nmstate/kubernetes-nmstate/test/e2e/policy"
    32  	testenv "github.com/nmstate/kubernetes-nmstate/test/env"
    33  )
    34  
    35  // We just check the labe at CREATE/UPDATE events since mutated data is already
    36  // check at unit test.
    37  var _ = Describe("Mutating Admission Webhook", func() {
    38  	Context("when policy is created", func() {
    39  		BeforeEach(func() {
    40  			// Make sure test policy is not there so
    41  			// we exercise CREATE event
    42  			resetDesiredStateForNodes()
    43  			updateDesiredStateAndWait(linuxBrUp(bridge1))
    44  		})
    45  		AfterEach(func() {
    46  			updateDesiredStateAndWait(linuxBrAbsent(bridge1))
    47  			resetDesiredStateForNodes()
    48  		})
    49  
    50  		It("should have an annotation with mutation timestamp", func() {
    51  			policy := nodeNetworkConfigurationPolicy(TestPolicy)
    52  			Expect(policy.ObjectMeta.Annotations).To(HaveKey(nncpwebhook.TimestampLabelKey))
    53  		})
    54  		Context("and we updated it", func() {
    55  			var (
    56  				oldPolicy nmstatev1.NodeNetworkConfigurationPolicy
    57  			)
    58  			BeforeEach(func() {
    59  				oldPolicy = nodeNetworkConfigurationPolicy(TestPolicy)
    60  				updateDesiredStateAndWait(linuxBrAbsent(bridge1))
    61  			})
    62  			It("should have an annotation with newer mutation timestamp", func() {
    63  				newPolicy := nodeNetworkConfigurationPolicy(TestPolicy)
    64  				Expect(newPolicy.ObjectMeta.Annotations).To(HaveKey(nncpwebhook.TimestampLabelKey))
    65  
    66  				oldAnnotation := oldPolicy.ObjectMeta.Annotations[nncpwebhook.TimestampLabelKey]
    67  				oldConditionsMutation, err := strconv.ParseInt(oldAnnotation, 10, 64)
    68  				Expect(err).ToNot(HaveOccurred())
    69  				newAnnotation := newPolicy.ObjectMeta.Annotations[nncpwebhook.TimestampLabelKey]
    70  				newConditionsMutation, err := strconv.ParseInt(newAnnotation, 10, 64)
    71  				Expect(err).ToNot(HaveOccurred())
    72  
    73  				Expect(newConditionsMutation).To(BeNumerically(">", oldConditionsMutation), "mutation timestamp not updated")
    74  			})
    75  		})
    76  	})
    77  })
    78  
    79  var _ = Describe("Validation Admission Webhook", func() {
    80  	Context("When a policy is created and progressing", func() {
    81  		BeforeEach(func() {
    82  			By("Creating a policy without waiting for it to be available")
    83  			updateDesiredState(linuxBrUp(bridge1))
    84  		})
    85  		AfterEach(func() {
    86  			policy.WaitForAvailablePolicy(TestPolicy)
    87  			updateDesiredStateAndWait(linuxBrAbsent(bridge1))
    88  			resetDesiredStateForNodes()
    89  		})
    90  		It("Should deny updating rolled out policy when it's in progress", func() {
    91  			Byf("Updating the policy %s", TestPolicy)
    92  			err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
    93  				return setDesiredStateWithPolicyAndNodeSelector(TestPolicy, linuxBrUpNoPorts(bridge1), map[string]string{})
    94  			})
    95  			Expect(err).
    96  				To(
    97  					MatchError(
    98  						"admission webhook \"nodenetworkconfigurationpolicies-update-validate.nmstate.io\" denied the request: " +
    99  							"failed to admit NodeNetworkConfigurationPolicy test-policy: message: policy test-policy is still in progress. ",
   100  					),
   101  				)
   102  		})
   103  	})
   104  	Context("When a policy with too long name is created", func() {
   105  		const tooLongName = "this-is-longer-than-sixty-three-characters-hostnames-bar-bar.com"
   106  		It("Should deny creating policy with name longer than 63 characters", func() {
   107  			policy := nmstatev1.NodeNetworkConfigurationPolicy{}
   108  			policy.Name = tooLongName
   109  			err := testenv.Client.Create(context.TODO(), &policy)
   110  			Expect(err).
   111  				To(
   112  					MatchError(
   113  						"admission webhook \"nodenetworkconfigurationpolicies-create-validate.nmstate.io\" denied the request: " +
   114  							"failed to admit NodeNetworkConfigurationPolicy this-is-longer-than-sixty-three-characters-hostnames-bar-bar.com:" +
   115  							" message: invalid policy name: \"this-is-longer-than-sixty-three-characters-hostnames-bar-bar.com\": " +
   116  							"must be no more than 63 characters. ",
   117  					),
   118  				)
   119  		})
   120  	})
   121  	Context("When a policy capture field is updated", func() {
   122  		BeforeEach(func() {
   123  			By("Create a policy without capture field")
   124  			updateDesiredStateAndWait(linuxBrUp(bridge1))
   125  		})
   126  		It("should deny creating the capture field", func() {
   127  			By("Add capture field to the NNCP")
   128  			capture := map[string]string{"default-gw": `routes.running.destination=="0.0.0.0/0"`}
   129  			err := setDesiredStateWithPolicyAndCaptureAndNodeSelector(TestPolicy, linuxBrUpNoPorts(bridge1), capture, map[string]string{})
   130  			Expect(err).
   131  				To(
   132  					MatchError(
   133  						"admission webhook \"nodenetworkconfigurationpolicies-update-validate.nmstate.io\" denied the request: " +
   134  							"failed to admit NodeNetworkConfigurationPolicy test-policy: message: invalid policy operation: " +
   135  							"capture field cannot be modified. ",
   136  					),
   137  				)
   138  		})
   139  		AfterEach(func() {
   140  			updateDesiredStateAndWait(linuxBrAbsent(bridge1))
   141  			resetDesiredStateForNodes()
   142  		})
   143  	})
   144  })