github.com/nmstate/kubernetes-nmstate@v0.82.0/test/e2e/handler/simple_ovs_bridge_and_bond_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  
    23  	. "github.com/onsi/ginkgo/v2"
    24  	. "github.com/onsi/gomega"
    25  
    26  	nmstate "github.com/nmstate/kubernetes-nmstate/api/shared"
    27  )
    28  
    29  func ovsBrUpLAGEth1AndEth2(bridgeName, bondName, port1Name, port2Name string) nmstate.State {
    30  	return nmstate.NewState(fmt.Sprintf(`interfaces:
    31    - name: %s
    32      type: ovs-bridge
    33      state: up
    34      bridge:
    35        options:
    36          stp: false
    37        port:
    38          - name: %s
    39            link-aggregation:
    40              mode: balance-slb
    41              port:
    42                - name: %s
    43                - name: %s
    44  `, bridgeName, bondName, port1Name, port2Name))
    45  }
    46  
    47  func ovsBrUpLAGEth1Eth2WithInternalPort(bridgeName, internalPortName, internalPortMac, port1Name, port2Name string) nmstate.State {
    48  	return nmstate.NewState(fmt.Sprintf(`interfaces:
    49    - name: %s
    50      type: ovs-interface
    51      state: up
    52      mac-address: %s
    53    - name: %s
    54      type: ovs-bridge
    55      state: up
    56      bridge:
    57        options:
    58          stp: false
    59          mcast-snooping-enable: false
    60          rstp: false
    61        port:
    62        - name: bond0
    63          link-aggregation:
    64            mode: balance-slb
    65            port:
    66            - name: %s
    67            - name: %s
    68        - name: %s
    69  `, internalPortName, internalPortMac, bridgeName, port1Name, port2Name, internalPortName))
    70  }
    71  
    72  func ovsBrUpLinuxBondEth1AndEth2(bridgeName, bondName string) nmstate.State {
    73  	return nmstate.NewState(fmt.Sprintf(`interfaces:
    74    - name: %s
    75      type: bond
    76      state: up
    77      link-aggregation:
    78        mode: balance-rr
    79        options:
    80          miimon: %s
    81        %s:
    82          - %s
    83          - %s
    84    - name: %s
    85      type: ovs-bridge
    86      state: up
    87      bridge:
    88        options:
    89          stp: false
    90        port:
    91          - name: %s
    92  `, bondName, fmt.Sprintf(miimonFormat, 140), portFieldName, firstSecondaryNic, secondSecondaryNic, bridgeName, bondName))
    93  }
    94  
    95  func ovsBrAndBondAbsent(bridgeName, bondName string) nmstate.State {
    96  	return nmstate.NewState(fmt.Sprintf(`interfaces:
    97    - name: %s
    98      type: bond
    99      state: absent
   100    - name: %s
   101      type: ovs-bridge
   102      state: absent
   103  `, bondName, bridgeName))
   104  }
   105  
   106  func ovsBrAndInternalPortAbsent(bridgeName, internalPortName string) nmstate.State {
   107  	return nmstate.NewState(fmt.Sprintf(`interfaces:
   108    - name: %s
   109      type: ovs-interface
   110      state: absent
   111    - name: %s
   112      type: ovs-bridge
   113      state: absent
   114  `, internalPortName, bridgeName))
   115  }
   116  
   117  var _ = Describe("OVS Bridge", func() {
   118  	Context("when desiredState is updated with ovs-bridge with link aggregation port", func() {
   119  		verifyInterfaces := func() {
   120  			for _, node := range nodes {
   121  				interfacesForNode(node).Should(ContainElement(SatisfyAll(
   122  					HaveKeyWithValue("name", bridge1),
   123  					HaveKeyWithValue("type", "ovs-bridge"),
   124  					HaveKeyWithValue("state", "up"),
   125  				)))
   126  			}
   127  		}
   128  
   129  		AfterEach(func() {
   130  			updateDesiredStateAndWait(ovsBrAbsent(bridge1))
   131  			for _, node := range nodes {
   132  				interfacesNameForNodeEventually(node).ShouldNot(ContainElement(bridge1))
   133  			}
   134  			resetDesiredStateForNodes()
   135  		})
   136  		Context("without capture", func() {
   137  			BeforeEach(func() {
   138  				updateDesiredStateAndWait(ovsBrUpLAGEth1AndEth2(bridge1, bond1, firstSecondaryNic, secondSecondaryNic))
   139  			})
   140  
   141  			It("should have the ovs-bridge at currentState", func() {
   142  				By("Verify all required interfaces are present at currentState")
   143  				verifyInterfaces()
   144  			})
   145  		})
   146  		Context("with capture", func() {
   147  			BeforeEach(func() {
   148  				capture := map[string]string{
   149  					"ethernet-ifaces":             `interfaces.type=="ethernet"`,
   150  					"ethernet-not-ignored-ifaces": `capture.ethernet-ifaces | interfaces.state!="ignore"`,
   151  					"secondary-ifaces":            `capture.ethernet-not-ignored-ifaces | interfaces.ipv4.enabled==false`,
   152  				}
   153  				updateDesiredStateWithCaptureAndWait(
   154  					ovsBrUpLAGEth1AndEth2(
   155  						bridge1,
   156  						bond1,
   157  						`"{{ capture.secondary-ifaces.interfaces.0.name }}"`,
   158  						`"{{ capture.secondary-ifaces.interfaces.1.name }}"`,
   159  					),
   160  					capture,
   161  				)
   162  				deletePolicy(TestPolicy)
   163  			})
   164  
   165  			It("should have the ovs-bridge at currentState", func() {
   166  				By("Verify all required interfaces are present at currentState")
   167  				verifyInterfaces()
   168  			})
   169  		})
   170  	})
   171  	Context("when desiredState is updated with ovs-bridge with linux bond as port", func() {
   172  		BeforeEach(func() {
   173  			updateDesiredStateAndWait(ovsBrUpLinuxBondEth1AndEth2(bridge1, bond1))
   174  		})
   175  		AfterEach(func() {
   176  			updateDesiredStateAndWait(ovsBrAndBondAbsent(bridge1, bond1))
   177  			for _, node := range nodes {
   178  				interfacesNameForNodeEventually(node).ShouldNot(ContainElement(bridge1))
   179  				interfacesNameForNodeEventually(node).ShouldNot(ContainElement(bond1))
   180  			}
   181  			resetDesiredStateForNodes()
   182  		})
   183  		It("should have the ovs-bridge and bond at currentState", func() {
   184  			By("Verify all required interfaces are present at currentState")
   185  			for _, node := range nodes {
   186  				interfacesForNode(node).Should(SatisfyAll(
   187  					ContainElement(SatisfyAll(
   188  						HaveKeyWithValue("name", bridge1),
   189  						HaveKeyWithValue("type", "ovs-bridge"),
   190  						HaveKeyWithValue("state", "up"),
   191  					)),
   192  					ContainElement(SatisfyAll(
   193  						HaveKeyWithValue("name", bond1),
   194  						HaveKeyWithValue("type", "bond"),
   195  						HaveKeyWithValue("state", "up"),
   196  					))))
   197  			}
   198  		})
   199  	},
   200  	)
   201  	Context("when desiredState is updated with ovs-bridge with link aggregation port and ovs-interface port", func() {
   202  		const ovsPortName = "ovs1"
   203  		var (
   204  			designatedNode string
   205  			macAddr        = ""
   206  		)
   207  
   208  		verifyInterfaces := func() {
   209  			By("Verify all required interfaces are present at currentState")
   210  			interfacesForNode(designatedNode).Should(SatisfyAll(
   211  				ContainElement(SatisfyAll(
   212  					HaveKeyWithValue("name", bridge1),
   213  					HaveKeyWithValue("type", "ovs-bridge"),
   214  					HaveKeyWithValue("state", "up"),
   215  				)),
   216  				ContainElement(SatisfyAll(
   217  					HaveKeyWithValue("name", ovsPortName),
   218  					HaveKeyWithValue("type", "ovs-interface"),
   219  					HaveKeyWithValue("state", "up"),
   220  				))))
   221  		}
   222  
   223  		BeforeEach(func() {
   224  			designatedNode = nodes[0]
   225  		})
   226  
   227  		AfterEach(func() {
   228  			updateDesiredStateAtNodeAndWait(designatedNode, ovsBrAndInternalPortAbsent(bridge1, ovsPortName))
   229  			for _, node := range nodes {
   230  				interfacesNameForNodeEventually(node).ShouldNot(ContainElement(bridge1))
   231  				interfacesNameForNodeEventually(node).ShouldNot(ContainElement(ovsPortName))
   232  			}
   233  			resetDesiredStateForNodes()
   234  		})
   235  
   236  		Context("without capture", func() {
   237  			BeforeEach(func() {
   238  				By(fmt.Sprintf("Getting mac address of %s on %s", firstSecondaryNic, designatedNode))
   239  				macAddr = macAddress(designatedNode, firstSecondaryNic)
   240  
   241  				By("Creating policy with desiredState")
   242  				updateDesiredStateAtNodeAndWait(
   243  					designatedNode,
   244  					ovsBrUpLAGEth1Eth2WithInternalPort(bridge1, ovsPortName, macAddr, firstSecondaryNic, secondSecondaryNic),
   245  				)
   246  			})
   247  
   248  			It("should have the ovs-bridge and internal port at currentState", func() {
   249  				By("Verify all required interfaces are present at currentState")
   250  				verifyInterfaces()
   251  			})
   252  		})
   253  
   254  		Context("with capture", func() {
   255  			BeforeEach(func() {
   256  				By("Creating policy with desiredState")
   257  				capture := map[string]string{
   258  					"first-secondary-iface":       fmt.Sprintf(`interfaces.name=="%s"`, firstSecondaryNic),
   259  					"ethernet-ifaces":             `interfaces.type=="ethernet"`,
   260  					"ethernet-not-ignored-ifaces": `capture.ethernet-ifaces | interfaces.state!="ignore"`,
   261  					"secondary-ifaces":            `capture.ethernet-not-ignored-ifaces | interfaces.ipv4.enabled==false`,
   262  				}
   263  
   264  				macAddr = `"{{ capture.first-secondary-iface.interfaces.0.mac-address }}"`
   265  				port1 := `"{{ capture.secondary-ifaces.interfaces.0.name }}"`
   266  				port2 := `"{{ capture.secondary-ifaces.interfaces.1.name }}"`
   267  
   268  				updateDesiredStateWithCaptureAtNodeAndWait(
   269  					designatedNode,
   270  					ovsBrUpLAGEth1Eth2WithInternalPort(bridge1, ovsPortName, macAddr, port1, port2),
   271  					capture,
   272  				)
   273  				deletePolicy(TestPolicy)
   274  			})
   275  
   276  			It("should have the ovs-bridge and internal port at currentState", func() {
   277  				By("Verify all required interfaces are present at currentState")
   278  				verifyInterfaces()
   279  			})
   280  		})
   281  	})
   282  })