github.com/gophercloud/gophercloud@v1.11.0/internal/acceptance/openstack/networking/v2/extensions/layer3/layer3.go (about) 1 package layer3 2 3 import ( 4 "testing" 5 6 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/addressscopes" 7 8 "github.com/gophercloud/gophercloud" 9 "github.com/gophercloud/gophercloud/internal/acceptance/clients" 10 "github.com/gophercloud/gophercloud/internal/acceptance/tools" 11 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" 12 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/portforwarding" 13 14 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers" 15 "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" 16 th "github.com/gophercloud/gophercloud/testhelper" 17 ) 18 19 // CreateFloatingIP creates a floating IP on a given network and port. An error 20 // will be returned if the creation failed. 21 func CreateFloatingIP(t *testing.T, client *gophercloud.ServiceClient, networkID, portID string) (*floatingips.FloatingIP, error) { 22 t.Logf("Attempting to create floating IP on port: %s", portID) 23 24 fipDescription := "Test floating IP" 25 createOpts := &floatingips.CreateOpts{ 26 Description: fipDescription, 27 FloatingNetworkID: networkID, 28 PortID: portID, 29 } 30 31 floatingIP, err := floatingips.Create(client, createOpts).Extract() 32 if err != nil { 33 return floatingIP, err 34 } 35 36 t.Logf("Created floating IP.") 37 38 th.AssertEquals(t, floatingIP.Description, fipDescription) 39 40 return floatingIP, err 41 } 42 43 // CreateFloatingIPWithFixedIP creates a floating IP on a given network and port with a 44 // defined fixed IP. An error will be returned if the creation failed. 45 func CreateFloatingIPWithFixedIP(t *testing.T, client *gophercloud.ServiceClient, networkID, portID, fixedIP string) (*floatingips.FloatingIP, error) { 46 t.Logf("Attempting to create floating IP on port: %s and address: %s", portID, fixedIP) 47 48 fipDescription := "Test floating IP" 49 createOpts := &floatingips.CreateOpts{ 50 Description: fipDescription, 51 FloatingNetworkID: networkID, 52 PortID: portID, 53 FixedIP: fixedIP, 54 } 55 56 floatingIP, err := floatingips.Create(client, createOpts).Extract() 57 if err != nil { 58 return floatingIP, err 59 } 60 61 t.Logf("Created floating IP.") 62 63 th.AssertEquals(t, floatingIP.Description, fipDescription) 64 th.AssertEquals(t, floatingIP.FixedIP, fixedIP) 65 66 return floatingIP, err 67 } 68 69 // CreatePortForwarding creates a port forwarding for a given floating IP 70 // and port. An error will be returned if the creation failed. 71 func CreatePortForwarding(t *testing.T, client *gophercloud.ServiceClient, fipID string, portID string, portFixedIPs []ports.IP) (*portforwarding.PortForwarding, error) { 72 t.Logf("Attempting to create Port forwarding for floating IP with ID: %s", fipID) 73 74 fixedIP := portFixedIPs[0] 75 internalIP := fixedIP.IPAddress 76 createOpts := &portforwarding.CreateOpts{ 77 Protocol: "tcp", 78 InternalPort: 25, 79 ExternalPort: 2230, 80 InternalIPAddress: internalIP, 81 InternalPortID: portID, 82 } 83 84 pf, err := portforwarding.Create(client, fipID, createOpts).Extract() 85 if err != nil { 86 return pf, err 87 } 88 89 t.Logf("Created Port Forwarding.") 90 91 th.AssertEquals(t, pf.Protocol, "tcp") 92 93 return pf, err 94 } 95 96 // DeletePortForwarding deletes a Port Forwarding with a given ID and a given floating IP ID. 97 // A fatal error is returned if the deletion fails. Works best as a deferred function 98 func DeletePortForwarding(t *testing.T, client *gophercloud.ServiceClient, fipID string, pfID string) { 99 t.Logf("Attempting to delete the port forwarding with ID %s for floating IP with ID %s", pfID, fipID) 100 101 err := portforwarding.Delete(client, fipID, pfID).ExtractErr() 102 if err != nil { 103 t.Fatalf("Failed to delete Port forwarding with ID %s for floating IP with ID %s", pfID, fipID) 104 } 105 t.Logf("Successfully deleted the port forwarding with ID %s for floating IP with ID %s", pfID, fipID) 106 107 } 108 109 // CreateExternalRouter creates a router on the external network. This requires 110 // the OS_EXTGW_ID environment variable to be set. An error is returned if the 111 // creation failed. 112 func CreateExternalRouter(t *testing.T, client *gophercloud.ServiceClient) (*routers.Router, error) { 113 var router *routers.Router 114 choices, err := clients.AcceptanceTestChoicesFromEnv() 115 if err != nil { 116 return router, err 117 } 118 119 routerName := tools.RandomString("TESTACC-", 8) 120 routerDescription := tools.RandomString("TESTACC-DESC-", 8) 121 122 t.Logf("Attempting to create external router: %s", routerName) 123 124 adminStateUp := true 125 gatewayInfo := routers.GatewayInfo{ 126 NetworkID: choices.ExternalNetworkID, 127 } 128 129 createOpts := routers.CreateOpts{ 130 Name: routerName, 131 Description: routerDescription, 132 AdminStateUp: &adminStateUp, 133 GatewayInfo: &gatewayInfo, 134 } 135 136 router, err = routers.Create(client, createOpts).Extract() 137 if err != nil { 138 return router, err 139 } 140 141 if err := WaitForRouterToCreate(client, router.ID); err != nil { 142 return router, err 143 } 144 145 t.Logf("Created router: %s", routerName) 146 147 th.AssertEquals(t, router.Name, routerName) 148 th.AssertEquals(t, router.Description, routerDescription) 149 150 return router, nil 151 } 152 153 // CreateRouter creates a router on a specified Network ID. An error will be 154 // returned if the creation failed. 155 func CreateRouter(t *testing.T, client *gophercloud.ServiceClient, networkID string) (*routers.Router, error) { 156 routerName := tools.RandomString("TESTACC-", 8) 157 routerDescription := tools.RandomString("TESTACC-DESC-", 8) 158 159 t.Logf("Attempting to create router: %s", routerName) 160 161 adminStateUp := true 162 createOpts := routers.CreateOpts{ 163 Name: routerName, 164 Description: routerDescription, 165 AdminStateUp: &adminStateUp, 166 } 167 168 router, err := routers.Create(client, createOpts).Extract() 169 if err != nil { 170 return router, err 171 } 172 173 if err := WaitForRouterToCreate(client, router.ID); err != nil { 174 return router, err 175 } 176 177 t.Logf("Created router: %s", routerName) 178 179 th.AssertEquals(t, router.Name, routerName) 180 th.AssertEquals(t, router.Description, routerDescription) 181 182 return router, nil 183 } 184 185 // CreateRouterInterface will attach a subnet to a router. An error will be 186 // returned if the operation fails. 187 func CreateRouterInterface(t *testing.T, client *gophercloud.ServiceClient, portID, routerID string) (*routers.InterfaceInfo, error) { 188 t.Logf("Attempting to add port %s to router %s", portID, routerID) 189 190 aiOpts := routers.AddInterfaceOpts{ 191 PortID: portID, 192 } 193 194 iface, err := routers.AddInterface(client, routerID, aiOpts).Extract() 195 if err != nil { 196 return iface, err 197 } 198 199 if err := WaitForRouterInterfaceToAttach(client, portID); err != nil { 200 return iface, err 201 } 202 203 t.Logf("Successfully added port %s to router %s", portID, routerID) 204 return iface, nil 205 } 206 207 // CreateRouterInterfaceOnSubnet will attach a subnet to a router. An error will be 208 // returned if the operation fails. 209 func CreateRouterInterfaceOnSubnet(t *testing.T, client *gophercloud.ServiceClient, subnetID, routerID string) (*routers.InterfaceInfo, error) { 210 t.Logf("Attempting to add subnet %s to router %s", subnetID, routerID) 211 212 aiOpts := routers.AddInterfaceOpts{ 213 SubnetID: subnetID, 214 } 215 216 iface, err := routers.AddInterface(client, routerID, aiOpts).Extract() 217 if err != nil { 218 return iface, err 219 } 220 221 if err := WaitForRouterInterfaceToAttach(client, iface.PortID); err != nil { 222 return iface, err 223 } 224 225 t.Logf("Successfully added subnet %s to router %s", subnetID, routerID) 226 return iface, nil 227 } 228 229 // DeleteRouter deletes a router of a specified ID. A fatal error will occur 230 // if the deletion failed. This works best when used as a deferred function. 231 func DeleteRouter(t *testing.T, client *gophercloud.ServiceClient, routerID string) { 232 t.Logf("Attempting to delete router: %s", routerID) 233 234 err := routers.Delete(client, routerID).ExtractErr() 235 if err != nil { 236 t.Fatalf("Error deleting router: %v", err) 237 } 238 239 if err := WaitForRouterToDelete(client, routerID); err != nil { 240 t.Fatalf("Error waiting for router to delete: %v", err) 241 } 242 243 t.Logf("Deleted router: %s", routerID) 244 } 245 246 // DeleteRouterInterface will detach a subnet to a router. A fatal error will 247 // occur if the deletion failed. This works best when used as a deferred 248 // function. 249 func DeleteRouterInterface(t *testing.T, client *gophercloud.ServiceClient, portID, routerID string) { 250 t.Logf("Attempting to detach port %s from router %s", portID, routerID) 251 252 riOpts := routers.RemoveInterfaceOpts{ 253 PortID: portID, 254 } 255 256 _, err := routers.RemoveInterface(client, routerID, riOpts).Extract() 257 if err != nil { 258 t.Fatalf("Failed to detach port %s from router %s", portID, routerID) 259 } 260 261 if err := WaitForRouterInterfaceToDetach(client, portID); err != nil { 262 t.Fatalf("Failed to wait for port %s to detach from router %s", portID, routerID) 263 } 264 265 t.Logf("Successfully detached port %s from router %s", portID, routerID) 266 } 267 268 // DeleteFloatingIP deletes a floatingIP of a specified ID. A fatal error will 269 // occur if the deletion failed. This works best when used as a deferred 270 // function. 271 func DeleteFloatingIP(t *testing.T, client *gophercloud.ServiceClient, floatingIPID string) { 272 t.Logf("Attempting to delete floating IP: %s", floatingIPID) 273 274 err := floatingips.Delete(client, floatingIPID).ExtractErr() 275 if err != nil { 276 t.Fatalf("Failed to delete floating IP: %v", err) 277 } 278 279 t.Logf("Deleted floating IP: %s", floatingIPID) 280 } 281 282 func WaitForRouterToCreate(client *gophercloud.ServiceClient, routerID string) error { 283 return tools.WaitFor(func() (bool, error) { 284 r, err := routers.Get(client, routerID).Extract() 285 if err != nil { 286 return false, err 287 } 288 289 if r.Status == "ACTIVE" { 290 return true, nil 291 } 292 293 return false, nil 294 }) 295 } 296 297 func WaitForRouterToDelete(client *gophercloud.ServiceClient, routerID string) error { 298 return tools.WaitFor(func() (bool, error) { 299 _, err := routers.Get(client, routerID).Extract() 300 if err != nil { 301 if _, ok := err.(gophercloud.ErrDefault404); ok { 302 return true, nil 303 } 304 305 return false, err 306 } 307 308 return false, nil 309 }) 310 } 311 312 func WaitForRouterInterfaceToAttach(client *gophercloud.ServiceClient, routerInterfaceID string) error { 313 return tools.WaitFor(func() (bool, error) { 314 r, err := ports.Get(client, routerInterfaceID).Extract() 315 if err != nil { 316 return false, err 317 } 318 319 if r.Status == "ACTIVE" { 320 return true, nil 321 } 322 323 return false, nil 324 }) 325 } 326 327 func WaitForRouterInterfaceToDetach(client *gophercloud.ServiceClient, routerInterfaceID string) error { 328 return tools.WaitFor(func() (bool, error) { 329 r, err := ports.Get(client, routerInterfaceID).Extract() 330 if err != nil { 331 if _, ok := err.(gophercloud.ErrDefault404); ok { 332 return true, nil 333 } 334 335 if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { 336 if errCode.Actual == 409 { 337 return false, nil 338 } 339 } 340 341 return false, err 342 } 343 344 if r.Status == "ACTIVE" { 345 return true, nil 346 } 347 348 return false, nil 349 }) 350 } 351 352 // CreateAddressScope will create an address-scope. An error will be returned if 353 // the address-scope could not be created. 354 func CreateAddressScope(t *testing.T, client *gophercloud.ServiceClient) (*addressscopes.AddressScope, error) { 355 addressScopeName := tools.RandomString("TESTACC-", 8) 356 createOpts := addressscopes.CreateOpts{ 357 Name: addressScopeName, 358 IPVersion: 4, 359 } 360 361 t.Logf("Attempting to create an address-scope: %s", addressScopeName) 362 363 addressScope, err := addressscopes.Create(client, createOpts).Extract() 364 if err != nil { 365 return nil, err 366 } 367 368 t.Logf("Successfully created the addressscopes.") 369 370 th.AssertEquals(t, addressScope.Name, addressScopeName) 371 th.AssertEquals(t, addressScope.IPVersion, int(gophercloud.IPv4)) 372 373 return addressScope, nil 374 } 375 376 // DeleteAddressScope will delete an address-scope with the specified ID. 377 // A fatal error will occur if the delete was not successful. 378 func DeleteAddressScope(t *testing.T, client *gophercloud.ServiceClient, addressScopeID string) { 379 t.Logf("Attempting to delete the address-scope: %s", addressScopeID) 380 381 err := addressscopes.Delete(client, addressScopeID).ExtractErr() 382 if err != nil { 383 t.Fatalf("Unable to delete address-scope %s: %v", addressScopeID, err) 384 } 385 386 t.Logf("Deleted address-scope: %s", addressScopeID) 387 }