github.com/nmstate/kubernetes-nmstate@v0.82.0/test/e2e/handler/nnce_conditions_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 "fmt" 22 "sync" 23 "time" 24 25 . "github.com/onsi/ginkgo/v2" 26 . "github.com/onsi/gomega" 27 28 nmstate "github.com/nmstate/kubernetes-nmstate/api/shared" 29 enactmentconditions "github.com/nmstate/kubernetes-nmstate/pkg/enactmentstatus/conditions" 30 policyconditions "github.com/nmstate/kubernetes-nmstate/test/e2e/policy" 31 ) 32 33 func invalidConfig(bridgeName string) nmstate.State { 34 return nmstate.NewState(fmt.Sprintf(`interfaces: 35 - name: %s 36 type: linux-bridge 37 state: invalid_state 38 `, bridgeName)) 39 } 40 41 var _ = Describe("EnactmentCondition", func() { 42 Context("when applying valid config", func() { 43 AfterEach(func() { 44 By("Remove the bridge") 45 updateDesiredStateAndWait(linuxBrAbsent(bridge1)) 46 47 By("Reset desired state at all nodes") 48 resetDesiredStateForNodes() 49 }) 50 It("should go from Progressing to Available", func() { 51 var wg sync.WaitGroup 52 wg.Add(len(nodes)) 53 for i := range nodes { 54 node := nodes[i] 55 go func() { 56 defer wg.Done() 57 defer GinkgoRecover() 58 policyconditions.EnactmentConditionsStatusEventually(node). 59 Should(policyconditions.MatchConditionsFrom(enactmentconditions.SetProgressing), "should reach progressing state at %s", node) 60 policyconditions.EnactmentConditionsStatusEventually(node). 61 Should(policyconditions.MatchConditionsFrom(enactmentconditions.SetSuccess), "should reach available state at %s", node) 62 policyconditions.EnactmentConditionsStatusConsistently(node). 63 Should(policyconditions.MatchConditionsFrom(enactmentconditions.SetSuccess), "should keep available state at %s", node) 64 }() 65 } 66 // Run the policy after we set the nnce conditions assert so we 67 // make sure we catch progressing state. 68 updateDesiredState(linuxBrUp(bridge1)) 69 70 wg.Wait() 71 72 By("Check policy is at available state") 73 policyconditions.WaitForAvailableTestPolicy() 74 }) 75 }) 76 77 Context("when applying invalid configuration", func() { 78 BeforeEach(func() { 79 updateDesiredState(invalidConfig(bridge1)) 80 }) 81 82 AfterEach(func() { 83 By("Remove the bridge") 84 updateDesiredStateAndWait(linuxBrAbsent(bridge1)) 85 By("Reset desired state at all nodes") 86 resetDesiredStateForNodes() 87 }) 88 89 It("should have Failing ConditionType set to true", func() { 90 for _, node := range nodes { 91 Byf("Check %s failing state is reached", node) 92 policyconditions.EnactmentConditionsStatusEventually(node).Should( 93 SatisfyAny( 94 policyconditions.MatchConditionsFrom(enactmentconditions.SetFailedToConfigure), 95 policyconditions.MatchConditionsFrom(enactmentconditions.SetConfigurationAborted), 96 ), "should eventually reach failing or aborted conditions at enactments", 97 ) 98 } 99 By("Check policy is at degraded state") 100 policyconditions.WaitForDegradedTestPolicy() 101 102 By("Check that the enactment stays in failing state") 103 var wg sync.WaitGroup 104 wg.Add(len(nodes)) 105 for i := range nodes { 106 node := nodes[i] 107 go func() { 108 defer wg.Done() 109 defer GinkgoRecover() 110 Byf("Check %s failing state is kept", node) 111 policyconditions.EnactmentConditionsStatusConsistently(node).Should( 112 SatisfyAny( 113 policyconditions.MatchConditionsFrom(enactmentconditions.SetFailedToConfigure), 114 policyconditions.MatchConditionsFrom(enactmentconditions.SetConfigurationAborted), 115 ), "should consistently keep failing or aborted conditions at enactments", 116 ) 117 }() 118 } 119 wg.Wait() 120 }) 121 122 It("should have up to maxUnavailable Failing and the rest Aborted ConditionType set to true", func() { 123 checkEnactmentCounts := func(policy string) { 124 failingConditions := 0 125 abortedConditions := 0 126 for _, node := range nodes { 127 conditionList := policyconditions.EnactmentConditionsStatus(node, TestPolicy) 128 success, _ := policyconditions.MatchConditionsFrom(enactmentconditions.SetFailedToConfigure).Match(conditionList) 129 if success { 130 failingConditions++ 131 } 132 success, _ = policyconditions.MatchConditionsFrom(enactmentconditions.SetConfigurationAborted).Match(conditionList) 133 if success { 134 abortedConditions++ 135 } 136 } 137 Expect(failingConditions).To(BeNumerically("<=", maxUnavailableNodes()), "one node only should have failing enactment") 138 Expect(abortedConditions).To(Equal(len(nodes)-failingConditions), "other nodes should have aborted enactment") 139 } 140 141 By("Wait for enactments to reach failing or aborted state") 142 var wg sync.WaitGroup 143 wg.Add(len(nodes)) 144 for i := range nodes { 145 node := nodes[i] 146 go func() { 147 defer wg.Done() 148 defer GinkgoRecover() 149 Byf("Check %s failing state is kept", node) 150 policyconditions.EnactmentConditionsStatusEventually(node).Should( 151 SatisfyAny( 152 policyconditions.MatchConditionsFrom(enactmentconditions.SetFailedToConfigure), 153 policyconditions.MatchConditionsFrom(enactmentconditions.SetConfigurationAborted), 154 ), "should consistently keep failing or aborted conditions at enactments") 155 }() 156 } 157 wg.Wait() 158 159 By("Check policy is at degraded state") 160 policyconditions.WaitForDegradedTestPolicy() 161 162 By("Check that the enactments stay in failing or aborted state") 163 wg.Add(len(nodes)) 164 for i := range nodes { 165 node := nodes[i] 166 go func() { 167 defer wg.Done() 168 defer GinkgoRecover() 169 Byf("Check %s failing state is kept", node) 170 policyconditions.EnactmentConditionsStatusConsistently(node).Should( 171 SatisfyAny( 172 policyconditions.MatchConditionsFrom(enactmentconditions.SetFailedToConfigure), 173 policyconditions.MatchConditionsFrom(enactmentconditions.SetConfigurationAborted), 174 ), "should consistently keep failing or aborted conditions at enactments") 175 }() 176 } 177 wg.Wait() 178 179 By("Check there is up to maxUnavailable failing enactments and the rest are aborted") 180 checkEnactmentCounts(TestPolicy) 181 }) 182 183 It("should mark policy as Degraded as soon as first enactment fails", func() { 184 failingEnactmentsCount := func(policy string) int { 185 failingConditions := 0 186 for _, node := range nodes { 187 conditionList := policyconditions.EnactmentConditionsStatus(node, TestPolicy) 188 found, _ := policyconditions.MatchConditionsFrom(enactmentconditions.SetFailedToConfigure).Match(conditionList) 189 if found { 190 failingConditions++ 191 } 192 } 193 return failingConditions 194 } 195 196 By("Waiting for first enactment to fail") 197 Eventually(func() int { 198 return failingEnactmentsCount(TestPolicy) 199 }, 180*time.Second, 1*time.Second).Should(BeNumerically(">=", 1)) 200 201 By("Checking the policy is marked as Degraded") 202 Eventually(func() nmstate.ConditionList { 203 return policyconditions.Status(TestPolicy) 204 }, 2*time.Second, 100*time.Millisecond).Should(policyconditions.ContainPolicyDegraded(), "policy should be marked as Degraded") 205 }) 206 }) 207 })