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