github.com/nmstate/kubernetes-nmstate@v0.82.0/test/e2e/handler/static_addr_and_route_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 // ipV4AddrAndRoute creates an IP address and routes for the default routing table. 30 func ipV4AddrAndRoute(firstSecondaryNic, ipAddress, destIPAddress, prefixLen, nextHopIPAddress string) nmstate.State { 31 return ipV4AddrAndRouteWithTableID(firstSecondaryNic, ipAddress, destIPAddress, prefixLen, nextHopIPAddress, "") 32 } 33 34 // ipV4AddrAndRouteWithTableID creates an IP address and routes for a given routing table ID. 35 func ipV4AddrAndRouteWithTableID(firstSecondaryNic, ipAddress, destIPAddress, prefixLen, nextHopIPAddress, 36 tableID string) nmstate.State { 37 if tableID == "" { 38 tableID = "254" 39 } 40 return nmstate.NewState(fmt.Sprintf(`interfaces: 41 - name: %s 42 type: ethernet 43 state: up 44 ipv4: 45 address: 46 - ip: %s 47 prefix-length: %s 48 dhcp: false 49 enabled: true 50 routes: 51 config: 52 - destination: %s 53 metric: 150 54 next-hop-address: %s 55 next-hop-interface: %s 56 table-id: %s 57 `, firstSecondaryNic, ipAddress, prefixLen, destIPAddress, nextHopIPAddress, firstSecondaryNic, tableID)) 58 } 59 60 func ipV4AddrAndRouteAbsent(firstSecondaryNic string) nmstate.State { 61 return nmstate.NewState(fmt.Sprintf(`interfaces: 62 - name: %s 63 type: ethernet 64 state: up 65 ipv4: 66 enabled: false 67 routes: 68 config: 69 - next-hop-interface: %s 70 state: absent 71 `, firstSecondaryNic, firstSecondaryNic)) 72 } 73 74 func ipV4AddrAndRouteAndBridgeAbsent(firstSecondaryNic, bridgeName string) nmstate.State { 75 return nmstate.NewState(fmt.Sprintf(`interfaces: 76 - name: %s 77 type: ethernet 78 state: up 79 ipv4: 80 enabled: false 81 - name: %s 82 type: linux-bridge 83 state: absent 84 routes: 85 config: 86 - next-hop-interface: %s 87 state: absent 88 `, firstSecondaryNic, bridgeName, bridgeName)) 89 } 90 91 func ipV6Addr(firstSecondaryNic, ipAddressV6, prefixLenV6 string) nmstate.State { 92 return nmstate.NewState(fmt.Sprintf(`interfaces: 93 - name: %s 94 type: ethernet 95 state: up 96 ipv6: 97 address: 98 - ip: %s 99 prefix-length: %s 100 dhcp: false 101 enabled: true 102 `, firstSecondaryNic, ipAddressV6, prefixLenV6)) 103 } 104 105 func ipV6AddrAbsent(firstSecondaryNic string) nmstate.State { 106 return nmstate.NewState(fmt.Sprintf(`interfaces: 107 - name: %s 108 type: ethernet 109 state: up 110 ipv6: 111 enabled: false 112 `, firstSecondaryNic)) 113 } 114 115 func ipV6AddrAndRoute(firstSecondaryNic, ipAddressV6, destIPAddressV6, prefixLenV6, nextHopIPAddressV6 string) nmstate.State { 116 return nmstate.NewState(fmt.Sprintf(`interfaces: 117 - name: %s 118 type: ethernet 119 state: up 120 ipv6: 121 address: 122 - ip: %s 123 prefix-length: %s 124 dhcp: false 125 enabled: true 126 routes: 127 config: 128 - destination: %s 129 metric: 150 130 next-hop-address: %s 131 next-hop-interface: %s 132 table-id: 254 133 `, firstSecondaryNic, ipAddressV6, prefixLenV6, destIPAddressV6, nextHopIPAddressV6, firstSecondaryNic)) 134 } 135 136 func ipV6AddrAndRouteAbsent(firstSecondaryNic string) nmstate.State { 137 return nmstate.NewState(fmt.Sprintf(`interfaces: 138 - name: %s 139 type: ethernet 140 state: up 141 ipv6: 142 enabled: false 143 routes: 144 config: 145 - next-hop-interface: %s 146 state: absent 147 `, firstSecondaryNic, firstSecondaryNic)) 148 } 149 150 var _ = Describe("Static addresses and routes", func() { 151 Context("when desiredState is configured", func() { 152 var ( 153 node string 154 ipAddress = "192.0.2.251" 155 destIPAddress = "198.51.100.0/24" 156 prefixLen = "24" 157 nextHopIPAddress = "192.0.2.1" 158 ipAddressV6 = "2001:db8::1:1" 159 prefixLenV6 = "64" 160 destIPAddressV6 = "2001:dc8::/64" 161 nextHopIPAddressV6 = "2001:db8::1:2" 162 bridgeName = "brext" 163 ) 164 BeforeEach(func() { 165 node = nodes[0] 166 }) 167 Context("with static V4 address", func() { 168 BeforeEach(func() { 169 170 updateDesiredStateAtNodeAndWait(node, ifaceUpWithStaticIP(firstSecondaryNic, ipAddress, prefixLen)) 171 172 }) 173 AfterEach(func() { 174 updateDesiredStateAndWait(ifaceUpWithStaticIPAbsent(firstSecondaryNic)) 175 ipAddressForNodeInterfaceEventually(node, firstSecondaryNic).Should(BeEmpty()) 176 resetDesiredStateForNodes() 177 }) 178 It("should have the static V4 address", func() { 179 ipAddressForNodeInterfaceEventually(node, firstSecondaryNic).Should(Equal(ipAddress)) 180 }) 181 }) 182 183 Context("with static V4 address and route", func() { 184 BeforeEach(func() { 185 updateDesiredStateAtNodeAndWait( 186 node, 187 ipV4AddrAndRoute(firstSecondaryNic, ipAddress, destIPAddress, prefixLen, nextHopIPAddress), 188 ) 189 }) 190 AfterEach(func() { 191 updateDesiredStateAndWait(ipV4AddrAndRouteAbsent(firstSecondaryNic)) 192 ipAddressForNodeInterfaceEventually(node, firstSecondaryNic).Should(BeEmpty()) 193 routeDestForNodeInterfaceEventually(node, destIPAddress).ShouldNot(Equal(firstSecondaryNic)) 194 resetDesiredStateForNodes() 195 }) 196 It("should have the static V4 address and route at currentState", func() { 197 ipAddressForNodeInterfaceEventually(node, firstSecondaryNic).Should(Equal(ipAddress)) 198 routeNextHopInterface(node, destIPAddress).Should(Equal(firstSecondaryNic)) 199 }) 200 }) 201 202 Context("with bridge taking over the static networking of the slave", func() { 203 BeforeEach(func() { 204 updateDesiredStateAtNodeAndWait( 205 node, 206 ipV4AddrAndRoute(firstSecondaryNic, ipAddress, destIPAddress, prefixLen, nextHopIPAddress), 207 ) 208 ipAddressForNodeInterfaceEventually(node, firstSecondaryNic).Should(Equal(ipAddress)) 209 routeNextHopInterface(node, destIPAddress).Should(Equal(firstSecondaryNic)) 210 // The policy has to be removed since it is not possible to update capture of an existing policy 211 deletePolicy(TestPolicy) 212 213 capture := map[string]string{ 214 "gw": fmt.Sprintf(`routes.running.destination==%q`, destIPAddress), 215 "secondary-iface": `interfaces.name==capture.gw.routes.running.0.next-hop-interface`, 216 "secondary-iface-routes": `routes.running.next-hop-interface==capture.secondary-iface.interfaces.0.name`, 217 "bridge-routes": fmt.Sprintf( 218 `capture.secondary-iface-routes | routes.running.next-hop-interface:="%s"`, bridgeName, 219 ), 220 } 221 updateDesiredStateWithCaptureAtNodeAndWait(node, bridgeOnTheSecondaryInterfaceState(), capture) 222 deletePolicy(TestPolicy) 223 }) 224 AfterEach(func() { 225 updateDesiredStateAndWait(ipV4AddrAndRouteAndBridgeAbsent(firstSecondaryNic, bridgeName)) 226 ipAddressForNodeInterfaceEventually(node, firstSecondaryNic).Should(BeEmpty()) 227 routeDestForNodeInterfaceEventually(node, destIPAddress).ShouldNot(Equal(firstSecondaryNic)) 228 routeDestForNodeInterfaceEventually(node, destIPAddress).ShouldNot(Equal(bridgeName)) 229 resetDesiredStateForNodes() 230 }) 231 It("should have the bridge and the routes created", func() { 232 routeNextHopInterface(node, destIPAddress).Should(Equal(bridgeName)) 233 }) 234 }) 235 236 Context("with static V6 address", func() { 237 BeforeEach(func() { 238 updateDesiredStateAtNodeAndWait(node, ipV6Addr(firstSecondaryNic, ipAddressV6, prefixLenV6)) 239 }) 240 AfterEach(func() { 241 updateDesiredStateAndWait(ipV6AddrAbsent(firstSecondaryNic)) 242 ipV6AddressForNodeInterfaceEventually(node, firstSecondaryNic).Should(BeEmpty()) 243 resetDesiredStateForNodes() 244 }) 245 It("should have the static V6 address", func() { 246 ipV6AddressForNodeInterfaceEventually(node, firstSecondaryNic).Should(Equal(ipAddressV6)) 247 }) 248 }) 249 250 Context("with static V6 address and route", func() { 251 BeforeEach(func() { 252 updateDesiredStateAtNodeAndWait( 253 node, 254 ipV6AddrAndRoute(firstSecondaryNic, ipAddressV6, destIPAddressV6, prefixLenV6, nextHopIPAddressV6), 255 ) 256 }) 257 AfterEach(func() { 258 updateDesiredStateAndWait(ipV6AddrAndRouteAbsent(firstSecondaryNic)) 259 ipV6AddressForNodeInterfaceEventually(node, firstSecondaryNic).Should(BeEmpty()) 260 routeDestForNodeInterfaceEventually(node, destIPAddressV6).ShouldNot(Equal(firstSecondaryNic)) 261 resetDesiredStateForNodes() 262 }) 263 It("should have the static V6 address and route at currentState", func() { 264 ipV6AddressForNodeInterfaceEventually(node, firstSecondaryNic).Should(Equal(ipAddressV6)) 265 routeNextHopInterface(node, destIPAddressV6).Should(Equal(firstSecondaryNic)) 266 }) 267 }) 268 }) 269 })