Gophercloud follows semver and each major release brings a number of changes breaking backward compatibility. This guide details those changes and explains how to migrate from one major version of Gophercloud to another.
The module is now named github.com/gophercloud/gophercloud/v2. Consequently,
you need to update all your imports:
import (
- "github.com/gophercloud/gophercloud"
- "github.com/gophercloud/gophercloud/pagination"
+ "github.com/gophercloud/gophercloud/v2"
+ "github.com/gophercloud/gophercloud/v2/pagination"
)If using gophercloud/utils, you will also need to update those imports:
import (
- "github.com/gophercloud/gophercloud"
- serverutils "github.com/gophercloud/utils/openstack/compute/v2/servers"
+ "github.com/gophercloud/gophercloud/v2"
+ serverutils "github.com/gophercloud/utils/v2/openstack/compute/v2/servers"
)The minimum go version for Gophercloud v2 is now v1.22.
Gophercloud is now context aware, for tracing and cancellation. All function
signatures triggering an HTTP call now take a context.Context as their first
argument.
While you previously called:
myServer, err := servers.Get(client, server.ID)You now need to pass it a context, for example:
ctx := context.TODO()
myServer, err := servers.Get(ctx, client, server.ID)Now that every method accept a context, it is no longer possible to attach a context to the Provider client. Use per-call context instead.
The WaitFor functions now take a context as well, and we've dropped the
timeout argument. This means that the following code:
err = attachments.WaitForStatus(client, attachment.ID, "attached", 60)Must be changed to use a context with timeout. For example:
ctx, cancel := context.WithTimeout(context.TODO(), 60*time.Second)
defer cancel()
err = attachments.WaitForStatus(ctx, client, attachment.ID, "attached")The error types for specific response codes (ErrDefault400, ErrDefault401, etc.) have been removed.
All unexpected response codes will now return ErrUnexpectedResponseCode instead.
For quickly checking whether a request resulted in a specific response code, use the new ResponseCodeIs function:
server, err := servers.Get(ctx, client, serverID).Extract()
// before
if _, ok := err.(gophercloud.ErrDefault404); ok {
handleServerNotFound()
}
// after
if gophercloud.ResponseCodeIs(err, http.StatusNotFound) {
handleServerNotFound()
}Furthermore, the error messages returned by ErrUnexpectedResponseCode now include less newlines than before. If you match on error messages using regexes, please double-check your regexes.
If using the utils library, note that the IDFromName functions return
ErrResourceNotFound rather than ErrUnexpectedResponseCode. In that
scenario, type assertions for a "not found" error are still necessary:
func IsNotFound(err error) bool {
if _, ok := err.(gophercloud.ErrResourceNotFound); ok { // <-- this
return true
}
return gophercloud.ResponseCodeIs(err, http.StatusNotFound)
}A number of services previously supported API extensions but have long since switched to using microversions to allow API changes. This is now reflected in Gophercloud v2 and the contents of the follow modules have been largely migrated:
openstack/blockstorage/extensionsopenstack/compute/v2/extensionsopenstack/identity/v2/extensionsopenstack/identity/v3/extensions
The replacement for these depends on the type of the former extension. For extensions that added wholly new APIs, these APIs have been moved into the main module for the corresponding service. These are:
-
openstack/blockstorage/extensions/availabilityzonesMoved to
openstack/blockstorage/v2/availabilityzonesandopenstack/blockstorage/v3/availabilityzones. -
openstack/blockstorage/extensions/backupsMoved to
openstack/blockstorage/v2/backupsandopenstack/blockstorage/v3/backups. -
openstack/blockstorage/extensions/limitsMoved to
openstack/blockstorage/v2/limitsandopenstack/blockstorage/v3/limits. -
openstack/blockstorage/extensions/quotasetsMoved to
openstack/blockstorage/v2/quotasetsandopenstack/blockstorage/v3/quotasets. -
openstack/blockstorage/extensions/schedulerstatsMoved to
openstack/blockstorage/v2/schedulerstatsandopenstack/blockstorage/v3/schedulerstats. -
openstack/blockstorage/extensions/servicesMoved to
openstack/blockstorage/v2/servicesandopenstack/blockstorage/v3/services. -
openstack/blockstorage/extensions/volumetransfersMoved to
openstack/blockstorage/v2/transfersandopenstack/blockstorage/v3/transfers. -
openstack/compute/v2/extensions/aggregatesMoved to
openstack/compute/v2/aggregates. -
openstack/compute/v2/extensions/attachinterfacesMoved to
openstack/compute/v2/attachinterfaces. -
openstack/compute/v2/extensions/diagnosticsMoved to
openstack/compute/v2/diagnostics. -
openstack/compute/v2/extensions/hypervisorsMoved to
openstack/compute/v2/hypervisors. -
openstack/compute/v2/extensions/instanceactionsMoved to
openstack/compute/v2/instanceactions. -
openstack/compute/v2/extensions/keypairsMoved to
openstack/compute/v2/keypairs. -
openstack/compute/v2/extensions/limitsMoved to
openstack/compute/v2/limits. -
openstack/compute/v2/extensions/quotasetsMoved to
openstack/compute/v2/quotasets. -
openstack/compute/v2/extensions/remoteconsolesMoved to
openstack/compute/v2/remoteconsoles. -
openstack/compute/v2/extensions/secgroupsMoved to
openstack/compute/v2/secgroups. -
openstack/compute/v2/extensions/servergroupsMoved to
openstack/compute/v2/servergroups. -
openstack/compute/v2/extensions/servicesMoved to
openstack/compute/v2/services. -
openstack/compute/v2/extensions/tagsMoved to
openstack/compute/v2/tags. -
openstack/compute/v2/extensions/usageMoved to
openstack/compute/v2/usage. -
openstack/compute/v2/extensions/volumeattachMoved to
openstack/compute/v2/volumeattach. -
openstack/identity/v2/extensions/admin/rolesMoved to
openstack/identity/v2/roles. -
openstack/identity/v3/extensions/ec2credentialsMoved to
openstack/identity/v3/ec2credentials. -
openstack/identity/v3/extensions/ec2tokensMoved to
openstack/identity/v3/ec2tokens. -
openstack/identity/v3/extensions/federationMoved to
openstack/identity/v3/federation -
openstack/identity/v3/extensions/oauth1.Moved to
openstack/identity/v3/oauth1 -
openstack/identity/v3/extensions/projectendpointsMoved to
openstack/identity/v3/projectendpoints.
For extensions that modified existing APIs, these modifications have been folded into the modified APIs. These are:
-
openstack/blockstorage/extensions/schedulerhintsSchedulerHintshas been renamed toSchedulerHintOptsand moved toopenstack/blockstorage/v2/volumesandopenstack/blockstorage/v3/volumes. This is now a required argument ofvolumes.Createfor both modules. -
openstack/blockstorage/extensions/volumeactionsAll functions and supporting structs and interfaces have been moved to
openstack/blockstorage/v2/volumesandopenstack/blockstorage/v3/volumes. -
openstack/blockstorage/extensions/volumehostThe
VolumeHostExtstruct has been removed and aHostfield added to theVolumestruct inopenstack/blockstorage/v2/volumesandopenstack/blockstorage/v3/volumes. -
openstack/blockstorage/extensions/volumetenantsThe
VolumeTenantExtstruct has been removed and aTenantIDfield added to theVolumestruct inopenstack/blockstorage/v2/volumesandopenstack/blockstorage/v3/volumes. -
openstack/compute/v2/extensions/bootfromvolumeThe
CreateOptsExtstruct has been removed and aBlockDevicefield added to theCreateOptsstruct inopenstack/compute/v2/servers. -
openstack/compute/v2/extensions/diskconfigThe
CreateOptsExtstruct has been removed and aDiskConfigfield added to theCreateOptsstruct inopenstack/compute/v2/servers. -
openstack/compute/v2/extensions/evacuateAll functions and supporting structs and interfaces have been moved to
openstack/compute/v2/servers. -
openstack/compute/v2/extensions/extendedserverattributesThe
ServerAttributesExtstruct has been removed and all fields added to theServerstruct inopenstack/compute/v2/servers. -
openstack/compute/v2/extensions/extendedstatusThe
ServerExtendedStatusExtstruct has been removed and all fields added to theServerstruct inopenstack/compute/v2/servers. -
openstack/compute/v2/extensions/injectnetworkinfoAll functions and supporting structs and interfaces have been moved to
openstack/compute/v2/servers. -
openstack/compute/v2/extensions/lockunlockAll functions and supporting structs and interfaces have been moved to
openstack/compute/v2/servers. -
openstack/compute/v2/extensions/migrateAll functions and supporting structs and interfaces have been moved to
openstack/compute/v2/servers. -
openstack/compute/v2/extensions/pauseunpauseAll functions and supporting structs and interfaces have been moved to
openstack/compute/v2/servers. -
openstack/compute/v2/extensions/rescueunrescueAll functions and supporting structs and interfaces have been moved to
openstack/compute/v2/servers. -
openstack/compute/v2/extensions/resetnetworkAll functions and supporting structs and interfaces have been moved to
openstack/compute/v2/servers. -
openstack/compute/v2/extensions/resetstateAll functions and supporting structs and interfaces have been moved to
openstack/compute/v2/servers. -
openstack/compute/v2/extensions/schedulerhintsSchedulerHintshas been moved toopenstack/compute/v2/serversand renamed toSchedulerHintOpts. This is now a required argument ofservers.Create. -
openstack/compute/v2/extensions/serverusageThe
serverusagestruct has been removed and all fields added to theServerstruct inopenstack/compute/v2/servers. -
openstack/compute/v2/extensions/shelveunshelveAll functions and supporting structs and interfaces have been moved to
openstack/compute/v2/servers. -
openstack/compute/v2/extensions/startstopAll functions and supporting structs and interfaces have been moved to
openstack/compute/v2/servers. -
openstack/compute/v2/extensions/suspendresumeAll functions and supporting structs and interfaces have been moved to
openstack/compute/v2/servers.
For extensions that added new APIs and modified existing APIs, the new APIs are moved into the main module of the corresponding service while the modifications are folded into the modified APIs. These are:
-
openstack/compute/v2/extensions/availabilityzonesThe
ServerAvailabilityZoneExtstruct has been removed and aAvailabilityZonefield added to theServerstruct inopenstack/compute/v2/servers. Everything else is moved moved toopenstack/compute/v2/availabilityzones. -
openstack/identity/v3/extensions/trustsThe
AuthOptsExtstruct has been removed and aTrustIDfield added to theScopestruct inopenstack/identity/v3/tokens. Everything else is moved moved toopenstack/identity/v3/trusts.
Finally, for extensions that are deprecated and have been removed in a microversion, the APIs were removed entirely. These are:
-
openstack/compute/v2/extensions/defsecrulesThis was a proxy for the Networking service, Neutron. Use
openstack/networking/v2/extensions/security/groupsinstead. -
openstack/compute/v2/extensions/floatingipsThis was a proxy for the Networking service, Neutron. Use
openstack/networking/v2/extensions/layer3/floatingipsinstead. -
openstack/compute/v2/extensions/imagesThis was a proxy for the Image service, Glance. Use
openstack/image/v2/imagesinstead. -
openstack/compute/v2/extensions/networksThis was a proxy for the Networking service, Neutron. Use
openstack/networking/v2/networksinstead. -
openstack/compute/v2/extensions/tenantnetworksThis was a proxy for the Networking service, Neutron. Use
openstack/networking/v2/networksinstead.
loadbalancer/v2/pools/CreateOpts.Members is now a slice of CreateMemberOpts
rather than a slice of BatchUpdateMemberOpts.
blockstorage/v3/volumes/CreateOpts.Multiattach is removed. Use a volume type
with multiattach capability instead.
The following structs are no longer comparable due to the addition of a non-comparable field:
compute/v2/flavors/Flavorloadbalancer/v2/l7policies/CreateRuleOptsloadbalancer/v2/l7policies/UpdateOptsloadbalancer/v2/l7policies/UpdateRuleOptsloadbalancer/v2/listeners/ListOptsloadbalancer/v2/monitors/ListOptsloadbalancer/v2/monitors/CreateOptsloadbalancer/v2/monitors/UpdateOptsloadbalancer/v2/pools/ListOpts
This means that you were previously able to use == to compare these objects,
this is no longer the case with Gophercloud v2.
The imageservice service is renamed to simply image to conform with the other services.
If you previously imported from
github.com/gophercloud/gophercloud/v2/openstack/imageservice/, you now need
to import from github.com/gophercloud/gophercloud/v2/openstack/image/.
Additionally, NewImageServiceV2() is renamed NewImageV2().
The Baremetal inventory types moved from
baremetalintrospection/v1/introspection to baremetal/inventory. This
includes BootInfoType, CPUType, LLDPTLVType, InterfaceType,
InventoryType, MemoryType, RootDiskType, SystemFirmwareType,
SystemVendorType, ExtraHardwareDataType, ExtraHardwareData,
ExtraHardwareDataSection, NUMATopology, NUMACPU, NUMANIC, and
NUMARAM.
Additionally, a few of these types were renamed in the process:
ExtraHardwareDataTypebecameExtraDataTypeExtraHardwareDatabecameExtraDataItemExtraHardwareDataSectionbecameExtraHardwareDataSection
Gophercloud now escapes container and object names in all objects and
containers functions. If you were previously escaping names (with, for
example, url.PathEscape or url.QueryEscape), then you should REMOVE that
and pass the intended names to Gophercloud directly.
The objectstorage/v1/containers.ListOpts#Full and
objectstorage/v1/objects.ListOpts#Full properties are removed from the
Gophercloud API. Plaintext listing is unfixably wrong and won't handle special
characters reliably (i.e. \n). Object listing and container listing now
always behave like “Full” did.
Empty container names, container names containing a slash (/), and empty
object names are now rejected in Gophercloud before any call to Swift.
The ErrInvalidContainerName error has been moved from
objectstorage/v1/containers to objectstorage/v1. In addition, two new name
validation errors have been added: objectstorage.v1.ErrEmptyContainerName and
objectstorage.v1.ErrEmptyObjectName.
The objectstorage/v1/objects.Copy#Destination field must be in the form
/container/object. The function will reject a destination path if it doesn't
start with a slash (/).
Support for services that are no longer supported upstream has been removed. Users that still rely on theses old services should continue using Gophercloud v1.
- Cinder (Blockstorage) v1 (
openstack/blockstorage/v1) - Neutron (Networking) LBaaS and LBaaS v2 extensions
(
openstack/networking/v2/extensions/lbaas,openstack/networking/v2/extensions/lbaas_v2) - Neutron (Networking) FWaaS extension
(
openstack/networking/v2/extensions/fwaas) - Poppy (CDNaaS) service (
openstack/cdn) - Senlin (Clustering) service (
openstack/clustering)
After running the script, your code may not compile. The idea is that at this point, you're only left with a few changes that can't reasonably be automated.
- Add
/v2to all Gophercloud imports, except to the packages that have been removed without replacement - Adjust the import path of moved packages
- Adjust the package identifier in the code where possible
- Add
context.TODO()where required
- it doesn't fix the use of removed extensions. For example, if you used
openstack/blockstorage/extensions/availabilityzones, you will have to manually put that back into e.g.servers.CreateOpts - it will just put
context.TODO()where a context is required to satisfy the function signature. It's up to you to actually replace that with a variable and provide proper cancellation - it will add
context.TODO()toblockstorage/v1calls, even though that package only exists in Gophercloud v1
# Adjust the blockstorage version appropriately
blockstorageversion=v3
openstack='github.com/gophercloud/gophercloud/openstack'
openstack_utils='github.com/gophercloud/utils/openstack'
find . -type f -name '*.go' -not -path "*/vendor/*" -exec sed -i '
/^import ($/,/^)$/ {
# 1: These packages have been removed and their functionality moved into the main module for the corresponding service.
/\(\/openstack\/blockstorage\/v1\|\/openstack\/networking\/v2\/extensions\/lbaas\|\/openstack\/networking\/v2\/extensions\/lbaas_v2\|\/openstack\/networking\/v2\/extensions\/fwaas\|\/openstack\/cdn\|\/openstack\/clustering\)/! {
/\/openstack\/blockstorage\/extensions\/volumehost/d
/\/openstack\/blockstorage\/extensions\/volumetenants/d
/\/openstack\/compute\/v2\/extensions\/bootfromvolume/d
/\/openstack\/compute\/v2\/extensions\/diskconfig/d
/\/openstack\/compute\/v2\/extensions\/extendedserverattributes/d
/\/openstack\/compute\/v2\/extensions\/extendedstatus/d
/\/openstack\/compute\/v2\/extensions\/schedulerhints/d
/\/openstack\/compute\/v2\/extensions\/serverusage/d
/\/openstack\/compute\/v2\/extensions\/availabilityzones/d
/\/openstack\/identity\/v3\/extensions\/trusts/d
}
'"
# 2: Functions and supporting structs and interfaces of these packages have been moved to an existing package
s|${openstack}/blockstorage/extensions/schedulerhints|${openstack}/blockstorage/${blockstorageversion}/volumes|g
s|${openstack}/blockstorage/extensions/volumeactions|${openstack}/blockstorage/${blockstorageversion}/volumes|g
s|${openstack}/compute/v2/extensions/evacuate|${openstack}/compute/v2/servers|g
s|${openstack}/compute/v2/extensions/injectnetworkinfo|${openstack}/compute/v2/servers|g
s|${openstack}/compute/v2/extensions/lockunlock|${openstack}/compute/v2/servers|g
s|${openstack}/compute/v2/extensions/migrate|${openstack}/compute/v2/servers|g
s|${openstack}/compute/v2/extensions/pauseunpause|${openstack}/compute/v2/servers|g
s|${openstack}/compute/v2/extensions/rescueunrescue|${openstack}/compute/v2/servers|g
s|${openstack}/compute/v2/extensions/resetnetwork|${openstack}/compute/v2/servers|g
s|${openstack}/compute/v2/extensions/resetstate|${openstack}/compute/v2/servers|g
s|${openstack}/compute/v2/extensions/shelveunshelve|${openstack}/compute/v2/servers|g
s|${openstack}/compute/v2/extensions/startstop|${openstack}/compute/v2/servers|g
s|${openstack}/compute/v2/extensions/suspendresume|${openstack}/compute/v2/servers|g
# 3: These packages have been renamed
s|${openstack}/imageservice|${openstack}/image|g
s|${openstack_utils}/imageservice|${openstack_utils}/image|g
s|${openstack}/blockstorage/extensions/availabilityzones|${openstack}/blockstorage/${blockstorageversion}/availabilityzones|g
s|${openstack}/blockstorage/extensions/backups|${openstack}/blockstorage/${blockstorageversion}/backups|g
s|${openstack}/blockstorage/extensions/limits|${openstack}/blockstorage/${blockstorageversion}/limits|g
s|${openstack}/blockstorage/extensions/quotasets|${openstack}/blockstorage/${blockstorageversion}/quotasets|g
s|${openstack}/blockstorage/extensions/schedulerstats|${openstack}/blockstorage/${blockstorageversion}/schedulerstats|g
s|${openstack}/blockstorage/extensions/services|${openstack}/blockstorage/${blockstorageversion}/services|g
s|${openstack}/blockstorage/extensions/volumetransfers|${openstack}/blockstorage/${blockstorageversion}/transfers|g
s|${openstack}/compute/v2/extensions/aggregates|${openstack}/compute/v2/aggregates|g
s|${openstack}/compute/v2/extensions/attachinterfaces|${openstack}/compute/v2/attachinterfaces|g
s|${openstack}/compute/v2/extensions/diagnostics|${openstack}/compute/v2/diagnostics|g
s|${openstack}/compute/v2/extensions/hypervisors|${openstack}/compute/v2/hypervisors|g
s|${openstack}/compute/v2/extensions/instanceactions|${openstack}/compute/v2/instanceactions|g
s|${openstack}/compute/v2/extensions/keypairs|${openstack}/compute/v2/keypairs|g
s|${openstack}/compute/v2/extensions/limits|${openstack}/compute/v2/limits|g
s|${openstack}/compute/v2/extensions/quotasets|${openstack}/compute/v2/quotasets|g
s|${openstack}/compute/v2/extensions/remoteconsoles|${openstack}/compute/v2/remoteconsoles|g
s|${openstack}/compute/v2/extensions/secgroups|${openstack}/compute/v2/secgroups|g
s|${openstack}/compute/v2/extensions/servergroups|${openstack}/compute/v2/servergroups|g
s|${openstack}/compute/v2/extensions/services|${openstack}/compute/v2/services|g
s|${openstack}/compute/v2/extensions/tags|${openstack}/compute/v2/tags|g
s|${openstack}/compute/v2/extensions/usage|${openstack}/compute/v2/usage|g
s|${openstack}/compute/v2/extensions/volumeattach|${openstack}/compute/v2/volumeattach|g
s|${openstack}/identity/v2/extensions/admin/roles|${openstack}/identity/v2/roles|g
s|${openstack}/identity/v3/extensions/ec2credentials|${openstack}/identity/v3/ec2credentials|g
s|${openstack}/identity/v3/extensions/ec2tokens|${openstack}/identity/v3/ec2tokens|g
s|${openstack}/identity/v3/extensions/federation|${openstack}/identity/v3/federation|g
s|${openstack}/identity/v3/extensions/oauth1|${openstack}/identity/v3/oauth1|g
s|${openstack}/identity/v3/extensions/projectendpoints|${openstack}/identity/v3/projectendpoints|g
# 4: These removed packages existed as proxies of others
s|${openstack}/compute/v2/extensions/defsecrules|${openstack}/networking/v2/extensions/security/groups|g
s|${openstack}/compute/v2/extensions/floatingips|${openstack}/networking/v2/extensions/layer3/floatingips|g
s|${openstack}/compute/v2/extensions/images|${openstack}/image/v2/images|g
s|${openstack}/compute/v2/extensions/networks|${openstack}/networking/v2/networks|g
s|${openstack}/compute/v2/extensions/tenantnetworks|${openstack}/networking/v2/networks|g
"'
# 5: Update to v2, except for packages that were removed without replacement
s|github.com/gophercloud/utils|github.com/gophercloud/utils/v2|g
/\(\/openstack\/blockstorage\/v1\|\/openstack\/networking\/v2\/extensions\/lbaas\|\/openstack\/networking\/v2\/extensions\/lbaas_v2\|\/openstack\/networking\/v2\/extensions\/fwaas\|\/openstack\/cdn\|\/openstack\/clustering\)/! s|github.com/gophercloud/gophercloud|github.com/gophercloud/gophercloud/v2|g
}
/^)$/,$ {
# 6: Rename identifiers of items of step 2 above
s#\(schedulerhints\|volumeactions\)\.\([A-Z][A-Z_a-z_0-9]*\)#volumes.\2#g
s#\(evacuate\|injectnetworkinfo\|lockunlock\|migrate\|pauseunpause\|rescueunrescue\|resetnetwork\|resetstate\|shelveunshelve\|startstop\|suspendresume\)\.\([A-Z][A-Z_a-z_0-9]*\)#servers.\2#g
# 7: Add context.TODO()
s#\(accept\.Create\|accept\.Get\|accounts\.Get\|accounts\.Update\|acls\.DeleteContainerACL\|acls\.DeleteSecretACL\|acls\.GetContainerACL\|acls\.GetSecretACL\|acls\.SetContainerACL\|acls\.SetSecretACL\|acls\.UpdateContainerACL\|acls\.UpdateSecretACL\|addressscopes\.Create\|addressscopes\.Delete\|addressscopes\.Get\|addressscopes\.Update\|agents\.Delete\|agents\.Get\|agents\.ListDHCPNetworks\|agents\.ListL3Routers\|agents\.RemoveBGPSpeaker\|agents\.RemoveDHCPNetwork\|agents\.RemoveL3Router\|agents\.ScheduleBGPSpeaker\|agents\.ScheduleDHCPNetwork\|agents\.ScheduleL3Router\|agents\.Update\|aggregates\.AddHost\|aggregates\.Create\|aggregates\.Delete\|aggregates\.Get\|aggregates\.RemoveHost\|aggregates\.SetMetadata\|aggregates\.Update\|allocations\.Create\|allocations\.Delete\|allocations\.Get\|amphorae\.Failover\|amphorae\.Get\|apiversions\.Get\|apiversions\.List\|applicationcredentials\.Create\|applicationcredentials\.Delete\|applicationcredentials\.DeleteAccessRule\|applicationcredentials\.Get\|applicationcredentials\.GetAccessRule\|attachinterfaces\.Create\|attachinterfaces\.Delete\|attachinterfaces\.Get\|attachments\.Complete\|attachments\.Create\|attachments\.Delete\|attachments\.Get\|attachments\.Update\|attachments\.WaitForStatus\|backups\.Create\|backups\.Delete\|backups\.Export\|backups\.ForceDelete\|backups\.Get\|backups\.Import\|backups\.ResetStatus\|backups\.RestoreFromBackup\|backups\.Update\|bgpvpns\.Create\|bgpvpns\.CreateNetworkAssociation\|bgpvpns\.CreatePortAssociation\|bgpvpns\.CreateRouterAssociation\|bgpvpns\.Delete\|bgpvpns\.DeleteNetworkAssociation\|bgpvpns\.DeletePortAssociation\|bgpvpns\.DeleteRouterAssociation\|bgpvpns\.Get\|bgpvpns\.GetNetworkAssociation\|bgpvpns\.GetPortAssociation\|bgpvpns\.GetRouterAssociation\|bgpvpns\.Update\|bgpvpns\.UpdatePortAssociation\|bgpvpns\.UpdateRouterAssociation\|buildinfo\.Get\|capsules\.Create\|capsules\.Delete\|capsules\.Get\|certificates\.Create\|certificates\.Get\|certificates\.Update\|claims\.Create\|claims\.Delete\|claims\.Get\|claims\.Update\|clusters\.Create\|clusters\.Delete\|clusters\.Get\|clusters\.Resize\|clusters\.Update\|clusters\.Upgrade\|clustertemplates\.Create\|clustertemplates\.Delete\|clustertemplates\.Get\|clustertemplates\.Update\|conductors\.Get\|config\.NewProviderClient\|configurations\.Create\|configurations\.Delete\|configurations\.Get\|configurations\.GetDatastoreParam\|configurations\.GetGlobalParam\|configurations\.Replace\|configurations\.Update\|containers\.BulkDelete\|containers\.Create\|containers\.CreateConsumer\|containers\.CreateSecretRef\|containers\.Delete\|containers\.DeleteConsumer\|containers\.DeleteSecretRef\|containers\.Get\|containers\.Update\|credentials\.Create\|credentials\.Delete\|credentials\.Get\|credentials\.Update\|crontriggers\.Create\|crontriggers\.Delete\|crontriggers\.Get\|databases\.Create\|databases\.Delete\|datastores\.Get\|datastores\.GetVersion\|diagnostics\.Get\|domains\.Create\|domains\.Delete\|domains\.Get\|domains\.Update\|drivers\.GetDriverDetails\|drivers\.GetDriverDiskProperties\|drivers\.GetDriverProperties\|ec2credentials\.Create\|ec2credentials\.Delete\|ec2credentials\.Get\|ec2tokens\.Create\|ec2tokens\.ValidateS3Token\|endpointgroups\.Create\|endpointgroups\.Delete\|endpointgroups\.Get\|endpointgroups\.Update\|endpoints\.Create\|endpoints\.Delete\|endpoints\.Update\|executions\.Create\|executions\.Delete\|executions\.Get\|extensions\.Get\|extraroutes\.Add\|extraroutes\.Remove\|federation\.CreateMapping\|federation\.DeleteMapping\|federation\.GetMapping\|federation\.UpdateMapping\|flavorprofiles\.Create\|flavorprofiles\.Delete\|flavorprofiles\.Get\|flavorprofiles\.Update\|flavors\.AddAccess\|flavors\.Create\|flavors\.CreateExtraSpecs\|flavors\.Delete\|flavors\.DeleteExtraSpec\|flavors\.Get\|flavors\.GetExtraSpec\|flavors\.ListExtraSpecs\|flavors\.RemoveAccess\|flavors\.Update\|flavors\.UpdateExtraSpec\|floatingips\.Create\|floatingips\.Delete\|floatingips\.Get\|floatingips\.Update\|gophercloud\.WaitFor\|groups\.Create\|groups\.Delete\|groups\.Get\|groups\.RemoveEgressPolicy\|groups\.RemoveIngressPolicy\|groups\.Update\|hypervisors\.Get\|hypervisors\.GetStatistics\|hypervisors\.GetUptime\|ikepolicies\.Create\|ikepolicies\.Delete\|ikepolicies\.Get\|ikepolicies\.Update\|imagedata\.Download\|imagedata\.Stage\|imagedata\.Upload\|imageimport\.Create\|imageimport\.Get\|images\.Create\|images\.Delete\|images\.Get\|images\.Update\|instanceactions\.Get\|instances\.AttachConfigurationGroup\|instances\.Create\|instances\.Delete\|instances\.DetachConfigurationGroup\|instances\.EnableRootUser\|instances\.Get\|instances\.IsRootEnabled\|instances\.Resize\|instances\.ResizeVolume\|instances\.Restart\|introspection\.AbortIntrospection\|introspection\.GetIntrospectionData\|introspection\.GetIntrospectionStatus\|introspection\.ReApplyIntrospection\|introspection\.StartIntrospection\|ipsecpolicies\.Create\|ipsecpolicies\.Delete\|ipsecpolicies\.Get\|ipsecpolicies\.Update\|keypairs\.Create\|keypairs\.Delete\|keypairs\.Get\|l7policies\.Create\|l7policies\.CreateRule\|l7policies\.Delete\|l7policies\.DeleteRule\|l7policies\.Get\|l7policies\.GetRule\|l7policies\.Update\|l7policies\.UpdateRule\|limits\.BatchCreate\|limits\.Delete\|limits\.Get\|limits\.GetEnforcementModel\|limits\.Update\|listeners\.Create\|listeners\.Delete\|listeners\.Get\|listeners\.GetStats\|listeners\.Update\|loadbalancers\.Create\|loadbalancers\.Delete\|loadbalancers\.Failover\|loadbalancers\.Get\|loadbalancers\.GetStats\|loadbalancers\.GetStatuses\|loadbalancers\.Update\|members\.Create\|members\.Delete\|members\.Get\|members\.Update\|messages\.Create\|messages\.Delete\|messages\.DeleteMessages\|messages\.Get\|messages\.GetMessages\|messages\.PopMessages\|monitors\.Create\|monitors\.Delete\|monitors\.Get\|monitors\.Update\|networkipavailabilities\.Get\|networks\.Create\|networks\.Delete\|networks\.Get\|networks\.Update\|nodegroups\.Create\|nodegroups\.Delete\|nodegroups\.Get\|nodegroups\.Update\|nodes\.AttachVirtualMedia\|nodes\.ChangePowerState\|nodes\.ChangeProvisionState\|nodes\.Create\|nodes\.CreateSubscription\|nodes\.Delete\|nodes\.DeleteSubscription\|nodes\.DetachVirtualMedia\|nodes\.Get\|nodes\.GetAllSubscriptions\|nodes\.GetBIOSSetting\|nodes\.GetBootDevice\|nodes\.GetInventory\|nodes\.GetSubscription\|nodes\.GetSupportedBootDevices\|nodes\.GetVendorPassthruMethods\|nodes\.InjectNMI\|nodes\.ListBIOSSettings\|nodes\.ListFirmware\|nodes\.SetBootDevice\|nodes\.SetMaintenance\|nodes\.SetRAIDConfig\|nodes\.UnsetMaintenance\|nodes\.Update\|nodes\.Validate\|nodes\.WaitForProvisionState\|oauth1\.AuthorizeToken\|oauth1\.Create\|oauth1\.CreateAccessToken\|oauth1\.CreateConsumer\|oauth1\.DeleteConsumer\|oauth1\.GetAccessToken\|oauth1\.GetAccessTokenRole\|oauth1\.GetConsumer\|oauth1\.RequestToken\|oauth1\.RevokeAccessToken\|oauth1\.UpdateConsumer\|objects\.BulkDelete\|objects\.Copy\|objects\.Create\|objects\.CreateTempURL\|objects\.Delete\|objects\.Download\|objects\.Get\|objects\.Update\|openstack\.Authenticate\|openstack\.AuthenticatedClient\|openstack\.AuthenticateV2\|openstack\.AuthenticateV3\|orders\.Create\|orders\.Delete\|orders\.Get\|osinherit\.Assign\|osinherit\.Unassign\|osinherit\.Validate\|pagination\.Request\|peers\.Create\|peers\.Delete\|peers\.Get\|peers\.Update\|policies\.Create\|policies\.Delete\|policies\.Get\|policies\.InsertRule\|policies\.RemoveRule\|policies\.Update\|pools\.BatchUpdateMembers\|pools\.Create\|pools\.CreateMember\|pools\.Delete\|pools\.DeleteMember\|pools\.Get\|pools\.GetMember\|pools\.Update\|pools\.UpdateMember\|portforwarding\.Create\|portforwarding\.Delete\|portforwarding\.Get\|portforwarding\.Update\|ports\.Create\|ports\.Delete\|ports\.Get\|ports\.Update\|projectendpoints\.Create\|projectendpoints\.Delete\|projects\.Create\|projects\.Delete\|projects\.DeleteTags\|projects\.Get\|projects\.ListTags\|projects\.ModifyTags\|projects\.Update\|qos\.Associate\|qos\.Create\|qos\.Delete\|qos\.DeleteKeys\|qos\.Disassociate\|qos\.DisassociateAll\|qos\.Get\|qos\.Update\|queues\.Create\|queues\.Delete\|queues\.Get\|queues\.GetStats\|queues\.Purge\|queues\.Share\|queues\.Update\|quotas\.Create\|quotasets\.Delete\|quotasets\.Get\|quotasets\.GetDefaults\|quotasets\.GetDetail\|quotasets\.GetUsage\|quotasets\.Update\|quotas\.Get\|quotas\.GetDetail\|quotas\.Update\|rbacpolicies\.Create\|rbacpolicies\.Delete\|rbacpolicies\.Get\|rbacpolicies\.Update\|recordsets\.Create\|recordsets\.Delete\|recordsets\.Get\|recordsets\.Update\|regions\.Create\|regions\.Delete\|regions\.Get\|regions\.Update\|registeredlimits\.BatchCreate\|registeredlimits\.Delete\|registeredlimits\.Get\|registeredlimits\.Update\|remoteconsoles\.Create\|replicas\.Create\|replicas\.Delete\|replicas\.ForceDelete\|replicas\.Get\|replicas\.GetExportLocation\|replicas\.ListExportLocations\|replicas\.Promote\|replicas\.ResetState\|replicas\.ResetStatus\|replicas\.Resync\|request\.Create\|request\.Delete\|request\.Get\|request\.Update\|resourceproviders\.Create\|resourceproviders\.Delete\|resourceproviders\.Get\|resourceproviders\.GetAllocations\|resourceproviders\.GetInventories\|resourceproviders\.GetTraits\|resourceproviders\.GetUsages\|resourceproviders\.Update\|resourcetypes\.GenerateTemplate\|resourcetypes\.GetSchema\|resourcetypes\.List\|roles\.AddUser\|roles\.Assign\|roles\.Create\|roles\.CreateRoleInferenceRule\|roles\.Delete\|roles\.DeleteRoleInferenceRule\|roles\.DeleteUser\|roles\.Get\|roles\.GetRoleInferenceRule\|roles\.ListRoleInferenceRules\|roles\.Unassign\|roles\.Update\|routers\.AddInterface\|routers\.Create\|routers\.Delete\|routers\.Get\|routers\.RemoveInterface\|routers\.Update\|rules\.Create\|rules\.CreateBandwidthLimitRule\|rules\.CreateDSCPMarkingRule\|rules\.CreateMinimumBandwidthRule\|rules\.Delete\|rules\.DeleteBandwidthLimitRule\|rules\.DeleteDSCPMarkingRule\|rules\.DeleteMinimumBandwidthRule\|rules\.Get\|rules\.GetBandwidthLimitRule\|rules\.GetDSCPMarkingRule\|rules\.GetMinimumBandwidthRule\|rules\.Update\|rules\.UpdateBandwidthLimitRule\|rules\.UpdateDSCPMarkingRule\|rules\.UpdateMinimumBandwidthRule\|ruletypes\.GetRuleType\|secgroups\.AddServer\|secgroups\.Create\|secgroups\.CreateRule\|secgroups\.Delete\|secgroups\.DeleteRule\|secgroups\.Get\|secgroups\.RemoveServer\|secgroups\.Update\|secrets\.Create\|secrets\.CreateMetadata\|secrets\.CreateMetadatum\|secrets\.Delete\|secrets\.DeleteMetadatum\|secrets\.Get\|secrets\.GetMetadata\|secrets\.GetMetadatum\|secrets\.GetPayload\|secrets\.Update\|secrets\.UpdateMetadatum\|securityservices\.Create\|securityservices\.Delete\|securityservices\.Get\|securityservices\.Update\|servergroups\.Create\|servergroups\.Delete\|servergroups\.Get\|servers\.ChangeAdminPassword\|servers\.ConfirmResize\|servers\.Create\|servers\.CreateImage\|servers\.CreateMetadatum\|servers\.Delete\|servers\.DeleteMetadatum\|servers\.Evacuate\|servers\.ForceDelete\|servers\.Get\|servers\.GetPassword\|servers\.InjectNetworkInfo\|servers\.LiveMigrate\|servers\.Lock\|servers\.Metadata\|servers\.Metadatum\|servers\.Migrate\|servers\.Pause\|servers\.Reboot\|servers\.Rebuild\|servers\.Rescue\|servers\.ResetMetadata\|servers\.ResetNetwork\|servers\.ResetState\|servers\.Resize\|servers\.Resume\|servers\.RevertResize\|servers\.Shelve\|servers\.ShelveOffload\|servers\.ShowConsoleOutput\|servers\.Start\|servers\.Stop\|servers\.Suspend\|servers\.Unlock\|servers\.Unpause\|servers\.Unrescue\|servers\.Unshelve\|servers\.Update\|servers\.UpdateMetadata\|servers\.WaitForStatus\|services\.Create\|services\.Delete\|services\.Get\|services\.Update\|shareaccessrules\.Get\|shareaccessrules\.List\|sharenetworks\.AddSecurityService\|sharenetworks\.Create\|sharenetworks\.Delete\|sharenetworks\.Get\|sharenetworks\.RemoveSecurityService\|sharenetworks\.Update\|shares\.Create\|shares\.Delete\|shares\.DeleteMetadatum\|shares\.Extend\|shares\.ForceDelete\|shares\.Get\|shares\.GetExportLocation\|shares\.GetMetadata\|shares\.GetMetadatum\|shares\.GrantAccess\|shares\.ListAccessRights\|shares\.ListExportLocations\|shares\.ResetStatus\|shares\.Revert\|shares\.RevokeAccess\|shares\.SetMetadata\|shares\.Shrink\|shares\.Unmanage\|shares\.Update\|shares\.UpdateMetadata\|sharetransfers\.Accept\|sharetransfers\.Create\|sharetransfers\.Delete\|sharetransfers\.Get\|sharetypes\.AddAccess\|sharetypes\.Create\|sharetypes\.Delete\|sharetypes\.GetDefault\|sharetypes\.GetExtraSpecs\|sharetypes\.RemoveAccess\|sharetypes\.SetExtraSpecs\|sharetypes\.ShowAccess\|sharetypes\.UnsetExtraSpecs\|siteconnections\.Create\|siteconnections\.Delete\|siteconnections\.Get\|siteconnections\.Update\|snapshots\.Create\|snapshots\.Delete\|snapshots\.ForceDelete\|snapshots\.Get\|snapshots\.ResetStatus\|snapshots\.Update\|snapshots\.UpdateMetadata\|snapshots\.UpdateStatus\|snapshots\.WaitForStatus\|speakers\.AddBGPPeer\|speakers\.AddGatewayNetwork\|speakers\.Create\|speakers\.Delete\|speakers\.Get\|speakers\.RemoveBGPPeer\|speakers\.RemoveGatewayNetwork\|speakers\.Update\|stackevents\.Find\|stackevents\.Get\|stackresources\.Find\|stackresources\.Get\|stackresources\.MarkUnhealthy\|stackresources\.Metadata\|stackresources\.Schema\|stackresources\.Template\|stacks\.Abandon\|stacks\.Adopt\|stacks\.Create\|stacks\.Delete\|stacks\.Find\|stacks\.Get\|stacks\.Preview\|stacks\.Update\|stacks\.UpdatePatch\|stacktemplates\.Get\|stacktemplates\.Validate\|subnetpools\.Create\|subnetpools\.Delete\|subnetpools\.Get\|subnetpools\.Update\|subnets\.Create\|subnets\.Delete\|subnets\.Get\|subnets\.Update\|swauth\.Auth\|swauth\.NewObjectStorageV1\|tags\.Add\|tags\.Check\|tags\.Delete\|tags\.DeleteAll\|tags\.List\|tags\.ReplaceAll\|tasks\.Create\|tasks\.Get\|tenants\.Create\|tenants\.Delete\|tenants\.Get\|tenants\.Update\|tokens\.Create\|tokens\.Get\|tokens\.Revoke\|tokens\.Validate\|transfers\.Accept\|transfers\.Create\|transfers\.Delete\|transfers\.Get\|trunks\.AddSubports\|trunks\.Create\|trunks\.Delete\|trunks\.Get\|trunks\.GetSubports\|trunks\.RemoveSubports\|trunks\.Update\|trusts\.CheckRole\|trusts\.Create\|trusts\.Delete\|trusts\.Get\|trusts\.GetRole\|users\.AddToGroup\|users\.ChangePassword\|users\.Create\|users\.Delete\|users\.Get\|users\.IsMemberOfGroup\|users\.RemoveFromGroup\|users\.Update\|utils\.ChooseVersion\|utils\.GetSupportedMicroversions\|utils\.RequireMicroversion\|volumeattach\.Create\|volumeattach\.Delete\|volumeattach\.Get\|volumes\.Attach\|volumes\.BeginDetaching\|volumes\.ChangeType\|volumes\.Create\|volumes\.Delete\|volumes\.Detach\|volumes\.ExtendSize\|volumes\.ForceDelete\|volumes\.Get\|volumes\.InitializeConnection\|volumes\.ReImage\|volumes\.Reserve\|volumes\.ResetStatus\|volumes\.SetBootable\|volumes\.SetImageMetadata\|volumes\.TerminateConnection\|volumes\.Unreserve\|volumes\.Update\|volumes\.UploadImage\|volumes\.WaitForStatus\|volumetypes\.AddAccess\|volumetypes\.Create\|volumetypes\.CreateEncryption\|volumetypes\.CreateExtraSpecs\|volumetypes\.Delete\|volumetypes\.DeleteEncryption\|volumetypes\.DeleteExtraSpec\|volumetypes\.Get\|volumetypes\.GetEncryption\|volumetypes\.GetEncryptionSpec\|volumetypes\.GetExtraSpec\|volumetypes\.ListExtraSpecs\|volumetypes\.RemoveAccess\|volumetypes\.Update\|volumetypes\.UpdateEncryption\|volumetypes\.UpdateExtraSpec\|workflows\.Create\|workflows\.Delete\|workflows\.Get\|zones\.Create\|zones\.Delete\|zones\.Get\|zones\.Update\)(#\1(context.TODO(), #g
s#\(\.AllPages(\)#\1context.TODO(), #g
s#\(\.EachPage(\)\(func(\)#\1context.TODO(), \2ctx context.Context, #g
# 8: Rename identifiers that were changed in v2
s#\(\(volumes\|servers\)\.SchedulerHint\)s#\2.SchedulerHintOpts#g
# 9: Tentatively replace error handling
s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault400); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusBadRequest) {#g
s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault401); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusUnauthorized) {#g
s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault403); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusForbidden) {#g
s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault404); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusNotFound) {#g
s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault405); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusMethodNotAllowed) {#g
s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault408); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusRequestTimeout) {#g
s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault409); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusConflict) {#g
s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault429); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusTooManyRequests) {#g
s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault500); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusInternalServerError) {#g
s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault502); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusBadGateway) {#g
s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault503); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusServiceUnavailable) {#g
s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault504); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusGatewayTimeout) {#g
}
' {} \;
grep -r -l 'context\.TODO' | xargs -r sed -i '
/^import ($/ a "context"
'
grep -r -l 'http\.Status' | xargs -r sed -i '
/^import ($/ a "net/http"
'
goimports -format-only -w .
go mod tidy