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