diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 9cced92e1c..fe43770a94 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -106,7 +106,7 @@ }, { "ImportPath": "github.com/Microsoft/go-winio", - "Comment": "v0.4.5", + "Comment": "v0.4.4-7-g7843996", "Rev": "78439966b38d69bf38227fbf57ac8a6fee70f69a" }, { @@ -487,32 +487,32 @@ }, { "ImportPath": "github.com/containernetworking/cni/libcni", - "Comment": "v0.6.0", + "Comment": "v0.6.0-rc1-6-ga7885cb", "Rev": "a7885cb6f8ab03fba07852ded351e4f5e7a112bf" }, { "ImportPath": "github.com/containernetworking/cni/pkg/invoke", - "Comment": "v0.6.0", + "Comment": "v0.6.0-rc1-6-ga7885cb", "Rev": "a7885cb6f8ab03fba07852ded351e4f5e7a112bf" }, { "ImportPath": "github.com/containernetworking/cni/pkg/types", - "Comment": "v0.6.0", + "Comment": "v0.6.0-rc1-6-ga7885cb", "Rev": "a7885cb6f8ab03fba07852ded351e4f5e7a112bf" }, { "ImportPath": "github.com/containernetworking/cni/pkg/types/020", - "Comment": "v0.6.0", + "Comment": "v0.6.0-rc1-6-ga7885cb", "Rev": "a7885cb6f8ab03fba07852ded351e4f5e7a112bf" }, { "ImportPath": "github.com/containernetworking/cni/pkg/types/current", - "Comment": "v0.6.0", + "Comment": "v0.6.0-rc1-6-ga7885cb", "Rev": "a7885cb6f8ab03fba07852ded351e4f5e7a112bf" }, { "ImportPath": "github.com/containernetworking/cni/pkg/version", - "Comment": "v0.6.0", + "Comment": "v0.6.0-rc1-6-ga7885cb", "Rev": "a7885cb6f8ab03fba07852ded351e4f5e7a112bf" }, { @@ -1057,17 +1057,17 @@ }, { "ImportPath": "github.com/docker/go-connections/nat", - "Comment": "v0.3.0", + "Comment": "v0.2.1-30-g3ede32e", "Rev": "3ede32e2033de7505e6500d6c868c2b9ed9f169d" }, { "ImportPath": "github.com/docker/go-connections/sockets", - "Comment": "v0.3.0", + "Comment": "v0.2.1-30-g3ede32e", "Rev": "3ede32e2033de7505e6500d6c868c2b9ed9f169d" }, { "ImportPath": "github.com/docker/go-connections/tlsconfig", - "Comment": "v0.3.0", + "Comment": "v0.2.1-30-g3ede32e", "Rev": "3ede32e2033de7505e6500d6c868c2b9ed9f169d" }, { @@ -1633,111 +1633,115 @@ }, { "ImportPath": "github.com/gophercloud/gophercloud", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" + }, + { + "ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes", + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/common/extensions", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/flavors", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/images", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/servers", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/ports", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/utils", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/pagination", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gorilla/context", diff --git a/Godeps/LICENSES b/Godeps/LICENSES index 9ea07201e7..95d876a70f 100644 --- a/Godeps/LICENSES +++ b/Godeps/LICENSES @@ -55942,6 +55942,205 @@ specific language governing permissions and limitations under the License. ================================================================================ +================================================================================ += vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes licensed under: = + +Copyright 2012-2013 Rackspace, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. + +------ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + += vendor/github.com/gophercloud/gophercloud/LICENSE dd19699707373c2ca31531a659130416 +================================================================================ + + ================================================================================ = vendor/github.com/gophercloud/gophercloud/openstack/common/extensions licensed under: = diff --git a/pkg/cloudprovider/providers/openstack/BUILD b/pkg/cloudprovider/providers/openstack/BUILD index 3b04ef8c04..d08ecb4553 100644 --- a/pkg/cloudprovider/providers/openstack/BUILD +++ b/pkg/cloudprovider/providers/openstack/BUILD @@ -32,6 +32,7 @@ go_library( "//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions:go_default_library", "//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes:go_default_library", "//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes:go_default_library", + "//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes:go_default_library", "//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces:go_default_library", "//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach:go_default_library", "//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers:go_default_library", diff --git a/pkg/cloudprovider/providers/openstack/openstack.go b/pkg/cloudprovider/providers/openstack/openstack.go index 455717ae69..a2a517a4d3 100644 --- a/pkg/cloudprovider/providers/openstack/openstack.go +++ b/pkg/cloudprovider/providers/openstack/openstack.go @@ -660,27 +660,36 @@ func (os *OpenStack) volumeService(forceVersion string) (volumeService, error) { } glog.V(3).Infof("Using Blockstorage API V2") return &VolumesV2{sClient, os.bsOpts}, nil - case "auto": - // Currently kubernetes just support Cinder v1 and Cinder v2. - // Choose Cinder v2 firstly, if kubernetes can't initialize cinder v2 client, try to initialize cinder v1 client. - // Return appropriate message when kubernetes can't initialize them. - // TODO(FengyunPan): revisit 'auto' after supporting Cinder v3. - sClient, err := os.NewBlockStorageV2() + case "v3": + sClient, err := os.NewBlockStorageV3() if err != nil { - sClient, err = os.NewBlockStorageV1() - if err != nil { - // Nothing suitable found, failed autodetection, just exit with appropriate message - err_txt := "BlockStorage API version autodetection failed. " + - "Please set it explicitly in cloud.conf in section [BlockStorage] with key `bs-version`" - return nil, errors.New(err_txt) - } else { - glog.V(3).Infof("Using Blockstorage API V1") - return &VolumesV1{sClient, os.bsOpts}, nil - } - } else { + return nil, err + } + glog.V(3).Infof("Using Blockstorage API V3") + return &VolumesV3{sClient, os.bsOpts}, nil + case "auto": + // Currently kubernetes support Cinder v1 / Cinder v2 / Cinder v3. + // Choose Cinder v3 firstly, if kubernetes can't initialize cinder v3 client, try to initialize cinder v2 client. + // If kubernetes can't initialize cinder v2 client, try to initialize cinder v1 client. + // Return appropriate message when kubernetes can't initialize them. + if sClient, err := os.NewBlockStorageV3(); err == nil { + glog.V(3).Infof("Using Blockstorage API V3") + return &VolumesV3{sClient, os.bsOpts}, nil + } + + if sClient, err := os.NewBlockStorageV2(); err == nil { glog.V(3).Infof("Using Blockstorage API V2") return &VolumesV2{sClient, os.bsOpts}, nil } + + if sClient, err := os.NewBlockStorageV1(); err == nil { + glog.V(3).Infof("Using Blockstorage API V1") + return &VolumesV1{sClient, os.bsOpts}, nil + } + + err_txt := "BlockStorage API version autodetection failed. " + + "Please set it explicitly in cloud.conf in section [BlockStorage] with key `bs-version`" + return nil, errors.New(err_txt) default: err_txt := fmt.Sprintf("Config error: unrecognised bs-version \"%v\"", os.bsOpts.BSVersion) return nil, errors.New(err_txt) diff --git a/pkg/cloudprovider/providers/openstack/openstack_client.go b/pkg/cloudprovider/providers/openstack/openstack_client.go index b8563e3c75..04851070e4 100644 --- a/pkg/cloudprovider/providers/openstack/openstack_client.go +++ b/pkg/cloudprovider/providers/openstack/openstack_client.go @@ -63,6 +63,16 @@ func (os *OpenStack) NewBlockStorageV2() (*gophercloud.ServiceClient, error) { return storage, nil } +func (os *OpenStack) NewBlockStorageV3() (*gophercloud.ServiceClient, error) { + storage, err := openstack.NewBlockStorageV3(os.provider, gophercloud.EndpointOpts{ + Region: os.region, + }) + if err != nil { + return nil, fmt.Errorf("unable to initialize cinder v3 client for region %s: %v", os.region, err) + } + return storage, nil +} + func (os *OpenStack) NewLoadBalancerV2() (*gophercloud.ServiceClient, error) { var lb *gophercloud.ServiceClient var err error diff --git a/pkg/cloudprovider/providers/openstack/openstack_volumes.go b/pkg/cloudprovider/providers/openstack/openstack_volumes.go index aa3ec6f90c..e95f2330fd 100644 --- a/pkg/cloudprovider/providers/openstack/openstack_volumes.go +++ b/pkg/cloudprovider/providers/openstack/openstack_volumes.go @@ -31,6 +31,7 @@ import ( volumeexpand "github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions" volumes_v1 "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes" volumes_v2 "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes" + volumes_v3 "github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes" "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach" "github.com/prometheus/client_golang/prometheus" @@ -56,6 +57,12 @@ type VolumesV2 struct { opts BlockStorageOpts } +// Volumes implementation for v3 +type VolumesV3 struct { + blockstorage *gophercloud.ServiceClient + opts BlockStorageOpts +} + type Volume struct { // ID of the instance, to which this volume is attached. "" if not attached AttachedServerId string @@ -131,6 +138,26 @@ func (volumes *VolumesV2) createVolume(opts VolumeCreateOpts) (string, string, e return vol.ID, vol.AvailabilityZone, nil } +func (volumes *VolumesV3) createVolume(opts VolumeCreateOpts) (string, string, error) { + startTime := time.Now() + + create_opts := volumes_v3.CreateOpts{ + Name: opts.Name, + Size: opts.Size, + VolumeType: opts.VolumeType, + AvailabilityZone: opts.Availability, + Metadata: opts.Metadata, + } + + vol, err := volumes_v3.Create(volumes.blockstorage, create_opts).Extract() + timeTaken := time.Since(startTime).Seconds() + recordOpenstackOperationMetric("create_v3_volume", timeTaken, err) + if err != nil { + return "", "", err + } + return vol.ID, vol.AvailabilityZone, nil +} + func (volumes *VolumesV1) getVolume(volumeID string) (Volume, error) { startTime := time.Now() volumeV1, err := volumes_v1.Get(volumes.blockstorage, volumeID).Extract() @@ -179,6 +206,29 @@ func (volumes *VolumesV2) getVolume(volumeID string) (Volume, error) { return volume, nil } +func (volumes *VolumesV3) getVolume(volumeID string) (Volume, error) { + startTime := time.Now() + volumeV3, err := volumes_v3.Get(volumes.blockstorage, volumeID).Extract() + timeTaken := time.Since(startTime).Seconds() + recordOpenstackOperationMetric("get_v3_volume", timeTaken, err) + if err != nil { + return Volume{}, fmt.Errorf("error occurred getting volume by ID: %s, err: %v", volumeID, err) + } + + volume := Volume{ + ID: volumeV3.ID, + Name: volumeV3.Name, + Status: volumeV3.Status, + } + + if len(volumeV3.Attachments) > 0 { + volume.AttachedServerId = volumeV3.Attachments[0].ServerID + volume.AttachedDevice = volumeV3.Attachments[0].Device + } + + return volume, nil +} + func (volumes *VolumesV1) deleteVolume(volumeID string) error { startTime := time.Now() err := volumes_v1.Delete(volumes.blockstorage, volumeID).ExtractErr() @@ -195,6 +245,14 @@ func (volumes *VolumesV2) deleteVolume(volumeID string) error { return err } +func (volumes *VolumesV3) deleteVolume(volumeID string) error { + startTime := time.Now() + err := volumes_v3.Delete(volumes.blockstorage, volumeID).ExtractErr() + timeTaken := time.Since(startTime).Seconds() + recordOpenstackOperationMetric("delete_v3_volume", timeTaken, err) + return err +} + func (volumes *VolumesV1) expandVolume(volumeID string, newSize int) error { startTime := time.Now() create_opts := volumeexpand.ExtendSizeOpts{ @@ -203,7 +261,6 @@ func (volumes *VolumesV1) expandVolume(volumeID string, newSize int) error { err := volumeexpand.ExtendSize(volumes.blockstorage, volumeID, create_opts).ExtractErr() timeTaken := time.Since(startTime).Seconds() recordOpenstackOperationMetric("expand_volume", timeTaken, err) - return err } @@ -215,7 +272,17 @@ func (volumes *VolumesV2) expandVolume(volumeID string, newSize int) error { err := volumeexpand.ExtendSize(volumes.blockstorage, volumeID, create_opts).ExtractErr() timeTaken := time.Since(startTime).Seconds() recordOpenstackOperationMetric("expand_volume", timeTaken, err) + return err +} +func (volumes *VolumesV3) expandVolume(volumeID string, newSize int) error { + startTime := time.Now() + create_opts := volumeexpand.ExtendSizeOpts{ + NewSize: newSize, + } + err := volumeexpand.ExtendSize(volumes.blockstorage, volumeID, create_opts).ExtractErr() + timeTaken := time.Since(startTime).Seconds() + recordOpenstackOperationMetric("expand_volume", timeTaken, err) return err } diff --git a/staging/src/k8s.io/apiserver/Godeps/Godeps.json b/staging/src/k8s.io/apiserver/Godeps/Godeps.json index 62c9dd5b09..de78fc380a 100644 --- a/staging/src/k8s.io/apiserver/Godeps/Godeps.json +++ b/staging/src/k8s.io/apiserver/Godeps/Godeps.json @@ -408,31 +408,31 @@ }, { "ImportPath": "github.com/gophercloud/gophercloud", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/utils", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/pagination", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gregjones/httpcache", diff --git a/staging/src/k8s.io/client-go/Godeps/Godeps.json b/staging/src/k8s.io/client-go/Godeps/Godeps.json index a65c35d05d..8b56b71a90 100644 --- a/staging/src/k8s.io/client-go/Godeps/Godeps.json +++ b/staging/src/k8s.io/client-go/Godeps/Godeps.json @@ -172,31 +172,31 @@ }, { "ImportPath": "github.com/gophercloud/gophercloud", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/utils", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gophercloud/gophercloud/pagination", - "Rev": "54086d6c81b90e91e1d52b866ee726baf5cbe2b1" + "Rev": "db5f840b1d1a595280d643defc09ce277996959e" }, { "ImportPath": "github.com/gregjones/httpcache", diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/BUILD b/vendor/github.com/gophercloud/gophercloud/openstack/BUILD index 23c91277e3..65166006a8 100644 --- a/vendor/github.com/gophercloud/gophercloud/openstack/BUILD +++ b/vendor/github.com/gophercloud/gophercloud/openstack/BUILD @@ -33,6 +33,7 @@ filegroup( "//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions:all-srcs", "//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes:all-srcs", "//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes:all-srcs", + "//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes:all-srcs", "//vendor/github.com/gophercloud/gophercloud/openstack/common/extensions:all-srcs", "//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces:all-srcs", "//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach:all-srcs", diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/BUILD b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/BUILD new file mode 100644 index 0000000000..7ba7ef4e98 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/BUILD @@ -0,0 +1,32 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "requests.go", + "results.go", + "urls.go", + "util.go", + ], + importpath = "github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes", + visibility = ["//visibility:public"], + deps = [ + "//vendor/github.com/gophercloud/gophercloud:go_default_library", + "//vendor/github.com/gophercloud/gophercloud/pagination:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/doc.go new file mode 100644 index 0000000000..307b8b12d2 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/doc.go @@ -0,0 +1,5 @@ +// Package volumes provides information and interaction with volumes in the +// OpenStack Block Storage service. A volume is a detachable block storage +// device, akin to a USB hard drive. It can only be attached to one instance at +// a time. +package volumes diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/requests.go new file mode 100644 index 0000000000..18c9cb272e --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/requests.go @@ -0,0 +1,182 @@ +package volumes + +import ( + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/pagination" +) + +// CreateOptsBuilder allows extensions to add additional parameters to the +// Create request. +type CreateOptsBuilder interface { + ToVolumeCreateMap() (map[string]interface{}, error) +} + +// CreateOpts contains options for creating a Volume. This object is passed to +// the volumes.Create function. For more information about these parameters, +// see the Volume object. +type CreateOpts struct { + // The size of the volume, in GB + Size int `json:"size" required:"true"` + // The availability zone + AvailabilityZone string `json:"availability_zone,omitempty"` + // ConsistencyGroupID is the ID of a consistency group + ConsistencyGroupID string `json:"consistencygroup_id,omitempty"` + // The volume description + Description string `json:"description,omitempty"` + // One or more metadata key and value pairs to associate with the volume + Metadata map[string]string `json:"metadata,omitempty"` + // The volume name + Name string `json:"name,omitempty"` + // the ID of the existing volume snapshot + SnapshotID string `json:"snapshot_id,omitempty"` + // SourceReplica is a UUID of an existing volume to replicate with + SourceReplica string `json:"source_replica,omitempty"` + // the ID of the existing volume + SourceVolID string `json:"source_volid,omitempty"` + // The ID of the image from which you want to create the volume. + // Required to create a bootable volume. + ImageID string `json:"imageRef,omitempty"` + // The associated volume type + VolumeType string `json:"volume_type,omitempty"` +} + +// ToVolumeCreateMap assembles a request body based on the contents of a +// CreateOpts. +func (opts CreateOpts) ToVolumeCreateMap() (map[string]interface{}, error) { + return gophercloud.BuildRequestBody(opts, "volume") +} + +// Create will create a new Volume based on the values in CreateOpts. To extract +// the Volume object from the response, call the Extract method on the +// CreateResult. +func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToVolumeCreateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{202}, + }) + return +} + +// Delete will delete the existing Volume with the provided ID. +func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) { + _, r.Err = client.Delete(deleteURL(client, id), nil) + return +} + +// Get retrieves the Volume with the provided ID. To extract the Volume object +// from the response, call the Extract method on the GetResult. +func Get(client *gophercloud.ServiceClient, id string) (r GetResult) { + _, r.Err = client.Get(getURL(client, id), &r.Body, nil) + return +} + +// ListOptsBuilder allows extensions to add additional parameters to the List +// request. +type ListOptsBuilder interface { + ToVolumeListQuery() (string, error) +} + +// ListOpts holds options for listing Volumes. It is passed to the volumes.List +// function. +type ListOpts struct { + // admin-only option. Set it to true to see all tenant volumes. + AllTenants bool `q:"all_tenants"` + // List only volumes that contain Metadata. + Metadata map[string]string `q:"metadata"` + // List only volumes that have Name as the display name. + Name string `q:"name"` + // List only volumes that have a status of Status. + Status string `q:"status"` +} + +// ToVolumeListQuery formats a ListOpts into a query string. +func (opts ListOpts) ToVolumeListQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + +// List returns Volumes optionally limited by the conditions provided in ListOpts. +func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { + url := listURL(client) + if opts != nil { + query, err := opts.ToVolumeListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + + return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { + return VolumePage{pagination.SinglePageBase(r)} + }) +} + +// UpdateOptsBuilder allows extensions to add additional parameters to the +// Update request. +type UpdateOptsBuilder interface { + ToVolumeUpdateMap() (map[string]interface{}, error) +} + +// UpdateOpts contain options for updating an existing Volume. This object is passed +// to the volumes.Update function. For more information about the parameters, see +// the Volume object. +type UpdateOpts struct { + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Metadata map[string]string `json:"metadata,omitempty"` +} + +// ToVolumeUpdateMap assembles a request body based on the contents of an +// UpdateOpts. +func (opts UpdateOpts) ToVolumeUpdateMap() (map[string]interface{}, error) { + return gophercloud.BuildRequestBody(opts, "volume") +} + +// Update will update the Volume with provided information. To extract the updated +// Volume from the response, call the Extract method on the UpdateResult. +func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToVolumeUpdateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = client.Put(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +// IDFromName is a convienience function that returns a server's ID given its name. +func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) { + count := 0 + id := "" + pages, err := List(client, nil).AllPages() + if err != nil { + return "", err + } + + all, err := ExtractVolumes(pages) + if err != nil { + return "", err + } + + for _, s := range all { + if s.Name == name { + count++ + id = s.ID + } + } + + switch count { + case 0: + return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "volume"} + case 1: + return id, nil + default: + return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "volume"} + } +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/results.go new file mode 100644 index 0000000000..5ebe36a338 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/results.go @@ -0,0 +1,159 @@ +package volumes + +import ( + "encoding/json" + "time" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/pagination" +) + +// Attachment represents a Volume Attachment record +type Attachment struct { + AttachedAt time.Time `json:"-"` + AttachmentID string `json:"attachment_id"` + Device string `json:"device"` + HostName string `json:"host_name"` + ID string `json:"id"` + ServerID string `json:"server_id"` + VolumeID string `json:"volume_id"` +} + +// UnmarshalJSON is our unmarshalling helper +func (r *Attachment) UnmarshalJSON(b []byte) error { + type tmp Attachment + var s struct { + tmp + AttachedAt gophercloud.JSONRFC3339MilliNoZ `json:"attached_at"` + } + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + *r = Attachment(s.tmp) + + r.AttachedAt = time.Time(s.AttachedAt) + + return err +} + +// Volume contains all the information associated with an OpenStack Volume. +type Volume struct { + // Unique identifier for the volume. + ID string `json:"id"` + // Current status of the volume. + Status string `json:"status"` + // Size of the volume in GB. + Size int `json:"size"` + // AvailabilityZone is which availability zone the volume is in. + AvailabilityZone string `json:"availability_zone"` + // The date when this volume was created. + CreatedAt time.Time `json:"-"` + // The date when this volume was last updated + UpdatedAt time.Time `json:"-"` + // Instances onto which the volume is attached. + Attachments []Attachment `json:"attachments"` + // Human-readable display name for the volume. + Name string `json:"name"` + // Human-readable description for the volume. + Description string `json:"description"` + // The type of volume to create, either SATA or SSD. + VolumeType string `json:"volume_type"` + // The ID of the snapshot from which the volume was created + SnapshotID string `json:"snapshot_id"` + // The ID of another block storage volume from which the current volume was created + SourceVolID string `json:"source_volid"` + // Arbitrary key-value pairs defined by the user. + Metadata map[string]string `json:"metadata"` + // UserID is the id of the user who created the volume. + UserID string `json:"user_id"` + // Indicates whether this is a bootable volume. + Bootable string `json:"bootable"` + // Encrypted denotes if the volume is encrypted. + Encrypted bool `json:"encrypted"` + // ReplicationStatus is the status of replication. + ReplicationStatus string `json:"replication_status"` + // ConsistencyGroupID is the consistency group ID. + ConsistencyGroupID string `json:"consistencygroup_id"` + // Multiattach denotes if the volume is multi-attach capable. + Multiattach bool `json:"multiattach"` +} + +// UnmarshalJSON another unmarshalling function +func (r *Volume) UnmarshalJSON(b []byte) error { + type tmp Volume + var s struct { + tmp + CreatedAt gophercloud.JSONRFC3339MilliNoZ `json:"created_at"` + UpdatedAt gophercloud.JSONRFC3339MilliNoZ `json:"updated_at"` + } + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + *r = Volume(s.tmp) + + r.CreatedAt = time.Time(s.CreatedAt) + r.UpdatedAt = time.Time(s.UpdatedAt) + + return err +} + +// VolumePage is a pagination.pager that is returned from a call to the List function. +type VolumePage struct { + pagination.SinglePageBase +} + +// IsEmpty returns true if a ListResult contains no Volumes. +func (r VolumePage) IsEmpty() (bool, error) { + volumes, err := ExtractVolumes(r) + return len(volumes) == 0, err +} + +// ExtractVolumes extracts and returns Volumes. It is used while iterating over a volumes.List call. +func ExtractVolumes(r pagination.Page) ([]Volume, error) { + var s []Volume + err := ExtractVolumesInto(r, &s) + return s, err +} + +type commonResult struct { + gophercloud.Result +} + +// Extract will get the Volume object out of the commonResult object. +func (r commonResult) Extract() (*Volume, error) { + var s Volume + err := r.ExtractInto(&s) + return &s, err +} + +// ExtractInto converts our response data into a volume struct +func (r commonResult) ExtractInto(v interface{}) error { + return r.Result.ExtractIntoStructPtr(v, "volume") +} + +// ExtractVolumesInto similar to ExtractInto but operates on a `list` of volumes +func ExtractVolumesInto(r pagination.Page, v interface{}) error { + return r.(VolumePage).Result.ExtractIntoSlicePtr(v, "volumes") +} + +// CreateResult contains the response body and error from a Create request. +type CreateResult struct { + commonResult +} + +// GetResult contains the response body and error from a Get request. +type GetResult struct { + commonResult +} + +// UpdateResult contains the response body and error from an Update request. +type UpdateResult struct { + commonResult +} + +// DeleteResult contains the response body and error from a Delete request. +type DeleteResult struct { + gophercloud.ErrResult +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/urls.go new file mode 100644 index 0000000000..170724905a --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/urls.go @@ -0,0 +1,23 @@ +package volumes + +import "github.com/gophercloud/gophercloud" + +func createURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL("volumes") +} + +func listURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL("volumes", "detail") +} + +func deleteURL(c *gophercloud.ServiceClient, id string) string { + return c.ServiceURL("volumes", id) +} + +func getURL(c *gophercloud.ServiceClient, id string) string { + return deleteURL(c, id) +} + +func updateURL(c *gophercloud.ServiceClient, id string) string { + return deleteURL(c, id) +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/util.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/util.go new file mode 100644 index 0000000000..e86c1b4b4e --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/util.go @@ -0,0 +1,22 @@ +package volumes + +import ( + "github.com/gophercloud/gophercloud" +) + +// WaitForStatus will continually poll the resource, checking for a particular +// status. It will do this for the amount of seconds defined. +func WaitForStatus(c *gophercloud.ServiceClient, id, status string, secs int) error { + return gophercloud.WaitFor(secs, func() (bool, error) { + current, err := Get(c, id).Extract() + if err != nil { + return false, err + } + + if current.Status == status { + return true, nil + } + + return false, nil + }) +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/client.go b/vendor/github.com/gophercloud/gophercloud/openstack/client.go index adcf90bcef..c796795b8e 100644 --- a/vendor/github.com/gophercloud/gophercloud/openstack/client.go +++ b/vendor/github.com/gophercloud/gophercloud/openstack/client.go @@ -308,8 +308,12 @@ func NewBlockStorageV2(client *gophercloud.ProviderClient, eo gophercloud.Endpoi return initClientOpts(client, eo, "volumev2") } -// NewSharedFileSystemV2 creates a ServiceClient that may be used to access the -// v2 shared file system service. +// NewBlockStorageV3 creates a ServiceClient that may be used to access the v3 block storage service. +func NewBlockStorageV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { + return initClientOpts(client, eo, "volumev3") +} + +// NewSharedFileSystemV2 creates a ServiceClient that may be used to access the v2 shared file system service. func NewSharedFileSystemV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { return initClientOpts(client, eo, "sharev2") } diff --git a/vendor/github.com/gophercloud/gophercloud/service_client.go b/vendor/github.com/gophercloud/gophercloud/service_client.go index 1160fefa7c..d1a48fea35 100644 --- a/vendor/github.com/gophercloud/gophercloud/service_client.go +++ b/vendor/github.com/gophercloud/gophercloud/service_client.go @@ -114,6 +114,8 @@ func (client *ServiceClient) setMicroversionHeader(opts *RequestOpts) { opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion case "sharev2": opts.MoreHeaders["X-OpenStack-Manila-API-Version"] = client.Microversion + case "volume": + opts.MoreHeaders["X-OpenStack-Volume-API-Version"] = client.Microversion } if client.Type != "" {