github.com/nmstate/kubernetes-nmstate@v0.82.0/test/e2e/handler/default_ovs_bridged_network_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  func ovsBridgeWithTheDefaultInterface(ovsBridgeName, defaultInterfaceMac string) nmstate.State {
    32  	return nmstate.NewState(fmt.Sprintf(`interfaces:
    33  - name: ovs0
    34    type: ovs-interface
    35    state: up
    36    ipv4:
    37      enabled: true
    38      dhcp: true
    39    mac-address: %s
    40  - name: %s
    41    type: ovs-bridge
    42    state: up
    43    bridge:
    44      options:
    45        stp: true
    46      port:
    47      - name: %s
    48      - name: ovs0
    49  `, defaultInterfaceMac, ovsBridgeName, primaryNic))
    50  }
    51  
    52  func ovsBridgeWithTheDefaultInterfaceAbsent(ovsBridgeName, ovsBridgeInternalPortName string) nmstate.State {
    53  	return nmstate.NewState(fmt.Sprintf(`interfaces:
    54  - name: %s
    55    type: ethernet
    56    state: up
    57    ipv4:
    58      enabled: true
    59      dhcp: true
    60  - name: %s
    61    type: ovs-interface
    62    state: absent
    63  - name: %s
    64    type: ovs-bridge
    65    state: absent
    66  `, primaryNic, ovsBridgeInternalPortName, ovsBridgeName))
    67  }
    68  
    69  var _ = Describe("NodeNetworkConfigurationPolicy default ovs-bridged network", func() {
    70  	Context("when there is a default interface with dynamic address", func() {
    71  		const (
    72  			ovsDefaultNetwork     = "ovs-default-network"
    73  			ovsBridgeInternalPort = "ovs0"
    74  		)
    75  		var (
    76  			node     string
    77  			ipv4Addr = ""
    78  			macAddr  = ""
    79  		)
    80  
    81  		BeforeEach(func() {
    82  			node = nodes[0]
    83  
    84  			Byf("Check %s is the default route interface and has dynamic address", primaryNic)
    85  			defaultRouteNextHopInterface(node).Should(Equal(primaryNic))
    86  			Expect(dhcpFlag(node, primaryNic)).Should(BeTrue())
    87  
    88  			By("Fetching node current IP address and MAC")
    89  			Eventually(func() string {
    90  				ipv4Addr = ipv4Address(node, primaryNic)
    91  				return ipv4Addr
    92  			}, 15*time.Second, 1*time.Second).ShouldNot(BeEmpty(), fmt.Sprintf("Interface %s has no ipv4 address", primaryNic))
    93  			macAddr = macAddress(node, primaryNic)
    94  		})
    95  
    96  		Context("and ovs bridge on top of the default interface",
    97  			func() {
    98  				BeforeEach(func() {
    99  					Byf("Creating the %s policy", ovsDefaultNetwork)
   100  					setDesiredStateWithPolicyAndNodeSelectorEventually(
   101  						ovsDefaultNetwork, ovsBridgeWithTheDefaultInterface(bridge1, macAddr),
   102  						map[string]string{"kubernetes.io/hostname": node},
   103  					)
   104  
   105  					By("Waiting until the node becomes ready again")
   106  					waitForNodesReady()
   107  
   108  					By("Waiting for policy to be ready")
   109  					policy.WaitForAvailablePolicy(ovsDefaultNetwork)
   110  				})
   111  
   112  				AfterEach(func() {
   113  					Byf("Removing bridge and configuring %s with dhcp", primaryNic)
   114  					setDesiredStateWithPolicy(ovsDefaultNetwork, ovsBridgeWithTheDefaultInterfaceAbsent(bridge1, ovsBridgeInternalPort))
   115  
   116  					By("Waiting until the node becomes ready again")
   117  					waitForNodesReady()
   118  
   119  					By("Waiting for policy to be ready")
   120  					policy.WaitForAvailablePolicy(ovsDefaultNetwork)
   121  
   122  					Byf("Check %s has the default ip address", primaryNic)
   123  					Eventually(func() string {
   124  						return ipv4Address(node, primaryNic)
   125  					}, 30*time.Second, 1*time.Second).Should(Equal(ipv4Addr), fmt.Sprintf("Interface %s address is not the original one", primaryNic))
   126  
   127  					Byf("Check %s is back as the default route interface", primaryNic)
   128  					defaultRouteNextHopInterface(node).Should(Equal(primaryNic))
   129  
   130  					Byf("Remove the %s policy", ovsDefaultNetwork)
   131  					deletePolicy(ovsDefaultNetwork)
   132  
   133  					By("Reset desired state at all nodes")
   134  					resetDesiredStateForNodes()
   135  				})
   136  
   137  				checkThatOvsBridgeTookOverTheDefaultIP := func(node string, internalPortName string) {
   138  					By("Verifying that ovs-interface obtained node's default IP")
   139  					Eventually(
   140  						func() string {
   141  							return ipv4Address(node, internalPortName)
   142  						},
   143  						15*time.Second,
   144  						1*time.Second,
   145  					).Should(Equal(ipv4Addr), fmt.Sprintf("Interface %s has not taken over the %s address", bridge1, primaryNic))
   146  
   147  					By("Verify that next-hop-interface for default route is ovs0")
   148  					defaultRouteNextHopInterface(node).Should(Equal(ovsBridgeInternalPort))
   149  				}
   150  
   151  				It("should successfully move default IP address to the ovs-interface", func() {
   152  					checkThatOvsBridgeTookOverTheDefaultIP(node, ovsBridgeInternalPort)
   153  				})
   154  
   155  				It("should keep the default IP address after node reboot", func() {
   156  					restartNodeWithoutWaiting(node)
   157  
   158  					By("Wait for policy re-reconciled after node reboot")
   159  					policy.WaitForPolicyTransitionUpdate(ovsDefaultNetwork)
   160  					policy.WaitForAvailablePolicy(ovsDefaultNetwork)
   161  
   162  					Byf("Node %s was rebooted, verifying that bridge took over the default IP", node)
   163  					checkThatOvsBridgeTookOverTheDefaultIP(node, ovsBridgeInternalPort)
   164  				})
   165  			},
   166  		)
   167  
   168  		Context("when desiredState is configured with internal port with wrong IP address", func() {
   169  			const (
   170  				ovsWrongIPPolicy    = "ovs-wrong-ip"
   171  				ovsInternalPortName = "ovs666"
   172  			)
   173  			ovsBridgeWithInternalPortAndWrongIP := func(bridgeName string, internalPortName string, internalPortMac string) nmstate.State {
   174  				return nmstate.NewState(fmt.Sprintf(`interfaces:
   175    - name: %s
   176      type: ovs-interface
   177      state: up
   178      mac-address: %s
   179      ipv4:
   180        enabled: true
   181        dhcp: false
   182        address:
   183          - ip: 1.2.3.4
   184            prefix-length: 24
   185    - name: %s
   186      type: ethernet
   187      state: up
   188      ipv4:
   189        enabled: false
   190    - name: %s
   191      type: ovs-bridge
   192      state: up
   193      bridge:
   194        options:
   195          stp: true
   196        port:
   197          - name: %s
   198          - name: %s`,
   199  					internalPortName, internalPortMac, primaryNic, bridgeName, primaryNic, internalPortName))
   200  			}
   201  
   202  			BeforeEach(func() {
   203  				node = nodes[0]
   204  
   205  				Byf("Check %s is the default route interface and has dynamic address", primaryNic)
   206  				defaultRouteNextHopInterface(node).Should(Equal(primaryNic))
   207  				Expect(dhcpFlag(node, primaryNic)).Should(BeTrue())
   208  
   209  				By("Fetching node current IP address and MAC")
   210  				Eventually(func() string {
   211  					ipv4Addr = ipv4Address(node, primaryNic)
   212  					return ipv4Addr
   213  				}, 15*time.Second, 1*time.Second).ShouldNot(BeEmpty(), fmt.Sprintf("Interface %s has no ipv4 address", primaryNic))
   214  				macAddr = macAddress(node, primaryNic)
   215  			})
   216  
   217  			AfterEach(func() {
   218  				Byf("Remove the %s policy", ovsWrongIPPolicy)
   219  				deletePolicy(ovsWrongIPPolicy)
   220  
   221  				By("Reset desired state at all nodes")
   222  				resetDesiredStateForNodes()
   223  			})
   224  
   225  			It("should fail to configure and rollback", func() {
   226  				Byf("Creating the %s policy", ovsWrongIPPolicy)
   227  				setDesiredStateWithPolicyAndNodeSelectorEventually(
   228  					ovsWrongIPPolicy, ovsBridgeWithInternalPortAndWrongIP(bridge1, ovsInternalPortName, macAddr),
   229  					map[string]string{"kubernetes.io/hostname": node},
   230  				)
   231  				By("Wait for the policy to fail")
   232  				policy.WaitForDegradedPolicy(ovsWrongIPPolicy)
   233  
   234  				Byf("Check %s still has the default ip address", primaryNic)
   235  				Eventually(func() string {
   236  					return ipv4Address(node, primaryNic)
   237  				}, 30*time.Second, 1*time.Second).Should(Equal(ipv4Addr), fmt.Sprintf("Interface %s address is not the original one", primaryNic))
   238  
   239  				Byf("Check %s is still the default route interface", primaryNic)
   240  				defaultRouteNextHopInterface(node).Should(Equal(primaryNic))
   241  			})
   242  		})
   243  	})
   244  })