github.com/nmstate/kubernetes-nmstate@v0.82.0/test/e2e/handler/rollback_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  	"time"
    23  
    24  	. "github.com/onsi/ginkgo/v2"
    25  	. "github.com/onsi/gomega"
    26  
    27  	nmstate "github.com/nmstate/kubernetes-nmstate/api/shared"
    28  	"github.com/nmstate/kubernetes-nmstate/test/e2e/policy"
    29  )
    30  
    31  // We cannot change routes at nmstate if the interface is with dhcp true
    32  // that's why we need to set it static with the same ip it has previously.
    33  func badDefaultGw(address, nic string, routingTable int) nmstate.State {
    34  	return nmstate.NewState(fmt.Sprintf(`interfaces:
    35    - name: %s
    36      type: ethernet
    37      state: up
    38      ipv4:
    39        dhcp: false
    40        enabled: true
    41        address:
    42          - ip: %s
    43            prefix-length: 24
    44  routes:
    45    config:
    46      - destination: 0.0.0.0/0
    47        metric: 150
    48        next-hop-address: 192.0.2.1
    49        next-hop-interface: %s
    50        table-id: %d
    51  `, nic, address, nic, routingTable))
    52  }
    53  
    54  func removeNameServers(nic string) nmstate.State {
    55  	return nmstate.NewState(fmt.Sprintf(`dns-resolver:
    56    config:
    57      search: []
    58      server: []
    59  interfaces:
    60  - name: %s
    61    type: ethernet
    62    state: up
    63    ipv4:
    64      auto-dns: false
    65      dhcp: true
    66      enabled: true
    67    ipv6:
    68      auto-dns: false
    69      dhcp: true
    70      autoconf: true
    71      enabled: true
    72  `, nic))
    73  }
    74  
    75  func setBadNameServers(nic string) nmstate.State {
    76  	return nmstate.NewState(fmt.Sprintf(`dns-resolver:
    77    config:
    78      search: []
    79      server:
    80        - "fe80::deef:1%%%[1]s"
    81        - "fe80::deef:2%%%[1]s"
    82  interfaces:
    83  - name: %[1]s
    84    type: ethernet
    85    state: up
    86    ipv4:
    87      auto-dns: false
    88      dhcp: true
    89      enabled: true
    90    ipv6:
    91      auto-dns: false
    92      dhcp: true
    93      autoconf: true
    94      enabled: true
    95  `, nic))
    96  }
    97  
    98  func discoverNameServers(nic string) nmstate.State {
    99  	return nmstate.NewState(fmt.Sprintf(`
   100  dns-resolver:
   101    config:
   102      search: []
   103      server: []
   104  interfaces:
   105  - name: %s
   106    type: ethernet
   107    state: up
   108    ipv4:
   109      auto-dns: true
   110      dhcp: true
   111      enabled: true
   112    ipv6:
   113      auto-dns: true
   114      dhcp: true
   115      autoconf: true
   116      enabled: true
   117  `, nic))
   118  }
   119  
   120  var _ = Describe("rollback", func() {
   121  	// This spec is done only at first node since policy has to be different
   122  	// per node (ip addresses has to be different at cluster).
   123  	Context("when connectivity to default gw is lost after state configuration", func() {
   124  		BeforeEach(func() {
   125  			By("Configure a invalid default gw")
   126  			var address string
   127  			Eventually(func() string {
   128  				address = ipv4Address(nodes[0], primaryNic)
   129  				return address
   130  			}, ReadTimeout, ReadInterval).ShouldNot(BeEmpty())
   131  			updateDesiredStateAtNode(nodes[0], badDefaultGw(address, primaryNic, 254))
   132  		})
   133  		AfterEach(func() {
   134  			By("Clean up desired state")
   135  			resetDesiredStateForNodes()
   136  		})
   137  		It("should rollback to a good gw configuration", func() {
   138  			By("Should not be available") // Fail fast
   139  			policy.StatusConsistently().ShouldNot(policy.ContainPolicyAvailable())
   140  
   141  			By("Wait for reconcile to fail")
   142  			policy.WaitForDegradedTestPolicy()
   143  			Byf("Check that %s is rolled back", primaryNic)
   144  			Eventually(func() bool {
   145  				return dhcpFlag(nodes[0], primaryNic)
   146  			}, 480*time.Second, ReadInterval).Should(BeTrue(), "DHCP flag hasn't rollback to true")
   147  
   148  			Byf("Check that %s continue with rolled back state", primaryNic)
   149  			Consistently(func() bool {
   150  				return dhcpFlag(nodes[0], primaryNic)
   151  			}, 5*time.Second, 1*time.Second).Should(BeTrue(), "DHCP flag has change to false")
   152  		})
   153  	})
   154  
   155  	Context("when changing the default gw to a routing table different from main", func() {
   156  		secondaryNicCustomAddress := "192.168.100.1"
   157  		BeforeEach(func() {
   158  			By("Configure a invalid default gw")
   159  			applyTime := time.Now()
   160  			updateDesiredStateAtNode(nodes[0], badDefaultGw(secondaryNicCustomAddress, firstSecondaryNic, 200))
   161  			policy.WaitForPolicyTransitionUpdateWithTime(TestPolicy, applyTime)
   162  			policy.WaitForAvailablePolicy(TestPolicy)
   163  		})
   164  		AfterEach(func() {
   165  			By("Clean up desired state")
   166  			resetDesiredStateForNodes()
   167  		})
   168  		It("should not rollback to the previous configuration", func() {
   169  			Eventually(func() string {
   170  				return ipv4Address(nodes[0], firstSecondaryNic)
   171  			}, 3*time.Minute, ReadInterval).Should(Equal(secondaryNicCustomAddress), "IP has not being set")
   172  
   173  			Byf("Check that %s is not rolled back", firstSecondaryNic)
   174  			Consistently(func() string {
   175  				return ipv4Address(nodes[0], firstSecondaryNic)
   176  			}, 20*time.Second, ReadInterval).Should(Equal(secondaryNicCustomAddress), "IP has rolled back to empty")
   177  		})
   178  	})
   179  
   180  	Context("when name servers are lost after state configuration", func() {
   181  		BeforeEach(func() {
   182  			updateDesiredStateAtNode(nodes[0], removeNameServers(primaryNic))
   183  		})
   184  		AfterEach(func() {
   185  			updateDesiredStateAtNode(nodes[0], discoverNameServers(primaryNic))
   186  			By("Clean up desired state")
   187  			resetDesiredStateForNodes()
   188  		})
   189  		It("should rollback to previous name servers", func() {
   190  			By("Should not be available") // Fail fast
   191  			policy.StatusConsistently().ShouldNot(policy.ContainPolicyAvailable())
   192  
   193  			By("Wait for reconcile to fail")
   194  			policy.WaitForDegradedTestPolicy()
   195  			Byf("Check that %s is rolled back", primaryNic)
   196  			Eventually(func() bool {
   197  				return autoDNS(nodes[0], primaryNic)
   198  			}, 480*time.Second, ReadInterval).Should(BeTrue(), "should eventually have auto-dns=true")
   199  
   200  			Byf("Check that %s continue with rolled back state", primaryNic)
   201  			Consistently(func() bool {
   202  				return autoDNS(nodes[0], primaryNic)
   203  			}, 5*time.Second, 1*time.Second).Should(BeTrue(), "should consistently have auto-dns=true")
   204  
   205  		})
   206  	})
   207  
   208  	Context("when name servers are wrong after state configuration", func() {
   209  		BeforeEach(func() {
   210  			updateDesiredStateAtNode(nodes[0], setBadNameServers(primaryNic))
   211  		})
   212  		AfterEach(func() {
   213  			updateDesiredStateAtNode(nodes[0], discoverNameServers(primaryNic))
   214  			By("Clean up desired state")
   215  			resetDesiredStateForNodes()
   216  		})
   217  		It("should rollback to previous name servers", func() {
   218  			By("Should not be available") // Fail fast
   219  			policy.StatusConsistently().ShouldNot(policy.ContainPolicyAvailable())
   220  
   221  			By("Wait for reconcile to fail")
   222  			policy.WaitForDegradedTestPolicy()
   223  			Byf("Check that %s is rolled back", primaryNic)
   224  			Eventually(func() bool {
   225  				return autoDNS(nodes[0], primaryNic)
   226  			}, 480*time.Second, ReadInterval).Should(BeTrue(), "should eventually have auto-dns=true")
   227  
   228  			Byf("Check that %s continue with rolled back state", primaryNic)
   229  			Consistently(func() bool {
   230  				return autoDNS(nodes[0], primaryNic)
   231  			}, 5*time.Second, 1*time.Second).Should(BeTrue(), "should consistently have auto-dns=true")
   232  
   233  		})
   234  	})
   235  })