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