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