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