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 })