diff --git a/LICENSES/vendor/github.com/gophercloud/gophercloud/LICENSE b/LICENSES/vendor/github.com/gophercloud/gophercloud/LICENSE deleted file mode 100644 index 19c07b7c731..00000000000 --- a/LICENSES/vendor/github.com/gophercloud/gophercloud/LICENSE +++ /dev/null @@ -1,195 +0,0 @@ -= vendor/github.com/gophercloud/gophercloud 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 diff --git a/cluster/addons/storage-class/openstack/default.yaml b/cluster/addons/storage-class/openstack/default.yaml deleted file mode 100644 index 435b31d222b..00000000000 --- a/cluster/addons/storage-class/openstack/default.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: storage.k8s.io/v1 -kind: StorageClass -metadata: - name: standard - annotations: - storageclass.kubernetes.io/is-default-class: "true" - labels: - addonmanager.kubernetes.io/mode: EnsureExists -provisioner: kubernetes.io/cinder diff --git a/cmd/cloud-controller-manager/providers.go b/cmd/cloud-controller-manager/providers.go index aa063d92844..b75e7b07cbe 100644 --- a/cmd/cloud-controller-manager/providers.go +++ b/cmd/cloud-controller-manager/providers.go @@ -28,6 +28,5 @@ import ( _ "k8s.io/legacy-cloud-providers/aws" _ "k8s.io/legacy-cloud-providers/azure" _ "k8s.io/legacy-cloud-providers/gce" - _ "k8s.io/legacy-cloud-providers/openstack" _ "k8s.io/legacy-cloud-providers/vsphere" ) diff --git a/cmd/kube-controller-manager/app/plugins_providers.go b/cmd/kube-controller-manager/app/plugins_providers.go index 99b1586d203..8b7d66d2f86 100644 --- a/cmd/kube-controller-manager/app/plugins_providers.go +++ b/cmd/kube-controller-manager/app/plugins_providers.go @@ -28,7 +28,6 @@ import ( "k8s.io/kubernetes/pkg/volume/awsebs" "k8s.io/kubernetes/pkg/volume/azure_file" "k8s.io/kubernetes/pkg/volume/azuredd" - "k8s.io/kubernetes/pkg/volume/cinder" "k8s.io/kubernetes/pkg/volume/csimigration" "k8s.io/kubernetes/pkg/volume/gcepd" "k8s.io/kubernetes/pkg/volume/portworx" @@ -66,7 +65,6 @@ func appendAttachableLegacyProviderVolumes(allPlugins []volume.VolumePlugin, fea pluginMigrationStatus := make(map[string]pluginInfo) pluginMigrationStatus[plugins.AWSEBSInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationAWS, pluginUnregisterFeature: features.InTreePluginAWSUnregister, pluginProbeFunction: awsebs.ProbeVolumePlugins} pluginMigrationStatus[plugins.GCEPDInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationGCE, pluginUnregisterFeature: features.InTreePluginGCEUnregister, pluginProbeFunction: gcepd.ProbeVolumePlugins} - pluginMigrationStatus[plugins.CinderInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationOpenStack, pluginUnregisterFeature: features.InTreePluginOpenStackUnregister, pluginProbeFunction: cinder.ProbeVolumePlugins} pluginMigrationStatus[plugins.AzureDiskInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationAzureDisk, pluginUnregisterFeature: features.InTreePluginAzureDiskUnregister, pluginProbeFunction: azuredd.ProbeVolumePlugins} pluginMigrationStatus[plugins.VSphereInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationvSphere, pluginUnregisterFeature: features.InTreePluginvSphereUnregister, pluginProbeFunction: vsphere_volume.ProbeVolumePlugins} pluginMigrationStatus[plugins.PortworxVolumePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationPortworx, pluginUnregisterFeature: features.InTreePluginPortworxUnregister, pluginProbeFunction: portworx.ProbeVolumePlugins} diff --git a/cmd/kubelet/app/plugins_providers.go b/cmd/kubelet/app/plugins_providers.go index 9b4a6391f76..26e408e3dbe 100644 --- a/cmd/kubelet/app/plugins_providers.go +++ b/cmd/kubelet/app/plugins_providers.go @@ -33,7 +33,6 @@ import ( "k8s.io/kubernetes/pkg/volume/awsebs" "k8s.io/kubernetes/pkg/volume/azure_file" "k8s.io/kubernetes/pkg/volume/azuredd" - "k8s.io/kubernetes/pkg/volume/cinder" "k8s.io/kubernetes/pkg/volume/csimigration" "k8s.io/kubernetes/pkg/volume/gcepd" "k8s.io/kubernetes/pkg/volume/portworx" @@ -72,7 +71,6 @@ func appendLegacyProviderVolumes(allPlugins []volume.VolumePlugin, featureGate f pluginMigrationStatus := make(map[string]pluginInfo) pluginMigrationStatus[plugins.AWSEBSInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationAWS, pluginUnregisterFeature: features.InTreePluginAWSUnregister, pluginProbeFunction: awsebs.ProbeVolumePlugins} pluginMigrationStatus[plugins.GCEPDInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationGCE, pluginUnregisterFeature: features.InTreePluginGCEUnregister, pluginProbeFunction: gcepd.ProbeVolumePlugins} - pluginMigrationStatus[plugins.CinderInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationOpenStack, pluginUnregisterFeature: features.InTreePluginOpenStackUnregister, pluginProbeFunction: cinder.ProbeVolumePlugins} pluginMigrationStatus[plugins.AzureDiskInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationAzureDisk, pluginUnregisterFeature: features.InTreePluginAzureDiskUnregister, pluginProbeFunction: azuredd.ProbeVolumePlugins} pluginMigrationStatus[plugins.AzureFileInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationAzureFile, pluginUnregisterFeature: features.InTreePluginAzureFileUnregister, pluginProbeFunction: azure_file.ProbeVolumePlugins} pluginMigrationStatus[plugins.VSphereInTreePluginName] = pluginInfo{pluginMigrationFeature: features.CSIMigrationvSphere, pluginUnregisterFeature: features.InTreePluginvSphereUnregister, pluginProbeFunction: vsphere_volume.ProbeVolumePlugins} diff --git a/go.mod b/go.mod index 2406b3da679..01bb93bd112 100644 --- a/go.mod +++ b/go.mod @@ -180,7 +180,6 @@ require ( github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/googleapis/gax-go/v2 v2.1.1 // indirect - github.com/gophercloud/gophercloud v0.1.0 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect @@ -398,7 +397,6 @@ replace ( github.com/google/shlex => github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/uuid => github.com/google/uuid v1.1.2 github.com/googleapis/gax-go/v2 => github.com/googleapis/gax-go/v2 v2.1.1 - github.com/gophercloud/gophercloud => github.com/gophercloud/gophercloud v0.1.0 github.com/gopherjs/gopherjs => github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 github.com/gorilla/mux => github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket => github.com/gorilla/websocket v1.4.2 diff --git a/go.sum b/go.sum index f046333e69a..e8b1488b178 100644 --- a/go.sum +++ b/go.sum @@ -233,8 +233,6 @@ github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.1.1 h1:dp3bWCh+PPO1zjRRiCSczJav13sBvG4UhNyVTa1KqdU= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= diff --git a/hack/local-up-cluster.sh b/hack/local-up-cluster.sh index 0a49b29697a..69dacaa5ead 100755 --- a/hack/local-up-cluster.sh +++ b/hack/local-up-cluster.sh @@ -133,18 +133,6 @@ KUBE_CONTROLLERS="${KUBE_CONTROLLERS:-"*"}" # Audit policy AUDIT_POLICY_FILE=${AUDIT_POLICY_FILE:-""} -# sanity check for OpenStack provider -if [ "${CLOUD_PROVIDER}" == "openstack" ]; then - if [ "${CLOUD_CONFIG}" == "" ]; then - echo "Missing CLOUD_CONFIG env for OpenStack provider!" - exit 1 - fi - if [ ! -f "${CLOUD_CONFIG}" ]; then - echo "Cloud config ${CLOUD_CONFIG} doesn't exist" - exit 1 - fi -fi - # Stop right away if the build fails set -e diff --git a/pkg/apis/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go index 21eebc64082..703748b2ffc 100644 --- a/pkg/apis/core/validation/validation_test.go +++ b/pkg/apis/core/validation/validation_test.go @@ -4092,20 +4092,6 @@ func TestValidateVolumes(t *testing.T) { field: "rbd.image", }}, }, - // Cinder - { - name: "valid Cinder", - vol: core.Volume{ - Name: "cinder", - VolumeSource: core.VolumeSource{ - Cinder: &core.CinderVolumeSource{ - VolumeID: "29ea5088-4f60-4757-962e-dba678767887", - FSType: "ext4", - ReadOnly: false, - }, - }, - }, - }, // CephFS { name: "valid CephFS", diff --git a/pkg/cloudprovider/providers/providers.go b/pkg/cloudprovider/providers/providers.go index a78450a0e41..dda8b56585f 100644 --- a/pkg/cloudprovider/providers/providers.go +++ b/pkg/cloudprovider/providers/providers.go @@ -24,6 +24,5 @@ import ( _ "k8s.io/legacy-cloud-providers/aws" _ "k8s.io/legacy-cloud-providers/azure" _ "k8s.io/legacy-cloud-providers/gce" - _ "k8s.io/legacy-cloud-providers/openstack" _ "k8s.io/legacy-cloud-providers/vsphere" ) diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index 5a0dbd7e81a..d9da0304dd4 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -140,13 +140,6 @@ const ( // Enables the GCE PD in-tree driver to GCE CSI Driver migration feature. CSIMigrationGCE featuregate.Feature = "CSIMigrationGCE" - // owner: @adisky - // alpha: v1.14 - // beta: v1.18 - // - // Enables the OpenStack Cinder in-tree driver to OpenStack Cinder CSI Driver migration feature. - CSIMigrationOpenStack featuregate.Feature = "CSIMigrationOpenStack" - // owner: @trierra // alpha: v1.23 // @@ -410,12 +403,6 @@ const ( // Disables the GCE PD in-tree driver. InTreePluginGCEUnregister featuregate.Feature = "InTreePluginGCEUnregister" - // owner: @adisky - // alpha: v1.21 - // - // Disables the OpenStack Cinder in-tree driver. - InTreePluginOpenStackUnregister featuregate.Feature = "InTreePluginOpenStackUnregister" - // owner: @trierra // alpha: v1.23 // @@ -923,8 +910,6 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS CSIMigrationGCE: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // GA in 1.25 (requires GCE PD CSI Driver) - CSIMigrationOpenStack: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.26 - CSIMigrationPortworx: {Default: false, PreRelease: featuregate.Beta}, // Off by default (requires Portworx CSI driver) CSIMigrationRBD: {Default: false, PreRelease: featuregate.Alpha}, // Off by default (requires RBD CSI driver) @@ -999,8 +984,6 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS InTreePluginGCEUnregister: {Default: false, PreRelease: featuregate.Alpha}, - InTreePluginOpenStackUnregister: {Default: false, PreRelease: featuregate.Alpha}, - InTreePluginPortworxUnregister: {Default: false, PreRelease: featuregate.Alpha}, InTreePluginRBDUnregister: {Default: false, PreRelease: featuregate.Alpha}, diff --git a/pkg/scheduler/framework/plugins/names/names.go b/pkg/scheduler/framework/plugins/names/names.go index 2c65ff732ea..83aafca8015 100644 --- a/pkg/scheduler/framework/plugins/names/names.go +++ b/pkg/scheduler/framework/plugins/names/names.go @@ -30,7 +30,6 @@ const ( NodeUnschedulable = "NodeUnschedulable" NodeVolumeLimits = "NodeVolumeLimits" AzureDiskLimits = "AzureDiskLimits" - CinderLimits = "CinderLimits" EBSLimits = "EBSLimits" GCEPDLimits = "GCEPDLimits" PodTopologySpread = "PodTopologySpread" diff --git a/pkg/scheduler/framework/plugins/nodevolumelimits/csi_test.go b/pkg/scheduler/framework/plugins/nodevolumelimits/csi_test.go index 420493394a5..2b1da3fba27 100644 --- a/pkg/scheduler/framework/plugins/nodevolumelimits/csi_test.go +++ b/pkg/scheduler/framework/plugins/nodevolumelimits/csi_test.go @@ -58,8 +58,6 @@ func getVolumeLimitKey(filterType string) v1.ResourceName { return v1.ResourceName(volumeutil.GCEVolumeLimitKey) case azureDiskVolumeFilterType: return v1.ResourceName(volumeutil.AzureVolumeLimitKey) - case cinderVolumeFilterType: - return v1.ResourceName(volumeutil.CinderVolumeLimitKey) default: return v1.ResourceName(volumeutil.GetCSIAttachLimitKey(filterType)) } diff --git a/pkg/scheduler/framework/plugins/nodevolumelimits/non_csi.go b/pkg/scheduler/framework/plugins/nodevolumelimits/non_csi.go index 4a2535e5f26..32ba541cf76 100644 --- a/pkg/scheduler/framework/plugins/nodevolumelimits/non_csi.go +++ b/pkg/scheduler/framework/plugins/nodevolumelimits/non_csi.go @@ -56,8 +56,6 @@ const ( gcePDVolumeFilterType = "GCE" // azureDiskVolumeFilterType defines the filter name for azureDiskVolumeFilter. azureDiskVolumeFilterType = "AzureDisk" - // cinderVolumeFilterType defines the filter name for cinderVolumeFilter. - cinderVolumeFilterType = "Cinder" // ErrReasonMaxVolumeCountExceeded is used for MaxVolumeCount predicate error. ErrReasonMaxVolumeCountExceeded = "node(s) exceed max volume count" @@ -75,15 +73,6 @@ func NewAzureDisk(_ runtime.Object, handle framework.Handle, fts feature.Feature return newNonCSILimitsWithInformerFactory(azureDiskVolumeFilterType, informerFactory, fts), nil } -// CinderName is the name of the plugin used in the plugin registry and configurations. -const CinderName = names.CinderLimits - -// NewCinder returns function that initializes a new plugin and returns it. -func NewCinder(_ runtime.Object, handle framework.Handle, fts feature.Features) (framework.Plugin, error) { - informerFactory := handle.SharedInformerFactory() - return newNonCSILimitsWithInformerFactory(cinderVolumeFilterType, informerFactory, fts), nil -} - // EBSName is the name of the plugin used in the plugin registry and configurations. const EBSName = names.EBSLimits @@ -171,10 +160,6 @@ func newNonCSILimits( name = AzureDiskName filter = azureDiskVolumeFilter volumeLimitKey = v1.ResourceName(volumeutil.AzureVolumeLimitKey) - case cinderVolumeFilterType: - name = CinderName - filter = cinderVolumeFilter - volumeLimitKey = v1.ResourceName(volumeutil.CinderVolumeLimitKey) default: klog.ErrorS(errors.New("wrong filterName"), "Cannot create nonCSILimits plugin") return nil @@ -475,32 +460,6 @@ var azureDiskVolumeFilter = VolumeFilter{ }, } -// cinderVolumeFilter is a VolumeFilter for filtering cinder Volumes. -// It will be deprecated once Openstack cloudprovider has been removed from in-tree. -var cinderVolumeFilter = VolumeFilter{ - FilterVolume: func(vol *v1.Volume) (string, bool) { - if vol.Cinder != nil { - return vol.Cinder.VolumeID, true - } - return "", false - }, - - FilterPersistentVolume: func(pv *v1.PersistentVolume) (string, bool) { - if pv.Spec.Cinder != nil { - return pv.Spec.Cinder.VolumeID, true - } - return "", false - }, - - MatchProvisioner: func(sc *storage.StorageClass) bool { - return sc.Provisioner == csilibplugins.CinderInTreePluginName - }, - - IsMigrated: func(csiNode *storage.CSINode) bool { - return isCSIMigrationOn(csiNode, csilibplugins.CinderInTreePluginName) - }, -} - func getMaxVolumeFunc(filterName string) func(node *v1.Node) int { return func(node *v1.Node) int { maxVolumesFromEnv := getMaxVolLimitFromEnv() @@ -522,8 +481,6 @@ func getMaxVolumeFunc(filterName string) func(node *v1.Node) int { return defaultMaxGCEPDVolumes case azureDiskVolumeFilterType: return defaultMaxAzureDiskVolumes - case cinderVolumeFilterType: - return volumeutil.DefaultMaxCinderVolumes default: return -1 } diff --git a/pkg/scheduler/framework/plugins/nodevolumelimits/utils.go b/pkg/scheduler/framework/plugins/nodevolumelimits/utils.go index 79d625e17c2..2dde31ce1b6 100644 --- a/pkg/scheduler/framework/plugins/nodevolumelimits/utils.go +++ b/pkg/scheduler/framework/plugins/nodevolumelimits/utils.go @@ -55,8 +55,6 @@ func isCSIMigrationOn(csiNode *storagev1.CSINode, pluginName string) bool { if !utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAzureDisk) { return false } - case csilibplugins.CinderInTreePluginName: - return true case csilibplugins.RBDVolumePluginName: if !utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationRBD) { return false diff --git a/pkg/scheduler/framework/plugins/registry.go b/pkg/scheduler/framework/plugins/registry.go index 0f29e6ce96a..3c822536a5e 100644 --- a/pkg/scheduler/framework/plugins/registry.go +++ b/pkg/scheduler/framework/plugins/registry.go @@ -70,7 +70,6 @@ func NewInTreeRegistry() runtime.Registry { nodevolumelimits.EBSName: runtime.FactoryAdapter(fts, nodevolumelimits.NewEBS), nodevolumelimits.GCEPDName: runtime.FactoryAdapter(fts, nodevolumelimits.NewGCEPD), nodevolumelimits.AzureDiskName: runtime.FactoryAdapter(fts, nodevolumelimits.NewAzureDisk), - nodevolumelimits.CinderName: runtime.FactoryAdapter(fts, nodevolumelimits.NewCinder), interpodaffinity.Name: interpodaffinity.New, queuesort.Name: queuesort.New, defaultbinder.Name: defaultbinder.New, diff --git a/pkg/scheduler/framework/plugins/volumebinding/binder.go b/pkg/scheduler/framework/plugins/volumebinding/binder.go index 1c116431b92..0c906dcb166 100644 --- a/pkg/scheduler/framework/plugins/volumebinding/binder.go +++ b/pkg/scheduler/framework/plugins/volumebinding/binder.go @@ -1007,8 +1007,6 @@ func isCSIMigrationOnForPlugin(pluginName string) bool { return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationGCE) case csiplugins.AzureDiskInTreePluginName: return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAzureDisk) - case csiplugins.CinderInTreePluginName: - return true case csiplugins.PortworxVolumePluginName: return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationPortworx) case csiplugins.RBDVolumePluginName: diff --git a/pkg/volume/cinder/OWNERS b/pkg/volume/cinder/OWNERS deleted file mode 100644 index 798d555dfae..00000000000 --- a/pkg/volume/cinder/OWNERS +++ /dev/null @@ -1,14 +0,0 @@ -# See the OWNERS docs at https://go.k8s.io/owners - -approvers: - - jsafrane - - anguslees - - dims -reviewers: - - anguslees - - saad-ali - - jsafrane - - jingxu97 - - msau42 -emeritus_approvers: - - FengyunPan2 diff --git a/pkg/volume/cinder/attacher.go b/pkg/volume/cinder/attacher.go deleted file mode 100644 index 94d1ede0403..00000000000 --- a/pkg/volume/cinder/attacher.go +++ /dev/null @@ -1,434 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package cinder - -import ( - "context" - "fmt" - "os" - "path" - "strings" - "time" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/klog/v2" - "k8s.io/mount-utils" - - "k8s.io/kubernetes/pkg/volume" - volumeutil "k8s.io/kubernetes/pkg/volume/util" -) - -type cinderDiskAttacher struct { - host volume.VolumeHost - cinderProvider BlockStorageProvider -} - -var _ volume.Attacher = &cinderDiskAttacher{} - -var _ volume.DeviceMounter = &cinderDiskAttacher{} - -var _ volume.AttachableVolumePlugin = &cinderPlugin{} - -var _ volume.DeviceMountableVolumePlugin = &cinderPlugin{} - -const ( - probeVolumeInitDelay = 1 * time.Second - probeVolumeFactor = 2.0 - operationFinishInitDelay = 1 * time.Second - operationFinishFactor = 1.1 - operationFinishSteps = 10 - diskAttachInitDelay = 1 * time.Second - diskAttachFactor = 1.2 - diskAttachSteps = 15 - diskDetachInitDelay = 1 * time.Second - diskDetachFactor = 1.2 - diskDetachSteps = 13 -) - -func (plugin *cinderPlugin) NewAttacher() (volume.Attacher, error) { - cinder, err := plugin.getCloudProvider() - if err != nil { - return nil, err - } - return &cinderDiskAttacher{ - host: plugin.host, - cinderProvider: cinder, - }, nil -} - -func (plugin *cinderPlugin) NewDeviceMounter() (volume.DeviceMounter, error) { - return plugin.NewAttacher() -} - -func (plugin *cinderPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) { - mounter := plugin.host.GetMounter(plugin.GetPluginName()) - return mounter.GetMountRefs(deviceMountPath) -} - -func (attacher *cinderDiskAttacher) waitOperationFinished(volumeID string) error { - backoff := wait.Backoff{ - Duration: operationFinishInitDelay, - Factor: operationFinishFactor, - Steps: operationFinishSteps, - } - - var volumeStatus string - err := wait.ExponentialBackoff(backoff, func() (bool, error) { - var pending bool - var err error - pending, volumeStatus, err = attacher.cinderProvider.OperationPending(volumeID) - if err != nil { - return false, err - } - return !pending, nil - }) - - if err == wait.ErrWaitTimeout { - err = fmt.Errorf("volume %q is %s, can't finish within the alloted time", volumeID, volumeStatus) - } - - return err -} - -func (attacher *cinderDiskAttacher) waitDiskAttached(instanceID, volumeID string) error { - backoff := wait.Backoff{ - Duration: diskAttachInitDelay, - Factor: diskAttachFactor, - Steps: diskAttachSteps, - } - - err := wait.ExponentialBackoff(backoff, func() (bool, error) { - attached, err := attacher.cinderProvider.DiskIsAttached(instanceID, volumeID) - if err != nil { - return false, err - } - return attached, nil - }) - - if err == wait.ErrWaitTimeout { - err = fmt.Errorf("volume %q failed to be attached within the alloted time", volumeID) - } - - return err -} - -func (attacher *cinderDiskAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string, error) { - volumeID, _, _, err := getVolumeInfo(spec) - if err != nil { - return "", err - } - - instanceID, err := attacher.nodeInstanceID(nodeName) - if err != nil { - return "", err - } - - if err := attacher.waitOperationFinished(volumeID); err != nil { - return "", err - } - - attached, err := attacher.cinderProvider.DiskIsAttached(instanceID, volumeID) - if err != nil { - // Log error and continue with attach - klog.Warningf( - "Error checking if volume (%q) is already attached to current instance (%q). Will continue and try attach anyway. err=%v", - volumeID, instanceID, err) - } - - if err == nil && attached { - // Volume is already attached to instance. - klog.Infof("Attach operation is successful. volume %q is already attached to instance %q.", volumeID, instanceID) - } else { - _, err = attacher.cinderProvider.AttachDisk(instanceID, volumeID) - if err == nil { - if err = attacher.waitDiskAttached(instanceID, volumeID); err != nil { - klog.Errorf("Error waiting for volume %q to be attached from node %q: %v", volumeID, nodeName, err) - return "", err - } - klog.Infof("Attach operation successful: volume %q attached to instance %q.", volumeID, instanceID) - } else { - klog.Infof("Attach volume %q to instance %q failed with: %v", volumeID, instanceID, err) - return "", err - } - } - - devicePath, err := attacher.cinderProvider.GetAttachmentDiskPath(instanceID, volumeID) - if err != nil { - klog.Infof("Can not get device path of volume %q which be attached to instance %q, failed with: %v", volumeID, instanceID, err) - return "", err - } - - return devicePath, nil -} - -func (attacher *cinderDiskAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) { - volumesAttachedCheck := make(map[*volume.Spec]bool) - volumeSpecMap := make(map[string]*volume.Spec) - volumeIDList := []string{} - for _, spec := range specs { - volumeID, _, _, err := getVolumeInfo(spec) - if err != nil { - klog.Errorf("Error getting volume (%q) source : %v", spec.Name(), err) - continue - } - - volumeIDList = append(volumeIDList, volumeID) - volumesAttachedCheck[spec] = true - volumeSpecMap[volumeID] = spec - } - - attachedResult, err := attacher.cinderProvider.DisksAreAttachedByName(nodeName, volumeIDList) - if err != nil { - // Log error and continue with attach - klog.Errorf( - "Error checking if Volumes (%v) are already attached to current node (%q). Will continue and try attach anyway. err=%v", - volumeIDList, nodeName, err) - return volumesAttachedCheck, err - } - - for volumeID, attached := range attachedResult { - if !attached { - spec := volumeSpecMap[volumeID] - volumesAttachedCheck[spec] = false - klog.V(2).Infof("VolumesAreAttached: check volume %q (specName: %q) is no longer attached", volumeID, spec.Name()) - } - } - return volumesAttachedCheck, nil -} - -func (attacher *cinderDiskAttacher) WaitForAttach(spec *volume.Spec, devicePath string, _ *v1.Pod, timeout time.Duration) (string, error) { - // NOTE: devicePath is path as reported by Cinder, which may be incorrect and should not be used. See Issue #33128 - volumeID, _, _, err := getVolumeInfo(spec) - if err != nil { - return "", err - } - - if devicePath == "" { - return "", fmt.Errorf("WaitForAttach failed for Cinder disk %q: devicePath is empty", volumeID) - } - - ticker := time.NewTicker(probeVolumeInitDelay) - defer ticker.Stop() - timer := time.NewTimer(timeout) - defer timer.Stop() - - duration := probeVolumeInitDelay - for { - select { - case <-ticker.C: - klog.V(5).Infof("Checking Cinder disk %q is attached.", volumeID) - probeAttachedVolume() - if !attacher.cinderProvider.ShouldTrustDevicePath() { - // Using the Cinder volume ID, find the real device path (See Issue #33128) - devicePath = attacher.cinderProvider.GetDevicePath(volumeID) - } - exists, err := mount.PathExists(devicePath) - if exists && err == nil { - klog.Infof("Successfully found attached Cinder disk %q at %v.", volumeID, devicePath) - return devicePath, nil - } - // Log an error, and continue checking periodically - klog.Errorf("Error: could not find attached Cinder disk %q (path: %q): %v", volumeID, devicePath, err) - // Using exponential backoff instead of linear - ticker.Stop() - duration = time.Duration(float64(duration) * probeVolumeFactor) - ticker = time.NewTicker(duration) - case <-timer.C: - return "", fmt.Errorf("could not find attached Cinder disk %q. Timeout waiting for mount paths to be created", volumeID) - } - } -} - -func (attacher *cinderDiskAttacher) GetDeviceMountPath( - spec *volume.Spec) (string, error) { - volumeID, _, _, err := getVolumeInfo(spec) - if err != nil { - return "", err - } - - return makeGlobalPDName(attacher.host, volumeID), nil -} - -// FIXME: this method can be further pruned. -func (attacher *cinderDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string, _ volume.DeviceMounterArgs) error { - mounter := attacher.host.GetMounter(cinderVolumePluginName) - notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) - if err != nil { - if os.IsNotExist(err) { - if err := os.MkdirAll(deviceMountPath, 0750); err != nil { - return err - } - notMnt = true - } else { - return err - } - } - - _, volumeFSType, readOnly, err := getVolumeInfo(spec) - if err != nil { - return err - } - - options := []string{} - if readOnly { - options = append(options, "ro") - } - if notMnt { - diskMounter := volumeutil.NewSafeFormatAndMountFromHost(cinderVolumePluginName, attacher.host) - mountOptions := volumeutil.MountOptionFromSpec(spec, options...) - err = diskMounter.FormatAndMount(devicePath, deviceMountPath, volumeFSType, mountOptions) - if err != nil { - os.Remove(deviceMountPath) - return err - } - } - return nil -} - -type cinderDiskDetacher struct { - mounter mount.Interface - cinderProvider BlockStorageProvider -} - -var _ volume.Detacher = &cinderDiskDetacher{} - -var _ volume.DeviceUnmounter = &cinderDiskDetacher{} - -func (plugin *cinderPlugin) NewDetacher() (volume.Detacher, error) { - cinder, err := plugin.getCloudProvider() - if err != nil { - return nil, err - } - return &cinderDiskDetacher{ - mounter: plugin.host.GetMounter(plugin.GetPluginName()), - cinderProvider: cinder, - }, nil -} - -func (plugin *cinderPlugin) NewDeviceUnmounter() (volume.DeviceUnmounter, error) { - return plugin.NewDetacher() -} - -func (detacher *cinderDiskDetacher) waitOperationFinished(volumeID string) error { - backoff := wait.Backoff{ - Duration: operationFinishInitDelay, - Factor: operationFinishFactor, - Steps: operationFinishSteps, - } - - var volumeStatus string - err := wait.ExponentialBackoff(backoff, func() (bool, error) { - var pending bool - var err error - pending, volumeStatus, err = detacher.cinderProvider.OperationPending(volumeID) - if err != nil { - return false, err - } - return !pending, nil - }) - - if err == wait.ErrWaitTimeout { - err = fmt.Errorf("volume %q is %s, can't finish within the alloted time", volumeID, volumeStatus) - } - - return err -} - -func (detacher *cinderDiskDetacher) waitDiskDetached(instanceID, volumeID string) error { - backoff := wait.Backoff{ - Duration: diskDetachInitDelay, - Factor: diskDetachFactor, - Steps: diskDetachSteps, - } - - err := wait.ExponentialBackoff(backoff, func() (bool, error) { - attached, err := detacher.cinderProvider.DiskIsAttached(instanceID, volumeID) - if err != nil { - return false, err - } - return !attached, nil - }) - - if err == wait.ErrWaitTimeout { - err = fmt.Errorf("volume %q failed to detach within the alloted time", volumeID) - } - - return err -} - -func (detacher *cinderDiskDetacher) Detach(volumeName string, nodeName types.NodeName) error { - volumeID := path.Base(volumeName) - if err := detacher.waitOperationFinished(volumeID); err != nil { - return err - } - attached, instanceID, err := detacher.cinderProvider.DiskIsAttachedByName(nodeName, volumeID) - if err != nil { - // Log error and continue with detach - klog.Errorf( - "Error checking if volume (%q) is already attached to current node (%q). Will continue and try detach anyway. err=%v", - volumeID, nodeName, err) - } - - if err == nil && !attached { - // Volume is already detached from node. - klog.Infof("detach operation was successful. volume %q is already detached from node %q.", volumeID, nodeName) - return nil - } - - if err = detacher.cinderProvider.DetachDisk(instanceID, volumeID); err != nil { - klog.Errorf("Error detaching volume %q from node %q: %v", volumeID, nodeName, err) - return err - } - if err = detacher.waitDiskDetached(instanceID, volumeID); err != nil { - klog.Errorf("Error waiting for volume %q to detach from node %q: %v", volumeID, nodeName, err) - return err - } - klog.Infof("detached volume %q from node %q", volumeID, nodeName) - return nil -} - -func (detacher *cinderDiskDetacher) UnmountDevice(deviceMountPath string) error { - return mount.CleanupMountPoint(deviceMountPath, detacher.mounter, false) -} - -func (plugin *cinderPlugin) CanAttach(spec *volume.Spec) (bool, error) { - return true, nil -} - -func (plugin *cinderPlugin) CanDeviceMount(spec *volume.Spec) (bool, error) { - return true, nil -} - -func (attacher *cinderDiskAttacher) nodeInstanceID(nodeName types.NodeName) (string, error) { - instances, res := attacher.cinderProvider.Instances() - if !res { - return "", fmt.Errorf("failed to list openstack instances") - } - instanceID, err := instances.InstanceID(context.TODO(), nodeName) - if err != nil { - return "", err - } - if ind := strings.LastIndex(instanceID, "/"); ind >= 0 { - instanceID = instanceID[(ind + 1):] - } - return instanceID, nil -} diff --git a/pkg/volume/cinder/attacher_test.go b/pkg/volume/cinder/attacher_test.go deleted file mode 100644 index f5b3ab0ec5e..00000000000 --- a/pkg/volume/cinder/attacher_test.go +++ /dev/null @@ -1,758 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package cinder - -import ( - "context" - "errors" - "os" - "path/filepath" - "reflect" - "testing" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" - cloudprovider "k8s.io/cloud-provider" - "k8s.io/kubernetes/pkg/volume" - volumetest "k8s.io/kubernetes/pkg/volume/testing" - - "fmt" - "sort" - - "k8s.io/apimachinery/pkg/types" - "k8s.io/klog/v2" -) - -const ( - VolumeStatusPending = "pending" - VolumeStatusDone = "done" -) - -var attachStatus = "Attach" -var detachStatus = "Detach" - -func TestGetDeviceName_Volume(t *testing.T) { - plugin := newPlugin(t) - name := "my-cinder-volume" - spec := createVolSpec(name, false) - - deviceName, err := plugin.GetVolumeName(spec) - if err != nil { - t.Errorf("GetDeviceName error: %v", err) - } - if deviceName != name { - t.Errorf("GetDeviceName error: expected %s, got %s", name, deviceName) - } -} - -func TestGetDeviceName_PersistentVolume(t *testing.T) { - plugin := newPlugin(t) - name := "my-cinder-pv" - spec := createPVSpec(name, true) - - deviceName, err := plugin.GetVolumeName(spec) - if err != nil { - t.Errorf("GetDeviceName error: %v", err) - } - if deviceName != name { - t.Errorf("GetDeviceName error: expected %s, got %s", name, deviceName) - } -} - -func TestGetDeviceMountPath(t *testing.T) { - name := "cinder-volume-id" - spec := createVolSpec(name, false) - rootDir := "/var/lib/kubelet/" - host := volumetest.NewFakeVolumeHost(t, rootDir, nil, nil) - - attacher := &cinderDiskAttacher{ - host: host, - } - - //test the path - path, err := attacher.GetDeviceMountPath(spec) - if err != nil { - t.Errorf("Get device mount path error") - } - expectedPath := filepath.Join(rootDir, "plugins/kubernetes.io/cinder/mounts", name) - if path != expectedPath { - t.Errorf("Device mount path error: expected %s, got %s ", expectedPath, path) - } -} - -// One testcase for TestAttachDetach table test below -type testcase struct { - name string - // For fake GCE: - attach attachCall - detach detachCall - operationPending operationPendingCall - diskIsAttached diskIsAttachedCall - disksAreAttached disksAreAttachedCall - diskPath diskPathCall - t *testing.T - attachOrDetach *string - - instanceID string - // Actual test to run - test func(test *testcase) (string, error) - // Expected return of the test - expectedResult string - expectedError error -} - -func TestAttachDetach(t *testing.T) { - volumeID := "disk" - instanceID := "instance" - pending := VolumeStatusPending - done := VolumeStatusDone - nodeName := types.NodeName("nodeName") - readOnly := false - spec := createVolSpec(volumeID, readOnly) - attachError := errors.New("fake attach error") - detachError := errors.New("fake detach error") - diskCheckError := errors.New("fake DiskIsAttached error") - diskPathError := errors.New("fake GetAttachmentDiskPath error") - disksCheckError := errors.New("fake DisksAreAttached error") - operationFinishTimeout := errors.New("fake waitOperationFinished error") - tests := []testcase{ - // Successful Attach call - { - name: "Attach_Positive", - instanceID: instanceID, - operationPending: operationPendingCall{volumeID, false, done, nil}, - diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, nil}, - attach: attachCall{instanceID, volumeID, "", nil}, - diskPath: diskPathCall{instanceID, volumeID, "/dev/sda", nil}, - test: func(testcase *testcase) (string, error) { - attacher := newAttacher(testcase) - return attacher.Attach(spec, nodeName) - }, - expectedResult: "/dev/sda", - }, - - // Disk is already attached - { - name: "Attach_Positive_AlreadyAttached", - instanceID: instanceID, - operationPending: operationPendingCall{volumeID, false, done, nil}, - diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, true, nil}, - diskPath: diskPathCall{instanceID, volumeID, "/dev/sda", nil}, - test: func(testcase *testcase) (string, error) { - attacher := newAttacher(testcase) - return attacher.Attach(spec, nodeName) - }, - expectedResult: "/dev/sda", - }, - - // Disk is attaching - { - name: "Attach_is_attaching", - instanceID: instanceID, - operationPending: operationPendingCall{volumeID, true, pending, operationFinishTimeout}, - test: func(testcase *testcase) (string, error) { - attacher := newAttacher(testcase) - return attacher.Attach(spec, nodeName) - }, - expectedError: operationFinishTimeout, - }, - - // Attach call fails - { - name: "Attach_Negative", - instanceID: instanceID, - operationPending: operationPendingCall{volumeID, false, done, nil}, - diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, diskCheckError}, - attach: attachCall{instanceID, volumeID, "/dev/sda", attachError}, - test: func(testcase *testcase) (string, error) { - attacher := newAttacher(testcase) - return attacher.Attach(spec, nodeName) - }, - expectedError: attachError, - }, - - // GetAttachmentDiskPath call fails - { - name: "Attach_Negative_DiskPatchFails", - instanceID: instanceID, - operationPending: operationPendingCall{volumeID, false, done, nil}, - diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, nil}, - attach: attachCall{instanceID, volumeID, "", nil}, - diskPath: diskPathCall{instanceID, volumeID, "", diskPathError}, - test: func(testcase *testcase) (string, error) { - attacher := newAttacher(testcase) - return attacher.Attach(spec, nodeName) - }, - expectedError: diskPathError, - }, - - // Successful VolumesAreAttached call, attached - { - name: "VolumesAreAttached_Positive", - instanceID: instanceID, - disksAreAttached: disksAreAttachedCall{instanceID, nodeName, []string{volumeID}, map[string]bool{volumeID: true}, nil}, - test: func(testcase *testcase) (string, error) { - attacher := newAttacher(testcase) - attachments, err := attacher.VolumesAreAttached([]*volume.Spec{spec}, nodeName) - return serializeAttachments(attachments), err - }, - expectedResult: serializeAttachments(map[*volume.Spec]bool{spec: true}), - }, - - // Successful VolumesAreAttached call, not attached - { - name: "VolumesAreAttached_Negative", - instanceID: instanceID, - disksAreAttached: disksAreAttachedCall{instanceID, nodeName, []string{volumeID}, map[string]bool{volumeID: false}, nil}, - test: func(testcase *testcase) (string, error) { - attacher := newAttacher(testcase) - attachments, err := attacher.VolumesAreAttached([]*volume.Spec{spec}, nodeName) - return serializeAttachments(attachments), err - }, - expectedResult: serializeAttachments(map[*volume.Spec]bool{spec: false}), - }, - - // Treat as attached when DisksAreAttached call fails - { - name: "VolumesAreAttached_CinderFailed", - instanceID: instanceID, - disksAreAttached: disksAreAttachedCall{instanceID, nodeName, []string{volumeID}, nil, disksCheckError}, - test: func(testcase *testcase) (string, error) { - attacher := newAttacher(testcase) - attachments, err := attacher.VolumesAreAttached([]*volume.Spec{spec}, nodeName) - return serializeAttachments(attachments), err - }, - expectedResult: serializeAttachments(map[*volume.Spec]bool{spec: true}), - expectedError: disksCheckError, - }, - - // Detach succeeds - { - name: "Detach_Positive", - instanceID: instanceID, - operationPending: operationPendingCall{volumeID, false, done, nil}, - diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, true, nil}, - detach: detachCall{instanceID, volumeID, nil}, - test: func(testcase *testcase) (string, error) { - detacher := newDetacher(testcase) - return "", detacher.Detach(volumeID, nodeName) - }, - }, - - // Disk is already detached - { - name: "Detach_Positive_AlreadyDetached", - instanceID: instanceID, - operationPending: operationPendingCall{volumeID, false, done, nil}, - diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, nil}, - test: func(testcase *testcase) (string, error) { - detacher := newDetacher(testcase) - return "", detacher.Detach(volumeID, nodeName) - }, - }, - - // Detach succeeds when DiskIsAttached fails - { - name: "Detach_Positive_CheckFails", - instanceID: instanceID, - operationPending: operationPendingCall{volumeID, false, done, nil}, - diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, diskCheckError}, - detach: detachCall{instanceID, volumeID, nil}, - test: func(testcase *testcase) (string, error) { - detacher := newDetacher(testcase) - return "", detacher.Detach(volumeID, nodeName) - }, - }, - - // Detach fails - { - name: "Detach_Negative", - instanceID: instanceID, - operationPending: operationPendingCall{volumeID, false, done, nil}, - diskIsAttached: diskIsAttachedCall{instanceID, nodeName, volumeID, false, diskCheckError}, - detach: detachCall{instanceID, volumeID, detachError}, - test: func(testcase *testcase) (string, error) { - detacher := newDetacher(testcase) - return "", detacher.Detach(volumeID, nodeName) - }, - expectedError: detachError, - }, - - // // Disk is detaching - { - name: "Detach_Is_Detaching", - instanceID: instanceID, - operationPending: operationPendingCall{volumeID, true, pending, operationFinishTimeout}, - test: func(testcase *testcase) (string, error) { - detacher := newDetacher(testcase) - return "", detacher.Detach(volumeID, nodeName) - }, - expectedError: operationFinishTimeout, - }, - } - - for _, testcase := range tests { - testcase.t = t - attachOrDetach := "" - testcase.attachOrDetach = &attachOrDetach - result, err := testcase.test(&testcase) - if err != testcase.expectedError { - t.Errorf("%s failed: expected err=%q, got %q", testcase.name, testcase.expectedError, err) - } - if result != testcase.expectedResult { - t.Errorf("%s failed: expected result=%q, got %q", testcase.name, testcase.expectedResult, result) - } - } -} - -type volumeAttachmentFlag struct { - volumeID string - attached bool -} - -type volumeAttachmentFlags []volumeAttachmentFlag - -func (va volumeAttachmentFlags) Len() int { - return len(va) -} - -func (va volumeAttachmentFlags) Swap(i, j int) { - va[i], va[j] = va[j], va[i] -} - -func (va volumeAttachmentFlags) Less(i, j int) bool { - if va[i].volumeID < va[j].volumeID { - return true - } - if va[i].volumeID > va[j].volumeID { - return false - } - return va[j].attached -} - -func serializeAttachments(attachments map[*volume.Spec]bool) string { - var attachmentFlags volumeAttachmentFlags - for spec, attached := range attachments { - attachmentFlags = append(attachmentFlags, volumeAttachmentFlag{spec.Name(), attached}) - } - sort.Sort(attachmentFlags) - return fmt.Sprint(attachmentFlags) -} - -// newPlugin creates a new gcePersistentDiskPlugin with fake cloud, NewAttacher -// and NewDetacher won't work. -func newPlugin(t *testing.T) *cinderPlugin { - host := volumetest.NewFakeVolumeHost(t, os.TempDir(), nil, nil) - plugins := ProbeVolumePlugins() - plugin := plugins[0] - plugin.Init(host) - return plugin.(*cinderPlugin) -} - -func newAttacher(testcase *testcase) *cinderDiskAttacher { - return &cinderDiskAttacher{ - host: nil, - cinderProvider: testcase, - } -} - -func newDetacher(testcase *testcase) *cinderDiskDetacher { - return &cinderDiskDetacher{ - cinderProvider: testcase, - } -} - -func createVolSpec(name string, readOnly bool) *volume.Spec { - return &volume.Spec{ - Volume: &v1.Volume{ - Name: name, - VolumeSource: v1.VolumeSource{ - Cinder: &v1.CinderVolumeSource{ - VolumeID: name, - ReadOnly: readOnly, - }, - }, - }, - } -} - -func createPVSpec(name string, readOnly bool) *volume.Spec { - return &volume.Spec{ - PersistentVolume: &v1.PersistentVolume{ - Spec: v1.PersistentVolumeSpec{ - PersistentVolumeSource: v1.PersistentVolumeSource{ - Cinder: &v1.CinderPersistentVolumeSource{ - VolumeID: name, - ReadOnly: readOnly, - }, - }, - }, - }, - } -} - -// Fake GCE implementation - -type attachCall struct { - instanceID string - volumeID string - retDeviceName string - ret error -} - -type detachCall struct { - instanceID string - devicePath string - ret error -} - -type operationPendingCall struct { - diskName string - pending bool - volumeStatus string - ret error -} - -type diskIsAttachedCall struct { - instanceID string - nodeName types.NodeName - volumeID string - isAttached bool - ret error -} - -type diskPathCall struct { - instanceID string - volumeID string - retPath string - ret error -} - -type disksAreAttachedCall struct { - instanceID string - nodeName types.NodeName - volumeIDs []string - areAttached map[string]bool - ret error -} - -func (testcase *testcase) AttachDisk(instanceID, volumeID string) (string, error) { - expected := &testcase.attach - - if expected.volumeID == "" && expected.instanceID == "" { - // testcase.attach looks uninitialized, test did not expect to call - // AttachDisk - testcase.t.Errorf("unexpected AttachDisk call") - return "", errors.New("unexpected AttachDisk call") - } - - if expected.volumeID != volumeID { - testcase.t.Errorf("unexpected AttachDisk call: expected volumeID %s, got %s", expected.volumeID, volumeID) - return "", errors.New("unexpected AttachDisk call: wrong volumeID") - } - - if expected.instanceID != instanceID { - testcase.t.Errorf("unexpected AttachDisk call: expected instanceID %s, got %s", expected.instanceID, instanceID) - return "", errors.New("unexpected AttachDisk call: wrong instanceID") - } - - klog.V(4).Infof("AttachDisk call: %s, %s, returning %q, %v", volumeID, instanceID, expected.retDeviceName, expected.ret) - - testcase.attachOrDetach = &attachStatus - return expected.retDeviceName, expected.ret -} - -func (testcase *testcase) DetachDisk(instanceID, volumeID string) error { - expected := &testcase.detach - - if expected.devicePath == "" && expected.instanceID == "" { - // testcase.detach looks uninitialized, test did not expect to call - // DetachDisk - testcase.t.Errorf("unexpected DetachDisk call") - return errors.New("unexpected DetachDisk call") - } - - if expected.devicePath != volumeID { - testcase.t.Errorf("unexpected DetachDisk call: expected volumeID %s, got %s", expected.devicePath, volumeID) - return errors.New("unexpected DetachDisk call: wrong volumeID") - } - - if expected.instanceID != instanceID { - testcase.t.Errorf("unexpected DetachDisk call: expected instanceID %s, got %s", expected.instanceID, instanceID) - return errors.New("unexpected DetachDisk call: wrong instanceID") - } - - klog.V(4).Infof("DetachDisk call: %s, %s, returning %v", volumeID, instanceID, expected.ret) - - testcase.attachOrDetach = &detachStatus - return expected.ret -} - -func (testcase *testcase) OperationPending(diskName string) (bool, string, error) { - expected := &testcase.operationPending - - if expected.volumeStatus == VolumeStatusPending { - klog.V(4).Infof("OperationPending call: %s, returning %v, %v, %v", diskName, expected.pending, expected.volumeStatus, expected.ret) - return true, expected.volumeStatus, expected.ret - } - - klog.V(4).Infof("OperationPending call: %s, returning %v, %v, %v", diskName, expected.pending, expected.volumeStatus, expected.ret) - - return false, expected.volumeStatus, expected.ret -} - -func (testcase *testcase) DiskIsAttached(instanceID, volumeID string) (bool, error) { - expected := &testcase.diskIsAttached - // If testcase call DetachDisk*, return false - if *testcase.attachOrDetach == detachStatus { - return false, nil - } - - // If testcase call AttachDisk*, return true - if *testcase.attachOrDetach == attachStatus { - return true, nil - } - - if expected.volumeID == "" && expected.instanceID == "" { - // testcase.diskIsAttached looks uninitialized, test did not expect to - // call DiskIsAttached - testcase.t.Errorf("unexpected DiskIsAttached call") - return false, errors.New("unexpected DiskIsAttached call") - } - - if expected.volumeID != volumeID { - testcase.t.Errorf("unexpected DiskIsAttached call: expected volumeID %s, got %s", expected.volumeID, volumeID) - return false, errors.New("unexpected DiskIsAttached call: wrong volumeID") - } - - if expected.instanceID != instanceID { - testcase.t.Errorf("unexpected DiskIsAttached call: expected instanceID %s, got %s", expected.instanceID, instanceID) - return false, errors.New("unexpected DiskIsAttached call: wrong instanceID") - } - - klog.V(4).Infof("DiskIsAttached call: %s, %s, returning %v, %v", volumeID, instanceID, expected.isAttached, expected.ret) - - return expected.isAttached, expected.ret -} - -func (testcase *testcase) GetAttachmentDiskPath(instanceID, volumeID string) (string, error) { - expected := &testcase.diskPath - if expected.volumeID == "" && expected.instanceID == "" { - // testcase.diskPath looks uninitialized, test did not expect to - // call GetAttachmentDiskPath - testcase.t.Errorf("unexpected GetAttachmentDiskPath call") - return "", errors.New("unexpected GetAttachmentDiskPath call") - } - - if expected.volumeID != volumeID { - testcase.t.Errorf("unexpected GetAttachmentDiskPath call: expected volumeID %s, got %s", expected.volumeID, volumeID) - return "", errors.New("unexpected GetAttachmentDiskPath call: wrong volumeID") - } - - if expected.instanceID != instanceID { - testcase.t.Errorf("unexpected GetAttachmentDiskPath call: expected instanceID %s, got %s", expected.instanceID, instanceID) - return "", errors.New("unexpected GetAttachmentDiskPath call: wrong instanceID") - } - - klog.V(4).Infof("GetAttachmentDiskPath call: %s, %s, returning %v, %v", volumeID, instanceID, expected.retPath, expected.ret) - - return expected.retPath, expected.ret -} - -func (testcase *testcase) ShouldTrustDevicePath() bool { - return true -} - -func (testcase *testcase) DiskIsAttachedByName(nodeName types.NodeName, volumeID string) (bool, string, error) { - expected := &testcase.diskIsAttached - instanceID := expected.instanceID - // If testcase call DetachDisk*, return false - if *testcase.attachOrDetach == detachStatus { - return false, instanceID, nil - } - - // If testcase call AttachDisk*, return true - if *testcase.attachOrDetach == attachStatus { - return true, instanceID, nil - } - - if expected.nodeName != nodeName { - testcase.t.Errorf("unexpected DiskIsAttachedByName call: expected nodename %s, got %s", expected.nodeName, nodeName) - return false, instanceID, errors.New("unexpected DiskIsAttachedByName call: wrong nodename") - } - - if expected.volumeID == "" && expected.instanceID == "" { - // testcase.diskIsAttached looks uninitialized, test did not expect to - // call DiskIsAttached - testcase.t.Errorf("unexpected DiskIsAttachedByName call") - return false, instanceID, errors.New("unexpected DiskIsAttachedByName call") - } - - if expected.volumeID != volumeID { - testcase.t.Errorf("unexpected DiskIsAttachedByName call: expected volumeID %s, got %s", expected.volumeID, volumeID) - return false, instanceID, errors.New("unexpected DiskIsAttachedByName call: wrong volumeID") - } - - if expected.instanceID != instanceID { - testcase.t.Errorf("unexpected DiskIsAttachedByName call: expected instanceID %s, got %s", expected.instanceID, instanceID) - return false, instanceID, errors.New("unexpected DiskIsAttachedByName call: wrong instanceID") - } - - klog.V(4).Infof("DiskIsAttachedByName call: %s, %s, returning %v, %v, %v", volumeID, nodeName, expected.isAttached, expected.instanceID, expected.ret) - - return expected.isAttached, expected.instanceID, expected.ret -} - -func (testcase *testcase) CreateVolume(name string, size int, vtype, availability string, tags *map[string]string) (string, string, string, bool, error) { - return "", "", "", false, errors.New("not implemented") -} - -func (testcase *testcase) GetDevicePath(volumeID string) string { - return "" -} - -func (testcase *testcase) InstanceID() (string, error) { - return testcase.instanceID, nil -} - -func (testcase *testcase) ExpandVolume(volumeID string, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) { - return resource.Quantity{}, nil -} - -func (testcase *testcase) DeleteVolume(volumeID string) error { - return errors.New("not implemented") -} - -func (testcase *testcase) GetAutoLabelsForPD(name string) (map[string]string, error) { - return map[string]string{}, errors.New("not implemented") -} - -func (testcase *testcase) Instances() (cloudprovider.Instances, bool) { - return &instances{testcase.instanceID}, true -} - -func (testcase *testcase) InstancesV2() (cloudprovider.InstancesV2, bool) { - return nil, false -} - -func (testcase *testcase) DisksAreAttached(instanceID string, volumeIDs []string) (map[string]bool, error) { - expected := &testcase.disksAreAttached - - areAttached := make(map[string]bool) - - if len(expected.volumeIDs) == 0 && expected.instanceID == "" { - // testcase.volumeIDs looks uninitialized, test did not expect to call DisksAreAttached - testcase.t.Errorf("Unexpected DisksAreAttached call!") - return areAttached, errors.New("unexpected DisksAreAttached call") - } - - if !reflect.DeepEqual(expected.volumeIDs, volumeIDs) { - testcase.t.Errorf("Unexpected DisksAreAttached call: expected volumeIDs %v, got %v", expected.volumeIDs, volumeIDs) - return areAttached, errors.New("unexpected DisksAreAttached call: wrong volumeID") - } - - if expected.instanceID != instanceID { - testcase.t.Errorf("Unexpected DisksAreAttached call: expected instanceID %s, got %s", expected.instanceID, instanceID) - return areAttached, errors.New("unexpected DisksAreAttached call: wrong instanceID") - } - - klog.V(4).Infof("DisksAreAttached call: %v, %s, returning %v, %v", volumeIDs, instanceID, expected.areAttached, expected.ret) - - return expected.areAttached, expected.ret -} - -func (testcase *testcase) DisksAreAttachedByName(nodeName types.NodeName, volumeIDs []string) (map[string]bool, error) { - expected := &testcase.disksAreAttached - areAttached := make(map[string]bool) - - instanceID := expected.instanceID - if expected.nodeName != nodeName { - testcase.t.Errorf("Unexpected DisksAreAttachedByName call: expected nodeName %s, got %s", expected.nodeName, nodeName) - return areAttached, errors.New("unexpected DisksAreAttachedByName call: wrong nodename") - } - if len(expected.volumeIDs) == 0 && expected.instanceID == "" { - // testcase.volumeIDs looks uninitialized, test did not expect to call DisksAreAttached - testcase.t.Errorf("Unexpected DisksAreAttachedByName call!") - return areAttached, errors.New("unexpected DisksAreAttachedByName call") - } - - if !reflect.DeepEqual(expected.volumeIDs, volumeIDs) { - testcase.t.Errorf("Unexpected DisksAreAttachedByName call: expected volumeIDs %v, got %v", expected.volumeIDs, volumeIDs) - return areAttached, errors.New("unexpected DisksAreAttachedByName call: wrong volumeID") - } - - if expected.instanceID != instanceID { - testcase.t.Errorf("Unexpected DisksAreAttachedByName call: expected instanceID %s, got %s", expected.instanceID, instanceID) - return areAttached, errors.New("unexpected DisksAreAttachedByName call: wrong instanceID") - } - - klog.V(4).Infof("DisksAreAttachedByName call: %v, %s, returning %v, %v", volumeIDs, nodeName, expected.areAttached, expected.ret) - - return expected.areAttached, expected.ret -} - -// Implementation of fake cloudprovider.Instances -type instances struct { - instanceID string -} - -func (instances *instances) NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.NodeAddress, error) { - return []v1.NodeAddress{}, errors.New("not implemented") -} - -func (instances *instances) NodeAddressesByProviderID(ctx context.Context, providerID string) ([]v1.NodeAddress, error) { - return []v1.NodeAddress{}, errors.New("not implemented") -} - -func (instances *instances) InstanceID(ctx context.Context, name types.NodeName) (string, error) { - return instances.instanceID, nil -} - -func (instances *instances) InstanceType(ctx context.Context, name types.NodeName) (string, error) { - return "", errors.New("not implemented") -} - -func (instances *instances) InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error) { - return "", errors.New("not implemented") -} - -func (instances *instances) InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) { - return false, errors.New("unimplemented") -} - -func (instances *instances) InstanceShutdownByProviderID(ctx context.Context, providerID string) (bool, error) { - return false, errors.New("unimplemented") -} - -func (instances *instances) InstanceMetadataByProviderID(ctx context.Context, providerID string) (*cloudprovider.InstanceMetadata, error) { - return nil, errors.New("unimplemented") -} - -func (instances *instances) List(filter string) ([]types.NodeName, error) { - return []types.NodeName{}, errors.New("not implemented") -} - -func (instances *instances) AddSSHKeyToAllInstances(ctx context.Context, user string, keyData []byte) error { - return cloudprovider.NotImplemented -} - -func (instances *instances) CurrentNodeName(ctx context.Context, hostname string) (types.NodeName, error) { - return "", errors.New("not implemented") -} diff --git a/pkg/volume/cinder/cinder.go b/pkg/volume/cinder/cinder.go deleted file mode 100644 index ef422e24c5c..00000000000 --- a/pkg/volume/cinder/cinder.go +++ /dev/null @@ -1,635 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2015 The Kubernetes Authors. - -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. -*/ - -package cinder - -import ( - "errors" - "fmt" - "os" - "path" - "path/filepath" - - "k8s.io/klog/v2" - "k8s.io/mount-utils" - "k8s.io/utils/keymutex" - utilstrings "k8s.io/utils/strings" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - cloudprovider "k8s.io/cloud-provider" - "k8s.io/kubernetes/pkg/volume" - "k8s.io/kubernetes/pkg/volume/util" - "k8s.io/legacy-cloud-providers/openstack" -) - -const ( - // DefaultCloudConfigPath is the default path for cloud configuration - DefaultCloudConfigPath = "/etc/kubernetes/cloud-config" -) - -// ProbeVolumePlugins is the primary entrypoint for volume plugins. -func ProbeVolumePlugins() []volume.VolumePlugin { - return []volume.VolumePlugin{&cinderPlugin{}} -} - -// BlockStorageProvider is the interface for accessing cinder functionality. -type BlockStorageProvider interface { - AttachDisk(instanceID, volumeID string) (string, error) - DetachDisk(instanceID, volumeID string) error - DeleteVolume(volumeID string) error - CreateVolume(name string, size int, vtype, availability string, tags *map[string]string) (string, string, string, bool, error) - GetDevicePath(volumeID string) string - InstanceID() (string, error) - GetAttachmentDiskPath(instanceID, volumeID string) (string, error) - OperationPending(diskName string) (bool, string, error) - DiskIsAttached(instanceID, volumeID string) (bool, error) - DiskIsAttachedByName(nodeName types.NodeName, volumeID string) (bool, string, error) - DisksAreAttachedByName(nodeName types.NodeName, volumeIDs []string) (map[string]bool, error) - ShouldTrustDevicePath() bool - Instances() (cloudprovider.Instances, bool) - ExpandVolume(volumeID string, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) -} - -type cinderPlugin struct { - host volume.VolumeHost - // Guarding SetUp and TearDown operations - volumeLocks keymutex.KeyMutex -} - -var _ volume.VolumePlugin = &cinderPlugin{} -var _ volume.PersistentVolumePlugin = &cinderPlugin{} -var _ volume.DeletableVolumePlugin = &cinderPlugin{} -var _ volume.ProvisionableVolumePlugin = &cinderPlugin{} - -const ( - cinderVolumePluginName = "kubernetes.io/cinder" -) - -func getPath(uid types.UID, volName string, host volume.VolumeHost) string { - return host.GetPodVolumeDir(uid, utilstrings.EscapeQualifiedName(cinderVolumePluginName), volName) -} - -func (plugin *cinderPlugin) Init(host volume.VolumeHost) error { - plugin.host = host - plugin.volumeLocks = keymutex.NewHashed(0) - return nil -} - -func (plugin *cinderPlugin) GetPluginName() string { - return cinderVolumePluginName -} - -func (plugin *cinderPlugin) GetVolumeName(spec *volume.Spec) (string, error) { - volumeID, _, _, err := getVolumeInfo(spec) - if err != nil { - return "", err - } - - return volumeID, nil -} - -func (plugin *cinderPlugin) CanSupport(spec *volume.Spec) bool { - return (spec.Volume != nil && spec.Volume.Cinder != nil) || (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.Cinder != nil) -} - -func (plugin *cinderPlugin) RequiresRemount(spec *volume.Spec) bool { - return false -} - -func (plugin *cinderPlugin) SupportsMountOption() bool { - return true - -} -func (plugin *cinderPlugin) SupportsBulkVolumeVerification() bool { - return false -} - -func (plugin *cinderPlugin) SupportsSELinuxContextMount(spec *volume.Spec) (bool, error) { - return false, nil -} - -var _ volume.VolumePluginWithAttachLimits = &cinderPlugin{} - -func (plugin *cinderPlugin) GetVolumeLimits() (map[string]int64, error) { - volumeLimits := map[string]int64{ - util.CinderVolumeLimitKey: util.DefaultMaxCinderVolumes, - } - cloud := plugin.host.GetCloudProvider() - - // if we can't fetch cloudprovider we return an error - // hoping external CCM or admin can set it. Returning - // default values from here will mean, no one can - // override them. - if cloud == nil { - return nil, fmt.Errorf("no cloudprovider present") - } - - if cloud.ProviderName() != openstack.ProviderName { - return nil, fmt.Errorf("expected Openstack cloud, found %s", cloud.ProviderName()) - } - - openstackCloud, ok := cloud.(*openstack.OpenStack) - if ok && openstackCloud.NodeVolumeAttachLimit() > 0 { - volumeLimits[util.CinderVolumeLimitKey] = int64(openstackCloud.NodeVolumeAttachLimit()) - } - - return volumeLimits, nil -} - -func (plugin *cinderPlugin) VolumeLimitKey(spec *volume.Spec) string { - return util.CinderVolumeLimitKey -} - -func (plugin *cinderPlugin) GetAccessModes() []v1.PersistentVolumeAccessMode { - return []v1.PersistentVolumeAccessMode{ - v1.ReadWriteOnce, - } -} - -func (plugin *cinderPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) { - return plugin.newMounterInternal(spec, pod.UID, &DiskUtil{}, plugin.host.GetMounter(plugin.GetPluginName())) -} - -func (plugin *cinderPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager cdManager, mounter mount.Interface) (volume.Mounter, error) { - pdName, fsType, readOnly, err := getVolumeInfo(spec) - if err != nil { - return nil, err - } - - return &cinderVolumeMounter{ - cinderVolume: &cinderVolume{ - podUID: podUID, - volName: spec.Name(), - pdName: pdName, - mounter: mounter, - manager: manager, - plugin: plugin, - MetricsProvider: volume.NewMetricsStatFS(getPath(podUID, spec.Name(), plugin.host)), - }, - fsType: fsType, - readOnly: readOnly, - blockDeviceMounter: util.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host), - mountOptions: util.MountOptionFromSpec(spec), - }, nil -} - -func (plugin *cinderPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) { - return plugin.newUnmounterInternal(volName, podUID, &DiskUtil{}, plugin.host.GetMounter(plugin.GetPluginName())) -} - -func (plugin *cinderPlugin) newUnmounterInternal(volName string, podUID types.UID, manager cdManager, mounter mount.Interface) (volume.Unmounter, error) { - return &cinderVolumeUnmounter{ - &cinderVolume{ - podUID: podUID, - volName: volName, - manager: manager, - mounter: mounter, - plugin: plugin, - MetricsProvider: volume.NewMetricsStatFS(getPath(podUID, volName, plugin.host)), - }}, nil -} - -func (plugin *cinderPlugin) NewDeleter(spec *volume.Spec) (volume.Deleter, error) { - return plugin.newDeleterInternal(spec, &DiskUtil{}) -} - -func (plugin *cinderPlugin) newDeleterInternal(spec *volume.Spec, manager cdManager) (volume.Deleter, error) { - if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.Cinder == nil { - return nil, fmt.Errorf("spec.PersistentVolumeSource.Cinder is nil") - } - return &cinderVolumeDeleter{ - &cinderVolume{ - volName: spec.Name(), - pdName: spec.PersistentVolume.Spec.Cinder.VolumeID, - manager: manager, - plugin: plugin, - }}, nil -} - -func (plugin *cinderPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) { - return plugin.newProvisionerInternal(options, &DiskUtil{}) -} - -func (plugin *cinderPlugin) newProvisionerInternal(options volume.VolumeOptions, manager cdManager) (volume.Provisioner, error) { - return &cinderVolumeProvisioner{ - cinderVolume: &cinderVolume{ - manager: manager, - plugin: plugin, - }, - options: options, - }, nil -} - -func (plugin *cinderPlugin) getCloudProvider() (BlockStorageProvider, error) { - cloud := plugin.host.GetCloudProvider() - if cloud == nil { - if _, err := os.Stat(DefaultCloudConfigPath); err == nil { - var config *os.File - config, err = os.Open(DefaultCloudConfigPath) - if err != nil { - return nil, fmt.Errorf("unable to load OpenStack configuration from default path : %v", err) - } - defer config.Close() - cloud, err = cloudprovider.GetCloudProvider(openstack.ProviderName, config) - if err != nil { - return nil, fmt.Errorf("unable to create OpenStack cloud provider from default path : %v", err) - } - } else { - return nil, fmt.Errorf("OpenStack cloud provider was not initialized properly : %v", err) - } - } - - switch cloud := cloud.(type) { - case *openstack.OpenStack: - return cloud, nil - default: - return nil, errors.New("invalid cloud provider: expected OpenStack") - } -} - -func (plugin *cinderPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { - mounter := plugin.host.GetMounter(plugin.GetPluginName()) - kvh, ok := plugin.host.(volume.KubeletVolumeHost) - if !ok { - return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface") - } - hu := kvh.GetHostUtil() - pluginMntDir := util.GetPluginMountDir(plugin.host, plugin.GetPluginName()) - sourceName, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir) - if err != nil { - return nil, err - } - klog.V(4).Infof("Found volume %s mounted to %s", sourceName, mountPath) - cinderVolume := &v1.Volume{ - Name: volumeName, - VolumeSource: v1.VolumeSource{ - Cinder: &v1.CinderVolumeSource{ - VolumeID: sourceName, - }, - }, - } - return volume.NewSpecFromVolume(cinderVolume), nil -} - -var _ volume.ExpandableVolumePlugin = &cinderPlugin{} - -func (plugin *cinderPlugin) ExpandVolumeDevice(spec *volume.Spec, newSize resource.Quantity, oldSize resource.Quantity) (resource.Quantity, error) { - volumeID, _, _, err := getVolumeInfo(spec) - if err != nil { - return oldSize, err - } - cloud, err := plugin.getCloudProvider() - if err != nil { - return oldSize, err - } - - expandedSize, err := cloud.ExpandVolume(volumeID, oldSize, newSize) - if err != nil { - return oldSize, err - } - - klog.V(2).Infof("volume %s expanded to new size %d successfully", volumeID, int(newSize.Value())) - return expandedSize, nil -} - -func (plugin *cinderPlugin) NodeExpand(resizeOptions volume.NodeResizeOptions) (bool, error) { - fsVolume, err := util.CheckVolumeModeFilesystem(resizeOptions.VolumeSpec) - if err != nil { - return false, fmt.Errorf("error checking VolumeMode: %v", err) - } - // if volume is not a fs file system, there is nothing for us to do here. - if !fsVolume { - return true, nil - } - - _, err = util.GenericResizeFS(plugin.host, plugin.GetPluginName(), resizeOptions.DevicePath, resizeOptions.DeviceMountPath) - if err != nil { - return false, err - } - return true, nil -} - -var _ volume.NodeExpandableVolumePlugin = &cinderPlugin{} - -func (plugin *cinderPlugin) RequiresFSResize() bool { - return true -} - -// Abstract interface to PD operations. -type cdManager interface { - // Attaches the disk to the kubelet's host machine. - AttachDisk(mounter *cinderVolumeMounter, globalPDPath string) error - // Detaches the disk from the kubelet's host machine. - DetachDisk(unmounter *cinderVolumeUnmounter) error - // Creates a volume - CreateVolume(provisioner *cinderVolumeProvisioner, node *v1.Node, allowedTopologies []v1.TopologySelectorTerm) (volumeID string, volumeSizeGB int, labels map[string]string, fstype string, err error) - // Deletes a volume - DeleteVolume(deleter *cinderVolumeDeleter) error -} - -var _ volume.Mounter = &cinderVolumeMounter{} - -type cinderVolumeMounter struct { - *cinderVolume - fsType string - readOnly bool - blockDeviceMounter *mount.SafeFormatAndMount - mountOptions []string -} - -// cinderPersistentDisk volumes are disk resources provided by C3 -// that are attached to the kubelet's host machine and exposed to the pod. -type cinderVolume struct { - volName string - podUID types.UID - // Unique identifier of the volume, used to find the disk resource in the provider. - pdName string - // Filesystem type, optional. - fsType string - // Utility interface that provides API calls to the provider to attach/detach disks. - manager cdManager - // Mounter interface that provides system calls to mount the global path to the pod local path. - mounter mount.Interface - plugin *cinderPlugin - volume.MetricsProvider -} - -func (b *cinderVolumeMounter) GetAttributes() volume.Attributes { - return volume.Attributes{ - ReadOnly: b.readOnly, - Managed: !b.readOnly, - SELinuxRelabel: true, - } -} - -func (b *cinderVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -// SetUp bind mounts to the volume path. -func (b *cinderVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { - klog.V(5).Infof("Cinder SetUp %s to %s", b.pdName, dir) - - b.plugin.volumeLocks.LockKey(b.pdName) - defer b.plugin.volumeLocks.UnlockKey(b.pdName) - - notmnt, err := b.mounter.IsLikelyNotMountPoint(dir) - if err != nil && !os.IsNotExist(err) { - klog.Errorf("Cannot validate mount point: %s %v", dir, err) - return err - } - if !notmnt { - klog.V(4).Infof("Something is already mounted to target %s", dir) - return nil - } - globalPDPath := makeGlobalPDName(b.plugin.host, b.pdName) - - options := []string{"bind"} - if b.readOnly { - options = append(options, "ro") - } - - if err := os.MkdirAll(dir, 0750); err != nil { - klog.V(4).Infof("Could not create directory %s: %v", dir, err) - return err - } - - mountOptions := util.JoinMountOptions(options, b.mountOptions) - // Perform a bind mount to the full path to allow duplicate mounts of the same PD. - klog.V(4).Infof("Attempting to mount cinder volume %s to %s with options %v", b.pdName, dir, mountOptions) - err = b.mounter.MountSensitiveWithoutSystemd(globalPDPath, dir, "", options, nil) - if err != nil { - klog.V(4).Infof("Mount failed: %v", err) - notmnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir) - if mntErr != nil { - klog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr) - return err - } - if !notmnt { - if mntErr = b.mounter.Unmount(dir); mntErr != nil { - klog.Errorf("Failed to unmount: %v", mntErr) - return err - } - notmnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir) - if mntErr != nil { - klog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr) - return err - } - if !notmnt { - // This is very odd, we don't expect it. We'll try again next sync loop. - klog.Errorf("%s is still mounted, despite call to unmount(). Will try again next sync loop.", b.GetPath()) - return err - } - } - os.Remove(dir) - klog.Errorf("Failed to mount %s: %v", dir, err) - return err - } - - if !b.readOnly { - volume.SetVolumeOwnership(b, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy, util.FSGroupCompleteHook(b.plugin, nil)) - } - klog.V(3).Infof("Cinder volume %s mounted to %s", b.pdName, dir) - - return nil -} - -func makeGlobalPDName(host volume.VolumeHost, devName string) string { - return filepath.Join(host.GetPluginDir(cinderVolumePluginName), util.MountsInGlobalPDPath, devName) -} - -func (cd *cinderVolume) GetPath() string { - return getPath(cd.podUID, cd.volName, cd.plugin.host) -} - -type cinderVolumeUnmounter struct { - *cinderVolume -} - -var _ volume.Unmounter = &cinderVolumeUnmounter{} - -func (c *cinderVolumeUnmounter) TearDown() error { - return c.TearDownAt(c.GetPath()) -} - -// Unmounts the bind mount, and detaches the disk only if the PD -// resource was the last reference to that disk on the kubelet. -func (c *cinderVolumeUnmounter) TearDownAt(dir string) error { - if pathExists, pathErr := mount.PathExists(dir); pathErr != nil { - return fmt.Errorf("error checking if path exists: %v", pathErr) - } else if !pathExists { - klog.Warningf("Warning: Unmount skipped because path does not exist: %w", dir) - return nil - } - - klog.V(5).Infof("Cinder TearDown of %s", dir) - notmnt, err := c.mounter.IsLikelyNotMountPoint(dir) - if err != nil { - klog.V(4).Infof("IsLikelyNotMountPoint check failed: %v", err) - return err - } - if notmnt { - klog.V(4).Infof("Nothing is mounted to %s, ignoring", dir) - return os.Remove(dir) - } - - // Find Cinder volumeID to lock the right volume - // TODO: refactor VolumePlugin.NewUnmounter to get full volume.Spec just like - // NewMounter. We could then find volumeID there without probing MountRefs. - refs, err := c.mounter.GetMountRefs(dir) - if err != nil { - klog.V(4).Infof("GetMountRefs failed: %v", err) - return err - } - if len(refs) == 0 { - klog.V(4).Infof("Directory %s is not mounted", dir) - return fmt.Errorf("directory %s is not mounted", dir) - } - c.pdName = path.Base(refs[0]) - klog.V(4).Infof("Found volume %s mounted to %s", c.pdName, dir) - - // lock the volume (and thus wait for any concurrent SetUpAt to finish) - c.plugin.volumeLocks.LockKey(c.pdName) - defer c.plugin.volumeLocks.UnlockKey(c.pdName) - - // Reload list of references, there might be SetUpAt finished in the meantime - _, err = c.mounter.GetMountRefs(dir) - if err != nil { - klog.V(4).Infof("GetMountRefs failed: %v", err) - return err - } - if err := c.mounter.Unmount(dir); err != nil { - klog.V(4).Infof("Unmount failed: %v", err) - return err - } - klog.V(3).Infof("Successfully unmounted: %s\n", dir) - - notmnt, mntErr := c.mounter.IsLikelyNotMountPoint(dir) - if mntErr != nil { - klog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr) - return err - } - if notmnt { - if err := os.Remove(dir); err != nil { - klog.V(4).Infof("Failed to remove directory after unmount: %v", err) - return err - } - } - return nil -} - -type cinderVolumeDeleter struct { - *cinderVolume -} - -var _ volume.Deleter = &cinderVolumeDeleter{} - -func (r *cinderVolumeDeleter) GetPath() string { - return getPath(r.podUID, r.volName, r.plugin.host) -} - -func (r *cinderVolumeDeleter) Delete() error { - return r.manager.DeleteVolume(r) -} - -type cinderVolumeProvisioner struct { - *cinderVolume - options volume.VolumeOptions -} - -var _ volume.Provisioner = &cinderVolumeProvisioner{} - -func (c *cinderVolumeProvisioner) Provision(selectedNode *v1.Node, allowedTopologies []v1.TopologySelectorTerm) (*v1.PersistentVolume, error) { - if !util.ContainsAllAccessModes(c.plugin.GetAccessModes(), c.options.PVC.Spec.AccessModes) { - return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", c.options.PVC.Spec.AccessModes, c.plugin.GetAccessModes()) - } - - volumeID, sizeGB, labels, fstype, err := c.manager.CreateVolume(c, selectedNode, allowedTopologies) - if err != nil { - return nil, err - } - - if fstype == "" { - fstype = "ext4" - } - - volumeMode := c.options.PVC.Spec.VolumeMode - if volumeMode != nil && *volumeMode == v1.PersistentVolumeBlock { - // Block volumes should not have any FSType - fstype = "" - } - - pv := &v1.PersistentVolume{ - ObjectMeta: metav1.ObjectMeta{ - Name: c.options.PVName, - Labels: labels, - Annotations: map[string]string{ - util.VolumeDynamicallyCreatedByKey: "cinder-dynamic-provisioner", - }, - }, - Spec: v1.PersistentVolumeSpec{ - PersistentVolumeReclaimPolicy: c.options.PersistentVolumeReclaimPolicy, - AccessModes: c.options.PVC.Spec.AccessModes, - Capacity: v1.ResourceList{ - v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)), - }, - VolumeMode: volumeMode, - PersistentVolumeSource: v1.PersistentVolumeSource{ - Cinder: &v1.CinderPersistentVolumeSource{ - VolumeID: volumeID, - FSType: fstype, - ReadOnly: false, - }, - }, - MountOptions: c.options.MountOptions, - }, - } - if len(c.options.PVC.Spec.AccessModes) == 0 { - pv.Spec.AccessModes = c.plugin.GetAccessModes() - } - - requirements := make([]v1.NodeSelectorRequirement, 0) - for k, v := range labels { - if v != "" { - requirements = append(requirements, v1.NodeSelectorRequirement{Key: k, Operator: v1.NodeSelectorOpIn, Values: []string{v}}) - } - } - if len(requirements) > 0 { - pv.Spec.NodeAffinity = new(v1.VolumeNodeAffinity) - pv.Spec.NodeAffinity.Required = new(v1.NodeSelector) - pv.Spec.NodeAffinity.Required.NodeSelectorTerms = make([]v1.NodeSelectorTerm, 1) - pv.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions = requirements - } - - return pv, nil -} - -func getVolumeInfo(spec *volume.Spec) (string, string, bool, error) { - if spec.Volume != nil && spec.Volume.Cinder != nil { - return spec.Volume.Cinder.VolumeID, spec.Volume.Cinder.FSType, spec.Volume.Cinder.ReadOnly, nil - } else if spec.PersistentVolume != nil && - spec.PersistentVolume.Spec.Cinder != nil { - return spec.PersistentVolume.Spec.Cinder.VolumeID, spec.PersistentVolume.Spec.Cinder.FSType, spec.ReadOnly, nil - } - - return "", "", false, fmt.Errorf("Spec does not reference a Cinder volume type") -} diff --git a/pkg/volume/cinder/cinder_block.go b/pkg/volume/cinder/cinder_block.go deleted file mode 100644 index 618115770e3..00000000000 --- a/pkg/volume/cinder/cinder_block.go +++ /dev/null @@ -1,179 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2018 The Kubernetes Authors. - -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. -*/ - -package cinder - -import ( - "fmt" - "path/filepath" - - "k8s.io/klog/v2" - "k8s.io/mount-utils" - utilstrings "k8s.io/utils/strings" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/kubernetes/pkg/volume" - "k8s.io/kubernetes/pkg/volume/util/volumepathhandler" -) - -var _ volume.VolumePlugin = &cinderPlugin{} -var _ volume.PersistentVolumePlugin = &cinderPlugin{} -var _ volume.BlockVolumePlugin = &cinderPlugin{} -var _ volume.DeletableVolumePlugin = &cinderPlugin{} -var _ volume.ProvisionableVolumePlugin = &cinderPlugin{} -var _ volume.ExpandableVolumePlugin = &cinderPlugin{} - -func (plugin *cinderPlugin) ConstructBlockVolumeSpec(podUID types.UID, volumeName, mapPath string) (*volume.Spec, error) { - pluginDir := plugin.host.GetVolumeDevicePluginDir(cinderVolumePluginName) - blkutil := volumepathhandler.NewBlockVolumePathHandler() - globalMapPathUUID, err := blkutil.FindGlobalMapPathUUIDFromPod(pluginDir, mapPath, podUID) - if err != nil { - return nil, err - } - klog.V(5).Infof("globalMapPathUUID: %v, err: %v", globalMapPathUUID, err) - - globalMapPath := filepath.Dir(globalMapPathUUID) - if len(globalMapPath) <= 1 { - return nil, fmt.Errorf("failed to get volume plugin information from globalMapPathUUID: %v", globalMapPathUUID) - } - - return getVolumeSpecFromGlobalMapPath(volumeName, globalMapPath) -} - -func getVolumeSpecFromGlobalMapPath(volumeName, globalMapPath string) (*volume.Spec, error) { - // Get volume spec information from globalMapPath - // globalMapPath example: - // plugins/kubernetes.io/{PluginName}/{DefaultKubeletVolumeDevicesDirName}/{volumeID} - // plugins/kubernetes.io/cinder/volumeDevices/vol-XXXXXX - vID := filepath.Base(globalMapPath) - if len(vID) <= 1 { - return nil, fmt.Errorf("failed to get volumeID from global path=%s", globalMapPath) - } - block := v1.PersistentVolumeBlock - cinderVolume := &v1.PersistentVolume{ - ObjectMeta: metav1.ObjectMeta{ - Name: volumeName, - }, - Spec: v1.PersistentVolumeSpec{ - PersistentVolumeSource: v1.PersistentVolumeSource{ - Cinder: &v1.CinderPersistentVolumeSource{ - VolumeID: vID, - }, - }, - VolumeMode: &block, - }, - } - return volume.NewSpecFromPersistentVolume(cinderVolume, true), nil -} - -// NewBlockVolumeMapper creates a new volume.BlockVolumeMapper from an API specification. -func (plugin *cinderPlugin) NewBlockVolumeMapper(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.BlockVolumeMapper, error) { - // If this is called via GenerateUnmapDeviceFunc(), pod is nil. - // Pass empty string as dummy uid since uid isn't used in the case. - var uid types.UID - if pod != nil { - uid = pod.UID - } - - return plugin.newBlockVolumeMapperInternal(spec, uid, &DiskUtil{}, plugin.host.GetMounter(plugin.GetPluginName())) -} - -func (plugin *cinderPlugin) newBlockVolumeMapperInternal(spec *volume.Spec, podUID types.UID, manager cdManager, mounter mount.Interface) (volume.BlockVolumeMapper, error) { - pdName, fsType, readOnly, err := getVolumeInfo(spec) - if err != nil { - return nil, err - } - - mapper := &cinderVolumeMapper{ - cinderVolume: &cinderVolume{ - podUID: podUID, - volName: spec.Name(), - pdName: pdName, - fsType: fsType, - manager: manager, - mounter: mounter, - plugin: plugin, - }, - readOnly: readOnly, - } - - blockPath, err := mapper.GetGlobalMapPath(spec) - if err != nil { - return nil, fmt.Errorf("failed to get device path: %v", err) - } - mapper.MetricsProvider = volume.NewMetricsBlock(filepath.Join(blockPath, string(podUID))) - - return mapper, nil -} - -func (plugin *cinderPlugin) NewBlockVolumeUnmapper(volName string, podUID types.UID) (volume.BlockVolumeUnmapper, error) { - return plugin.newUnmapperInternal(volName, podUID, &DiskUtil{}, plugin.host.GetMounter(plugin.GetPluginName())) -} - -func (plugin *cinderPlugin) newUnmapperInternal(volName string, podUID types.UID, manager cdManager, mounter mount.Interface) (volume.BlockVolumeUnmapper, error) { - return &cinderPluginUnmapper{ - cinderVolume: &cinderVolume{ - podUID: podUID, - volName: volName, - manager: manager, - mounter: mounter, - plugin: plugin, - }}, nil -} - -type cinderPluginUnmapper struct { - *cinderVolume - volume.MetricsNil -} - -var _ volume.BlockVolumeUnmapper = &cinderPluginUnmapper{} - -type cinderVolumeMapper struct { - *cinderVolume - readOnly bool -} - -var _ volume.BlockVolumeMapper = &cinderVolumeMapper{} - -// GetGlobalMapPath returns global map path and error -// path: plugins/kubernetes.io/{PluginName}/volumeDevices/volumeID -// -// plugins/kubernetes.io/cinder/volumeDevices/vol-XXXXXX -func (cd *cinderVolume) GetGlobalMapPath(spec *volume.Spec) (string, error) { - pdName, _, _, err := getVolumeInfo(spec) - if err != nil { - return "", err - } - return filepath.Join(cd.plugin.host.GetVolumeDevicePluginDir(cinderVolumePluginName), pdName), nil -} - -// GetPodDeviceMapPath returns pod device map path and volume name -// path: pods/{podUid}/volumeDevices/kubernetes.io~cinder -func (cd *cinderVolume) GetPodDeviceMapPath() (string, string) { - name := cinderVolumePluginName - return cd.plugin.host.GetPodVolumeDeviceDir(cd.podUID, utilstrings.EscapeQualifiedName(name)), cd.volName -} - -// SupportsMetrics returns true for cinderVolumeMapper as it initializes the -// MetricsProvider. -func (cvm *cinderVolumeMapper) SupportsMetrics() bool { - return true -} diff --git a/pkg/volume/cinder/cinder_block_test.go b/pkg/volume/cinder/cinder_block_test.go deleted file mode 100644 index 0b0aa20321d..00000000000 --- a/pkg/volume/cinder/cinder_block_test.go +++ /dev/null @@ -1,151 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2018 The Kubernetes Authors. - -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. -*/ - -package cinder - -import ( - "os" - "path/filepath" - "testing" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - utiltesting "k8s.io/client-go/util/testing" - "k8s.io/kubernetes/pkg/volume" - volumetest "k8s.io/kubernetes/pkg/volume/testing" -) - -const ( - testVolName = "vol-1234" - testPVName = "pv1" - testGlobalPath = "plugins/kubernetes.io/cinder/volumeDevices/vol-1234" - testPodPath = "pods/poduid/volumeDevices/kubernetes.io~cinder" -) - -func TestGetVolumeSpecFromGlobalMapPath(t *testing.T) { - // make our test path for fake GlobalMapPath - // /tmp symbolized our pluginDir - // /tmp/testGlobalPathXXXXX/plugins/kubernetes.io/cinder/volumeDevices/pdVol1 - tmpVDir, err := utiltesting.MkTmpdir("cinderBlockTest") - if err != nil { - t.Fatalf("can't make a temp dir: %v", err) - } - //deferred clean up - defer os.RemoveAll(tmpVDir) - - expectedGlobalPath := filepath.Join(tmpVDir, testGlobalPath) - - //Bad Path - badspec, err := getVolumeSpecFromGlobalMapPath("", "") - if badspec != nil || err == nil { - t.Errorf("Expected not to get spec from GlobalMapPath but did") - } - - // Good Path - spec, err := getVolumeSpecFromGlobalMapPath("myVolume", expectedGlobalPath) - if spec == nil || err != nil { - t.Fatalf("Failed to get spec from GlobalMapPath: %v", err) - } - if spec.PersistentVolume.Name != "myVolume" { - t.Errorf("Invalid PV name from GlobalMapPath spec: %s", spec.PersistentVolume.Name) - } - if spec.PersistentVolume.Spec.Cinder.VolumeID != testVolName { - t.Errorf("Invalid volumeID from GlobalMapPath spec: %s", spec.PersistentVolume.Spec.Cinder.VolumeID) - } - block := v1.PersistentVolumeBlock - specMode := spec.PersistentVolume.Spec.VolumeMode - if specMode == nil { - t.Fatalf("Failed to get volumeMode from PersistentVolumeBlock") - } - if *specMode != block { - t.Errorf("Invalid volumeMode from GlobalMapPath spec: %v expected: %v", *specMode, block) - } -} - -func getTestVolume(readOnly bool, isBlock bool) *volume.Spec { - pv := &v1.PersistentVolume{ - ObjectMeta: metav1.ObjectMeta{ - Name: testPVName, - }, - Spec: v1.PersistentVolumeSpec{ - PersistentVolumeSource: v1.PersistentVolumeSource{ - Cinder: &v1.CinderPersistentVolumeSource{ - VolumeID: testVolName, - }, - }, - }, - } - - if isBlock { - blockMode := v1.PersistentVolumeBlock - pv.Spec.VolumeMode = &blockMode - } - return volume.NewSpecFromPersistentVolume(pv, readOnly) -} - -func TestGetPodAndPluginMapPaths(t *testing.T) { - tmpVDir, err := utiltesting.MkTmpdir("cinderBlockTest") - if err != nil { - t.Fatalf("can't make a temp dir: %v", err) - } - //deferred clean up - defer os.RemoveAll(tmpVDir) - - expectedGlobalPath := filepath.Join(tmpVDir, testGlobalPath) - expectedPodPath := filepath.Join(tmpVDir, testPodPath) - - spec := getTestVolume(false, true /*isBlock*/) - plugMgr := volume.VolumePluginMgr{} - plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(t, tmpVDir, nil, nil)) - plug, err := plugMgr.FindMapperPluginByName(cinderVolumePluginName) - if err != nil { - os.RemoveAll(tmpVDir) - t.Fatalf("Can't find the plugin by name: %q", cinderVolumePluginName) - } - if plug.GetPluginName() != cinderVolumePluginName { - t.Fatalf("Wrong name: %s", plug.GetPluginName()) - } - pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}} - mapper, err := plug.NewBlockVolumeMapper(spec, pod, volume.VolumeOptions{}) - if err != nil { - t.Fatalf("Failed to make a new Mounter: %v", err) - } - if mapper == nil { - t.Fatalf("Got a nil Mounter") - } - - //GetGlobalMapPath - gMapPath, err := mapper.GetGlobalMapPath(spec) - if err != nil || len(gMapPath) == 0 { - t.Fatalf("Invalid GlobalMapPath from spec: %s", spec.PersistentVolume.Spec.Cinder.VolumeID) - } - if gMapPath != expectedGlobalPath { - t.Errorf("Failed to get GlobalMapPath: %s %s", gMapPath, expectedGlobalPath) - } - - //GetPodDeviceMapPath - gDevicePath, gVolName := mapper.GetPodDeviceMapPath() - if gDevicePath != expectedPodPath { - t.Errorf("Got unexpected pod path: %s, expected %s", gDevicePath, expectedPodPath) - } - if gVolName != testPVName { - t.Errorf("Got unexpected volNamne: %s, expected %s", gVolName, testPVName) - } -} diff --git a/pkg/volume/cinder/cinder_test.go b/pkg/volume/cinder/cinder_test.go deleted file mode 100644 index 61c9bc27ac9..00000000000 --- a/pkg/volume/cinder/cinder_test.go +++ /dev/null @@ -1,365 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2015 The Kubernetes Authors. - -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. -*/ - -package cinder - -import ( - "fmt" - "os" - "path/filepath" - "testing" - "time" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - utiltesting "k8s.io/client-go/util/testing" - "k8s.io/mount-utils" - - "k8s.io/kubernetes/pkg/volume" - volumetest "k8s.io/kubernetes/pkg/volume/testing" - "k8s.io/kubernetes/pkg/volume/util" - "k8s.io/legacy-cloud-providers/openstack" -) - -func TestCanSupport(t *testing.T) { - tmpDir, err := utiltesting.MkTmpdir("cinderTest") - if err != nil { - t.Fatalf("can't make a temp dir: %v", err) - } - defer os.RemoveAll(tmpDir) - plugMgr := volume.VolumePluginMgr{} - plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil)) - - plug, err := plugMgr.FindPluginByName("kubernetes.io/cinder") - if err != nil { - t.Fatal("Can't find the plugin by name") - } - if plug.GetPluginName() != "kubernetes.io/cinder" { - t.Errorf("Wrong name: %s", plug.GetPluginName()) - } - if !plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{Cinder: &v1.CinderVolumeSource{}}}}) { - t.Errorf("Expected true") - } - - if !plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{Cinder: &v1.CinderPersistentVolumeSource{}}}}}) { - t.Errorf("Expected true") - } -} - -type fakePDManager struct { - // How long should AttachDisk/DetachDisk take - we need slower AttachDisk in a test. - attachDetachDuration time.Duration -} - -func getFakeDeviceName(host volume.VolumeHost, pdName string) string { - return filepath.Join(host.GetPluginDir(cinderVolumePluginName), "device", pdName) -} - -// Real Cinder AttachDisk attaches a cinder volume. If it is not yet mounted, -// it mounts it to globalPDPath. -// We create a dummy directory (="device") and bind-mount it to globalPDPath -func (fake *fakePDManager) AttachDisk(b *cinderVolumeMounter, globalPDPath string) error { - globalPath := makeGlobalPDName(b.plugin.host, b.pdName) - fakeDeviceName := getFakeDeviceName(b.plugin.host, b.pdName) - err := os.MkdirAll(fakeDeviceName, 0750) - if err != nil { - return err - } - // Attaching a Cinder volume can be slow... - time.Sleep(fake.attachDetachDuration) - - // The volume is "attached", bind-mount it if it's not mounted yet. - notmnt, err := b.mounter.IsLikelyNotMountPoint(globalPath) - if err != nil { - if os.IsNotExist(err) { - if err := os.MkdirAll(globalPath, 0750); err != nil { - return err - } - notmnt = true - } else { - return err - } - } - if notmnt { - err = b.mounter.MountSensitiveWithoutSystemd(fakeDeviceName, globalPath, "", []string{"bind"}, nil) - if err != nil { - return err - } - } - return nil -} - -func (fake *fakePDManager) DetachDisk(c *cinderVolumeUnmounter) error { - globalPath := makeGlobalPDName(c.plugin.host, c.pdName) - fakeDeviceName := getFakeDeviceName(c.plugin.host, c.pdName) - // unmount the bind-mount - should be fast - err := c.mounter.Unmount(globalPath) - if err != nil { - return err - } - - // "Detach" the fake "device" - err = os.RemoveAll(fakeDeviceName) - if err != nil { - return err - } - return nil -} - -func (fake *fakePDManager) CreateVolume(c *cinderVolumeProvisioner, node *v1.Node, allowedTopologies []v1.TopologySelectorTerm) (volumeID string, volumeSizeGB int, labels map[string]string, fstype string, err error) { - labels = make(map[string]string) - labels[v1.LabelTopologyZone] = "nova" - return "test-volume-name", 1, labels, "", nil -} - -func (fake *fakePDManager) DeleteVolume(cd *cinderVolumeDeleter) error { - if cd.pdName != "test-volume-name" { - return fmt.Errorf("Deleter got unexpected volume name: %s", cd.pdName) - } - return nil -} - -func TestPlugin(t *testing.T) { - tmpDir, err := utiltesting.MkTmpdir("cinderTest") - if err != nil { - t.Fatalf("can't make a temp dir: %v", err) - } - defer os.RemoveAll(tmpDir) - plugMgr := volume.VolumePluginMgr{} - plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeKubeletVolumeHost(t, tmpDir, nil, nil)) - - plug, err := plugMgr.FindPluginByName("kubernetes.io/cinder") - if err != nil { - t.Errorf("Can't find the plugin by name") - } - spec := &v1.Volume{ - Name: "vol1", - VolumeSource: v1.VolumeSource{ - Cinder: &v1.CinderVolumeSource{ - VolumeID: "pd", - FSType: "ext4", - }, - }, - } - mounter, err := plug.(*cinderPlugin).newMounterInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), &fakePDManager{0}, mount.NewFakeMounter(nil)) - if err != nil { - t.Errorf("Failed to make a new Mounter: %v", err) - } - if mounter == nil { - t.Errorf("Got a nil Mounter") - } - volPath := filepath.Join(tmpDir, "pods/poduid/volumes/kubernetes.io~cinder/vol1") - path := mounter.GetPath() - if path != volPath { - t.Errorf("Got unexpected path: %s", path) - } - - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { - t.Errorf("Expected success, got: %v", err) - } - if _, err := os.Stat(path); err != nil { - if os.IsNotExist(err) { - t.Errorf("SetUp() failed, volume path not created: %s", path) - } else { - t.Errorf("SetUp() failed: %v", err) - } - } - - unmounter, err := plug.(*cinderPlugin).newUnmounterInternal("vol1", types.UID("poduid"), &fakePDManager{0}, mount.NewFakeMounter(nil)) - if err != nil { - t.Errorf("Failed to make a new Unmounter: %v", err) - } - if unmounter == nil { - t.Errorf("Got a nil Unmounter") - } - - if err := unmounter.TearDown(); err != nil { - t.Errorf("Expected success, got: %v", err) - } - if _, err := os.Stat(path); err == nil { - t.Errorf("TearDown() failed, volume path still exists: %s", path) - } else if !os.IsNotExist(err) { - t.Errorf("TearDown() failed: %v", err) - } - - // Test Provisioner - options := volume.VolumeOptions{ - PVC: volumetest.CreateTestPVC("100Mi", []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}), - PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete, - } - provisioner, err := plug.(*cinderPlugin).newProvisionerInternal(options, &fakePDManager{0}) - if err != nil { - t.Errorf("ProvisionerInternal() failed: %v", err) - } - persistentSpec, err := provisioner.Provision(nil, nil) - if err != nil { - t.Errorf("Provision() failed: %v", err) - } - - if persistentSpec.Spec.PersistentVolumeSource.Cinder.VolumeID != "test-volume-name" { - t.Errorf("Provision() returned unexpected volume ID: %s", persistentSpec.Spec.PersistentVolumeSource.Cinder.VolumeID) - } - cap := persistentSpec.Spec.Capacity[v1.ResourceStorage] - size := cap.Value() - if size != 1024*1024*1024 { - t.Errorf("Provision() returned unexpected volume size: %v", size) - } - - // check nodeaffinity members - if persistentSpec.Spec.NodeAffinity == nil { - t.Errorf("Provision() returned unexpected nil NodeAffinity") - } - - if persistentSpec.Spec.NodeAffinity.Required == nil { - t.Errorf("Provision() returned unexpected nil NodeAffinity.Required") - } - - n := len(persistentSpec.Spec.NodeAffinity.Required.NodeSelectorTerms) - if n != 1 { - t.Errorf("Provision() returned unexpected number of NodeSelectorTerms %d. Expected %d", n, 1) - } - - n = len(persistentSpec.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions) - if n != 1 { - t.Errorf("Provision() returned unexpected number of MatchExpressions %d. Expected %d", n, 1) - } - - req := persistentSpec.Spec.NodeAffinity.Required.NodeSelectorTerms[0].MatchExpressions[0] - - if req.Key != v1.LabelTopologyZone { - t.Errorf("Provision() returned unexpected requirement key in NodeAffinity %v", req.Key) - } - - if req.Operator != v1.NodeSelectorOpIn { - t.Errorf("Provision() returned unexpected requirement operator in NodeAffinity %v", req.Operator) - } - - if len(req.Values) != 1 || req.Values[0] != "nova" { - t.Errorf("Provision() returned unexpected requirement value in NodeAffinity %v", req.Values) - } - - // Test Deleter - volSpec := &volume.Spec{ - PersistentVolume: persistentSpec, - } - deleter, err := plug.(*cinderPlugin).newDeleterInternal(volSpec, &fakePDManager{0}) - if err != nil { - t.Errorf("DeleterInternal() failed: %v", err) - } - err = deleter.Delete() - if err != nil { - t.Errorf("Deleter() failed: %v", err) - } -} - -func TestGetVolumeLimit(t *testing.T) { - tmpDir, err := utiltesting.MkTmpdir("cinderTest") - if err != nil { - t.Fatalf("can't make a temp dir: %v", err) - } - - cloud, err := getOpenstackCloudProvider() - if err != nil { - t.Fatalf("can not instantiate openstack cloudprovider : %v", err) - } - - defer os.RemoveAll(tmpDir) - plugMgr := volume.VolumePluginMgr{} - volumeHost := volumetest.NewFakeKubeletVolumeHostWithCloudProvider(t, tmpDir, nil, nil, cloud) - plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumeHost) - - plug, err := plugMgr.FindPluginByName("kubernetes.io/cinder") - if err != nil { - t.Fatalf("Can't find the plugin by name") - } - attachablePlugin, ok := plug.(volume.VolumePluginWithAttachLimits) - if !ok { - t.Fatalf("plugin %s is not of attachable type", plug.GetPluginName()) - } - - limits, err := attachablePlugin.GetVolumeLimits() - if err != nil { - t.Errorf("error fetching limits : %v", err) - } - if len(limits) == 0 { - t.Fatalf("expecting limit from openstack got none") - } - limit, _ := limits[util.CinderVolumeLimitKey] - if limit != 10 { - t.Fatalf("expected volume limit to be 10 got %d", limit) - } -} - -func getOpenstackCloudProvider() (*openstack.OpenStack, error) { - cfg := getOpenstackConfig() - return openstack.NewFakeOpenStackCloud(cfg) -} - -func getOpenstackConfig() openstack.Config { - cfg := openstack.Config{ - Global: struct { - AuthURL string `gcfg:"auth-url"` - Username string - UserID string `gcfg:"user-id"` - Password string `datapolicy:"password"` - TenantID string `gcfg:"tenant-id"` - TenantName string `gcfg:"tenant-name"` - TrustID string `gcfg:"trust-id"` - DomainID string `gcfg:"domain-id"` - DomainName string `gcfg:"domain-name"` - Region string - CAFile string `gcfg:"ca-file"` - SecretName string `gcfg:"secret-name"` - SecretNamespace string `gcfg:"secret-namespace"` - KubeconfigPath string `gcfg:"kubeconfig-path"` - }{ - Username: "user", - Password: "pass", - TenantID: "foobar", - DomainID: "2a73b8f597c04551a0fdc8e95544be8a", - DomainName: "local", - AuthURL: "http://auth.url", - UserID: "user", - }, - BlockStorage: openstack.BlockStorageOpts{ - NodeVolumeAttachLimit: 10, - }, - } - return cfg -} - -func TestUnsupportedVolumeHost(t *testing.T) { - tmpDir, err := utiltesting.MkTmpdir("cinderTest") - if err != nil { - t.Fatalf("can't make a temp dir: %v", err) - } - defer os.RemoveAll(tmpDir) - plugMgr := volume.VolumePluginMgr{} - plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil)) - - plug, err := plugMgr.FindPluginByName("kubernetes.io/cinder") - if err != nil { - t.Fatal("Can't find the plugin by name") - } - - _, err = plug.ConstructVolumeSpec("", "") - if err == nil { - t.Errorf("Expected failure constructing volume spec with unsupported VolumeHost") - } -} diff --git a/pkg/volume/cinder/cinder_util.go b/pkg/volume/cinder/cinder_util.go deleted file mode 100644 index 3d0dc45796b..00000000000 --- a/pkg/volume/cinder/cinder_util.go +++ /dev/null @@ -1,278 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2015 The Kubernetes Authors. - -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. -*/ - -package cinder - -import ( - "context" - "errors" - "fmt" - "io/ioutil" - "os" - "strings" - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/klog/v2" - - "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/util/sets" - clientset "k8s.io/client-go/kubernetes" - volumehelpers "k8s.io/cloud-provider/volume/helpers" - "k8s.io/kubernetes/pkg/volume" - volutil "k8s.io/kubernetes/pkg/volume/util" - "k8s.io/utils/exec" -) - -// DiskUtil has utility/helper methods -type DiskUtil struct{} - -// AttachDisk attaches a disk specified by a volume.CinderPersistenDisk to the current kubelet. -// Mounts the disk to its global path. -func (util *DiskUtil) AttachDisk(b *cinderVolumeMounter, globalPDPath string) error { - options := []string{} - if b.readOnly { - options = append(options, "ro") - } - cloud, err := b.plugin.getCloudProvider() - if err != nil { - return err - } - instanceid, err := cloud.InstanceID() - if err != nil { - return err - } - diskid, err := cloud.AttachDisk(instanceid, b.pdName) - if err != nil { - return err - } - - var devicePath string - numTries := 0 - for { - devicePath = cloud.GetDevicePath(diskid) - probeAttachedVolume() - - _, err := os.Stat(devicePath) - if err == nil { - break - } - if err != nil && !os.IsNotExist(err) { - return err - } - numTries++ - if numTries == 10 { - return errors.New("could not attach disk: Timeout after 60s") - } - time.Sleep(time.Second * 6) - } - notmnt, err := b.mounter.IsLikelyNotMountPoint(globalPDPath) - if err != nil { - if os.IsNotExist(err) { - if err := os.MkdirAll(globalPDPath, 0750); err != nil { - return err - } - notmnt = true - } else { - return err - } - } - if notmnt { - err = b.blockDeviceMounter.FormatAndMount(devicePath, globalPDPath, b.fsType, options) - if err != nil { - os.Remove(globalPDPath) - return err - } - klog.V(2).Infof("Safe mount successful: %q\n", devicePath) - } - return nil -} - -// DetachDisk unmounts the device and detaches the disk from the kubelet's host machine. -func (util *DiskUtil) DetachDisk(cd *cinderVolumeUnmounter) error { - globalPDPath := makeGlobalPDName(cd.plugin.host, cd.pdName) - if err := cd.mounter.Unmount(globalPDPath); err != nil { - return err - } - if err := os.Remove(globalPDPath); err != nil { - return err - } - klog.V(2).Infof("Successfully unmounted main device: %s\n", globalPDPath) - - cloud, err := cd.plugin.getCloudProvider() - if err != nil { - return err - } - instanceid, err := cloud.InstanceID() - if err != nil { - return err - } - if err = cloud.DetachDisk(instanceid, cd.pdName); err != nil { - return err - } - klog.V(2).Infof("Successfully detached cinder volume %s", cd.pdName) - return nil -} - -// DeleteVolume uses the cloud entrypoint to delete specified volume -func (util *DiskUtil) DeleteVolume(cd *cinderVolumeDeleter) error { - cloud, err := cd.plugin.getCloudProvider() - if err != nil { - return err - } - - if err = cloud.DeleteVolume(cd.pdName); err != nil { - // OpenStack cloud provider returns volume.tryAgainError when necessary, - // no handling needed here. - klog.V(2).Infof("Error deleting cinder volume %s: %v", cd.pdName, err) - return err - } - klog.V(2).Infof("Successfully deleted cinder volume %s", cd.pdName) - return nil -} - -func getZonesFromNodes(kubeClient clientset.Interface) (sets.String, error) { - // TODO: caching, currently it is overkill because it calls this function - // only when it creates dynamic PV - zones := make(sets.String) - nodes, err := kubeClient.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) - if err != nil { - klog.V(2).Infof("Error listing nodes") - return zones, err - } - for _, node := range nodes.Items { - if zone, ok := node.Labels[v1.LabelTopologyZone]; ok { - zones.Insert(zone) - } - } - klog.V(4).Infof("zones found: %v", zones) - return zones, nil -} - -// CreateVolume uses the cloud provider entrypoint for creating a volume -func (util *DiskUtil) CreateVolume(c *cinderVolumeProvisioner, node *v1.Node, allowedTopologies []v1.TopologySelectorTerm) (volumeID string, volumeSizeGB int, volumeLabels map[string]string, fstype string, err error) { - cloud, err := c.plugin.getCloudProvider() - if err != nil { - return "", 0, nil, "", err - } - - capacity := c.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] - // Cinder works with gigabytes, convert to GiB with rounding up - volSizeGiB, err := volumehelpers.RoundUpToGiBInt(capacity) - if err != nil { - return "", 0, nil, "", err - } - - name := volutil.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 255) // Cinder volume name can have up to 255 characters - vtype := "" - availability := "" - // Apply ProvisionerParameters (case-insensitive). We leave validation of - // the values to the cloud provider. - for k, v := range c.options.Parameters { - switch strings.ToLower(k) { - case "type": - vtype = v - case "availability": - availability = v - case volume.VolumeParameterFSType: - fstype = v - default: - return "", 0, nil, "", fmt.Errorf("invalid option %q for volume plugin %s", k, c.plugin.GetPluginName()) - } - } - // TODO: implement PVC.Selector parsing - if c.options.PVC.Spec.Selector != nil { - return "", 0, nil, "", fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on Cinder") - } - - if availability == "" { - // No zone specified, choose one randomly in the same region - zones, err := getZonesFromNodes(c.plugin.host.GetKubeClient()) - if err != nil { - klog.V(2).Infof("error getting zone information: %v", err) - return "", 0, nil, "", err - } - // if we did not get any zones, lets leave it blank and gophercloud will - // use zone "nova" as default - if len(zones) > 0 { - availability, err = volumehelpers.SelectZoneForVolume(false, false, "", nil, zones, node, allowedTopologies, c.options.PVC.Name) - if err != nil { - klog.V(2).Infof("error selecting zone for volume: %v", err) - return "", 0, nil, "", err - } - } - } - - volumeID, volumeAZ, volumeRegion, IgnoreVolumeAZ, err := cloud.CreateVolume(name, volSizeGiB, vtype, availability, c.options.CloudTags) - if err != nil { - klog.V(2).Infof("Error creating cinder volume: %v", err) - return "", 0, nil, "", err - } - klog.V(2).Infof("Successfully created cinder volume %s", volumeID) - - // these are needed that pod is spawning to same AZ - volumeLabels = make(map[string]string) - if IgnoreVolumeAZ == false { - if volumeAZ != "" { - volumeLabels[v1.LabelTopologyZone] = volumeAZ - } - if volumeRegion != "" { - volumeLabels[v1.LabelTopologyRegion] = volumeRegion - } - } - return volumeID, volSizeGiB, volumeLabels, fstype, nil -} - -func probeAttachedVolume() error { - // rescan scsi bus - scsiHostRescan() - - executor := exec.New() - - // udevadm settle waits for udevd to process the device creation - // events for all hardware devices, thus ensuring that any device - // nodes have been created successfully before proceeding. - argsSettle := []string{"settle"} - cmdSettle := executor.Command("udevadm", argsSettle...) - _, errSettle := cmdSettle.CombinedOutput() - if errSettle != nil { - klog.Errorf("error running udevadm settle %v\n", errSettle) - } - - args := []string{"trigger"} - cmd := executor.Command("udevadm", args...) - _, err := cmd.CombinedOutput() - if err != nil { - klog.Errorf("error running udevadm trigger %v\n", err) - return err - } - klog.V(4).Infof("Successfully probed all attachments") - return nil -} - -func scsiHostRescan() { - scsiPath := "/sys/class/scsi_host/" - if dirs, err := ioutil.ReadDir(scsiPath); err == nil { - for _, f := range dirs { - name := scsiPath + f.Name() + "/scan" - data := []byte("- - -") - ioutil.WriteFile(name, data, 0666) - } - } -} diff --git a/pkg/volume/cinder/doc.go b/pkg/volume/cinder/doc.go deleted file mode 100644 index 08e6fa8ab1b..00000000000 --- a/pkg/volume/cinder/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -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. -*/ - -// Package cinder contains the internal representation of cinder volumes. -package cinder // import "k8s.io/kubernetes/pkg/volume/cinder" diff --git a/pkg/volume/csi/csi_plugin.go b/pkg/volume/csi/csi_plugin.go index 976292de20e..39cc13ca7cf 100644 --- a/pkg/volume/csi/csi_plugin.go +++ b/pkg/volume/csi/csi_plugin.go @@ -222,9 +222,6 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error { csitranslationplugins.AWSEBSInTreePluginName: func() bool { return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAWS) }, - csitranslationplugins.CinderInTreePluginName: func() bool { - return true - }, csitranslationplugins.AzureDiskInTreePluginName: func() bool { return utilfeature.DefaultFeatureGate.Enabled(features.CSIMigrationAzureDisk) }, diff --git a/pkg/volume/csimigration/plugin_manager.go b/pkg/volume/csimigration/plugin_manager.go index b568e85ac15..2e09fc70cef 100644 --- a/pkg/volume/csimigration/plugin_manager.go +++ b/pkg/volume/csimigration/plugin_manager.go @@ -68,8 +68,6 @@ func (pm PluginManager) IsMigrationCompleteForPlugin(pluginName string) bool { return pm.featureGate.Enabled(features.InTreePluginAzureFileUnregister) case csilibplugins.AzureDiskInTreePluginName: return pm.featureGate.Enabled(features.InTreePluginAzureDiskUnregister) - case csilibplugins.CinderInTreePluginName: - return pm.featureGate.Enabled(features.InTreePluginOpenStackUnregister) case csilibplugins.VSphereInTreePluginName: return pm.featureGate.Enabled(features.InTreePluginvSphereUnregister) case csilibplugins.PortworxVolumePluginName: @@ -96,8 +94,6 @@ func (pm PluginManager) IsMigrationEnabledForPlugin(pluginName string) bool { return pm.featureGate.Enabled(features.CSIMigrationAzureFile) case csilibplugins.AzureDiskInTreePluginName: return pm.featureGate.Enabled(features.CSIMigrationAzureDisk) - case csilibplugins.CinderInTreePluginName: - return true case csilibplugins.VSphereInTreePluginName: return pm.featureGate.Enabled(features.CSIMigrationvSphere) case csilibplugins.PortworxVolumePluginName: diff --git a/pkg/volume/util/attach_limit.go b/pkg/volume/util/attach_limit.go index 943357b6538..8325dbf755b 100644 --- a/pkg/volume/util/attach_limit.go +++ b/pkg/volume/util/attach_limit.go @@ -40,13 +40,6 @@ const ( // GCEVolumeLimitKey stores resource name that will store volume limits for GCE node GCEVolumeLimitKey = "attachable-volumes-gce-pd" - // CinderVolumeLimitKey contains Volume limit key for Cinder - CinderVolumeLimitKey = "attachable-volumes-cinder" - // DefaultMaxCinderVolumes defines the maximum number of PD Volumes for Cinder - // For Openstack we are keeping this to a high enough value so as depending on backend - // cluster admins can configure it. - DefaultMaxCinderVolumes = 256 - // CSIAttachLimitPrefix defines prefix used for CSI volumes CSIAttachLimitPrefix = "attachable-volumes-csi-" diff --git a/pkg/volume/util/util_test.go b/pkg/volume/util/util_test.go index fe46963afbb..0274f3cbac2 100644 --- a/pkg/volume/util/util_test.go +++ b/pkg/volume/util/util_test.go @@ -21,7 +21,6 @@ import ( "os" "reflect" "runtime" - "strings" "testing" v1 "k8s.io/api/core/v1" @@ -261,30 +260,6 @@ func TestFsUserFrom(t *testing.T) { } } -func TestGenerateVolumeName(t *testing.T) { - - // Normal operation, no truncate - v1 := GenerateVolumeName("kubernetes", "pv-cinder-abcde", 255) - if v1 != "kubernetes-dynamic-pv-cinder-abcde" { - t.Errorf("Expected kubernetes-dynamic-pv-cinder-abcde, got %s", v1) - } - - // Truncate trailing "6789-dynamic" - prefix := strings.Repeat("0123456789", 9) // 90 characters prefix + 8 chars. of "-dynamic" - v2 := GenerateVolumeName(prefix, "pv-cinder-abcde", 100) - expect := prefix[:84] + "-pv-cinder-abcde" - if v2 != expect { - t.Errorf("Expected %s, got %s", expect, v2) - } - - // Truncate really long cluster name - prefix = strings.Repeat("0123456789", 1000) // 10000 characters prefix - v3 := GenerateVolumeName(prefix, "pv-cinder-abcde", 100) - if v3 != expect { - t.Errorf("Expected %s, got %s", expect, v3) - } -} - func TestMountOptionFromSpec(t *testing.T) { scenarios := map[string]struct { volume *volume.Spec diff --git a/plugin/pkg/admission/storage/persistentvolume/label/admission.go b/plugin/pkg/admission/storage/persistentvolume/label/admission.go index a7ae3ba5dfd..a874fac2768 100644 --- a/plugin/pkg/admission/storage/persistentvolume/label/admission.go +++ b/plugin/pkg/admission/storage/persistentvolume/label/admission.go @@ -55,13 +55,12 @@ var _ = admission.Interface(&persistentVolumeLabel{}) type persistentVolumeLabel struct { *admission.Handler - mutex sync.Mutex - cloudConfig []byte - awsPVLabeler cloudprovider.PVLabeler - gcePVLabeler cloudprovider.PVLabeler - azurePVLabeler cloudprovider.PVLabeler - openStackPVLabeler cloudprovider.PVLabeler - vspherePVLabeler cloudprovider.PVLabeler + mutex sync.Mutex + cloudConfig []byte + awsPVLabeler cloudprovider.PVLabeler + gcePVLabeler cloudprovider.PVLabeler + azurePVLabeler cloudprovider.PVLabeler + vspherePVLabeler cloudprovider.PVLabeler } var _ admission.MutationInterface = &persistentVolumeLabel{} @@ -73,7 +72,7 @@ var _ kubeapiserveradmission.WantsCloudConfig = &persistentVolumeLabel{} // As a side effect, the cloud provider may block invalid or non-existent volumes. func newPersistentVolumeLabel() *persistentVolumeLabel { // DEPRECATED: in a future release, we will use mutating admission webhooks to apply PV labels. - // Once the mutating admission webhook is used for AWS, Azure, GCE, and OpenStack, + // Once the mutating admission webhook is used for AWS, Azure and GCE, // this admission controller will be removed. klog.Warning("PersistentVolumeLabel admission controller is deprecated. " + "Please remove this controller from your configuration files and scripts.") @@ -219,12 +218,6 @@ func (l *persistentVolumeLabel) findVolumeLabels(volume *api.PersistentVolume) ( return nil, fmt.Errorf("error querying AzureDisk volume %s: %v", volume.Spec.AzureDisk.DiskName, err) } return labels, nil - case volume.Spec.Cinder != nil: - labels, err := l.findCinderDiskLabels(volume) - if err != nil { - return nil, fmt.Errorf("error querying Cinder volume %s: %v", volume.Spec.Cinder.VolumeID, err) - } - return labels, nil case volume.Spec.VsphereVolume != nil: labels, err := l.findVsphereVolumeLabels(volume) if err != nil { @@ -381,56 +374,6 @@ func (l *persistentVolumeLabel) findAzureDiskLabels(volume *api.PersistentVolume return pvlabler.GetLabelsForVolume(context.TODO(), pv) } -func (l *persistentVolumeLabel) getOpenStackPVLabeler() (cloudprovider.PVLabeler, error) { - l.mutex.Lock() - defer l.mutex.Unlock() - - if l.openStackPVLabeler == nil { - var cloudConfigReader io.Reader - if len(l.cloudConfig) > 0 { - cloudConfigReader = bytes.NewReader(l.cloudConfig) - } - - cloudProvider, err := cloudprovider.GetCloudProvider("openstack", cloudConfigReader) - if err != nil || cloudProvider == nil { - return nil, err - } - - openStackPVLabeler, ok := cloudProvider.(cloudprovider.PVLabeler) - if !ok { - return nil, errors.New("OpenStack cloud provider does not implement PV labeling") - } - - l.openStackPVLabeler = openStackPVLabeler - } - - return l.openStackPVLabeler, nil - -} - -func (l *persistentVolumeLabel) findCinderDiskLabels(volume *api.PersistentVolume) (map[string]string, error) { - // Ignore any volumes that are being provisioned - if volume.Spec.Cinder.VolumeID == cloudvolume.ProvisionedVolumeName { - return nil, nil - } - - pvlabler, err := l.getOpenStackPVLabeler() - if err != nil { - return nil, err - } - if pvlabler == nil { - return nil, fmt.Errorf("unable to build OpenStack cloud provider for Cinder disk") - } - - pv := &v1.PersistentVolume{} - err = k8s_api_v1.Convert_core_PersistentVolume_To_v1_PersistentVolume(volume, pv, nil) - if err != nil { - return nil, fmt.Errorf("failed to convert PersistentVolume to core/v1: %q", err) - } - return pvlabler.GetLabelsForVolume(context.TODO(), pv) - -} - func (l *persistentVolumeLabel) findVsphereVolumeLabels(volume *api.PersistentVolume) (map[string]string, error) { pvlabler, err := l.getVspherePVLabeler() if err != nil { diff --git a/plugin/pkg/admission/storage/persistentvolume/label/admission_test.go b/plugin/pkg/admission/storage/persistentvolume/label/admission_test.go index 84694431994..eb3d2d90689 100644 --- a/plugin/pkg/admission/storage/persistentvolume/label/admission_test.go +++ b/plugin/pkg/admission/storage/persistentvolume/label/admission_test.go @@ -560,72 +560,6 @@ func Test_PVLAdmission(t *testing.T) { }, err: nil, }, - { - name: "Cinder Disk PV labeled correctly", - handler: newPersistentVolumeLabel(), - pvlabeler: mockVolumeLabels(map[string]string{ - "a": "1", - "b": "2", - v1.LabelFailureDomainBetaZone: "1__2__3", - }), - preAdmissionPV: &api.PersistentVolume{ - ObjectMeta: metav1.ObjectMeta{ - Name: "azurepd", - Namespace: "myns", - }, - Spec: api.PersistentVolumeSpec{ - PersistentVolumeSource: api.PersistentVolumeSource{ - Cinder: &api.CinderPersistentVolumeSource{ - VolumeID: "123", - }, - }, - }, - }, - postAdmissionPV: &api.PersistentVolume{ - ObjectMeta: metav1.ObjectMeta{ - Name: "azurepd", - Namespace: "myns", - Labels: map[string]string{ - "a": "1", - "b": "2", - v1.LabelFailureDomainBetaZone: "1__2__3", - }, - }, - Spec: api.PersistentVolumeSpec{ - PersistentVolumeSource: api.PersistentVolumeSource{ - Cinder: &api.CinderPersistentVolumeSource{ - VolumeID: "123", - }, - }, - NodeAffinity: &api.VolumeNodeAffinity{ - Required: &api.NodeSelector{ - NodeSelectorTerms: []api.NodeSelectorTerm{ - { - MatchExpressions: []api.NodeSelectorRequirement{ - { - Key: "a", - Operator: api.NodeSelectorOpIn, - Values: []string{"1"}, - }, - { - Key: "b", - Operator: api.NodeSelectorOpIn, - Values: []string{"2"}, - }, - { - Key: v1.LabelFailureDomainBetaZone, - Operator: api.NodeSelectorOpIn, - Values: []string{"1", "2", "3"}, - }, - }, - }, - }, - }, - }, - }, - }, - err: nil, - }, { name: "AWS EBS PV overrides user applied labels", handler: newPersistentVolumeLabel(), @@ -983,7 +917,6 @@ func setPVLabeler(handler *persistentVolumeLabel, pvlabeler cloudprovider.PVLabe handler.awsPVLabeler = pvlabeler handler.gcePVLabeler = pvlabeler handler.azurePVLabeler = pvlabeler - handler.openStackPVLabeler = pvlabeler handler.vspherePVLabeler = pvlabeler } diff --git a/staging/publishing/rules.yaml b/staging/publishing/rules.yaml index f2d36a2f2ce..a41b7d7b383 100644 --- a/staging/publishing/rules.yaml +++ b/staging/publishing/rules.yaml @@ -1634,8 +1634,6 @@ rules: branch: master - repository: controller-manager branch: master - - repository: mount-utils - branch: master - repository: component-helpers branch: master source: diff --git a/staging/src/k8s.io/client-go/examples/README.md b/staging/src/k8s.io/client-go/examples/README.md index b24964119d3..57579f06e94 100644 --- a/staging/src/k8s.io/client-go/examples/README.md +++ b/staging/src/k8s.io/client-go/examples/README.md @@ -19,7 +19,6 @@ Or you can load specific auth plugins: import _ "k8s.io/client-go/plugin/pkg/client/auth/azure" import _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" import _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" -import _ "k8s.io/client-go/plugin/pkg/client/auth/openstack" ``` ### Configuration diff --git a/staging/src/k8s.io/client-go/examples/create-update-delete-deployment/main.go b/staging/src/k8s.io/client-go/examples/create-update-delete-deployment/main.go index 224dbc12519..dae3bc95f18 100644 --- a/staging/src/k8s.io/client-go/examples/create-update-delete-deployment/main.go +++ b/staging/src/k8s.io/client-go/examples/create-update-delete-deployment/main.go @@ -40,7 +40,6 @@ import ( // _ "k8s.io/client-go/plugin/pkg/client/auth/azure" // _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" // _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" - // _ "k8s.io/client-go/plugin/pkg/client/auth/openstack" ) func main() { diff --git a/staging/src/k8s.io/client-go/examples/dynamic-create-update-delete-deployment/main.go b/staging/src/k8s.io/client-go/examples/dynamic-create-update-delete-deployment/main.go index b7439e482d6..cc6b1226706 100644 --- a/staging/src/k8s.io/client-go/examples/dynamic-create-update-delete-deployment/main.go +++ b/staging/src/k8s.io/client-go/examples/dynamic-create-update-delete-deployment/main.go @@ -41,7 +41,6 @@ import ( // _ "k8s.io/client-go/plugin/pkg/client/auth/azure" // _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" // _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" - // _ "k8s.io/client-go/plugin/pkg/client/auth/openstack" ) func main() { diff --git a/staging/src/k8s.io/client-go/examples/in-cluster-client-configuration/main.go b/staging/src/k8s.io/client-go/examples/in-cluster-client-configuration/main.go index a8c71612e31..b583e337338 100644 --- a/staging/src/k8s.io/client-go/examples/in-cluster-client-configuration/main.go +++ b/staging/src/k8s.io/client-go/examples/in-cluster-client-configuration/main.go @@ -34,7 +34,6 @@ import ( // _ "k8s.io/client-go/plugin/pkg/client/auth/azure" // _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" // _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" - // _ "k8s.io/client-go/plugin/pkg/client/auth/openstack" ) func main() { diff --git a/staging/src/k8s.io/client-go/examples/out-of-cluster-client-configuration/main.go b/staging/src/k8s.io/client-go/examples/out-of-cluster-client-configuration/main.go index cf00d48094d..7698e132181 100644 --- a/staging/src/k8s.io/client-go/examples/out-of-cluster-client-configuration/main.go +++ b/staging/src/k8s.io/client-go/examples/out-of-cluster-client-configuration/main.go @@ -37,7 +37,6 @@ import ( // _ "k8s.io/client-go/plugin/pkg/client/auth/azure" // _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" // _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" - // _ "k8s.io/client-go/plugin/pkg/client/auth/openstack" ) func main() { diff --git a/staging/src/k8s.io/client-go/plugin/pkg/client/auth/openstack/openstack_stub.go b/staging/src/k8s.io/client-go/plugin/pkg/client/auth/openstack/openstack_stub.go deleted file mode 100644 index 6e404beda20..00000000000 --- a/staging/src/k8s.io/client-go/plugin/pkg/client/auth/openstack/openstack_stub.go +++ /dev/null @@ -1,36 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -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. -*/ - -package openstack - -import ( - "errors" - - "k8s.io/client-go/rest" - "k8s.io/klog/v2" -) - -func init() { - if err := rest.RegisterAuthProviderPlugin("openstack", newOpenstackAuthProvider); err != nil { - klog.Fatalf("Failed to register openstack auth plugin: %s", err) - } -} - -func newOpenstackAuthProvider(_ string, _ map[string]string, _ rest.AuthProviderConfigPersister) (rest.AuthProvider, error) { - return nil, errors.New(`The openstack auth plugin has been removed. -Please use the "client-keystone-auth" kubectl/client-go credential plugin instead. -See https://github.com/kubernetes/cloud-provider-openstack/blob/master/docs/using-client-keystone-auth.md for further details`) -} diff --git a/staging/src/k8s.io/client-go/plugin/pkg/client/auth/plugins_providers.go b/staging/src/k8s.io/client-go/plugin/pkg/client/auth/plugins_providers.go index ebfbd715c0c..3f0688774ee 100644 --- a/staging/src/k8s.io/client-go/plugin/pkg/client/auth/plugins_providers.go +++ b/staging/src/k8s.io/client-go/plugin/pkg/client/auth/plugins_providers.go @@ -23,5 +23,4 @@ import ( // Initialize client auth plugins for cloud providers. _ "k8s.io/client-go/plugin/pkg/client/auth/azure" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" - _ "k8s.io/client-go/plugin/pkg/client/auth/openstack" ) diff --git a/staging/src/k8s.io/cloud-provider/plugins.go b/staging/src/k8s.io/cloud-provider/plugins.go index bfd73163149..5300abdb4c0 100644 --- a/staging/src/k8s.io/cloud-provider/plugins.go +++ b/staging/src/k8s.io/cloud-provider/plugins.go @@ -43,7 +43,6 @@ var ( {"aws", false, "The AWS provider is deprecated and will be removed in a future release. Please use https://github.com/kubernetes/cloud-provider-aws"}, {"azure", false, "The Azure provider is deprecated and will be removed in a future release. Please use https://github.com/kubernetes-sigs/cloud-provider-azure"}, {"gce", false, "The GCE provider is deprecated and will be removed in a future release. Please use https://github.com/kubernetes/cloud-provider-gcp"}, - {"openstack", true, "https://github.com/kubernetes/cloud-provider-openstack"}, {"vsphere", false, "The vSphere provider is deprecated and will be removed in a future release. Please use https://github.com/kubernetes/cloud-provider-vsphere"}, } ) diff --git a/staging/src/k8s.io/csi-translation-lib/plugins/in_tree_volume_test.go b/staging/src/k8s.io/csi-translation-lib/plugins/in_tree_volume_test.go index 3cab797ee65..cbe50b21d75 100644 --- a/staging/src/k8s.io/csi-translation-lib/plugins/in_tree_volume_test.go +++ b/staging/src/k8s.io/csi-translation-lib/plugins/in_tree_volume_test.go @@ -421,48 +421,6 @@ func TestTranslateTopologyFromCSIToInTree(t *testing.T) { v1.LabelTopologyRegion: "us-east1", }, }, - { - name: "cinder translation", - key: CinderTopologyKey, - expErr: false, - regionParser: nil, - pv: &v1.PersistentVolume{ - ObjectMeta: metav1.ObjectMeta{ - Name: "cinder", Namespace: "myns", - }, - Spec: v1.PersistentVolumeSpec{ - NodeAffinity: &v1.VolumeNodeAffinity{ - Required: &v1.NodeSelector{ - NodeSelectorTerms: []v1.NodeSelectorTerm{ - { - MatchExpressions: []v1.NodeSelectorRequirement{ - { - Key: CinderTopologyKey, - Operator: v1.NodeSelectorOpIn, - Values: []string{"nova"}, - }, - }, - }, - }, - }, - }, - }, - }, - expectedNodeSelectorTerms: []v1.NodeSelectorTerm{ - { - MatchExpressions: []v1.NodeSelectorRequirement{ - { - Key: v1.LabelTopologyZone, - Operator: v1.NodeSelectorOpIn, - Values: []string{"nova"}, - }, - }, - }, - }, - expectedLabels: map[string]string{ - v1.LabelTopologyZone: "nova", - }, - }, } for _, tc := range testCases { diff --git a/staging/src/k8s.io/csi-translation-lib/plugins/openstack_cinder.go b/staging/src/k8s.io/csi-translation-lib/plugins/openstack_cinder.go deleted file mode 100644 index 92c5a133837..00000000000 --- a/staging/src/k8s.io/csi-translation-lib/plugins/openstack_cinder.go +++ /dev/null @@ -1,184 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors. - -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. -*/ - -package plugins - -import ( - "fmt" - "strings" - - v1 "k8s.io/api/core/v1" - storage "k8s.io/api/storage/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const ( - // CinderDriverName is the name of the CSI driver for Cinder - CinderDriverName = "cinder.csi.openstack.org" - // CinderTopologyKey is the zonal topology key for Cinder CSI Driver - CinderTopologyKey = "topology.cinder.csi.openstack.org/zone" - // CinderInTreePluginName is the name of the intree plugin for Cinder - CinderInTreePluginName = "kubernetes.io/cinder" -) - -var _ InTreePlugin = (*osCinderCSITranslator)(nil) - -// osCinderCSITranslator handles translation of PV spec from In-tree Cinder to CSI Cinder and vice versa -type osCinderCSITranslator struct{} - -// NewOpenStackCinderCSITranslator returns a new instance of osCinderCSITranslator -func NewOpenStackCinderCSITranslator() InTreePlugin { - return &osCinderCSITranslator{} -} - -// TranslateInTreeStorageClassToCSI translates InTree Cinder storage class parameters to CSI storage class -func (t *osCinderCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) { - var ( - params = map[string]string{} - ) - for k, v := range sc.Parameters { - switch strings.ToLower(k) { - case fsTypeKey: - params[csiFsTypeKey] = v - default: - // All other parameters are supported by the CSI driver. - // This includes also "availability", therefore do not translate it to sc.AllowedTopologies - params[k] = v - } - } - - if len(sc.AllowedTopologies) > 0 { - newTopologies, err := translateAllowedTopologies(sc.AllowedTopologies, CinderTopologyKey) - if err != nil { - return nil, fmt.Errorf("failed translating allowed topologies: %v", err) - } - sc.AllowedTopologies = newTopologies - } - - sc.Parameters = params - - return sc, nil -} - -// TranslateInTreeInlineVolumeToCSI takes a Volume with Cinder set from in-tree -// and converts the Cinder source to a CSIPersistentVolumeSource -func (t *osCinderCSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume, podNamespace string) (*v1.PersistentVolume, error) { - if volume == nil || volume.Cinder == nil { - return nil, fmt.Errorf("volume is nil or Cinder not defined on volume") - } - - cinderSource := volume.Cinder - pv := &v1.PersistentVolume{ - ObjectMeta: metav1.ObjectMeta{ - // Must be unique per disk as it is used as the unique part of the - // staging path - Name: fmt.Sprintf("%s-%s", CinderDriverName, cinderSource.VolumeID), - }, - Spec: v1.PersistentVolumeSpec{ - PersistentVolumeSource: v1.PersistentVolumeSource{ - CSI: &v1.CSIPersistentVolumeSource{ - Driver: CinderDriverName, - VolumeHandle: cinderSource.VolumeID, - ReadOnly: cinderSource.ReadOnly, - FSType: cinderSource.FSType, - VolumeAttributes: map[string]string{}, - }, - }, - AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, - }, - } - return pv, nil -} - -// TranslateInTreePVToCSI takes a PV with Cinder set from in-tree -// and converts the Cinder source to a CSIPersistentVolumeSource -func (t *osCinderCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { - if pv == nil || pv.Spec.Cinder == nil { - return nil, fmt.Errorf("pv is nil or Cinder not defined on pv") - } - - cinderSource := pv.Spec.Cinder - - csiSource := &v1.CSIPersistentVolumeSource{ - Driver: CinderDriverName, - VolumeHandle: cinderSource.VolumeID, - ReadOnly: cinderSource.ReadOnly, - FSType: cinderSource.FSType, - VolumeAttributes: map[string]string{}, - } - - if err := translateTopologyFromInTreeToCSI(pv, CinderTopologyKey); err != nil { - return nil, fmt.Errorf("failed to translate topology: %v", err) - } - - pv.Spec.Cinder = nil - pv.Spec.CSI = csiSource - return pv, nil -} - -// TranslateCSIPVToInTree takes a PV with CSIPersistentVolumeSource set and -// translates the Cinder CSI source to a Cinder In-tree source. -func (t *osCinderCSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { - if pv == nil || pv.Spec.CSI == nil { - return nil, fmt.Errorf("pv is nil or CSI source not defined on pv") - } - - csiSource := pv.Spec.CSI - - cinderSource := &v1.CinderPersistentVolumeSource{ - VolumeID: csiSource.VolumeHandle, - FSType: csiSource.FSType, - ReadOnly: csiSource.ReadOnly, - } - - // translate CSI topology to In-tree topology for rollback compatibility. - // It is not possible to guess Cinder Region from the Zone, therefore leave it empty. - if err := translateTopologyFromCSIToInTree(pv, CinderTopologyKey, nil); err != nil { - return nil, fmt.Errorf("failed to translate topology. PV:%+v. Error:%v", *pv, err) - } - - pv.Spec.CSI = nil - pv.Spec.Cinder = cinderSource - return pv, nil -} - -// CanSupport tests whether the plugin supports a given persistent volume -// specification from the API. The spec pointer should be considered -// const. -func (t *osCinderCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { - return pv != nil && pv.Spec.Cinder != nil -} - -// CanSupportInline tests whether the plugin supports a given inline volume -// specification from the API. The spec pointer should be considered -// const. -func (t *osCinderCSITranslator) CanSupportInline(volume *v1.Volume) bool { - return volume != nil && volume.Cinder != nil -} - -// GetInTreePluginName returns the name of the intree plugin driver -func (t *osCinderCSITranslator) GetInTreePluginName() string { - return CinderInTreePluginName -} - -// GetCSIPluginName returns the name of the CSI plugin -func (t *osCinderCSITranslator) GetCSIPluginName() string { - return CinderDriverName -} - -func (t *osCinderCSITranslator) RepairVolumeHandle(volumeHandle, nodeID string) (string, error) { - return volumeHandle, nil -} diff --git a/staging/src/k8s.io/csi-translation-lib/plugins/openstack_cinder_test.go b/staging/src/k8s.io/csi-translation-lib/plugins/openstack_cinder_test.go deleted file mode 100644 index e4a95da8083..00000000000 --- a/staging/src/k8s.io/csi-translation-lib/plugins/openstack_cinder_test.go +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright 2021 The Kubernetes Authors. - -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. -*/ - -package plugins - -import ( - "reflect" - "testing" - - v1 "k8s.io/api/core/v1" - storage "k8s.io/api/storage/v1" -) - -func TestTranslateCinderInTreeStorageClassToCSI(t *testing.T) { - translator := NewOpenStackCinderCSITranslator() - - cases := []struct { - name string - sc *storage.StorageClass - expSc *storage.StorageClass - expErr bool - }{ - { - name: "translate normal", - sc: NewStorageClass(map[string]string{"foo": "bar"}, nil), - expSc: NewStorageClass(map[string]string{"foo": "bar"}, nil), - }, - { - name: "translate empty map", - sc: NewStorageClass(map[string]string{}, nil), - expSc: NewStorageClass(map[string]string{}, nil), - }, - - { - name: "translate with fstype", - sc: NewStorageClass(map[string]string{"fstype": "ext3"}, nil), - expSc: NewStorageClass(map[string]string{"csi.storage.k8s.io/fstype": "ext3"}, nil), - }, - { - name: "translate with topology in parameters (no translation expected)", - sc: NewStorageClass(map[string]string{"availability": "nova"}, nil), - expSc: NewStorageClass(map[string]string{"availability": "nova"}, nil), - }, - { - name: "translate with topology", - sc: NewStorageClass(map[string]string{}, generateToplogySelectors(v1.LabelFailureDomainBetaZone, []string{"nova"})), - expSc: NewStorageClass(map[string]string{}, generateToplogySelectors(CinderTopologyKey, []string{"nova"})), - }, - } - - for _, tc := range cases { - t.Logf("Testing %v", tc.name) - got, err := translator.TranslateInTreeStorageClassToCSI(tc.sc) - if err != nil && !tc.expErr { - t.Errorf("Did not expect error but got: %v", err) - } - - if err == nil && tc.expErr { - t.Errorf("Expected error, but did not get one.") - } - - if !reflect.DeepEqual(got, tc.expSc) { - t.Errorf("Got parameters: %v, expected: %v", got, tc.expSc) - } - - } -} diff --git a/staging/src/k8s.io/csi-translation-lib/translate.go b/staging/src/k8s.io/csi-translation-lib/translate.go index 9dde216299b..96f2d609ce4 100644 --- a/staging/src/k8s.io/csi-translation-lib/translate.go +++ b/staging/src/k8s.io/csi-translation-lib/translate.go @@ -29,7 +29,6 @@ var ( inTreePlugins = map[string]plugins.InTreePlugin{ plugins.GCEPDDriverName: plugins.NewGCEPersistentDiskCSITranslator(), plugins.AWSEBSDriverName: plugins.NewAWSElasticBlockStoreCSITranslator(), - plugins.CinderDriverName: plugins.NewOpenStackCinderCSITranslator(), plugins.AzureDiskDriverName: plugins.NewAzureDiskCSITranslator(), plugins.AzureFileDriverName: plugins.NewAzureFileCSITranslator(), plugins.VSphereDriverName: plugins.NewvSphereCSITranslator(), diff --git a/staging/src/k8s.io/csi-translation-lib/translate_test.go b/staging/src/k8s.io/csi-translation-lib/translate_test.go index 8a08c6e6ed3..592edda9e2b 100644 --- a/staging/src/k8s.io/csi-translation-lib/translate_test.go +++ b/staging/src/k8s.io/csi-translation-lib/translate_test.go @@ -189,17 +189,6 @@ func TestTopologyTranslation(t *testing.T) { pv: makeAWSEBSPV(kubernetesGATopologyLabels, makeTopology(v1.LabelTopologyZone, "us-east-2a")), expectedNodeAffinity: makeNodeAffinity(false /*multiTerms*/, plugins.AWSEBSTopologyKey, "us-east-2a"), }, - // Cinder test cases: test mosty topology key, i.e., don't repeat testing done with GCE - { - name: "OpenStack Cinder with zone labels", - pv: makeCinderPV(kubernetesBetaTopologyLabels, nil /*topology*/), - expectedNodeAffinity: makeNodeAffinity(false /*multiTerms*/, plugins.CinderTopologyKey, "us-east-1a"), - }, - { - name: "OpenStack Cinder with zone labels and topology", - pv: makeCinderPV(kubernetesBetaTopologyLabels, makeTopology(v1.LabelFailureDomainBetaZone, "us-east-2a")), - expectedNodeAffinity: makeNodeAffinity(false /*multiTerms*/, plugins.CinderTopologyKey, "us-east-2a"), - }, } for _, test := range testCases { @@ -302,18 +291,6 @@ func makeAWSEBSPV(labels map[string]string, topology *v1.NodeSelectorRequirement return pv } -func makeCinderPV(labels map[string]string, topology *v1.NodeSelectorRequirement) *v1.PersistentVolume { - pv := makePV(labels, topology) - pv.Spec.PersistentVolumeSource = v1.PersistentVolumeSource{ - Cinder: &v1.CinderPersistentVolumeSource{ - VolumeID: "vol1", - FSType: "ext4", - ReadOnly: false, - }, - } - return pv -} - func makeNodeAffinity(multiTerms bool, key string, values ...string) *v1.VolumeNodeAffinity { nodeAffinity := &v1.VolumeNodeAffinity{ Required: &v1.NodeSelector{ @@ -412,12 +389,6 @@ func generateUniqueVolumeSource(driverName string) (v1.VolumeSource, error) { }, }, nil - case plugins.CinderDriverName: - return v1.VolumeSource{ - Cinder: &v1.CinderVolumeSource{ - VolumeID: string(uuid.NewUUID()), - }, - }, nil case plugins.AzureDiskDriverName: return v1.VolumeSource{ AzureDisk: &v1.AzureDiskVolumeSource{ diff --git a/staging/src/k8s.io/kubectl/pkg/describe/describe.go b/staging/src/k8s.io/kubectl/pkg/describe/describe.go index 484ed09f67c..456c779bd3d 100644 --- a/staging/src/k8s.io/kubectl/pkg/describe/describe.go +++ b/staging/src/k8s.io/kubectl/pkg/describe/describe.go @@ -947,8 +947,6 @@ func describeVolumes(volumes []corev1.Volume, w PrefixWriter, space string) { printAzureDiskVolumeSource(volume.VolumeSource.AzureDisk, w) case volume.VolumeSource.VsphereVolume != nil: printVsphereVolumeSource(volume.VolumeSource.VsphereVolume, w) - case volume.VolumeSource.Cinder != nil: - printCinderVolumeSource(volume.VolumeSource.Cinder, w) case volume.VolumeSource.PhotonPersistentDisk != nil: printPhotonPersistentDiskVolumeSource(volume.VolumeSource.PhotonPersistentDisk, w) case volume.VolumeSource.PortworxVolume != nil: @@ -1227,24 +1225,6 @@ func printPhotonPersistentDiskVolumeSource(photon *corev1.PhotonPersistentDiskVo photon.PdID, photon.FSType) } -func printCinderVolumeSource(cinder *corev1.CinderVolumeSource, w PrefixWriter) { - w.Write(LEVEL_2, "Type:\tCinder (a Persistent Disk resource in OpenStack)\n"+ - " VolumeID:\t%v\n"+ - " FSType:\t%v\n"+ - " ReadOnly:\t%v\n"+ - " SecretRef:\t%v\n", - cinder.VolumeID, cinder.FSType, cinder.ReadOnly, cinder.SecretRef) -} - -func printCinderPersistentVolumeSource(cinder *corev1.CinderPersistentVolumeSource, w PrefixWriter) { - w.Write(LEVEL_2, "Type:\tCinder (a Persistent Disk resource in OpenStack)\n"+ - " VolumeID:\t%v\n"+ - " FSType:\t%v\n"+ - " ReadOnly:\t%v\n"+ - " SecretRef:\t%v\n", - cinder.VolumeID, cinder.FSType, cinder.ReadOnly, cinder.SecretRef) -} - func printScaleIOVolumeSource(sio *corev1.ScaleIOVolumeSource, w PrefixWriter) { w.Write(LEVEL_2, "Type:\tScaleIO (a persistent volume backed by a block device in ScaleIO)\n"+ " Gateway:\t%v\n"+ @@ -1562,8 +1542,6 @@ func describePersistentVolume(pv *corev1.PersistentVolume, events *corev1.EventL printQuobyteVolumeSource(pv.Spec.Quobyte, w) case pv.Spec.VsphereVolume != nil: printVsphereVolumeSource(pv.Spec.VsphereVolume, w) - case pv.Spec.Cinder != nil: - printCinderPersistentVolumeSource(pv.Spec.Cinder, w) case pv.Spec.AzureDisk != nil: printAzureDiskVolumeSource(pv.Spec.AzureDisk, w) case pv.Spec.PhotonPersistentDisk != nil: diff --git a/staging/src/k8s.io/kubectl/pkg/describe/describe_test.go b/staging/src/k8s.io/kubectl/pkg/describe/describe_test.go index 5225ec2db13..37eee41ece8 100644 --- a/staging/src/k8s.io/kubectl/pkg/describe/describe_test.go +++ b/staging/src/k8s.io/kubectl/pkg/describe/describe_test.go @@ -1483,19 +1483,6 @@ func TestPersistentVolumeDescriber(t *testing.T) { }, unexpectedElements: []string{"VolumeMode", "Filesystem"}, }, - { - name: "test8", - plugin: "cinder", - pv: &corev1.PersistentVolume{ - ObjectMeta: metav1.ObjectMeta{Name: "bar"}, - Spec: corev1.PersistentVolumeSpec{ - PersistentVolumeSource: corev1.PersistentVolumeSource{ - Cinder: &corev1.CinderPersistentVolumeSource{}, - }, - }, - }, - unexpectedElements: []string{"VolumeMode", "Filesystem"}, - }, { name: "test9", plugin: "fc", diff --git a/staging/src/k8s.io/legacy-cloud-providers/go.mod b/staging/src/k8s.io/legacy-cloud-providers/go.mod index a4ac4504a1e..eaea2c0b7b8 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/go.mod +++ b/staging/src/k8s.io/legacy-cloud-providers/go.mod @@ -15,8 +15,6 @@ require ( github.com/aws/aws-sdk-go v1.38.49 github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.5.6 - github.com/gophercloud/gophercloud v0.1.0 - github.com/mitchellh/mapstructure v1.4.1 github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021 github.com/stretchr/testify v1.7.0 github.com/vmware/govmomi v0.20.3 @@ -31,7 +29,6 @@ require ( k8s.io/component-base v0.0.0 k8s.io/csi-translation-lib v0.0.0 k8s.io/klog/v2 v2.70.1 - k8s.io/mount-utils v0.0.0 k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed sigs.k8s.io/yaml v1.2.0 ) @@ -64,13 +61,11 @@ require ( github.com/google/gofuzz v1.1.0 // indirect github.com/google/uuid v1.1.2 // indirect github.com/googleapis/gax-go/v2 v2.1.1 // indirect - github.com/imdario/mergo v0.3.6 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.6 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/moby/sys/mountinfo v0.6.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect @@ -112,5 +107,4 @@ replace ( k8s.io/controller-manager => ../controller-manager k8s.io/csi-translation-lib => ../csi-translation-lib k8s.io/legacy-cloud-providers => ../legacy-cloud-providers - k8s.io/mount-utils => ../mount-utils ) diff --git a/staging/src/k8s.io/legacy-cloud-providers/go.sum b/staging/src/k8s.io/legacy-cloud-providers/go.sum index 86670b22689..9cda79986df 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/go.sum +++ b/staging/src/k8s.io/legacy-cloud-providers/go.sum @@ -238,15 +238,11 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1 h1:dp3bWCh+PPO1zjRRiCSczJav13sBvG4UhNyVTa1KqdU= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -280,10 +276,6 @@ github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/sys/mountinfo v0.6.0 h1:gUDhXQx58YNrpHlK4nSL+7y2pxFZkUcXqzFDKWdC0Oo= -github.com/moby/sys/mountinfo v0.6.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -367,7 +359,6 @@ go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -486,7 +477,6 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/staging/src/k8s.io/legacy-cloud-providers/openstack/MAINTAINERS.md b/staging/src/k8s.io/legacy-cloud-providers/openstack/MAINTAINERS.md deleted file mode 100644 index 0802490bcd1..00000000000 --- a/staging/src/k8s.io/legacy-cloud-providers/openstack/MAINTAINERS.md +++ /dev/null @@ -1,4 +0,0 @@ -# Maintainers - -* [Angus Lees](https://github.com/anguslees) - diff --git a/staging/src/k8s.io/legacy-cloud-providers/openstack/OWNERS b/staging/src/k8s.io/legacy-cloud-providers/openstack/OWNERS deleted file mode 100644 index 6b5183953e2..00000000000 --- a/staging/src/k8s.io/legacy-cloud-providers/openstack/OWNERS +++ /dev/null @@ -1,13 +0,0 @@ -# See the OWNERS docs at https://go.k8s.io/owners -# We are no longer accepting features into k8s.io/legacy-cloud-providers. -# Any kind/feature PRs must be approved by SIG Cloud Provider going forward. - -emeritus_approvers: - - anguslees - - NickrenREN - - dims - - FengyunPan2 -reviewers: - - anguslees - - NickrenREN - - dims diff --git a/staging/src/k8s.io/legacy-cloud-providers/openstack/metadata.go b/staging/src/k8s.io/legacy-cloud-providers/openstack/metadata.go deleted file mode 100644 index 948b32a5b67..00000000000 --- a/staging/src/k8s.io/legacy-cloud-providers/openstack/metadata.go +++ /dev/null @@ -1,201 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package openstack - -import ( - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "path/filepath" - "strings" - - "k8s.io/klog/v2" - "k8s.io/mount-utils" - "k8s.io/utils/exec" -) - -const ( - // metadataURLTemplate allows building an OpenStack Metadata service URL. - // It's a hardcoded IPv4 link-local address as documented in "OpenStack Cloud - // Administrator Guide", chapter Compute - Networking with nova-network. - //https://docs.openstack.org/nova/latest/admin/networking-nova.html#metadata-service - defaultMetadataVersion = "2012-08-10" - metadataURLTemplate = "http://169.254.169.254/openstack/%s/meta_data.json" - - // metadataID is used as an identifier on the metadata search order configuration. - metadataID = "metadataService" - - // Config drive is defined as an iso9660 or vfat (deprecated) drive - // with the "config-2" label. - //https://docs.openstack.org/nova/latest/user/config-drive.html - configDriveLabel = "config-2" - configDrivePathTemplate = "openstack/%s/meta_data.json" - - // configDriveID is used as an identifier on the metadata search order configuration. - configDriveID = "configDrive" -) - -// ErrBadMetadata is used to indicate a problem parsing data from metadata server -var ErrBadMetadata = errors.New("invalid OpenStack metadata, got empty uuid") - -// DeviceMetadata is a single/simplified data structure for all kinds of device metadata types. -type DeviceMetadata struct { - Type string `json:"type"` - Bus string `json:"bus,omitempty"` - Serial string `json:"serial,omitempty"` - Address string `json:"address,omitempty"` - // .. and other fields. -} - -// Metadata has the information fetched from OpenStack metadata service or -// config drives. Assumes the "2012-08-10" meta_data.json format. -// See http://docs.openstack.org/user-guide/cli_config_drive.html -type Metadata struct { - UUID string `json:"uuid"` - Name string `json:"name"` - AvailabilityZone string `json:"availability_zone"` - Devices []DeviceMetadata `json:"devices,omitempty"` - // .. and other fields we don't care about. Expand as necessary. -} - -// parseMetadata reads JSON from OpenStack metadata server and parses -// instance ID out of it. -func parseMetadata(r io.Reader) (*Metadata, error) { - var metadata Metadata - json := json.NewDecoder(r) - if err := json.Decode(&metadata); err != nil { - return nil, err - } - - if metadata.UUID == "" { - return nil, ErrBadMetadata - } - - return &metadata, nil -} - -func getMetadataURL(metadataVersion string) string { - return fmt.Sprintf(metadataURLTemplate, metadataVersion) -} - -func getConfigDrivePath(metadataVersion string) string { - return fmt.Sprintf(configDrivePathTemplate, metadataVersion) -} - -func getMetadataFromConfigDrive(metadataVersion string) (*Metadata, error) { - // Try to read instance UUID from config drive. - dev := "/dev/disk/by-label/" + configDriveLabel - if _, err := os.Stat(dev); os.IsNotExist(err) { - out, err := exec.New().Command( - "blkid", "-l", - "-t", "LABEL="+configDriveLabel, - "-o", "device", - ).CombinedOutput() - if err != nil { - return nil, fmt.Errorf("unable to run blkid: %v", err) - } - dev = strings.TrimSpace(string(out)) - } - - mntdir, err := ioutil.TempDir("", "configdrive") - if err != nil { - return nil, err - } - defer os.Remove(mntdir) - - klog.V(4).Infof("Attempting to mount configdrive %s on %s", dev, mntdir) - - mounter := mount.New("" /* default mount path */) - err = mounter.Mount(dev, mntdir, "iso9660", []string{"ro"}) - if err != nil { - err = mounter.Mount(dev, mntdir, "vfat", []string{"ro"}) - } - if err != nil { - return nil, fmt.Errorf("error mounting configdrive %s: %v", dev, err) - } - defer mounter.Unmount(mntdir) - - klog.V(4).Infof("Configdrive mounted on %s", mntdir) - - configDrivePath := getConfigDrivePath(metadataVersion) - f, err := os.Open( - filepath.Join(mntdir, configDrivePath)) - if err != nil { - return nil, fmt.Errorf("error reading %s on config drive: %v", configDrivePath, err) - } - defer f.Close() - - return parseMetadata(f) -} - -func getMetadataFromMetadataService(metadataVersion string) (*Metadata, error) { - // Try to get JSON from metadata server. - metadataURL := getMetadataURL(metadataVersion) - klog.V(4).Infof("Attempting to fetch metadata from %s", metadataURL) - resp, err := http.Get(metadataURL) - if err != nil { - return nil, fmt.Errorf("error fetching %s: %v", metadataURL, err) - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - err = fmt.Errorf("unexpected status code when reading metadata from %s: %s", metadataURL, resp.Status) - return nil, err - } - - return parseMetadata(resp.Body) -} - -// Metadata is fixed for the current host, so cache the value process-wide -var metadataCache *Metadata - -func getMetadata(order string) (*Metadata, error) { - if metadataCache == nil { - var md *Metadata - var err error - - elements := strings.Split(order, ",") - for _, id := range elements { - id = strings.TrimSpace(id) - switch id { - case configDriveID: - md, err = getMetadataFromConfigDrive(defaultMetadataVersion) - case metadataID: - md, err = getMetadataFromMetadataService(defaultMetadataVersion) - default: - err = fmt.Errorf("%s is not a valid metadata search order option. Supported options are %s and %s", id, configDriveID, metadataID) - } - - if err == nil { - break - } - } - - if err != nil { - return nil, err - } - metadataCache = md - } - return metadataCache, nil -} diff --git a/staging/src/k8s.io/legacy-cloud-providers/openstack/metadata_test.go b/staging/src/k8s.io/legacy-cloud-providers/openstack/metadata_test.go deleted file mode 100644 index d0eb67d54c6..00000000000 --- a/staging/src/k8s.io/legacy-cloud-providers/openstack/metadata_test.go +++ /dev/null @@ -1,118 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package openstack - -import ( - "strings" - "testing" -) - -var FakeMetadata = Metadata{ - UUID: "83679162-1378-4288-a2d4-70e13ec132aa", - Name: "test", - AvailabilityZone: "nova", -} - -func SetMetadataFixture(value *Metadata) { - metadataCache = value -} - -func ClearMetadata() { - metadataCache = nil -} - -func TestParseMetadata(t *testing.T) { - _, err := parseMetadata(strings.NewReader("bogus")) - if err == nil { - t.Errorf("Should fail when bad data is provided: %s", err) - } - - data := strings.NewReader(` -{ - "availability_zone": "nova", - "files": [ - { - "content_path": "/content/0000", - "path": "/etc/network/interfaces" - }, - { - "content_path": "/content/0001", - "path": "known_hosts" - } - ], - "hostname": "test.novalocal", - "launch_index": 0, - "name": "test", - "meta": { - "role": "webservers", - "essential": "false" - }, - "public_keys": { - "mykey": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDBqUfVvCSez0/Wfpd8dLLgZXV9GtXQ7hnMN+Z0OWQUyebVEHey1CXuin0uY1cAJMhUq8j98SiW+cU0sU4J3x5l2+xi1bodDm1BtFWVeLIOQINpfV1n8fKjHB+ynPpe1F6tMDvrFGUlJs44t30BrujMXBe8Rq44cCk6wqyjATA3rQ== Generated by Nova\n" - }, - "uuid": "83679162-1378-4288-a2d4-70e13ec132aa", - "devices": [ - { - "bus": "scsi", - "serial": "6df1888b-f373-41cf-b960-3786e60a28ef", - "tags": ["fake_tag"], - "type": "disk", - "address": "0:0:0:0" - } - ] -} -`) - md, err := parseMetadata(data) - if err != nil { - t.Fatalf("Should succeed when provided with valid data: %s", err) - } - - if md.Name != "test" { - t.Errorf("incorrect name: %s", md.Name) - } - - if md.UUID != "83679162-1378-4288-a2d4-70e13ec132aa" { - t.Errorf("incorrect uuid: %s", md.UUID) - } - - if md.AvailabilityZone != "nova" { - t.Errorf("incorrect az: %s", md.AvailabilityZone) - } - - if len(md.Devices) != 1 { - t.Errorf("expecting to find 1 device, found %d", len(md.Devices)) - } - - if md.Devices[0].Bus != "scsi" { - t.Errorf("incorrect disk bus: %s", md.Devices[0].Bus) - } - - if md.Devices[0].Address != "0:0:0:0" { - t.Errorf("incorrect disk address: %s", md.Devices[0].Address) - } - - if md.Devices[0].Type != "disk" { - t.Errorf("incorrect device type: %s", md.Devices[0].Type) - } - - if md.Devices[0].Serial != "6df1888b-f373-41cf-b960-3786e60a28ef" { - t.Errorf("incorrect device serial: %s", md.Devices[0].Serial) - } -} diff --git a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack.go b/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack.go deleted file mode 100644 index 668caaecc07..00000000000 --- a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack.go +++ /dev/null @@ -1,949 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2014 The Kubernetes Authors. - -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. -*/ - -package openstack - -import ( - "context" - "crypto/tls" - "errors" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "reflect" - "regexp" - "strings" - "time" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack" - "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces" - "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" - "github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts" - tokens3 "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens" - "github.com/gophercloud/gophercloud/pagination" - "github.com/mitchellh/mapstructure" - "gopkg.in/gcfg.v1" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - netutil "k8s.io/apimachinery/pkg/util/net" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" - certutil "k8s.io/client-go/util/cert" - cloudprovider "k8s.io/cloud-provider" - nodehelpers "k8s.io/cloud-provider/node/helpers" - "k8s.io/klog/v2" - netutils "k8s.io/utils/net" -) - -const ( - // ProviderName is the name of the openstack provider - ProviderName = "openstack" - - // TypeHostName is the name type of openstack instance - TypeHostName = "hostname" - availabilityZone = "availability_zone" - defaultTimeOut = 60 * time.Second -) - -// ErrNotFound is used to inform that the object is missing -var ErrNotFound = errors.New("failed to find object") - -// ErrMultipleResults is used when we unexpectedly get back multiple results -var ErrMultipleResults = errors.New("multiple results where only one expected") - -// ErrNoAddressFound is used when we cannot find an ip address for the host -var ErrNoAddressFound = errors.New("no address found for host") - -// MyDuration is the encoding.TextUnmarshaler interface for time.Duration -type MyDuration struct { - time.Duration -} - -// UnmarshalText is used to convert from text to Duration -func (d *MyDuration) UnmarshalText(text []byte) error { - res, err := time.ParseDuration(string(text)) - if err != nil { - return err - } - d.Duration = res - return nil -} - -// LoadBalancer is used for creating and maintaining load balancers -type LoadBalancer struct { - network *gophercloud.ServiceClient - compute *gophercloud.ServiceClient - lb *gophercloud.ServiceClient - opts LoadBalancerOpts -} - -// LoadBalancerOpts have the options to talk to Neutron LBaaSV2 or Octavia -type LoadBalancerOpts struct { - LBVersion string `gcfg:"lb-version"` // overrides autodetection. Only support v2. - UseOctavia bool `gcfg:"use-octavia"` // uses Octavia V2 service catalog endpoint - SubnetID string `gcfg:"subnet-id"` // overrides autodetection. - FloatingNetworkID string `gcfg:"floating-network-id"` // If specified, will create floating ip for loadbalancer, or do not create floating ip. - LBMethod string `gcfg:"lb-method"` // default to ROUND_ROBIN. - LBProvider string `gcfg:"lb-provider"` - CreateMonitor bool `gcfg:"create-monitor"` - MonitorDelay MyDuration `gcfg:"monitor-delay"` - MonitorTimeout MyDuration `gcfg:"monitor-timeout"` - MonitorMaxRetries uint `gcfg:"monitor-max-retries"` - ManageSecurityGroups bool `gcfg:"manage-security-groups"` - NodeSecurityGroupIDs []string // Do not specify, get it automatically when enable manage-security-groups. TODO(FengyunPan): move it into cache -} - -// BlockStorageOpts is used to talk to Cinder service -type BlockStorageOpts struct { - BSVersion string `gcfg:"bs-version"` // overrides autodetection. v1 or v2. Defaults to auto - TrustDevicePath bool `gcfg:"trust-device-path"` // See Issue #33128 - IgnoreVolumeAZ bool `gcfg:"ignore-volume-az"` - NodeVolumeAttachLimit int `gcfg:"node-volume-attach-limit"` // override volume attach limit for Cinder. Default is : 256 -} - -// RouterOpts is used for Neutron routes -type RouterOpts struct { - RouterID string `gcfg:"router-id"` // required -} - -// MetadataOpts is used for configuring how to talk to metadata service or config drive -type MetadataOpts struct { - SearchOrder string `gcfg:"search-order"` - RequestTimeout MyDuration `gcfg:"request-timeout"` -} - -var _ cloudprovider.Interface = (*OpenStack)(nil) -var _ cloudprovider.Zones = (*OpenStack)(nil) - -// OpenStack is an implementation of cloud provider Interface for OpenStack. -type OpenStack struct { - provider *gophercloud.ProviderClient - region string - lbOpts LoadBalancerOpts - bsOpts BlockStorageOpts - routeOpts RouterOpts - metadataOpts MetadataOpts - // InstanceID of the server where this OpenStack object is instantiated. - localInstanceID string -} - -// Config is used to read and store information from the cloud configuration file -// NOTE: Cloud config files should follow the same Kubernetes deprecation policy as -// flags or CLIs. Config fields should not change behavior in incompatible ways and -// should be deprecated for at least 2 release prior to removing. -// See https://kubernetes.io/docs/reference/using-api/deprecation-policy/#deprecating-a-flag-or-cli -// for more details. -type Config struct { - Global struct { - AuthURL string `gcfg:"auth-url"` - Username string - UserID string `gcfg:"user-id"` - Password string `datapolicy:"password"` - TenantID string `gcfg:"tenant-id"` - TenantName string `gcfg:"tenant-name"` - TrustID string `gcfg:"trust-id"` - DomainID string `gcfg:"domain-id"` - DomainName string `gcfg:"domain-name"` - Region string - CAFile string `gcfg:"ca-file"` - SecretName string `gcfg:"secret-name"` - SecretNamespace string `gcfg:"secret-namespace"` - KubeconfigPath string `gcfg:"kubeconfig-path"` - } - LoadBalancer LoadBalancerOpts - BlockStorage BlockStorageOpts - Route RouterOpts - Metadata MetadataOpts -} - -func init() { - registerMetrics() - - cloudprovider.RegisterCloudProvider(ProviderName, func(config io.Reader) (cloudprovider.Interface, error) { - cfg, err := readConfig(config) - if err != nil { - return nil, err - } - return newOpenStack(cfg) - }) -} - -func (cfg Config) toAuthOptions() gophercloud.AuthOptions { - return gophercloud.AuthOptions{ - IdentityEndpoint: cfg.Global.AuthURL, - Username: cfg.Global.Username, - UserID: cfg.Global.UserID, - Password: cfg.Global.Password, - TenantID: cfg.Global.TenantID, - TenantName: cfg.Global.TenantName, - DomainID: cfg.Global.DomainID, - DomainName: cfg.Global.DomainName, - - // Persistent service, so we need to be able to renew tokens. - AllowReauth: true, - } -} - -func (cfg Config) toAuth3Options() tokens3.AuthOptions { - return tokens3.AuthOptions{ - IdentityEndpoint: cfg.Global.AuthURL, - Username: cfg.Global.Username, - UserID: cfg.Global.UserID, - Password: cfg.Global.Password, - DomainID: cfg.Global.DomainID, - DomainName: cfg.Global.DomainName, - AllowReauth: true, - } -} - -// configFromEnv allows setting up credentials etc using the -// standard OS_* OpenStack client environment variables. -func configFromEnv() (cfg Config, ok bool) { - cfg.Global.AuthURL = os.Getenv("OS_AUTH_URL") - cfg.Global.Username = os.Getenv("OS_USERNAME") - cfg.Global.Region = os.Getenv("OS_REGION_NAME") - cfg.Global.UserID = os.Getenv("OS_USER_ID") - cfg.Global.TrustID = os.Getenv("OS_TRUST_ID") - - cfg.Global.TenantID = os.Getenv("OS_TENANT_ID") - if cfg.Global.TenantID == "" { - cfg.Global.TenantID = os.Getenv("OS_PROJECT_ID") - } - cfg.Global.TenantName = os.Getenv("OS_TENANT_NAME") - if cfg.Global.TenantName == "" { - cfg.Global.TenantName = os.Getenv("OS_PROJECT_NAME") - } - - cfg.Global.DomainID = os.Getenv("OS_DOMAIN_ID") - if cfg.Global.DomainID == "" { - cfg.Global.DomainID = os.Getenv("OS_USER_DOMAIN_ID") - } - cfg.Global.DomainName = os.Getenv("OS_DOMAIN_NAME") - if cfg.Global.DomainName == "" { - cfg.Global.DomainName = os.Getenv("OS_USER_DOMAIN_NAME") - } - - cfg.Global.SecretName = os.Getenv("SECRET_NAME") - cfg.Global.SecretNamespace = os.Getenv("SECRET_NAMESPACE") - cfg.Global.KubeconfigPath = os.Getenv("KUBECONFIG_PATH") - - ok = cfg.Global.AuthURL != "" && - cfg.Global.Username != "" && - cfg.Global.Password != "" && - (cfg.Global.TenantID != "" || cfg.Global.TenantName != "" || - cfg.Global.DomainID != "" || cfg.Global.DomainName != "" || - cfg.Global.Region != "" || cfg.Global.UserID != "" || - cfg.Global.TrustID != "") - - cfg.Metadata.SearchOrder = fmt.Sprintf("%s,%s", configDriveID, metadataID) - cfg.BlockStorage.BSVersion = "auto" - - return -} - -func createKubernetesClient(kubeconfigPath string) (*kubernetes.Clientset, error) { - klog.Info("Creating kubernetes API client.") - - cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath) - if err != nil { - return nil, err - } - cfg.DisableCompression = true - - client, err := kubernetes.NewForConfig(cfg) - if err != nil { - return nil, err - } - - v, err := client.Discovery().ServerVersion() - if err != nil { - return nil, err - } - - klog.Infof("Kubernetes API client created, server version %s", fmt.Sprintf("v%v.%v", v.Major, v.Minor)) - return client, nil -} - -// setConfigFromSecret allows setting up the config from k8s secret -func setConfigFromSecret(cfg *Config) error { - secretName := cfg.Global.SecretName - secretNamespace := cfg.Global.SecretNamespace - kubeconfigPath := cfg.Global.KubeconfigPath - - k8sClient, err := createKubernetesClient(kubeconfigPath) - if err != nil { - return fmt.Errorf("failed to get kubernetes client: %v", err) - } - - secret, err := k8sClient.CoreV1().Secrets(secretNamespace).Get(context.TODO(), secretName, metav1.GetOptions{}) - if err != nil { - klog.Warningf("Cannot get secret %s in namespace %s. error: %q", secretName, secretNamespace, err) - return err - } - - if content, ok := secret.Data["clouds.conf"]; ok { - err = gcfg.ReadStringInto(cfg, string(content)) - if err != nil { - klog.Error("Cannot parse data from the secret.") - return fmt.Errorf("cannot parse data from the secret") - } - return nil - } - - klog.Error("Cannot find \"clouds.conf\" key in the secret.") - return fmt.Errorf("cannot find \"clouds.conf\" key in the secret") -} - -func readConfig(config io.Reader) (Config, error) { - if config == nil { - return Config{}, fmt.Errorf("no OpenStack cloud provider config file given") - } - - cfg, _ := configFromEnv() - - // Set default values for config params - cfg.BlockStorage.BSVersion = "auto" - cfg.BlockStorage.TrustDevicePath = false - cfg.BlockStorage.IgnoreVolumeAZ = false - cfg.Metadata.SearchOrder = fmt.Sprintf("%s,%s", configDriveID, metadataID) - - err := gcfg.ReadInto(&cfg, config) - if err != nil { - // Warn instead of failing on non-fatal config parsing errors. - // This is important during the transition to external CCM we - // may be sharing user-managed configuration KCM, using legacy - // cloud provider, and CCM using external cloud provider. - // We do not want to prevent KCM from starting if the user adds - // new configuration which is only present in OpenStack CCM. - if gcfg.FatalOnly(err) == nil { - klog.Warningf("Non-fatal error parsing OpenStack cloud config. "+ - "This may happen when passing config directives exclusive to OpenStack CCM to the legacy cloud provider. "+ - "Legacy cloud provider has correctly parsed all directives it knows about: %s", err) - } else { - return cfg, err - } - } - - if cfg.Global.SecretName != "" && cfg.Global.SecretNamespace != "" { - klog.Infof("Set credentials from secret %s in namespace %s", cfg.Global.SecretName, cfg.Global.SecretNamespace) - err = setConfigFromSecret(&cfg) - if err != nil { - return cfg, err - } - } - - return cfg, nil -} - -// caller is a tiny helper for conditional unwind logic -type caller bool - -func newCaller() caller { return caller(true) } -func (c *caller) disarm() { *c = false } - -func (c *caller) call(f func()) { - if *c { - f() - } -} - -func readInstanceID(searchOrder string) (string, error) { - // Try to find instance ID on the local filesystem (created by cloud-init) - const instanceIDFile = "/var/lib/cloud/data/instance-id" - idBytes, err := ioutil.ReadFile(instanceIDFile) - if err == nil { - instanceID := string(idBytes) - instanceID = strings.TrimSpace(instanceID) - klog.V(3).Infof("Got instance id from %s: %s", instanceIDFile, instanceID) - if instanceID != "" { - return instanceID, nil - } - // Fall through to metadata server lookup - } - - md, err := getMetadata(searchOrder) - if err != nil { - return "", err - } - - return md.UUID, nil -} - -// check opts for OpenStack -func checkOpenStackOpts(openstackOpts *OpenStack) error { - lbOpts := openstackOpts.lbOpts - - // if need to create health monitor for Neutron LB, - // monitor-delay, monitor-timeout and monitor-max-retries should be set. - emptyDuration := MyDuration{} - if lbOpts.CreateMonitor { - if lbOpts.MonitorDelay == emptyDuration { - return fmt.Errorf("monitor-delay not set in cloud provider config") - } - if lbOpts.MonitorTimeout == emptyDuration { - return fmt.Errorf("monitor-timeout not set in cloud provider config") - } - if lbOpts.MonitorMaxRetries == uint(0) { - return fmt.Errorf("monitor-max-retries not set in cloud provider config") - } - } - return checkMetadataSearchOrder(openstackOpts.metadataOpts.SearchOrder) -} - -func newOpenStack(cfg Config) (*OpenStack, error) { - provider, err := openstack.NewClient(cfg.Global.AuthURL) - if err != nil { - return nil, err - } - if cfg.Global.CAFile != "" { - roots, err := certutil.NewPool(cfg.Global.CAFile) - if err != nil { - return nil, err - } - config := &tls.Config{} - config.RootCAs = roots - provider.HTTPClient.Transport = netutil.SetOldTransportDefaults(&http.Transport{TLSClientConfig: config}) - - } - if cfg.Global.TrustID != "" { - opts := cfg.toAuth3Options() - authOptsExt := trusts.AuthOptsExt{ - TrustID: cfg.Global.TrustID, - AuthOptionsBuilder: &opts, - } - err = openstack.AuthenticateV3(provider, authOptsExt, gophercloud.EndpointOpts{}) - } else { - err = openstack.Authenticate(provider, cfg.toAuthOptions()) - } - - if err != nil { - return nil, err - } - - emptyDuration := MyDuration{} - if cfg.Metadata.RequestTimeout == emptyDuration { - cfg.Metadata.RequestTimeout.Duration = time.Duration(defaultTimeOut) - } - provider.HTTPClient.Timeout = cfg.Metadata.RequestTimeout.Duration - - os := OpenStack{ - provider: provider, - region: cfg.Global.Region, - lbOpts: cfg.LoadBalancer, - bsOpts: cfg.BlockStorage, - routeOpts: cfg.Route, - metadataOpts: cfg.Metadata, - } - - err = checkOpenStackOpts(&os) - if err != nil { - return nil, err - } - - return &os, nil -} - -// NewFakeOpenStackCloud creates and returns an instance of Openstack cloudprovider. -// Mainly for use in tests that require instantiating Openstack without having -// to go through cloudprovider interface. -func NewFakeOpenStackCloud(cfg Config) (*OpenStack, error) { - provider, err := openstack.NewClient(cfg.Global.AuthURL) - if err != nil { - return nil, err - } - emptyDuration := MyDuration{} - if cfg.Metadata.RequestTimeout == emptyDuration { - cfg.Metadata.RequestTimeout.Duration = time.Duration(defaultTimeOut) - } - provider.HTTPClient.Timeout = cfg.Metadata.RequestTimeout.Duration - - os := OpenStack{ - provider: provider, - region: cfg.Global.Region, - lbOpts: cfg.LoadBalancer, - bsOpts: cfg.BlockStorage, - routeOpts: cfg.Route, - metadataOpts: cfg.Metadata, - } - - return &os, nil -} - -// Initialize passes a Kubernetes clientBuilder interface to the cloud provider -func (os *OpenStack) Initialize(clientBuilder cloudprovider.ControllerClientBuilder, stop <-chan struct{}) { -} - -// mapNodeNameToServerName maps a k8s NodeName to an OpenStack Server Name -// This is a simple string cast. -func mapNodeNameToServerName(nodeName types.NodeName) string { - return string(nodeName) -} - -// GetNodeNameByID maps instanceid to types.NodeName -func (os *OpenStack) GetNodeNameByID(instanceID string) (types.NodeName, error) { - client, err := os.NewComputeV2() - var nodeName types.NodeName - if err != nil { - return nodeName, err - } - - server, err := servers.Get(client, instanceID).Extract() - if err != nil { - return nodeName, err - } - nodeName = mapServerToNodeName(server) - return nodeName, nil -} - -// mapServerToNodeName maps an OpenStack Server to a k8s NodeName -func mapServerToNodeName(server *servers.Server) types.NodeName { - // Node names are always lowercase, and (at least) - // routecontroller does case-sensitive string comparisons - // assuming this - return types.NodeName(strings.ToLower(server.Name)) -} - -func foreachServer(client *gophercloud.ServiceClient, opts servers.ListOptsBuilder, handler func(*servers.Server) (bool, error)) error { - pager := servers.List(client, opts) - - err := pager.EachPage(func(page pagination.Page) (bool, error) { - s, err := servers.ExtractServers(page) - if err != nil { - return false, err - } - for _, server := range s { - ok, err := handler(&server) - if !ok || err != nil { - return false, err - } - } - return true, nil - }) - return err -} - -func getServerByName(client *gophercloud.ServiceClient, name types.NodeName) (*servers.Server, error) { - opts := servers.ListOpts{ - Name: fmt.Sprintf("^%s$", regexp.QuoteMeta(mapNodeNameToServerName(name))), - } - - pager := servers.List(client, opts) - - serverList := make([]servers.Server, 0, 1) - - err := pager.EachPage(func(page pagination.Page) (bool, error) { - s, err := servers.ExtractServers(page) - if err != nil { - return false, err - } - serverList = append(serverList, s...) - if len(serverList) > 1 { - return false, ErrMultipleResults - } - return true, nil - }) - if err != nil { - return nil, err - } - - if len(serverList) == 0 { - return nil, ErrNotFound - } - - return &serverList[0], nil -} - -func nodeAddresses(srv *servers.Server) ([]v1.NodeAddress, error) { - addrs := []v1.NodeAddress{} - - type Address struct { - IPType string `mapstructure:"OS-EXT-IPS:type"` - Addr string - } - - var addresses map[string][]Address - err := mapstructure.Decode(srv.Addresses, &addresses) - if err != nil { - return nil, err - } - - for network, addrList := range addresses { - for _, props := range addrList { - var addressType v1.NodeAddressType - if props.IPType == "floating" || network == "public" { - addressType = v1.NodeExternalIP - } else { - addressType = v1.NodeInternalIP - } - - nodehelpers.AddToNodeAddresses(&addrs, - v1.NodeAddress{ - Type: addressType, - Address: props.Addr, - }, - ) - } - } - - // AccessIPs are usually duplicates of "public" addresses. - if srv.AccessIPv4 != "" { - nodehelpers.AddToNodeAddresses(&addrs, - v1.NodeAddress{ - Type: v1.NodeExternalIP, - Address: srv.AccessIPv4, - }, - ) - } - - if srv.AccessIPv6 != "" { - nodehelpers.AddToNodeAddresses(&addrs, - v1.NodeAddress{ - Type: v1.NodeExternalIP, - Address: srv.AccessIPv6, - }, - ) - } - - if srv.Metadata[TypeHostName] != "" { - nodehelpers.AddToNodeAddresses(&addrs, - v1.NodeAddress{ - Type: v1.NodeHostName, - Address: srv.Metadata[TypeHostName], - }, - ) - } - - return addrs, nil -} - -func getAddressesByName(client *gophercloud.ServiceClient, name types.NodeName) ([]v1.NodeAddress, error) { - srv, err := getServerByName(client, name) - if err != nil { - return nil, err - } - - return nodeAddresses(srv) -} - -func getAddressByName(client *gophercloud.ServiceClient, name types.NodeName, needIPv6 bool) (string, error) { - addrs, err := getAddressesByName(client, name) - if err != nil { - return "", err - } else if len(addrs) == 0 { - return "", ErrNoAddressFound - } - - for _, addr := range addrs { - isIPv6 := netutils.ParseIPSloppy(addr.Address).To4() == nil - if (addr.Type == v1.NodeInternalIP) && (isIPv6 == needIPv6) { - return addr.Address, nil - } - } - - for _, addr := range addrs { - isIPv6 := netutils.ParseIPSloppy(addr.Address).To4() == nil - if (addr.Type == v1.NodeExternalIP) && (isIPv6 == needIPv6) { - return addr.Address, nil - } - } - // It should never return an address from a different IP Address family than the one needed - return "", ErrNoAddressFound -} - -// getAttachedInterfacesByID returns the node interfaces of the specified instance. -func getAttachedInterfacesByID(client *gophercloud.ServiceClient, serviceID string) ([]attachinterfaces.Interface, error) { - var interfaces []attachinterfaces.Interface - - pager := attachinterfaces.List(client, serviceID) - err := pager.EachPage(func(page pagination.Page) (bool, error) { - s, err := attachinterfaces.ExtractInterfaces(page) - if err != nil { - return false, err - } - interfaces = append(interfaces, s...) - return true, nil - }) - if err != nil { - return interfaces, err - } - - return interfaces, nil -} - -// Clusters is a no-op -func (os *OpenStack) Clusters() (cloudprovider.Clusters, bool) { - return nil, false -} - -// ProviderName returns the cloud provider ID. -func (os *OpenStack) ProviderName() string { - return ProviderName -} - -// HasClusterID returns true if the cluster has a clusterID -func (os *OpenStack) HasClusterID() bool { - return true -} - -// LoadBalancer initializes a LbaasV2 object -func (os *OpenStack) LoadBalancer() (cloudprovider.LoadBalancer, bool) { - klog.V(4).Info("openstack.LoadBalancer() called") - - if reflect.DeepEqual(os.lbOpts, LoadBalancerOpts{}) { - klog.V(4).Info("LoadBalancer section is empty/not defined in cloud-config") - return nil, false - } - - network, err := os.NewNetworkV2() - if err != nil { - return nil, false - } - - compute, err := os.NewComputeV2() - if err != nil { - return nil, false - } - - lb, err := os.NewLoadBalancerV2() - if err != nil { - return nil, false - } - - // LBaaS v1 is deprecated in the OpenStack Liberty release. - // Currently kubernetes OpenStack cloud provider just support LBaaS v2. - lbVersion := os.lbOpts.LBVersion - if lbVersion != "" && lbVersion != "v2" { - klog.Warningf("Config error: currently only support LBaaS v2, unrecognised lb-version \"%v\"", lbVersion) - return nil, false - } - - klog.V(1).Info("Claiming to support LoadBalancer") - - return &LbaasV2{LoadBalancer{network, compute, lb, os.lbOpts}}, true -} - -func isNotFound(err error) bool { - if _, ok := err.(gophercloud.ErrDefault404); ok { - return true - } - - if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { - if errCode.Actual == http.StatusNotFound { - return true - } - } - - return false -} - -// Zones indicates that we support zones -func (os *OpenStack) Zones() (cloudprovider.Zones, bool) { - klog.V(1).Info("Claiming to support Zones") - return os, true -} - -// GetZone returns the current zone -func (os *OpenStack) GetZone(ctx context.Context) (cloudprovider.Zone, error) { - md, err := getMetadata(os.metadataOpts.SearchOrder) - if err != nil { - return cloudprovider.Zone{}, err - } - - zone := cloudprovider.Zone{ - FailureDomain: md.AvailabilityZone, - Region: os.region, - } - klog.V(4).Infof("Current zone is %v", zone) - return zone, nil -} - -// GetZoneByProviderID implements Zones.GetZoneByProviderID -// This is particularly useful in external cloud providers where the kubelet -// does not initialize node data. -func (os *OpenStack) GetZoneByProviderID(ctx context.Context, providerID string) (cloudprovider.Zone, error) { - instanceID, err := instanceIDFromProviderID(providerID) - if err != nil { - return cloudprovider.Zone{}, err - } - - compute, err := os.NewComputeV2() - if err != nil { - return cloudprovider.Zone{}, err - } - - srv, err := servers.Get(compute, instanceID).Extract() - if err != nil { - return cloudprovider.Zone{}, err - } - - zone := cloudprovider.Zone{ - FailureDomain: srv.Metadata[availabilityZone], - Region: os.region, - } - klog.V(4).Infof("The instance %s in zone %v", srv.Name, zone) - return zone, nil -} - -// GetZoneByNodeName implements Zones.GetZoneByNodeName -// This is particularly useful in external cloud providers where the kubelet -// does not initialize node data. -func (os *OpenStack) GetZoneByNodeName(ctx context.Context, nodeName types.NodeName) (cloudprovider.Zone, error) { - compute, err := os.NewComputeV2() - if err != nil { - return cloudprovider.Zone{}, err - } - - srv, err := getServerByName(compute, nodeName) - if err != nil { - if err == ErrNotFound { - return cloudprovider.Zone{}, cloudprovider.InstanceNotFound - } - return cloudprovider.Zone{}, err - } - - zone := cloudprovider.Zone{ - FailureDomain: srv.Metadata[availabilityZone], - Region: os.region, - } - klog.V(4).Infof("The instance %s in zone %v", srv.Name, zone) - return zone, nil -} - -// Routes initializes routes support -func (os *OpenStack) Routes() (cloudprovider.Routes, bool) { - klog.V(4).Info("openstack.Routes() called") - - network, err := os.NewNetworkV2() - if err != nil { - return nil, false - } - - netExts, err := networkExtensions(network) - if err != nil { - klog.Warningf("Failed to list neutron extensions: %v", err) - return nil, false - } - - if !netExts["extraroute"] { - klog.V(3).Info("Neutron extraroute extension not found, required for Routes support") - return nil, false - } - - compute, err := os.NewComputeV2() - if err != nil { - return nil, false - } - - r, err := NewRoutes(compute, network, os.routeOpts) - if err != nil { - klog.Warningf("Error initialising Routes support: %v", err) - return nil, false - } - - klog.V(1).Info("Claiming to support Routes") - return r, true -} - -func (os *OpenStack) volumeService(forceVersion string) (volumeService, error) { - bsVersion := "" - if forceVersion == "" { - bsVersion = os.bsOpts.BSVersion - } else { - bsVersion = forceVersion - } - - switch bsVersion { - case "v1": - sClient, err := os.NewBlockStorageV1() - if err != nil { - return nil, err - } - klog.V(3).Info("Using Blockstorage API V1") - return &VolumesV1{sClient, os.bsOpts}, nil - case "v2": - sClient, err := os.NewBlockStorageV2() - if err != nil { - return nil, err - } - klog.V(3).Info("Using Blockstorage API V2") - return &VolumesV2{sClient, os.bsOpts}, nil - case "v3": - sClient, err := os.NewBlockStorageV3() - if err != nil { - return nil, err - } - klog.V(3).Info("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 { - klog.V(3).Info("Using Blockstorage API V3") - return &VolumesV3{sClient, os.bsOpts}, nil - } - - if sClient, err := os.NewBlockStorageV2(); err == nil { - klog.V(3).Info("Using Blockstorage API V2") - return &VolumesV2{sClient, os.bsOpts}, nil - } - - if sClient, err := os.NewBlockStorageV1(); err == nil { - klog.V(3).Info("Using Blockstorage API V1") - return &VolumesV1{sClient, os.bsOpts}, nil - } - - errTxt := "BlockStorage API version autodetection failed. " + - "Please set it explicitly in cloud.conf in section [BlockStorage] with key `bs-version`" - return nil, errors.New(errTxt) - default: - errTxt := fmt.Sprintf("Config error: unrecognised bs-version \"%v\"", os.bsOpts.BSVersion) - return nil, errors.New(errTxt) - } -} - -func checkMetadataSearchOrder(order string) error { - if order == "" { - return errors.New("invalid value in section [Metadata] with key `search-order`. Value cannot be empty") - } - - elements := strings.Split(order, ",") - if len(elements) > 2 { - return errors.New("invalid value in section [Metadata] with key `search-order`. Value cannot contain more than 2 elements") - } - - for _, id := range elements { - id = strings.TrimSpace(id) - switch id { - case configDriveID: - case metadataID: - default: - return fmt.Errorf("invalid element %q found in section [Metadata] with key `search-order`."+ - "Supported elements include %q and %q", id, configDriveID, metadataID) - } - } - - return nil -} diff --git a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_client.go b/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_client.go deleted file mode 100644 index 305af56284a..00000000000 --- a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_client.go +++ /dev/null @@ -1,101 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2017 The Kubernetes Authors. - -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. -*/ - -package openstack - -import ( - "fmt" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack" -) - -// NewNetworkV2 creates a ServiceClient that may be used with the neutron v2 API -func (os *OpenStack) NewNetworkV2() (*gophercloud.ServiceClient, error) { - network, err := openstack.NewNetworkV2(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - if err != nil { - return nil, fmt.Errorf("failed to find network v2 endpoint for region %s: %v", os.region, err) - } - return network, nil -} - -// NewComputeV2 creates a ServiceClient that may be used with the nova v2 API -func (os *OpenStack) NewComputeV2() (*gophercloud.ServiceClient, error) { - compute, err := openstack.NewComputeV2(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - if err != nil { - return nil, fmt.Errorf("failed to find compute v2 endpoint for region %s: %v", os.region, err) - } - return compute, nil -} - -// NewBlockStorageV1 creates a ServiceClient that may be used with the Cinder v1 API -func (os *OpenStack) NewBlockStorageV1() (*gophercloud.ServiceClient, error) { - storage, err := openstack.NewBlockStorageV1(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - if err != nil { - return nil, fmt.Errorf("unable to initialize cinder v1 client for region %s: %v", os.region, err) - } - return storage, nil -} - -// NewBlockStorageV2 creates a ServiceClient that may be used with the Cinder v2 API -func (os *OpenStack) NewBlockStorageV2() (*gophercloud.ServiceClient, error) { - storage, err := openstack.NewBlockStorageV2(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - if err != nil { - return nil, fmt.Errorf("unable to initialize cinder v2 client for region %s: %v", os.region, err) - } - return storage, nil -} - -// NewBlockStorageV3 creates a ServiceClient that may be used with the Cinder v3 API -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 -} - -// NewLoadBalancerV2 creates a ServiceClient that may be used with the Neutron LBaaS v2 API -func (os *OpenStack) NewLoadBalancerV2() (*gophercloud.ServiceClient, error) { - var lb *gophercloud.ServiceClient - var err error - if os.lbOpts.UseOctavia { - lb, err = openstack.NewLoadBalancerV2(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - } else { - lb, err = openstack.NewNetworkV2(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - } - if err != nil { - return nil, fmt.Errorf("failed to find load-balancer v2 endpoint for region %s: %v", os.region, err) - } - return lb, nil -} diff --git a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_instances.go b/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_instances.go deleted file mode 100644 index 37bc9383ad9..00000000000 --- a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_instances.go +++ /dev/null @@ -1,244 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package openstack - -import ( - "context" - "fmt" - "regexp" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" - v1 "k8s.io/api/core/v1" - "k8s.io/klog/v2" - - "k8s.io/apimachinery/pkg/types" - cloudprovider "k8s.io/cloud-provider" -) - -var _ cloudprovider.Instances = (*Instances)(nil) - -// Instances encapsulates an implementation of Instances for OpenStack. -type Instances struct { - compute *gophercloud.ServiceClient - opts MetadataOpts -} - -const ( - instanceShutoff = "SHUTOFF" -) - -// Instances returns an implementation of Instances for OpenStack. -func (os *OpenStack) Instances() (cloudprovider.Instances, bool) { - klog.V(4).Info("openstack.Instances() called") - - compute, err := os.NewComputeV2() - if err != nil { - klog.Errorf("unable to access compute v2 API : %v", err) - return nil, false - } - - klog.V(4).Info("Claiming to support Instances") - - return &Instances{ - compute: compute, - opts: os.metadataOpts, - }, true -} - -// InstancesV2 returns an implementation of InstancesV2 for OpenStack. -// TODO: implement ONLY for external cloud provider -func (os *OpenStack) InstancesV2() (cloudprovider.InstancesV2, bool) { - return nil, false -} - -// CurrentNodeName implements Instances.CurrentNodeName -// Note this is *not* necessarily the same as hostname. -func (i *Instances) CurrentNodeName(ctx context.Context, hostname string) (types.NodeName, error) { - md, err := getMetadata(i.opts.SearchOrder) - if err != nil { - return "", err - } - return types.NodeName(md.Name), nil -} - -// AddSSHKeyToAllInstances is not implemented for OpenStack -func (i *Instances) AddSSHKeyToAllInstances(ctx context.Context, user string, keyData []byte) error { - return cloudprovider.NotImplemented -} - -// NodeAddresses implements Instances.NodeAddresses -func (i *Instances) NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.NodeAddress, error) { - klog.V(4).Infof("NodeAddresses(%v) called", name) - - addrs, err := getAddressesByName(i.compute, name) - if err != nil { - return nil, err - } - - klog.V(4).Infof("NodeAddresses(%v) => %v", name, addrs) - return addrs, nil -} - -// NodeAddressesByProviderID returns the node addresses of an instances with the specified unique providerID -// This method will not be called from the node that is requesting this ID. i.e. metadata service -// and other local methods cannot be used here -func (i *Instances) NodeAddressesByProviderID(ctx context.Context, providerID string) ([]v1.NodeAddress, error) { - instanceID, err := instanceIDFromProviderID(providerID) - - if err != nil { - return []v1.NodeAddress{}, err - } - - server, err := servers.Get(i.compute, instanceID).Extract() - - if err != nil { - return []v1.NodeAddress{}, err - } - - addresses, err := nodeAddresses(server) - if err != nil { - return []v1.NodeAddress{}, err - } - - return addresses, nil -} - -// InstanceExistsByProviderID returns true if the instance with the given provider id still exist. -// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager. -func (i *Instances) InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) { - instanceID, err := instanceIDFromProviderID(providerID) - if err != nil { - return false, err - } - - _, err = servers.Get(i.compute, instanceID).Extract() - if err != nil { - if isNotFound(err) { - return false, nil - } - return false, err - } - - return true, nil -} - -// InstanceShutdownByProviderID returns true if the instances is in safe state to detach volumes -func (i *Instances) InstanceShutdownByProviderID(ctx context.Context, providerID string) (bool, error) { - instanceID, err := instanceIDFromProviderID(providerID) - if err != nil { - return false, err - } - - server, err := servers.Get(i.compute, instanceID).Extract() - if err != nil { - return false, err - } - - // SHUTOFF is the only state where we can detach volumes immediately - if server.Status == instanceShutoff { - return true, nil - } - return false, nil -} - -// InstanceID returns the kubelet's cloud provider ID. -func (os *OpenStack) InstanceID() (string, error) { - if len(os.localInstanceID) == 0 { - id, err := readInstanceID(os.metadataOpts.SearchOrder) - if err != nil { - return "", err - } - os.localInstanceID = id - } - return os.localInstanceID, nil -} - -// InstanceID returns the cloud provider ID of the specified instance. -func (i *Instances) InstanceID(ctx context.Context, name types.NodeName) (string, error) { - srv, err := getServerByName(i.compute, name) - if err != nil { - if err == ErrNotFound { - return "", cloudprovider.InstanceNotFound - } - return "", err - } - // In the future it is possible to also return an endpoint as: - // / - return "/" + srv.ID, nil -} - -// InstanceTypeByProviderID returns the cloudprovider instance type of the node with the specified unique providerID -// This method will not be called from the node that is requesting this ID. i.e. metadata service -// and other local methods cannot be used here -func (i *Instances) InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error) { - instanceID, err := instanceIDFromProviderID(providerID) - - if err != nil { - return "", err - } - - server, err := servers.Get(i.compute, instanceID).Extract() - - if err != nil { - return "", err - } - - return srvInstanceType(server) -} - -// InstanceType returns the type of the specified instance. -func (i *Instances) InstanceType(ctx context.Context, name types.NodeName) (string, error) { - srv, err := getServerByName(i.compute, name) - - if err != nil { - return "", err - } - - return srvInstanceType(srv) -} - -func srvInstanceType(srv *servers.Server) (string, error) { - keys := []string{"name", "id", "original_name"} - for _, key := range keys { - val, found := srv.Flavor[key] - if found { - flavor, ok := val.(string) - if ok { - return flavor, nil - } - } - } - return "", fmt.Errorf("flavor name/id not found") -} - -// instanceIDFromProviderID splits a provider's id and return instanceID. -// A providerID is build out of '${ProviderName}:///${instance-id}'which contains ':///'. -// See cloudprovider.GetInstanceProviderID and Instances.InstanceID. -func instanceIDFromProviderID(providerID string) (instanceID string, err error) { - // If Instances.InstanceID or cloudprovider.GetInstanceProviderID is changed, the regexp should be changed too. - var providerIDRegexp = regexp.MustCompile(`^` + ProviderName + `:///([^/]+)$`) - - matches := providerIDRegexp.FindStringSubmatch(providerID) - if len(matches) != 2 { - return "", fmt.Errorf("ProviderID \"%s\" didn't match expected format \"openstack:///InstanceID\"", providerID) - } - return matches[1], nil -} diff --git a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_loadbalancer.go b/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_loadbalancer.go deleted file mode 100644 index c735fbc0929..00000000000 --- a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_loadbalancer.go +++ /dev/null @@ -1,1578 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package openstack - -import ( - "context" - "fmt" - "reflect" - "strings" - "time" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers" - v2monitors "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors" - v2pools "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules" - "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" - neutronports "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" - "github.com/gophercloud/gophercloud/pagination" - "k8s.io/klog/v2" - netutils "k8s.io/utils/net" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apimachinery/pkg/util/wait" - cloudprovider "k8s.io/cloud-provider" - servicehelpers "k8s.io/cloud-provider/service/helpers" -) - -// Note: when creating a new Loadbalancer (VM), it can take some time before it is ready for use, -// this timeout is used for waiting until the Loadbalancer provisioning status goes to ACTIVE state. -const ( - // loadbalancerActive* is configuration of exponential backoff for - // going into ACTIVE loadbalancer provisioning status. Starting with 1 - // seconds, multiplying by 1.2 with each step and taking 19 steps at maximum - // it will time out after 128s, which roughly corresponds to 120s - loadbalancerActiveInitDelay = 1 * time.Second - loadbalancerActiveFactor = 1.2 - loadbalancerActiveSteps = 19 - - // loadbalancerDelete* is configuration of exponential backoff for - // waiting for delete operation to complete. Starting with 1 - // seconds, multiplying by 1.2 with each step and taking 13 steps at maximum - // it will time out after 32s, which roughly corresponds to 30s - loadbalancerDeleteInitDelay = 1 * time.Second - loadbalancerDeleteFactor = 1.2 - loadbalancerDeleteSteps = 13 - - activeStatus = "ACTIVE" - errorStatus = "ERROR" - - ServiceAnnotationLoadBalancerFloatingNetworkID = "loadbalancer.openstack.org/floating-network-id" - ServiceAnnotationLoadBalancerSubnetID = "loadbalancer.openstack.org/subnet-id" - - // ServiceAnnotationLoadBalancerInternal is the annotation used on the service - // to indicate that we want an internal loadbalancer service. - // If the value of ServiceAnnotationLoadBalancerInternal is false, it indicates that we want an external loadbalancer service. Default to false. - ServiceAnnotationLoadBalancerInternal = "service.beta.kubernetes.io/openstack-internal-load-balancer" -) - -var _ cloudprovider.LoadBalancer = (*LbaasV2)(nil) - -// LbaasV2 is a LoadBalancer implementation for Neutron LBaaS v2 API -type LbaasV2 struct { - LoadBalancer -} - -func networkExtensions(client *gophercloud.ServiceClient) (map[string]bool, error) { - seen := make(map[string]bool) - - pager := extensions.List(client) - err := pager.EachPage(func(page pagination.Page) (bool, error) { - exts, err := extensions.ExtractExtensions(page) - if err != nil { - return false, err - } - for _, ext := range exts { - seen[ext.Alias] = true - } - return true, nil - }) - - return seen, err -} - -func getFloatingIPByPortID(client *gophercloud.ServiceClient, portID string) (*floatingips.FloatingIP, error) { - opts := floatingips.ListOpts{ - PortID: portID, - } - pager := floatingips.List(client, opts) - - floatingIPList := make([]floatingips.FloatingIP, 0, 1) - - err := pager.EachPage(func(page pagination.Page) (bool, error) { - f, err := floatingips.ExtractFloatingIPs(page) - if err != nil { - return false, err - } - floatingIPList = append(floatingIPList, f...) - if len(floatingIPList) > 1 { - return false, ErrMultipleResults - } - return true, nil - }) - if err != nil { - if isNotFound(err) { - return nil, ErrNotFound - } - return nil, err - } - - if len(floatingIPList) == 0 { - return nil, ErrNotFound - } else if len(floatingIPList) > 1 { - return nil, ErrMultipleResults - } - - return &floatingIPList[0], nil -} - -func getLoadbalancerByName(client *gophercloud.ServiceClient, name string) (*loadbalancers.LoadBalancer, error) { - opts := loadbalancers.ListOpts{ - Name: name, - } - pager := loadbalancers.List(client, opts) - - loadbalancerList := make([]loadbalancers.LoadBalancer, 0, 1) - - err := pager.EachPage(func(page pagination.Page) (bool, error) { - v, err := loadbalancers.ExtractLoadBalancers(page) - if err != nil { - return false, err - } - loadbalancerList = append(loadbalancerList, v...) - if len(loadbalancerList) > 1 { - return false, ErrMultipleResults - } - return true, nil - }) - if err != nil { - if isNotFound(err) { - return nil, ErrNotFound - } - return nil, err - } - - if len(loadbalancerList) == 0 { - return nil, ErrNotFound - } else if len(loadbalancerList) > 1 { - return nil, ErrMultipleResults - } - - return &loadbalancerList[0], nil -} - -func getListenersByLoadBalancerID(client *gophercloud.ServiceClient, id string) ([]listeners.Listener, error) { - var existingListeners []listeners.Listener - err := listeners.List(client, listeners.ListOpts{LoadbalancerID: id}).EachPage(func(page pagination.Page) (bool, error) { - listenerList, err := listeners.ExtractListeners(page) - if err != nil { - return false, err - } - for _, l := range listenerList { - for _, lb := range l.Loadbalancers { - if lb.ID == id { - existingListeners = append(existingListeners, l) - break - } - } - } - - return true, nil - }) - if err != nil { - return nil, err - } - - return existingListeners, nil -} - -// get listener for a port or nil if does not exist -func getListenerForPort(existingListeners []listeners.Listener, port v1.ServicePort) *listeners.Listener { - for _, l := range existingListeners { - if listeners.Protocol(l.Protocol) == toListenersProtocol(port.Protocol) && l.ProtocolPort == int(port.Port) { - return &l - } - } - - return nil -} - -// Get pool for a listener. A listener always has exactly one pool. -func getPoolByListenerID(client *gophercloud.ServiceClient, loadbalancerID string, listenerID string) (*v2pools.Pool, error) { - listenerPools := make([]v2pools.Pool, 0, 1) - err := v2pools.List(client, v2pools.ListOpts{LoadbalancerID: loadbalancerID}).EachPage(func(page pagination.Page) (bool, error) { - poolsList, err := v2pools.ExtractPools(page) - if err != nil { - return false, err - } - for _, p := range poolsList { - for _, l := range p.Listeners { - if l.ID == listenerID { - listenerPools = append(listenerPools, p) - } - } - } - if len(listenerPools) > 1 { - return false, ErrMultipleResults - } - return true, nil - }) - if err != nil { - if isNotFound(err) { - return nil, ErrNotFound - } - return nil, err - } - - if len(listenerPools) == 0 { - return nil, ErrNotFound - } else if len(listenerPools) > 1 { - return nil, ErrMultipleResults - } - - return &listenerPools[0], nil -} - -func getMembersByPoolID(client *gophercloud.ServiceClient, id string) ([]v2pools.Member, error) { - var members []v2pools.Member - err := v2pools.ListMembers(client, id, v2pools.ListMembersOpts{}).EachPage(func(page pagination.Page) (bool, error) { - membersList, err := v2pools.ExtractMembers(page) - if err != nil { - return false, err - } - members = append(members, membersList...) - - return true, nil - }) - if err != nil { - return nil, err - } - - return members, nil -} - -// Check if a member exists for node -func memberExists(members []v2pools.Member, addr string, port int) bool { - for _, member := range members { - if member.Address == addr && member.ProtocolPort == port { - return true - } - } - - return false -} - -func popListener(existingListeners []listeners.Listener, id string) []listeners.Listener { - for i, existingListener := range existingListeners { - if existingListener.ID == id { - existingListeners[i] = existingListeners[len(existingListeners)-1] - existingListeners = existingListeners[:len(existingListeners)-1] - break - } - } - - return existingListeners -} - -func popMember(members []v2pools.Member, addr string, port int) []v2pools.Member { - for i, member := range members { - if member.Address == addr && member.ProtocolPort == port { - members[i] = members[len(members)-1] - members = members[:len(members)-1] - } - } - - return members -} - -func getSecurityGroupName(service *v1.Service) string { - securityGroupName := fmt.Sprintf("lb-sg-%s-%s-%s", service.UID, service.Namespace, service.Name) - //OpenStack requires that the name of a security group is shorter than 255 bytes. - if len(securityGroupName) > 255 { - securityGroupName = securityGroupName[:255] - } - - return securityGroupName -} - -func getSecurityGroupRules(client *gophercloud.ServiceClient, opts rules.ListOpts) ([]rules.SecGroupRule, error) { - - pager := rules.List(client, opts) - - var securityRules []rules.SecGroupRule - - err := pager.EachPage(func(page pagination.Page) (bool, error) { - ruleList, err := rules.ExtractRules(page) - if err != nil { - return false, err - } - securityRules = append(securityRules, ruleList...) - return true, nil - }) - - if err != nil { - return nil, err - } - - return securityRules, nil -} - -func waitLoadbalancerActiveProvisioningStatus(client *gophercloud.ServiceClient, loadbalancerID string) (string, error) { - backoff := wait.Backoff{ - Duration: loadbalancerActiveInitDelay, - Factor: loadbalancerActiveFactor, - Steps: loadbalancerActiveSteps, - } - - var provisioningStatus string - err := wait.ExponentialBackoff(backoff, func() (bool, error) { - loadbalancer, err := loadbalancers.Get(client, loadbalancerID).Extract() - if err != nil { - return false, err - } - provisioningStatus = loadbalancer.ProvisioningStatus - if loadbalancer.ProvisioningStatus == activeStatus { - return true, nil - } else if loadbalancer.ProvisioningStatus == errorStatus { - return true, fmt.Errorf("loadbalancer has gone into ERROR state") - } else { - return false, nil - } - - }) - - if err == wait.ErrWaitTimeout { - err = fmt.Errorf("loadbalancer failed to go into ACTIVE provisioning status within alloted time") - } - return provisioningStatus, err -} - -func waitLoadbalancerDeleted(client *gophercloud.ServiceClient, loadbalancerID string) error { - backoff := wait.Backoff{ - Duration: loadbalancerDeleteInitDelay, - Factor: loadbalancerDeleteFactor, - Steps: loadbalancerDeleteSteps, - } - err := wait.ExponentialBackoff(backoff, func() (bool, error) { - _, err := loadbalancers.Get(client, loadbalancerID).Extract() - if err != nil { - if isNotFound(err) { - return true, nil - } - return false, err - } - return false, nil - }) - - if err == wait.ErrWaitTimeout { - err = fmt.Errorf("loadbalancer failed to delete within the alloted time") - } - - return err -} - -func toRuleProtocol(protocol v1.Protocol) rules.RuleProtocol { - switch protocol { - case v1.ProtocolTCP: - return rules.ProtocolTCP - case v1.ProtocolUDP: - return rules.ProtocolUDP - default: - return rules.RuleProtocol(strings.ToLower(string(protocol))) - } -} - -func toListenersProtocol(protocol v1.Protocol) listeners.Protocol { - switch protocol { - case v1.ProtocolTCP: - return listeners.ProtocolTCP - default: - return listeners.Protocol(string(protocol)) - } -} - -func createNodeSecurityGroup(client *gophercloud.ServiceClient, nodeSecurityGroupID string, port int, protocol v1.Protocol, lbSecGroup string) error { - v4NodeSecGroupRuleCreateOpts := rules.CreateOpts{ - Direction: rules.DirIngress, - PortRangeMax: port, - PortRangeMin: port, - Protocol: toRuleProtocol(protocol), - RemoteGroupID: lbSecGroup, - SecGroupID: nodeSecurityGroupID, - EtherType: rules.EtherType4, - } - - v6NodeSecGroupRuleCreateOpts := rules.CreateOpts{ - Direction: rules.DirIngress, - PortRangeMax: port, - PortRangeMin: port, - Protocol: toRuleProtocol(protocol), - RemoteGroupID: lbSecGroup, - SecGroupID: nodeSecurityGroupID, - EtherType: rules.EtherType6, - } - - _, err := rules.Create(client, v4NodeSecGroupRuleCreateOpts).Extract() - - if err != nil { - return err - } - - _, err = rules.Create(client, v6NodeSecGroupRuleCreateOpts).Extract() - - if err != nil { - return err - } - return nil -} - -func (lbaas *LbaasV2) createLoadBalancer(service *v1.Service, name string, internalAnnotation bool) (*loadbalancers.LoadBalancer, error) { - createOpts := loadbalancers.CreateOpts{ - Name: name, - Description: fmt.Sprintf("Kubernetes external service %s", name), - VipSubnetID: lbaas.opts.SubnetID, - Provider: lbaas.opts.LBProvider, - } - - loadBalancerIP := service.Spec.LoadBalancerIP - if loadBalancerIP != "" && internalAnnotation { - createOpts.VipAddress = loadBalancerIP - } - - loadbalancer, err := loadbalancers.Create(lbaas.lb, createOpts).Extract() - if err != nil { - return nil, fmt.Errorf("error creating loadbalancer %v: %v", createOpts, err) - } - return loadbalancer, nil -} - -// GetLoadBalancer returns whether the specified load balancer exists and its status -func (lbaas *LbaasV2) GetLoadBalancer(ctx context.Context, clusterName string, service *v1.Service) (*v1.LoadBalancerStatus, bool, error) { - loadBalancerName := lbaas.GetLoadBalancerName(ctx, clusterName, service) - loadbalancer, err := getLoadbalancerByName(lbaas.lb, loadBalancerName) - if err == ErrNotFound { - return nil, false, nil - } - if loadbalancer == nil { - return nil, false, err - } - - status := &v1.LoadBalancerStatus{} - - portID := loadbalancer.VipPortID - if portID != "" { - floatIP, err := getFloatingIPByPortID(lbaas.network, portID) - if err != nil && err != ErrNotFound { - return nil, false, fmt.Errorf("error getting floating ip for port %s: %v", portID, err) - } - - if floatIP != nil { - status.Ingress = []v1.LoadBalancerIngress{{IP: floatIP.FloatingIP}} - } - } else { - status.Ingress = []v1.LoadBalancerIngress{{IP: loadbalancer.VipAddress}} - } - - return status, true, err -} - -// GetLoadBalancerName is an implementation of LoadBalancer.GetLoadBalancerName. -func (lbaas *LbaasV2) GetLoadBalancerName(ctx context.Context, clusterName string, service *v1.Service) string { - // TODO: replace DefaultLoadBalancerName to generate more meaningful loadbalancer names. - return cloudprovider.DefaultLoadBalancerName(service) -} - -// The LB needs to be configured with instance addresses on the same -// subnet as the LB (aka opts.SubnetID). Currently we're just -// guessing that the node's InternalIP is the right address. -// In case no InternalIP can be found, ExternalIP is tried. -// If neither InternalIP nor ExternalIP can be found an error is -// returned. -func nodeAddressForLB(node *v1.Node) (string, error) { - addrs := node.Status.Addresses - if len(addrs) == 0 { - return "", ErrNoAddressFound - } - - allowedAddrTypes := []v1.NodeAddressType{v1.NodeInternalIP, v1.NodeExternalIP} - - for _, allowedAddrType := range allowedAddrTypes { - for _, addr := range addrs { - if addr.Type == allowedAddrType { - return addr.Address, nil - } - } - } - - return "", ErrNoAddressFound -} - -// getStringFromServiceAnnotation searches a given v1.Service for a specific annotationKey and either returns the annotation's value or a specified defaultSetting -func getStringFromServiceAnnotation(service *v1.Service, annotationKey string, defaultSetting string) string { - klog.V(4).Infof("getStringFromServiceAnnotation(%v, %v, %v)", service, annotationKey, defaultSetting) - if annotationValue, ok := service.Annotations[annotationKey]; ok { - //if there is an annotation for this setting, set the "setting" var to it - // annotationValue can be empty, it is working as designed - // it makes possible for instance provisioning loadbalancer without floatingip - klog.V(4).Infof("Found a Service Annotation: %v = %v", annotationKey, annotationValue) - return annotationValue - } - //if there is no annotation, set "settings" var to the value from cloud config - klog.V(4).Infof("Could not find a Service Annotation; falling back on cloud-config setting: %v = %v", annotationKey, defaultSetting) - return defaultSetting -} - -// getSubnetIDForLB returns subnet-id for a specific node -func getSubnetIDForLB(compute *gophercloud.ServiceClient, node v1.Node) (string, error) { - ipAddress, err := nodeAddressForLB(&node) - if err != nil { - return "", err - } - - instanceID := node.Spec.ProviderID - if ind := strings.LastIndex(instanceID, "/"); ind >= 0 { - instanceID = instanceID[(ind + 1):] - } - - interfaces, err := getAttachedInterfacesByID(compute, instanceID) - if err != nil { - return "", err - } - - for _, intf := range interfaces { - for _, fixedIP := range intf.FixedIPs { - if fixedIP.IPAddress == ipAddress { - return fixedIP.SubnetID, nil - } - } - } - - return "", ErrNotFound -} - -// getNodeSecurityGroupIDForLB lists node-security-groups for specific nodes -func getNodeSecurityGroupIDForLB(compute *gophercloud.ServiceClient, network *gophercloud.ServiceClient, nodes []*v1.Node) ([]string, error) { - secGroupNames := sets.NewString() - - for _, node := range nodes { - nodeName := types.NodeName(node.Name) - srv, err := getServerByName(compute, nodeName) - if err != nil { - return []string{}, err - } - - // use the first node-security-groups - // case 0: node1:SG1 node2:SG1 return SG1 - // case 1: node1:SG1 node2:SG2 return SG1,SG2 - // case 2: node1:SG1,SG2 node2:SG3,SG4 return SG1,SG3 - // case 3: node1:SG1,SG2 node2:SG2,SG3 return SG1,SG2 - secGroupNames.Insert(srv.SecurityGroups[0]["name"].(string)) - } - - secGroupIDs := make([]string, secGroupNames.Len()) - for i, name := range secGroupNames.List() { - secGroupID, err := groups.IDFromName(network, name) - if err != nil { - return []string{}, err - } - secGroupIDs[i] = secGroupID - } - - return secGroupIDs, nil -} - -// isSecurityGroupNotFound return true while 'err' is object of gophercloud.ErrResourceNotFound -func isSecurityGroupNotFound(err error) bool { - errType := reflect.TypeOf(err).String() - errTypeSlice := strings.Split(errType, ".") - errTypeValue := "" - if len(errTypeSlice) != 0 { - errTypeValue = errTypeSlice[len(errTypeSlice)-1] - } - if errTypeValue == "ErrResourceNotFound" { - return true - } - - return false -} - -// getFloatingNetworkIDForLB returns a floating-network-id for cluster. -func getFloatingNetworkIDForLB(client *gophercloud.ServiceClient) (string, error) { - var floatingNetworkIds []string - - type NetworkWithExternalExt struct { - networks.Network - external.NetworkExternalExt - } - - err := networks.List(client, networks.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) { - var externalNetwork []NetworkWithExternalExt - err := networks.ExtractNetworksInto(page, &externalNetwork) - if err != nil { - return false, err - } - - for _, externalNet := range externalNetwork { - if externalNet.External { - floatingNetworkIds = append(floatingNetworkIds, externalNet.ID) - } - } - - if len(floatingNetworkIds) > 1 { - return false, ErrMultipleResults - } - return true, nil - }) - if err != nil { - if isNotFound(err) { - return "", ErrNotFound - } - - if err == ErrMultipleResults { - klog.V(4).Infof("find multiple external networks, pick the first one when there are no explicit configuration.") - return floatingNetworkIds[0], nil - } - return "", err - } - - if len(floatingNetworkIds) == 0 { - return "", ErrNotFound - } - - return floatingNetworkIds[0], nil -} - -// TODO: This code currently ignores 'region' and always creates a -// loadbalancer in only the current OpenStack region. We should take -// a list of regions (from config) and query/create loadbalancers in -// each region. - -// EnsureLoadBalancer creates a new load balancer 'name', or updates the existing one. -func (lbaas *LbaasV2) EnsureLoadBalancer(ctx context.Context, clusterName string, apiService *v1.Service, nodes []*v1.Node) (*v1.LoadBalancerStatus, error) { - klog.V(4).Infof("EnsureLoadBalancer(%v, %v, %v, %v, %v, %v, %v)", clusterName, apiService.Namespace, apiService.Name, apiService.Spec.LoadBalancerIP, apiService.Spec.Ports, nodes, apiService.Annotations) - - if len(nodes) == 0 { - return nil, fmt.Errorf("there are no available nodes for LoadBalancer service %s/%s", apiService.Namespace, apiService.Name) - } - - lbaas.opts.SubnetID = getStringFromServiceAnnotation(apiService, ServiceAnnotationLoadBalancerSubnetID, lbaas.opts.SubnetID) - if len(lbaas.opts.SubnetID) == 0 { - // Get SubnetID automatically. - // The LB needs to be configured with instance addresses on the same subnet, so get SubnetID by one node. - subnetID, err := getSubnetIDForLB(lbaas.compute, *nodes[0]) - if err != nil { - klog.Warningf("Failed to find subnet-id for loadbalancer service %s/%s: %v", apiService.Namespace, apiService.Name, err) - return nil, fmt.Errorf("no subnet-id for service %s/%s : subnet-id not set in cloud provider config, "+ - "and failed to find subnet-id from OpenStack: %v", apiService.Namespace, apiService.Name, err) - } - lbaas.opts.SubnetID = subnetID - } - - ports := apiService.Spec.Ports - if len(ports) == 0 { - return nil, fmt.Errorf("no ports provided to openstack load balancer") - } - - floatingPool := getStringFromServiceAnnotation(apiService, ServiceAnnotationLoadBalancerFloatingNetworkID, lbaas.opts.FloatingNetworkID) - if len(floatingPool) == 0 { - var err error - floatingPool, err = getFloatingNetworkIDForLB(lbaas.network) - if err != nil { - klog.Warningf("Failed to find floating-network-id for loadbalancer service %s/%s: %v", apiService.Namespace, apiService.Name, err) - } - } - - var internalAnnotation bool - internal := getStringFromServiceAnnotation(apiService, ServiceAnnotationLoadBalancerInternal, "false") - switch internal { - case "true": - klog.V(4).Info("Ensure an internal loadbalancer service.") - internalAnnotation = true - case "false": - if len(floatingPool) != 0 { - klog.V(4).Infof("Ensure an external loadbalancer service, using floatingPool: %v", floatingPool) - internalAnnotation = false - } else { - return nil, fmt.Errorf("floating-network-id or loadbalancer.openstack.org/floating-network-id should be specified when ensuring an external loadbalancer service") - } - default: - return nil, fmt.Errorf("unknown service.beta.kubernetes.io/openstack-internal-load-balancer annotation: %v, specify \"true\" or \"false\" ", - internal) - } - - // Check for TCP protocol on each port - // TODO: Convert all error messages to use an event recorder - for _, port := range ports { - if port.Protocol != v1.ProtocolTCP { - return nil, fmt.Errorf("only TCP LoadBalancer is supported for openstack load balancers") - } - } - - sourceRanges, err := servicehelpers.GetLoadBalancerSourceRanges(apiService) - if err != nil { - return nil, fmt.Errorf("failed to get source ranges for loadbalancer service %s/%s: %v", apiService.Namespace, apiService.Name, err) - } - - if !servicehelpers.IsAllowAll(sourceRanges) && !lbaas.opts.ManageSecurityGroups { - return nil, fmt.Errorf("source range restrictions are not supported for openstack load balancers without managing security groups") - } - - affinity := apiService.Spec.SessionAffinity - var persistence *v2pools.SessionPersistence - switch affinity { - case v1.ServiceAffinityNone: - persistence = nil - case v1.ServiceAffinityClientIP: - persistence = &v2pools.SessionPersistence{Type: "SOURCE_IP"} - default: - return nil, fmt.Errorf("unsupported load balancer affinity: %v", affinity) - } - - name := lbaas.GetLoadBalancerName(ctx, clusterName, apiService) - loadbalancer, err := getLoadbalancerByName(lbaas.lb, name) - if err != nil { - if err != ErrNotFound { - return nil, fmt.Errorf("error getting loadbalancer %s: %v", name, err) - } - klog.V(2).Infof("Creating loadbalancer %s", name) - loadbalancer, err = lbaas.createLoadBalancer(apiService, name, internalAnnotation) - if err != nil { - // Unknown error, retry later - return nil, fmt.Errorf("error creating loadbalancer %s: %v", name, err) - } - } else { - klog.V(2).Infof("LoadBalancer %s already exists", name) - } - - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return nil, fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - - lbmethod := v2pools.LBMethod(lbaas.opts.LBMethod) - if lbmethod == "" { - lbmethod = v2pools.LBMethodRoundRobin - } - - oldListeners, err := getListenersByLoadBalancerID(lbaas.lb, loadbalancer.ID) - if err != nil { - return nil, fmt.Errorf("error getting LB %s listeners: %v", name, err) - } - for portIndex, port := range ports { - listener := getListenerForPort(oldListeners, port) - if listener == nil { - klog.V(4).Infof("Creating listener for port %d", int(port.Port)) - listener, err = listeners.Create(lbaas.lb, listeners.CreateOpts{ - Name: fmt.Sprintf("listener_%s_%d", name, portIndex), - Protocol: listeners.Protocol(port.Protocol), - ProtocolPort: int(port.Port), - LoadbalancerID: loadbalancer.ID, - }).Extract() - if err != nil { - // Unknown error, retry later - return nil, fmt.Errorf("error creating LB listener: %v", err) - } - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return nil, fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - } - - klog.V(4).Infof("Listener for %s port %d: %s", string(port.Protocol), int(port.Port), listener.ID) - - // After all ports have been processed, remaining listeners are removed as obsolete. - // Pop valid listeners. - oldListeners = popListener(oldListeners, listener.ID) - pool, err := getPoolByListenerID(lbaas.lb, loadbalancer.ID, listener.ID) - if err != nil && err != ErrNotFound { - // Unknown error, retry later - return nil, fmt.Errorf("error getting pool for listener %s: %v", listener.ID, err) - } - if pool == nil { - klog.V(4).Infof("Creating pool for listener %s", listener.ID) - pool, err = v2pools.Create(lbaas.lb, v2pools.CreateOpts{ - Name: fmt.Sprintf("pool_%s_%d", name, portIndex), - Protocol: v2pools.Protocol(port.Protocol), - LBMethod: lbmethod, - ListenerID: listener.ID, - Persistence: persistence, - }).Extract() - if err != nil { - // Unknown error, retry later - return nil, fmt.Errorf("error creating pool for listener %s: %v", listener.ID, err) - } - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return nil, fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - - } - - klog.V(4).Infof("Pool for listener %s: %s", listener.ID, pool.ID) - members, err := getMembersByPoolID(lbaas.lb, pool.ID) - if err != nil && !isNotFound(err) { - return nil, fmt.Errorf("error getting pool members %s: %v", pool.ID, err) - } - for _, node := range nodes { - addr, err := nodeAddressForLB(node) - if err != nil { - if err == ErrNotFound { - // Node failure, do not create member - klog.Warningf("Failed to create LB pool member for node %s: %v", node.Name, err) - continue - } else { - return nil, fmt.Errorf("error getting address for node %s: %v", node.Name, err) - } - } - - if !memberExists(members, addr, int(port.NodePort)) { - klog.V(4).Infof("Creating member for pool %s", pool.ID) - _, err := v2pools.CreateMember(lbaas.lb, pool.ID, v2pools.CreateMemberOpts{ - Name: fmt.Sprintf("member_%s_%d_%s", name, portIndex, node.Name), - ProtocolPort: int(port.NodePort), - Address: addr, - SubnetID: lbaas.opts.SubnetID, - }).Extract() - if err != nil { - return nil, fmt.Errorf("error creating LB pool member for node: %s, %v", node.Name, err) - } - - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return nil, fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - } else { - // After all members have been processed, remaining members are deleted as obsolete. - members = popMember(members, addr, int(port.NodePort)) - } - - klog.V(4).Infof("Ensured pool %s has member for %s at %s", pool.ID, node.Name, addr) - } - - // Delete obsolete members for this pool - for _, member := range members { - klog.V(4).Infof("Deleting obsolete member %s for pool %s address %s", member.ID, pool.ID, member.Address) - err := v2pools.DeleteMember(lbaas.lb, pool.ID, member.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return nil, fmt.Errorf("error deleting obsolete member %s for pool %s address %s: %v", member.ID, pool.ID, member.Address, err) - } - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return nil, fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - } - - monitorID := pool.MonitorID - if monitorID == "" && lbaas.opts.CreateMonitor { - klog.V(4).Infof("Creating monitor for pool %s", pool.ID) - monitor, err := v2monitors.Create(lbaas.lb, v2monitors.CreateOpts{ - Name: fmt.Sprintf("monitor_%s_%d", name, portIndex), - PoolID: pool.ID, - Type: string(port.Protocol), - Delay: int(lbaas.opts.MonitorDelay.Duration.Seconds()), - Timeout: int(lbaas.opts.MonitorTimeout.Duration.Seconds()), - MaxRetries: int(lbaas.opts.MonitorMaxRetries), - }).Extract() - if err != nil { - return nil, fmt.Errorf("error creating LB pool healthmonitor: %v", err) - } - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return nil, fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - monitorID = monitor.ID - } else if !lbaas.opts.CreateMonitor { - klog.V(4).Infof("Do not create monitor for pool %s when create-monitor is false", pool.ID) - } - - if monitorID != "" { - klog.V(4).Infof("Monitor for pool %s: %s", pool.ID, monitorID) - } - } - - // All remaining listeners are obsolete, delete - for _, listener := range oldListeners { - klog.V(4).Infof("Deleting obsolete listener %s:", listener.ID) - // get pool for listener - pool, err := getPoolByListenerID(lbaas.lb, loadbalancer.ID, listener.ID) - if err != nil && err != ErrNotFound { - return nil, fmt.Errorf("error getting pool for obsolete listener %s: %v", listener.ID, err) - } - if pool != nil { - // get and delete monitor - monitorID := pool.MonitorID - if monitorID != "" { - klog.V(4).Infof("Deleting obsolete monitor %s for pool %s", monitorID, pool.ID) - err = v2monitors.Delete(lbaas.lb, monitorID).ExtractErr() - if err != nil && !isNotFound(err) { - return nil, fmt.Errorf("error deleting obsolete monitor %s for pool %s: %v", monitorID, pool.ID, err) - } - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return nil, fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - } - // get and delete pool members - members, err := getMembersByPoolID(lbaas.lb, pool.ID) - if err != nil && !isNotFound(err) { - return nil, fmt.Errorf("error getting members for pool %s: %v", pool.ID, err) - } - for _, member := range members { - klog.V(4).Infof("Deleting obsolete member %s for pool %s address %s", member.ID, pool.ID, member.Address) - err := v2pools.DeleteMember(lbaas.lb, pool.ID, member.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return nil, fmt.Errorf("error deleting obsolete member %s for pool %s address %s: %v", member.ID, pool.ID, member.Address, err) - } - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return nil, fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - } - klog.V(4).Infof("Deleting obsolete pool %s for listener %s", pool.ID, listener.ID) - // delete pool - err = v2pools.Delete(lbaas.lb, pool.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return nil, fmt.Errorf("error deleting obsolete pool %s for listener %s: %v", pool.ID, listener.ID, err) - } - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return nil, fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - } - // delete listener - err = listeners.Delete(lbaas.lb, listener.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return nil, fmt.Errorf("error deleteting obsolete listener: %v", err) - } - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return nil, fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - klog.V(2).Infof("Deleted obsolete listener: %s", listener.ID) - } - - portID := loadbalancer.VipPortID - floatIP, err := getFloatingIPByPortID(lbaas.network, portID) - if err != nil && err != ErrNotFound { - return nil, fmt.Errorf("error getting floating ip for port %s: %v", portID, err) - } - if floatIP == nil && floatingPool != "" && !internalAnnotation { - klog.V(4).Infof("Creating floating ip for loadbalancer %s port %s", loadbalancer.ID, portID) - floatIPOpts := floatingips.CreateOpts{ - FloatingNetworkID: floatingPool, - PortID: portID, - } - - loadBalancerIP := apiService.Spec.LoadBalancerIP - if loadBalancerIP != "" { - floatIPOpts.FloatingIP = loadBalancerIP - } - - floatIP, err = floatingips.Create(lbaas.network, floatIPOpts).Extract() - if err != nil { - return nil, fmt.Errorf("error creating LB floatingip %+v: %v", floatIPOpts, err) - } - } - - status := &v1.LoadBalancerStatus{} - - if floatIP != nil { - status.Ingress = []v1.LoadBalancerIngress{{IP: floatIP.FloatingIP}} - } else { - status.Ingress = []v1.LoadBalancerIngress{{IP: loadbalancer.VipAddress}} - } - - if lbaas.opts.ManageSecurityGroups { - err := lbaas.ensureSecurityGroup(clusterName, apiService, nodes, loadbalancer) - if err != nil { - return status, fmt.Errorf("Error reconciling security groups for LB service %v/%v: %v", apiService.Namespace, apiService.Name, err) - } - } - - return status, nil -} - -// ensureSecurityGroup ensures security group exist for specific loadbalancer service. -// Creating security group for specific loadbalancer service when it does not exist. -func (lbaas *LbaasV2) ensureSecurityGroup(clusterName string, apiService *v1.Service, nodes []*v1.Node, loadbalancer *loadbalancers.LoadBalancer) error { - // find node-security-group for service - var err error - if len(lbaas.opts.NodeSecurityGroupIDs) == 0 { - lbaas.opts.NodeSecurityGroupIDs, err = getNodeSecurityGroupIDForLB(lbaas.compute, lbaas.network, nodes) - if err != nil { - return fmt.Errorf("failed to find node-security-group for loadbalancer service %s/%s: %v", apiService.Namespace, apiService.Name, err) - } - } - klog.V(4).Infof("find node-security-group %v for loadbalancer service %s/%s", lbaas.opts.NodeSecurityGroupIDs, apiService.Namespace, apiService.Name) - - // get service ports - ports := apiService.Spec.Ports - if len(ports) == 0 { - return fmt.Errorf("no ports provided to openstack load balancer") - } - - // get service source ranges - sourceRanges, err := servicehelpers.GetLoadBalancerSourceRanges(apiService) - if err != nil { - return fmt.Errorf("failed to get source ranges for loadbalancer service %s/%s: %v", apiService.Namespace, apiService.Name, err) - } - - // ensure security group for LB - lbSecGroupName := getSecurityGroupName(apiService) - lbSecGroupID, err := groups.IDFromName(lbaas.network, lbSecGroupName) - if err != nil { - // If the security group of LB not exist, create it later - if isSecurityGroupNotFound(err) { - lbSecGroupID = "" - } else { - return fmt.Errorf("error occurred finding security group: %s: %v", lbSecGroupName, err) - } - } - if len(lbSecGroupID) == 0 { - // create security group - lbSecGroupCreateOpts := groups.CreateOpts{ - Name: getSecurityGroupName(apiService), - Description: fmt.Sprintf("Security Group for %s/%s Service LoadBalancer in cluster %s", apiService.Namespace, apiService.Name, clusterName), - } - - lbSecGroup, err := groups.Create(lbaas.network, lbSecGroupCreateOpts).Extract() - if err != nil { - return fmt.Errorf("failed to create Security Group for loadbalancer service %s/%s: %v", apiService.Namespace, apiService.Name, err) - } - lbSecGroupID = lbSecGroup.ID - - //add rule in security group - for _, port := range ports { - for _, sourceRange := range sourceRanges.StringSlice() { - ethertype := rules.EtherType4 - network, _, err := netutils.ParseCIDRSloppy(sourceRange) - - if err != nil { - return fmt.Errorf("error parsing source range %s as a CIDR: %v", sourceRange, err) - } - - if network.To4() == nil { - ethertype = rules.EtherType6 - } - - lbSecGroupRuleCreateOpts := rules.CreateOpts{ - Direction: rules.DirIngress, - PortRangeMax: int(port.Port), - PortRangeMin: int(port.Port), - Protocol: toRuleProtocol(port.Protocol), - RemoteIPPrefix: sourceRange, - SecGroupID: lbSecGroup.ID, - EtherType: ethertype, - } - - _, err = rules.Create(lbaas.network, lbSecGroupRuleCreateOpts).Extract() - - if err != nil { - return fmt.Errorf("error occurred creating rule for SecGroup %s: %v", lbSecGroup.ID, err) - } - } - } - - lbSecGroupRuleCreateOpts := rules.CreateOpts{ - Direction: rules.DirIngress, - PortRangeMax: 4, // ICMP: Code - Values for ICMP "Destination Unreachable: Fragmentation Needed and Don't Fragment was Set" - PortRangeMin: 3, // ICMP: Type - Protocol: rules.ProtocolICMP, - RemoteIPPrefix: "0.0.0.0/0", // The Fragmentation packet can come from anywhere along the path back to the sourceRange - we need to all this from all - SecGroupID: lbSecGroup.ID, - EtherType: rules.EtherType4, - } - - _, err = rules.Create(lbaas.network, lbSecGroupRuleCreateOpts).Extract() - - if err != nil { - return fmt.Errorf("error occurred creating rule for SecGroup %s: %v", lbSecGroup.ID, err) - } - - lbSecGroupRuleCreateOpts = rules.CreateOpts{ - Direction: rules.DirIngress, - PortRangeMax: 0, // ICMP: Code - Values for ICMP "Packet Too Big" - PortRangeMin: 2, // ICMP: Type - Protocol: rules.ProtocolICMP, - RemoteIPPrefix: "::/0", // The Fragmentation packet can come from anywhere along the path back to the sourceRange - we need to all this from all - SecGroupID: lbSecGroup.ID, - EtherType: rules.EtherType6, - } - - _, err = rules.Create(lbaas.network, lbSecGroupRuleCreateOpts).Extract() - if err != nil { - return fmt.Errorf("error occurred creating rule for SecGroup %s: %v", lbSecGroup.ID, err) - } - - // get security groups of port - portID := loadbalancer.VipPortID - port, err := getPortByID(lbaas.network, portID) - if err != nil { - return err - } - - // ensure the vip port has the security groups - found := false - for _, portSecurityGroups := range port.SecurityGroups { - if portSecurityGroups == lbSecGroup.ID { - found = true - break - } - } - - // update loadbalancer vip port - if !found { - port.SecurityGroups = append(port.SecurityGroups, lbSecGroup.ID) - updateOpts := neutronports.UpdateOpts{SecurityGroups: &port.SecurityGroups} - res := neutronports.Update(lbaas.network, portID, updateOpts) - if res.Err != nil { - msg := fmt.Sprintf("Error occurred updating port %s for loadbalancer service %s/%s: %v", portID, apiService.Namespace, apiService.Name, res.Err) - return fmt.Errorf(msg) - } - } - } - - // ensure rules for every node security group - for _, port := range ports { - for _, nodeSecurityGroupID := range lbaas.opts.NodeSecurityGroupIDs { - opts := rules.ListOpts{ - Direction: string(rules.DirIngress), - SecGroupID: nodeSecurityGroupID, - RemoteGroupID: lbSecGroupID, - PortRangeMax: int(port.NodePort), - PortRangeMin: int(port.NodePort), - Protocol: string(port.Protocol), - } - secGroupRules, err := getSecurityGroupRules(lbaas.network, opts) - if err != nil && !isNotFound(err) { - msg := fmt.Sprintf("Error finding rules for remote group id %s in security group id %s: %v", lbSecGroupID, nodeSecurityGroupID, err) - return fmt.Errorf(msg) - } - if len(secGroupRules) != 0 { - // Do not add rule when find rules for remote group in the Node Security Group - continue - } - - // Add the rules in the Node Security Group - err = createNodeSecurityGroup(lbaas.network, nodeSecurityGroupID, int(port.NodePort), port.Protocol, lbSecGroupID) - if err != nil { - return fmt.Errorf("error occurred creating security group for loadbalancer service %s/%s: %v", apiService.Namespace, apiService.Name, err) - } - } - } - - return nil -} - -// UpdateLoadBalancer updates hosts under the specified load balancer. -func (lbaas *LbaasV2) UpdateLoadBalancer(ctx context.Context, clusterName string, service *v1.Service, nodes []*v1.Node) error { - loadBalancerName := lbaas.GetLoadBalancerName(ctx, clusterName, service) - klog.V(4).Infof("UpdateLoadBalancer(%v, %v, %v)", clusterName, loadBalancerName, nodes) - - lbaas.opts.SubnetID = getStringFromServiceAnnotation(service, ServiceAnnotationLoadBalancerSubnetID, lbaas.opts.SubnetID) - if len(lbaas.opts.SubnetID) == 0 && len(nodes) > 0 { - // Get SubnetID automatically. - // The LB needs to be configured with instance addresses on the same subnet, so get SubnetID by one node. - subnetID, err := getSubnetIDForLB(lbaas.compute, *nodes[0]) - if err != nil { - klog.Warningf("Failed to find subnet-id for loadbalancer service %s/%s: %v", service.Namespace, service.Name, err) - return fmt.Errorf("no subnet-id for service %s/%s : subnet-id not set in cloud provider config, "+ - "and failed to find subnet-id from OpenStack: %v", service.Namespace, service.Name, err) - } - lbaas.opts.SubnetID = subnetID - } - - ports := service.Spec.Ports - if len(ports) == 0 { - return fmt.Errorf("no ports provided to openstack load balancer") - } - - loadbalancer, err := getLoadbalancerByName(lbaas.lb, loadBalancerName) - if err != nil { - return err - } - if loadbalancer == nil { - return fmt.Errorf("loadbalancer %s does not exist", loadBalancerName) - } - - // Get all listeners for this loadbalancer, by "port key". - type portKey struct { - Protocol listeners.Protocol - Port int - } - var listenerIDs []string - lbListeners := make(map[portKey]listeners.Listener) - allListeners, err := getListenersByLoadBalancerID(lbaas.lb, loadbalancer.ID) - if err != nil { - return fmt.Errorf("error getting listeners for LB %s: %v", loadBalancerName, err) - } - for _, l := range allListeners { - key := portKey{Protocol: listeners.Protocol(l.Protocol), Port: l.ProtocolPort} - lbListeners[key] = l - listenerIDs = append(listenerIDs, l.ID) - } - - // Get all pools for this loadbalancer, by listener ID. - lbPools := make(map[string]v2pools.Pool) - for _, listenerID := range listenerIDs { - pool, err := getPoolByListenerID(lbaas.lb, loadbalancer.ID, listenerID) - if err != nil { - return fmt.Errorf("error getting pool for listener %s: %v", listenerID, err) - } - lbPools[listenerID] = *pool - } - - // Compose Set of member (addresses) that _should_ exist - addrs := make(map[string]*v1.Node) - for _, node := range nodes { - addr, err := nodeAddressForLB(node) - if err != nil { - return err - } - addrs[addr] = node - } - - // Check for adding/removing members associated with each port - for portIndex, port := range ports { - // Get listener associated with this port - listener, ok := lbListeners[portKey{ - Protocol: toListenersProtocol(port.Protocol), - Port: int(port.Port), - }] - if !ok { - return fmt.Errorf("loadbalancer %s does not contain required listener for port %d and protocol %s", loadBalancerName, port.Port, port.Protocol) - } - - // Get pool associated with this listener - pool, ok := lbPools[listener.ID] - if !ok { - return fmt.Errorf("loadbalancer %s does not contain required pool for listener %s", loadBalancerName, listener.ID) - } - - // Find existing pool members (by address) for this port - getMembers, err := getMembersByPoolID(lbaas.lb, pool.ID) - if err != nil { - return fmt.Errorf("error getting pool members %s: %v", pool.ID, err) - } - members := make(map[string]v2pools.Member) - for _, member := range getMembers { - members[member.Address] = member - } - - // Add any new members for this port - for addr, node := range addrs { - if _, ok := members[addr]; ok && members[addr].ProtocolPort == int(port.NodePort) { - // Already exists, do not create member - continue - } - _, err := v2pools.CreateMember(lbaas.lb, pool.ID, v2pools.CreateMemberOpts{ - Name: fmt.Sprintf("member_%s_%d_%s", loadbalancer.Name, portIndex, node.Name), - Address: addr, - ProtocolPort: int(port.NodePort), - SubnetID: lbaas.opts.SubnetID, - }).Extract() - if err != nil { - return err - } - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - } - - // Remove any old members for this port - for _, member := range members { - if _, ok := addrs[member.Address]; ok && member.ProtocolPort == int(port.NodePort) { - // Still present, do not delete member - continue - } - err = v2pools.DeleteMember(lbaas.lb, pool.ID, member.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - } - } - - if lbaas.opts.ManageSecurityGroups { - err := lbaas.updateSecurityGroup(clusterName, service, nodes, loadbalancer) - if err != nil { - return fmt.Errorf("failed to update Security Group for loadbalancer service %s/%s: %v", service.Namespace, service.Name, err) - } - } - - return nil -} - -// updateSecurityGroup updating security group for specific loadbalancer service. -func (lbaas *LbaasV2) updateSecurityGroup(clusterName string, apiService *v1.Service, nodes []*v1.Node, loadbalancer *loadbalancers.LoadBalancer) error { - originalNodeSecurityGroupIDs := lbaas.opts.NodeSecurityGroupIDs - - var err error - lbaas.opts.NodeSecurityGroupIDs, err = getNodeSecurityGroupIDForLB(lbaas.compute, lbaas.network, nodes) - if err != nil { - return fmt.Errorf("failed to find node-security-group for loadbalancer service %s/%s: %v", apiService.Namespace, apiService.Name, err) - } - klog.V(4).Infof("find node-security-group %v for loadbalancer service %s/%s", lbaas.opts.NodeSecurityGroupIDs, apiService.Namespace, apiService.Name) - - original := sets.NewString(originalNodeSecurityGroupIDs...) - current := sets.NewString(lbaas.opts.NodeSecurityGroupIDs...) - removals := original.Difference(current) - - // Generate Name - lbSecGroupName := getSecurityGroupName(apiService) - lbSecGroupID, err := groups.IDFromName(lbaas.network, lbSecGroupName) - if err != nil { - return fmt.Errorf("error occurred finding security group: %s: %v", lbSecGroupName, err) - } - - ports := apiService.Spec.Ports - if len(ports) == 0 { - return fmt.Errorf("no ports provided to openstack load balancer") - } - - for _, port := range ports { - for removal := range removals { - // Delete the rules in the Node Security Group - opts := rules.ListOpts{ - Direction: string(rules.DirIngress), - SecGroupID: removal, - RemoteGroupID: lbSecGroupID, - PortRangeMax: int(port.NodePort), - PortRangeMin: int(port.NodePort), - Protocol: string(port.Protocol), - } - secGroupRules, err := getSecurityGroupRules(lbaas.network, opts) - if err != nil && !isNotFound(err) { - return fmt.Errorf("error finding rules for remote group id %s in security group id %s: %v", lbSecGroupID, removal, err) - } - - for _, rule := range secGroupRules { - res := rules.Delete(lbaas.network, rule.ID) - if res.Err != nil && !isNotFound(res.Err) { - return fmt.Errorf("error occurred deleting security group rule: %s: %v", rule.ID, res.Err) - } - } - } - - for _, nodeSecurityGroupID := range lbaas.opts.NodeSecurityGroupIDs { - opts := rules.ListOpts{ - Direction: string(rules.DirIngress), - SecGroupID: nodeSecurityGroupID, - RemoteGroupID: lbSecGroupID, - PortRangeMax: int(port.NodePort), - PortRangeMin: int(port.NodePort), - Protocol: string(port.Protocol), - } - secGroupRules, err := getSecurityGroupRules(lbaas.network, opts) - if err != nil && !isNotFound(err) { - return fmt.Errorf("error finding rules for remote group id %s in security group id %s: %v", lbSecGroupID, nodeSecurityGroupID, err) - } - if len(secGroupRules) != 0 { - // Do not add rule when find rules for remote group in the Node Security Group - continue - } - - // Add the rules in the Node Security Group - err = createNodeSecurityGroup(lbaas.network, nodeSecurityGroupID, int(port.NodePort), port.Protocol, lbSecGroupID) - if err != nil { - return fmt.Errorf("error occurred creating security group for loadbalancer service %s/%s: %v", apiService.Namespace, apiService.Name, err) - } - } - } - - return nil -} - -// EnsureLoadBalancerDeleted deletes the specified load balancer -func (lbaas *LbaasV2) EnsureLoadBalancerDeleted(ctx context.Context, clusterName string, service *v1.Service) error { - loadBalancerName := lbaas.GetLoadBalancerName(ctx, clusterName, service) - klog.V(4).Infof("EnsureLoadBalancerDeleted(%v, %v)", clusterName, loadBalancerName) - - loadbalancer, err := getLoadbalancerByName(lbaas.lb, loadBalancerName) - if err != nil && err != ErrNotFound { - return err - } - if loadbalancer == nil { - return nil - } - - if loadbalancer.VipPortID != "" { - portID := loadbalancer.VipPortID - floatingIP, err := getFloatingIPByPortID(lbaas.network, portID) - if err != nil && err != ErrNotFound { - return err - } - if floatingIP != nil { - err = floatingips.Delete(lbaas.network, floatingIP.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - } - } - - // get all listeners associated with this loadbalancer - listenerList, err := getListenersByLoadBalancerID(lbaas.lb, loadbalancer.ID) - if err != nil { - return fmt.Errorf("error getting LB %s listeners: %v", loadbalancer.ID, err) - } - - // get all pools (and health monitors) associated with this loadbalancer - var poolIDs []string - var monitorIDs []string - for _, listener := range listenerList { - pool, err := getPoolByListenerID(lbaas.lb, loadbalancer.ID, listener.ID) - if err != nil && err != ErrNotFound { - return fmt.Errorf("error getting pool for listener %s: %v", listener.ID, err) - } - if pool != nil { - poolIDs = append(poolIDs, pool.ID) - // If create-monitor of cloud-config is false, pool has not monitor. - if pool.MonitorID != "" { - monitorIDs = append(monitorIDs, pool.MonitorID) - } - } - } - - // delete all monitors - for _, monitorID := range monitorIDs { - err := v2monitors.Delete(lbaas.lb, monitorID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - } - - // delete all members and pools - for _, poolID := range poolIDs { - // get members for current pool - membersList, err := getMembersByPoolID(lbaas.lb, poolID) - if err != nil && !isNotFound(err) { - return fmt.Errorf("error getting pool members %s: %v", poolID, err) - } - // delete all members for this pool - for _, member := range membersList { - err := v2pools.DeleteMember(lbaas.lb, poolID, member.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - } - - // delete pool - err = v2pools.Delete(lbaas.lb, poolID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - } - - // delete all listeners - for _, listener := range listenerList { - err := listeners.Delete(lbaas.lb, listener.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - provisioningStatus, err := waitLoadbalancerActiveProvisioningStatus(lbaas.lb, loadbalancer.ID) - if err != nil { - return fmt.Errorf("failed to loadbalance ACTIVE provisioning status %v: %v", provisioningStatus, err) - } - } - - // delete loadbalancer - err = loadbalancers.Delete(lbaas.lb, loadbalancer.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - err = waitLoadbalancerDeleted(lbaas.lb, loadbalancer.ID) - if err != nil { - return fmt.Errorf("failed to delete loadbalancer: %v", err) - } - - // Delete the Security Group - if lbaas.opts.ManageSecurityGroups { - err := lbaas.EnsureSecurityGroupDeleted(clusterName, service) - if err != nil { - return fmt.Errorf("failed to delete Security Group for loadbalancer service %s/%s: %v", service.Namespace, service.Name, err) - } - } - - return nil -} - -// EnsureSecurityGroupDeleted deleting security group for specific loadbalancer service. -func (lbaas *LbaasV2) EnsureSecurityGroupDeleted(clusterName string, service *v1.Service) error { - // Generate Name - lbSecGroupName := getSecurityGroupName(service) - lbSecGroupID, err := groups.IDFromName(lbaas.network, lbSecGroupName) - if err != nil { - if isSecurityGroupNotFound(err) { - // It is OK when the security group has been deleted by others. - return nil - } - return fmt.Errorf("error occurred finding security group: %s: %v", lbSecGroupName, err) - } - - lbSecGroup := groups.Delete(lbaas.network, lbSecGroupID) - if lbSecGroup.Err != nil && !isNotFound(lbSecGroup.Err) { - return lbSecGroup.Err - } - - if len(lbaas.opts.NodeSecurityGroupIDs) == 0 { - // Just happen when nodes have not Security Group, or should not happen - // UpdateLoadBalancer and EnsureLoadBalancer can set lbaas.opts.NodeSecurityGroupIDs when it is empty - // And service controller call UpdateLoadBalancer to set lbaas.opts.NodeSecurityGroupIDs when controller manager service is restarted. - klog.Warningf("Can not find node-security-group from all the nodes of this cluster when delete loadbalancer service %s/%s", - service.Namespace, service.Name) - } else { - // Delete the rules in the Node Security Group - for _, nodeSecurityGroupID := range lbaas.opts.NodeSecurityGroupIDs { - opts := rules.ListOpts{ - SecGroupID: nodeSecurityGroupID, - RemoteGroupID: lbSecGroupID, - } - secGroupRules, err := getSecurityGroupRules(lbaas.network, opts) - - if err != nil && !isNotFound(err) { - msg := fmt.Sprintf("Error finding rules for remote group id %s in security group id %s: %v", lbSecGroupID, nodeSecurityGroupID, err) - return fmt.Errorf(msg) - } - - for _, rule := range secGroupRules { - res := rules.Delete(lbaas.network, rule.ID) - if res.Err != nil && !isNotFound(res.Err) { - return fmt.Errorf("error occurred deleting security group rule: %s: %v", rule.ID, res.Err) - } - } - } - } - - return nil -} diff --git a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_metrics.go b/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_metrics.go deleted file mode 100644 index 8d84a7758b6..00000000000 --- a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_metrics.go +++ /dev/null @@ -1,64 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2017 The Kubernetes Authors. - -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. -*/ - -package openstack - -import ( - "sync" - - "k8s.io/component-base/metrics" - "k8s.io/component-base/metrics/legacyregistry" -) - -const ( - openstackSubsystem = "openstack" - openstackOperationKey = "cloudprovider_openstack_api_request_duration_seconds" - openstackOperationErrorKey = "cloudprovider_openstack_api_request_errors" -) - -var ( - openstackOperationsLatency = metrics.NewHistogramVec( - &metrics.HistogramOpts{ - Subsystem: openstackSubsystem, - Name: openstackOperationKey, - Help: "Latency of openstack api call", - StabilityLevel: metrics.ALPHA, - }, - []string{"request"}, - ) - - openstackAPIRequestErrors = metrics.NewCounterVec( - &metrics.CounterOpts{ - Subsystem: openstackSubsystem, - Name: openstackOperationErrorKey, - Help: "Cumulative number of openstack Api call errors", - StabilityLevel: metrics.ALPHA, - }, - []string{"request"}, - ) -) - -var registerOnce sync.Once - -func registerMetrics() { - registerOnce.Do(func() { - legacyregistry.MustRegister(openstackOperationsLatency) - legacyregistry.MustRegister(openstackAPIRequestErrors) - }) -} diff --git a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_routes.go b/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_routes.go deleted file mode 100644 index 03163fcf048..00000000000 --- a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_routes.go +++ /dev/null @@ -1,347 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package openstack - -import ( - "context" - "errors" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers" - neutronports "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" - - "k8s.io/apimachinery/pkg/types" - cloudprovider "k8s.io/cloud-provider" - "k8s.io/klog/v2" - netutils "k8s.io/utils/net" -) - -var errNoRouterID = errors.New("router-id not set in cloud provider config") - -var _ cloudprovider.Routes = (*Routes)(nil) - -// Routes implements the cloudprovider.Routes for OpenStack clouds -type Routes struct { - compute *gophercloud.ServiceClient - network *gophercloud.ServiceClient - opts RouterOpts -} - -// NewRoutes creates a new instance of Routes -func NewRoutes(compute *gophercloud.ServiceClient, network *gophercloud.ServiceClient, opts RouterOpts) (cloudprovider.Routes, error) { - if opts.RouterID == "" { - return nil, errNoRouterID - } - - return &Routes{ - compute: compute, - network: network, - opts: opts, - }, nil -} - -// ListRoutes lists all managed routes that belong to the specified clusterName -func (r *Routes) ListRoutes(ctx context.Context, clusterName string) ([]*cloudprovider.Route, error) { - klog.V(4).Infof("ListRoutes(%v)", clusterName) - - nodeNamesByAddr := make(map[string]types.NodeName) - err := foreachServer(r.compute, servers.ListOpts{}, func(srv *servers.Server) (bool, error) { - addrs, err := nodeAddresses(srv) - if err != nil { - return false, err - } - - name := mapServerToNodeName(srv) - for _, addr := range addrs { - nodeNamesByAddr[addr.Address] = name - } - - return true, nil - }) - if err != nil { - return nil, err - } - - router, err := routers.Get(r.network, r.opts.RouterID).Extract() - if err != nil { - return nil, err - } - - var routes []*cloudprovider.Route - for _, item := range router.Routes { - nodeName, foundNode := nodeNamesByAddr[item.NextHop] - if !foundNode { - nodeName = types.NodeName(item.NextHop) - } - route := cloudprovider.Route{ - Name: item.DestinationCIDR, - TargetNode: nodeName, //contains the nexthop address if node was not found - Blackhole: !foundNode, - DestinationCIDR: item.DestinationCIDR, - } - routes = append(routes, &route) - } - - return routes, nil -} - -func updateRoutes(network *gophercloud.ServiceClient, router *routers.Router, newRoutes []routers.Route) (func(), error) { - origRoutes := router.Routes // shallow copy - - _, err := routers.Update(network, router.ID, routers.UpdateOpts{ - Routes: newRoutes, - }).Extract() - if err != nil { - return nil, err - } - - unwinder := func() { - klog.V(4).Infof("Reverting routes change to router %v", router.ID) - _, err := routers.Update(network, router.ID, routers.UpdateOpts{ - Routes: origRoutes, - }).Extract() - if err != nil { - klog.Warningf("Unable to reset routes during error unwind: %v", err) - } - } - - return unwinder, nil -} - -func updateAllowedAddressPairs(network *gophercloud.ServiceClient, port *neutronports.Port, newPairs []neutronports.AddressPair) (func(), error) { - origPairs := port.AllowedAddressPairs // shallow copy - - _, err := neutronports.Update(network, port.ID, neutronports.UpdateOpts{ - AllowedAddressPairs: &newPairs, - }).Extract() - if err != nil { - return nil, err - } - - unwinder := func() { - klog.V(4).Infof("Reverting allowed-address-pairs change to port %v", port.ID) - _, err := neutronports.Update(network, port.ID, neutronports.UpdateOpts{ - AllowedAddressPairs: &origPairs, - }).Extract() - if err != nil { - klog.Warningf("Unable to reset allowed-address-pairs during error unwind: %v", err) - } - } - - return unwinder, nil -} - -// CreateRoute creates the described managed route -func (r *Routes) CreateRoute(ctx context.Context, clusterName string, nameHint string, route *cloudprovider.Route) error { - klog.V(4).Infof("CreateRoute(%v, %v, %v)", clusterName, nameHint, route) - - onFailure := newCaller() - - ip, _, _ := netutils.ParseCIDRSloppy(route.DestinationCIDR) - isCIDRv6 := ip.To4() == nil - addr, err := getAddressByName(r.compute, route.TargetNode, isCIDRv6) - - if err != nil { - return err - } - - klog.V(4).Infof("Using nexthop %v for node %v", addr, route.TargetNode) - - router, err := routers.Get(r.network, r.opts.RouterID).Extract() - if err != nil { - return err - } - - routes := router.Routes - - for _, item := range routes { - if item.DestinationCIDR == route.DestinationCIDR && item.NextHop == addr { - klog.V(4).Infof("Skipping existing route: %v", route) - return nil - } - } - - routes = append(routes, routers.Route{ - DestinationCIDR: route.DestinationCIDR, - NextHop: addr, - }) - - unwind, err := updateRoutes(r.network, router, routes) - if err != nil { - return err - } - defer onFailure.call(unwind) - - // get the port of addr on target node. - portID, err := getPortIDByIP(r.compute, route.TargetNode, addr) - if err != nil { - return err - } - port, err := getPortByID(r.network, portID) - if err != nil { - return err - } - - found := false - for _, item := range port.AllowedAddressPairs { - if item.IPAddress == route.DestinationCIDR { - klog.V(4).Infof("Found existing allowed-address-pair: %v", item) - found = true - break - } - } - - if !found { - newPairs := append(port.AllowedAddressPairs, neutronports.AddressPair{ - IPAddress: route.DestinationCIDR, - }) - unwind, err := updateAllowedAddressPairs(r.network, port, newPairs) - if err != nil { - return err - } - defer onFailure.call(unwind) - } - - klog.V(4).Infof("Route created: %v", route) - onFailure.disarm() - return nil -} - -// DeleteRoute deletes the specified managed route -func (r *Routes) DeleteRoute(ctx context.Context, clusterName string, route *cloudprovider.Route) error { - klog.V(4).Infof("DeleteRoute(%v, %v)", clusterName, route) - - onFailure := newCaller() - - ip, _, _ := netutils.ParseCIDRSloppy(route.DestinationCIDR) - isCIDRv6 := ip.To4() == nil - - var addr string - - // Blackhole routes are orphaned and have no counterpart in OpenStack - if !route.Blackhole { - var err error - addr, err = getAddressByName(r.compute, route.TargetNode, isCIDRv6) - if err != nil { - return err - } - } - - router, err := routers.Get(r.network, r.opts.RouterID).Extract() - if err != nil { - return err - } - - routes := router.Routes - index := -1 - for i, item := range routes { - if item.DestinationCIDR == route.DestinationCIDR && (item.NextHop == addr || route.Blackhole && item.NextHop == string(route.TargetNode)) { - index = i - break - } - } - - if index == -1 { - klog.V(4).Infof("Skipping non-existent route: %v", route) - return nil - } - - // Delete element `index` - routes[index] = routes[len(routes)-1] - routes = routes[:len(routes)-1] - - unwind, err := updateRoutes(r.network, router, routes) - // If this was a blackhole route we are done, there are no ports to update - if err != nil || route.Blackhole { - return err - } - defer onFailure.call(unwind) - - // get the port of addr on target node. - portID, err := getPortIDByIP(r.compute, route.TargetNode, addr) - if err != nil { - return err - } - port, err := getPortByID(r.network, portID) - if err != nil { - return err - } - - addrPairs := port.AllowedAddressPairs - index = -1 - for i, item := range addrPairs { - if item.IPAddress == route.DestinationCIDR { - index = i - break - } - } - - if index != -1 { - // Delete element `index` - addrPairs[index] = addrPairs[len(addrPairs)-1] - addrPairs = addrPairs[:len(addrPairs)-1] - - unwind, err := updateAllowedAddressPairs(r.network, port, addrPairs) - if err != nil { - return err - } - defer onFailure.call(unwind) - } - - klog.V(4).Infof("Route deleted: %v", route) - onFailure.disarm() - return nil -} - -func getPortIDByIP(compute *gophercloud.ServiceClient, targetNode types.NodeName, ipAddress string) (string, error) { - srv, err := getServerByName(compute, targetNode) - if err != nil { - return "", err - } - - interfaces, err := getAttachedInterfacesByID(compute, srv.ID) - if err != nil { - return "", err - } - - for _, intf := range interfaces { - for _, fixedIP := range intf.FixedIPs { - if fixedIP.IPAddress == ipAddress { - return intf.PortID, nil - } - } - } - - return "", ErrNotFound -} - -func getPortByID(client *gophercloud.ServiceClient, portID string) (*neutronports.Port, error) { - targetPort, err := neutronports.Get(client, portID).Extract() - if err != nil { - return nil, err - } - - if targetPort == nil { - return nil, ErrNotFound - } - - return targetPort, nil -} diff --git a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_routes_test.go b/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_routes_test.go deleted file mode 100644 index 56752b5b6cf..00000000000 --- a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_routes_test.go +++ /dev/null @@ -1,128 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package openstack - -import ( - "context" - "testing" - - "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers" - "k8s.io/apimachinery/pkg/types" - cloudprovider "k8s.io/cloud-provider" - netutils "k8s.io/utils/net" -) - -func TestRoutes(t *testing.T) { - const clusterName = "ignored" - - cfg, ok := configFromEnv() - if !ok { - t.Skipf("No config found in environment") - } - - os, err := newOpenStack(cfg) - if err != nil { - t.Fatalf("Failed to construct/authenticate OpenStack: %s", err) - } - - vms := getServers(os) - _, err = os.InstanceID() - if err != nil || len(vms) == 0 { - t.Skipf("Please run this test in an OpenStack vm or create at least one VM in OpenStack before you run this test.") - } - - // We know we have at least one vm. - servername := vms[0].Name - - // Pick the first router and server to try a test with - os.routeOpts.RouterID = getRouters(os)[0].ID - - r, ok := os.Routes() - if !ok { - t.Skip("Routes() returned false - perhaps your stack does not support Neutron extraroute extension?") - } - - newroute := cloudprovider.Route{ - DestinationCIDR: "10.164.2.0/24", - TargetNode: types.NodeName(servername), - } - err = r.CreateRoute(context.TODO(), clusterName, "myhint", &newroute) - if err != nil { - t.Fatalf("CreateRoute error: %v", err) - } - - routelist, err := r.ListRoutes(context.TODO(), clusterName) - if err != nil { - t.Fatalf("ListRoutes() error: %v", err) - } - for _, route := range routelist { - _, cidr, err := netutils.ParseCIDRSloppy(route.DestinationCIDR) - if err != nil { - t.Logf("Ignoring route %s, unparsable CIDR: %v", route.Name, err) - continue - } - t.Logf("%s via %s", cidr, route.TargetNode) - } - - err = r.DeleteRoute(context.TODO(), clusterName, &newroute) - if err != nil { - t.Fatalf("DeleteRoute error: %v", err) - } -} - -func getServers(os *OpenStack) []servers.Server { - c, err := os.NewComputeV2() - if err != nil { - panic(err) - } - allPages, err := servers.List(c, servers.ListOpts{}).AllPages() - if err != nil { - panic(err) - } - allServers, err := servers.ExtractServers(allPages) - if err != nil { - panic(err) - } - if len(allServers) == 0 { - panic("No servers to test with") - } - return allServers -} - -func getRouters(os *OpenStack) []routers.Router { - listOpts := routers.ListOpts{} - n, err := os.NewNetworkV2() - if err != nil { - panic(err) - } - allPages, err := routers.List(n, listOpts).AllPages() - if err != nil { - panic(err) - } - allRouters, err := routers.ExtractRouters(allPages) - if err != nil { - panic(err) - } - if len(allRouters) == 0 { - panic("No routers to test with") - } - return allRouters -} diff --git a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_test.go b/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_test.go deleted file mode 100644 index 40fdf5bc2d9..00000000000 --- a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_test.go +++ /dev/null @@ -1,733 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2014 The Kubernetes Authors. - -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. -*/ - -package openstack - -import ( - "context" - "fmt" - "os" - "reflect" - "regexp" - "sort" - "strings" - "testing" - "time" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" - v1 "k8s.io/api/core/v1" - - "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/rand" - "k8s.io/apimachinery/pkg/util/wait" -) - -const ( - testClusterName = "testCluster" - - volumeStatusTimeoutSeconds = 30 - // volumeStatus* is configuration of exponential backoff for - // waiting for specified volume status. Starting with 1 - // seconds, multiplying by 1.2 with each step and taking 13 steps at maximum - // it will time out after 32s, which roughly corresponds to 30s - volumeStatusInitDelay = 1 * time.Second - volumeStatusFactor = 1.2 - volumeStatusSteps = 13 -) - -func WaitForVolumeStatus(t *testing.T, os *OpenStack, volumeName string, status string) { - backoff := wait.Backoff{ - Duration: volumeStatusInitDelay, - Factor: volumeStatusFactor, - Steps: volumeStatusSteps, - } - err := wait.ExponentialBackoff(backoff, func() (bool, error) { - getVol, err := os.getVolume(volumeName) - if err != nil { - return false, err - } - if getVol.Status == status { - t.Logf("Volume (%s) status changed to %s after %v seconds\n", - volumeName, - status, - volumeStatusTimeoutSeconds) - return true, nil - } - return false, nil - }) - if err == wait.ErrWaitTimeout { - t.Logf("Volume (%s) status did not change to %s after %v seconds\n", - volumeName, - status, - volumeStatusTimeoutSeconds) - return - } - if err != nil { - t.Fatalf("Cannot get existing Cinder volume (%s): %v", volumeName, err) - } -} - -func TestReadConfig(t *testing.T) { - _, err := readConfig(nil) - if err == nil { - t.Errorf("Should fail when no config is provided: %s", err) - } - - // Since we are setting env vars, we need to reset old - // values for other tests to succeed. - env := clearEnviron(t) - defer resetEnviron(t, env) - - os.Setenv("OS_PASSWORD", "mypass") // Fake value for testing. - defer os.Unsetenv("OS_PASSWORD") - - os.Setenv("OS_TENANT_NAME", "admin") - defer os.Unsetenv("OS_TENANT_NAME") - - cfg, err := readConfig(strings.NewReader(` - [Global] - auth-url = http://auth.url - user-id = user - tenant-name = demo - region = RegionOne - [LoadBalancer] - create-monitor = yes - monitor-delay = 1m - monitor-timeout = 30s - monitor-max-retries = 3 - [BlockStorage] - bs-version = auto - trust-device-path = yes - ignore-volume-az = yes - [Metadata] - search-order = configDrive, metadataService - `)) - cfg.Global.Password = os.Getenv("OS_PASSWORD") - - if err != nil { - t.Fatalf("Should succeed when a valid config is provided: %s", err) - } - if cfg.Global.AuthURL != "http://auth.url" { - t.Errorf("incorrect authurl: %s", cfg.Global.AuthURL) - } - - if cfg.Global.UserID != "user" { - t.Errorf("incorrect userid: %s", cfg.Global.UserID) - } - - if cfg.Global.Password != "mypass" { - t.Errorf("incorrect password: %s", cfg.Global.Password) - } - - // config file wins over environment variable - if cfg.Global.TenantName != "demo" { - t.Errorf("incorrect tenant name: %s", cfg.Global.TenantName) - } - - if cfg.Global.Region != "RegionOne" { - t.Errorf("incorrect region: %s", cfg.Global.Region) - } - - if !cfg.LoadBalancer.CreateMonitor { - t.Errorf("incorrect lb.createmonitor: %t", cfg.LoadBalancer.CreateMonitor) - } - if cfg.LoadBalancer.MonitorDelay.Duration != 1*time.Minute { - t.Errorf("incorrect lb.monitordelay: %s", cfg.LoadBalancer.MonitorDelay) - } - if cfg.LoadBalancer.MonitorTimeout.Duration != 30*time.Second { - t.Errorf("incorrect lb.monitortimeout: %s", cfg.LoadBalancer.MonitorTimeout) - } - if cfg.LoadBalancer.MonitorMaxRetries != 3 { - t.Errorf("incorrect lb.monitormaxretries: %d", cfg.LoadBalancer.MonitorMaxRetries) - } - if cfg.BlockStorage.TrustDevicePath != true { - t.Errorf("incorrect bs.trustdevicepath: %v", cfg.BlockStorage.TrustDevicePath) - } - if cfg.BlockStorage.BSVersion != "auto" { - t.Errorf("incorrect bs.bs-version: %v", cfg.BlockStorage.BSVersion) - } - if cfg.BlockStorage.IgnoreVolumeAZ != true { - t.Errorf("incorrect bs.IgnoreVolumeAZ: %v", cfg.BlockStorage.IgnoreVolumeAZ) - } - if cfg.Metadata.SearchOrder != "configDrive, metadataService" { - t.Errorf("incorrect md.search-order: %v", cfg.Metadata.SearchOrder) - } -} - -func TestToAuthOptions(t *testing.T) { - cfg := Config{} - cfg.Global.Username = "user" - cfg.Global.Password = "pass" // Fake value for testing. - cfg.Global.DomainID = "2a73b8f597c04551a0fdc8e95544be8a" - cfg.Global.DomainName = "local" - cfg.Global.AuthURL = "http://auth.url" - cfg.Global.UserID = "user" - - ao := cfg.toAuthOptions() - - if !ao.AllowReauth { - t.Errorf("Will need to be able to reauthenticate") - } - if ao.Username != cfg.Global.Username { - t.Errorf("Username %s != %s", ao.Username, cfg.Global.Username) - } - if ao.Password != cfg.Global.Password { - t.Errorf("Password %s != %s", ao.Password, cfg.Global.Password) - } - if ao.DomainID != cfg.Global.DomainID { - t.Errorf("DomainID %s != %s", ao.DomainID, cfg.Global.DomainID) - } - if ao.IdentityEndpoint != cfg.Global.AuthURL { - t.Errorf("IdentityEndpoint %s != %s", ao.IdentityEndpoint, cfg.Global.AuthURL) - } - if ao.UserID != cfg.Global.UserID { - t.Errorf("UserID %s != %s", ao.UserID, cfg.Global.UserID) - } - if ao.DomainName != cfg.Global.DomainName { - t.Errorf("DomainName %s != %s", ao.DomainName, cfg.Global.DomainName) - } - if ao.TenantID != cfg.Global.TenantID { - t.Errorf("TenantID %s != %s", ao.TenantID, cfg.Global.TenantID) - } -} - -func TestCheckOpenStackOpts(t *testing.T) { - delay := MyDuration{60 * time.Second} - timeout := MyDuration{30 * time.Second} - tests := []struct { - name string - openstackOpts *OpenStack - expectedError error - }{ - { - name: "test1", - openstackOpts: &OpenStack{ - provider: nil, - lbOpts: LoadBalancerOpts{ - LBVersion: "v2", - SubnetID: "6261548e-ffde-4bc7-bd22-59c83578c5ef", - FloatingNetworkID: "38b8b5f9-64dc-4424-bf86-679595714786", - LBMethod: "ROUND_ROBIN", - LBProvider: "haproxy", - CreateMonitor: true, - MonitorDelay: delay, - MonitorTimeout: timeout, - MonitorMaxRetries: uint(3), - ManageSecurityGroups: true, - }, - metadataOpts: MetadataOpts{ - SearchOrder: configDriveID, - }, - }, - expectedError: nil, - }, - { - name: "test2", - openstackOpts: &OpenStack{ - provider: nil, - lbOpts: LoadBalancerOpts{ - LBVersion: "v2", - FloatingNetworkID: "38b8b5f9-64dc-4424-bf86-679595714786", - LBMethod: "ROUND_ROBIN", - CreateMonitor: true, - MonitorDelay: delay, - MonitorTimeout: timeout, - MonitorMaxRetries: uint(3), - ManageSecurityGroups: true, - }, - metadataOpts: MetadataOpts{ - SearchOrder: configDriveID, - }, - }, - expectedError: nil, - }, - { - name: "test3", - openstackOpts: &OpenStack{ - provider: nil, - lbOpts: LoadBalancerOpts{ - LBVersion: "v2", - SubnetID: "6261548e-ffde-4bc7-bd22-59c83578c5ef", - FloatingNetworkID: "38b8b5f9-64dc-4424-bf86-679595714786", - LBMethod: "ROUND_ROBIN", - CreateMonitor: true, - MonitorTimeout: timeout, - MonitorMaxRetries: uint(3), - ManageSecurityGroups: true, - }, - metadataOpts: MetadataOpts{ - SearchOrder: configDriveID, - }, - }, - expectedError: fmt.Errorf("monitor-delay not set in cloud provider config"), - }, - { - name: "test4", - openstackOpts: &OpenStack{ - provider: nil, - metadataOpts: MetadataOpts{ - SearchOrder: "", - }, - }, - expectedError: fmt.Errorf("invalid value in section [Metadata] with key `search-order`. Value cannot be empty"), - }, - { - name: "test5", - openstackOpts: &OpenStack{ - provider: nil, - metadataOpts: MetadataOpts{ - SearchOrder: "value1,value2,value3", - }, - }, - expectedError: fmt.Errorf("invalid value in section [Metadata] with key `search-order`. Value cannot contain more than 2 elements"), - }, - { - name: "test6", - openstackOpts: &OpenStack{ - provider: nil, - metadataOpts: MetadataOpts{ - SearchOrder: "value1", - }, - }, - expectedError: fmt.Errorf("invalid element %q found in section [Metadata] with key `search-order`."+ - "Supported elements include %q and %q", "value1", configDriveID, metadataID), - }, - { - name: "test7", - openstackOpts: &OpenStack{ - provider: nil, - lbOpts: LoadBalancerOpts{ - LBVersion: "v2", - SubnetID: "6261548e-ffde-4bc7-bd22-59c83578c5ef", - FloatingNetworkID: "38b8b5f9-64dc-4424-bf86-679595714786", - LBMethod: "ROUND_ROBIN", - CreateMonitor: true, - MonitorDelay: delay, - MonitorTimeout: timeout, - ManageSecurityGroups: true, - }, - metadataOpts: MetadataOpts{ - SearchOrder: configDriveID, - }, - }, - expectedError: fmt.Errorf("monitor-max-retries not set in cloud provider config"), - }, - { - name: "test8", - openstackOpts: &OpenStack{ - provider: nil, - lbOpts: LoadBalancerOpts{ - LBVersion: "v2", - SubnetID: "6261548e-ffde-4bc7-bd22-59c83578c5ef", - FloatingNetworkID: "38b8b5f9-64dc-4424-bf86-679595714786", - LBMethod: "ROUND_ROBIN", - CreateMonitor: true, - MonitorDelay: delay, - MonitorMaxRetries: uint(3), - ManageSecurityGroups: true, - }, - metadataOpts: MetadataOpts{ - SearchOrder: configDriveID, - }, - }, - expectedError: fmt.Errorf("monitor-timeout not set in cloud provider config"), - }, - } - - for _, testcase := range tests { - err := checkOpenStackOpts(testcase.openstackOpts) - - if err == nil && testcase.expectedError == nil { - continue - } - if (err != nil && testcase.expectedError == nil) || (err == nil && testcase.expectedError != nil) || err.Error() != testcase.expectedError.Error() { - t.Errorf("%s failed: expected err=%q, got %q", - testcase.name, testcase.expectedError, err) - } - } -} - -func TestCaller(t *testing.T) { - called := false - myFunc := func() { called = true } - - c := newCaller() - c.call(myFunc) - - if !called { - t.Errorf("caller failed to call function in default case") - } - - c.disarm() - called = false - c.call(myFunc) - - if called { - t.Error("caller still called function when disarmed") - } - - // Confirm the "usual" deferred caller pattern works as expected - - called = false - successCase := func() { - c := newCaller() - defer c.call(func() { called = true }) - c.disarm() - } - if successCase(); called { - t.Error("Deferred success case still invoked unwind") - } - - called = false - failureCase := func() { - c := newCaller() - defer c.call(func() { called = true }) - } - if failureCase(); !called { - t.Error("Deferred failure case failed to invoke unwind") - } -} - -// An arbitrary sort.Interface, just for easier comparison -type AddressSlice []v1.NodeAddress - -func (a AddressSlice) Len() int { return len(a) } -func (a AddressSlice) Less(i, j int) bool { return a[i].Address < a[j].Address } -func (a AddressSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -func TestNodeAddresses(t *testing.T) { - srv := servers.Server{ - Status: "ACTIVE", - HostID: "29d3c8c896a45aa4c34e52247875d7fefc3d94bbcc9f622b5d204362", - AccessIPv4: "50.56.176.99", - AccessIPv6: "2001:4800:790e:510:be76:4eff:fe04:82a8", - Addresses: map[string]interface{}{ - "private": []interface{}{ - map[string]interface{}{ - "OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:7c:1b:2b", - "version": float64(4), - "addr": "10.0.0.32", - "OS-EXT-IPS:type": "fixed", - }, - map[string]interface{}{ - "version": float64(4), - "addr": "50.56.176.36", - "OS-EXT-IPS:type": "floating", - }, - map[string]interface{}{ - "version": float64(4), - "addr": "10.0.0.31", - // No OS-EXT-IPS:type - }, - }, - "public": []interface{}{ - map[string]interface{}{ - "version": float64(4), - "addr": "50.56.176.35", - }, - map[string]interface{}{ - "version": float64(6), - "addr": "2001:4800:780e:510:be76:4eff:fe04:84a8", - }, - }, - }, - Metadata: map[string]string{ - "name": "a1-yinvcez57-0-bvynoyawrhcg-kube-minion-fg5i4jwcc2yy", - TypeHostName: "a1-yinvcez57-0-bvynoyawrhcg-kube-minion-fg5i4jwcc2yy.novalocal", - }, - } - - addrs, err := nodeAddresses(&srv) - if err != nil { - t.Fatalf("nodeAddresses returned error: %v", err) - } - - sort.Sort(AddressSlice(addrs)) - t.Logf("addresses is %v", addrs) - - want := []v1.NodeAddress{ - {Type: v1.NodeInternalIP, Address: "10.0.0.31"}, - {Type: v1.NodeInternalIP, Address: "10.0.0.32"}, - {Type: v1.NodeExternalIP, Address: "2001:4800:780e:510:be76:4eff:fe04:84a8"}, - {Type: v1.NodeExternalIP, Address: "2001:4800:790e:510:be76:4eff:fe04:82a8"}, - {Type: v1.NodeExternalIP, Address: "50.56.176.35"}, - {Type: v1.NodeExternalIP, Address: "50.56.176.36"}, - {Type: v1.NodeExternalIP, Address: "50.56.176.99"}, - {Type: v1.NodeHostName, Address: "a1-yinvcez57-0-bvynoyawrhcg-kube-minion-fg5i4jwcc2yy.novalocal"}, - } - - if !reflect.DeepEqual(want, addrs) { - t.Errorf("nodeAddresses returned incorrect value %v", addrs) - } -} - -func configFromEnvWithPasswd() (cfg Config, ok bool) { - cfg, ok = configFromEnv() - if !ok { - return cfg, ok - } - cfg.Global.Password = os.Getenv("OS_PASSWORD") - return cfg, ok -} - -func TestNewOpenStack(t *testing.T) { - cfg, ok := configFromEnvWithPasswd() - if !ok { - t.Skip("No config found in environment") - } - - _, err := newOpenStack(cfg) - if err != nil { - t.Fatalf("Failed to construct/authenticate OpenStack: %s", err) - } -} - -func TestLoadBalancer(t *testing.T) { - cfg, ok := configFromEnvWithPasswd() - if !ok { - t.Skip("No config found in environment") - } - - versions := []string{"v2", ""} - - for _, v := range versions { - t.Logf("Trying LBVersion = '%s'\n", v) - cfg.LoadBalancer.LBVersion = v - - os, err := newOpenStack(cfg) - if err != nil { - t.Fatalf("Failed to construct/authenticate OpenStack: %s", err) - } - - lb, ok := os.LoadBalancer() - if !ok { - t.Fatalf("LoadBalancer() returned false - perhaps your stack doesn't support Neutron?") - } - - _, exists, err := lb.GetLoadBalancer(context.TODO(), testClusterName, &v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "noexist"}}) - if err != nil { - t.Fatalf("GetLoadBalancer(\"noexist\") returned error: %s", err) - } - if exists { - t.Fatalf("GetLoadBalancer(\"noexist\") returned exists") - } - } -} - -func TestZones(t *testing.T) { - SetMetadataFixture(&FakeMetadata) - defer ClearMetadata() - - os := OpenStack{ - provider: &gophercloud.ProviderClient{ - IdentityBase: "http://auth.url/", - }, - region: "myRegion", - } - - z, ok := os.Zones() - if !ok { - t.Fatalf("Zones() returned false") - } - - zone, err := z.GetZone(context.TODO()) - if err != nil { - t.Fatalf("GetZone() returned error: %s", err) - } - - if zone.Region != "myRegion" { - t.Fatalf("GetZone() returned wrong region (%s)", zone.Region) - } - - if zone.FailureDomain != "nova" { - t.Fatalf("GetZone() returned wrong failure domain (%s)", zone.FailureDomain) - } -} - -var diskPathRegexp = regexp.MustCompile("/dev/disk/(?:by-id|by-path)/") - -func TestVolumes(t *testing.T) { - cfg, ok := configFromEnvWithPasswd() - if !ok { - t.Skip("No config found in environment") - } - - os, err := newOpenStack(cfg) - if err != nil { - t.Fatalf("Failed to construct/authenticate OpenStack: %s", err) - } - - tags := map[string]string{ - "test": "value", - } - vol, _, _, _, err := os.CreateVolume("kubernetes-test-volume-"+rand.String(10), 1, "", "", &tags) - if err != nil { - t.Fatalf("Cannot create a new Cinder volume: %v", err) - } - t.Logf("Volume (%s) created\n", vol) - - WaitForVolumeStatus(t, os, vol, volumeAvailableStatus) - - id, err := os.InstanceID() - if err != nil { - t.Logf("Cannot find instance id: %v - perhaps you are running this test outside a VM launched by OpenStack", err) - } else { - diskID, err := os.AttachDisk(id, vol) - if err != nil { - t.Fatalf("Cannot AttachDisk Cinder volume %s: %v", vol, err) - } - t.Logf("Volume (%s) attached, disk ID: %s\n", vol, diskID) - - WaitForVolumeStatus(t, os, vol, volumeInUseStatus) - - devicePath := os.GetDevicePath(diskID) - if diskPathRegexp.FindString(devicePath) == "" { - t.Fatalf("GetDevicePath returned and unexpected path for Cinder volume %s, returned %s", vol, devicePath) - } - t.Logf("Volume (%s) found at path: %s\n", vol, devicePath) - - err = os.DetachDisk(id, vol) - if err != nil { - t.Fatalf("Cannot DetachDisk Cinder volume %s: %v", vol, err) - } - t.Logf("Volume (%s) detached\n", vol) - - WaitForVolumeStatus(t, os, vol, volumeAvailableStatus) - } - - expectedVolSize := resource.MustParse("2Gi") - newVolSize, err := os.ExpandVolume(vol, resource.MustParse("1Gi"), expectedVolSize) - if err != nil { - t.Fatalf("Cannot expand a Cinder volume: %v", err) - } - if newVolSize != expectedVolSize { - t.Logf("Expected: %v but got: %v ", expectedVolSize, newVolSize) - } - t.Logf("Volume expanded to (%v) \n", newVolSize) - - WaitForVolumeStatus(t, os, vol, volumeAvailableStatus) - - err = os.DeleteVolume(vol) - if err != nil { - t.Fatalf("Cannot delete Cinder volume %s: %v", vol, err) - } - t.Logf("Volume (%s) deleted\n", vol) - -} - -func TestInstanceIDFromProviderID(t *testing.T) { - testCases := []struct { - providerID string - instanceID string - fail bool - }{ - { - providerID: ProviderName + "://" + "/" + "7b9cf879-7146-417c-abfd-cb4272f0c935", - instanceID: "7b9cf879-7146-417c-abfd-cb4272f0c935", - fail: false, - }, - { - providerID: "openstack://7b9cf879-7146-417c-abfd-cb4272f0c935", - instanceID: "", - fail: true, - }, - { - providerID: "7b9cf879-7146-417c-abfd-cb4272f0c935", - instanceID: "", - fail: true, - }, - { - providerID: "other-provider:///7b9cf879-7146-417c-abfd-cb4272f0c935", - instanceID: "", - fail: true, - }, - } - - for _, test := range testCases { - instanceID, err := instanceIDFromProviderID(test.providerID) - if (err != nil) != test.fail { - t.Errorf("%s yielded `err != nil` as %t. expected %t", test.providerID, (err != nil), test.fail) - } - - if test.fail { - continue - } - - if instanceID != test.instanceID { - t.Errorf("%s yielded %s. expected %s", test.providerID, instanceID, test.instanceID) - } - } -} - -func TestToAuth3Options(t *testing.T) { - cfg := Config{} - cfg.Global.Username = "user" - cfg.Global.Password = "pass" // Fake value for testing. - cfg.Global.DomainID = "2a73b8f597c04551a0fdc8e95544be8a" - cfg.Global.DomainName = "local" - cfg.Global.AuthURL = "http://auth.url" - cfg.Global.UserID = "user" - - ao := cfg.toAuth3Options() - - if !ao.AllowReauth { - t.Errorf("Will need to be able to reauthenticate") - } - if ao.Username != cfg.Global.Username { - t.Errorf("Username %s != %s", ao.Username, cfg.Global.Username) - } - if ao.Password != cfg.Global.Password { - t.Errorf("Password %s != %s", ao.Password, cfg.Global.Password) - } - if ao.DomainID != cfg.Global.DomainID { - t.Errorf("DomainID %s != %s", ao.DomainID, cfg.Global.DomainID) - } - if ao.IdentityEndpoint != cfg.Global.AuthURL { - t.Errorf("IdentityEndpoint %s != %s", ao.IdentityEndpoint, cfg.Global.AuthURL) - } - if ao.UserID != cfg.Global.UserID { - t.Errorf("UserID %s != %s", ao.UserID, cfg.Global.UserID) - } - if ao.DomainName != cfg.Global.DomainName { - t.Errorf("DomainName %s != %s", ao.DomainName, cfg.Global.DomainName) - } -} - -func clearEnviron(t *testing.T) []string { - env := os.Environ() - for _, pair := range env { - if strings.HasPrefix(pair, "OS_") { - i := strings.Index(pair, "=") + 1 - os.Unsetenv(pair[:i-1]) - } - } - return env -} -func resetEnviron(t *testing.T, items []string) { - for _, pair := range items { - if strings.HasPrefix(pair, "OS_") { - i := strings.Index(pair, "=") + 1 - if err := os.Setenv(pair[:i-1], pair[i:]); err != nil { - t.Errorf("Setenv(%q, %q) failed during reset: %v", pair[:i-1], pair[i:], err) - } - } - } -} diff --git a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_volumes.go b/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_volumes.go deleted file mode 100644 index 3c4dda06811..00000000000 --- a/staging/src/k8s.io/legacy-cloud-providers/openstack/openstack_volumes.go +++ /dev/null @@ -1,769 +0,0 @@ -//go:build !providerless -// +build !providerless - -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package openstack - -import ( - "context" - "errors" - "fmt" - "io/ioutil" - "path" - "path/filepath" - "strings" - "time" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" - "k8s.io/apimachinery/pkg/types" - cloudprovider "k8s.io/cloud-provider" - cloudvolume "k8s.io/cloud-provider/volume" - volerr "k8s.io/cloud-provider/volume/errors" - volumehelpers "k8s.io/cloud-provider/volume/helpers" - "k8s.io/component-base/metrics" - - "github.com/gophercloud/gophercloud" - 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" - "k8s.io/klog/v2" -) - -type volumeService interface { - createVolume(opts volumeCreateOpts) (string, string, error) - getVolume(volumeID string) (Volume, error) - deleteVolume(volumeName string) error - expandVolume(volumeID string, newSize int) error -} - -// VolumesV1 is a Volumes implementation for cinder v1 -type VolumesV1 struct { - blockstorage *gophercloud.ServiceClient - opts BlockStorageOpts -} - -// VolumesV2 is a Volumes implementation for cinder v2 -type VolumesV2 struct { - blockstorage *gophercloud.ServiceClient - opts BlockStorageOpts -} - -// VolumesV3 is a Volumes implementation for cinder v3 -type VolumesV3 struct { - blockstorage *gophercloud.ServiceClient - opts BlockStorageOpts -} - -// Volume stores information about a single volume -type Volume struct { - // ID of the instance, to which this volume is attached. "" if not attached - AttachedServerID string - // Device file path - AttachedDevice string - // availabilityZone is which availability zone the volume is in - AvailabilityZone string - // Unique identifier for the volume. - ID string - // Human-readable display name for the volume. - Name string - // Current status of the volume. - Status string - // Volume size in GB - Size int -} - -type volumeCreateOpts struct { - Size int - Availability string - Name string - VolumeType string - Metadata map[string]string -} - -// implements PVLabeler. -var _ cloudprovider.PVLabeler = (*OpenStack)(nil) - -const ( - volumeAvailableStatus = "available" - volumeInUseStatus = "in-use" - volumeDeletedStatus = "deleted" - volumeErrorStatus = "error" - - // On some environments, we need to query the metadata service in order - // to locate disks. We'll use the Newton version, which includes device - // metadata. - newtonMetadataVersion = "2016-06-30" -) - -func (volumes *VolumesV1) createVolume(opts volumeCreateOpts) (string, string, error) { - startTime := time.Now() - - createOpts := volumes_v1.CreateOpts{ - Name: opts.Name, - Size: opts.Size, - VolumeType: opts.VolumeType, - AvailabilityZone: opts.Availability, - Metadata: opts.Metadata, - } - - vol, err := volumes_v1.Create(volumes.blockstorage, createOpts).Extract() - timeTaken := time.Since(startTime).Seconds() - recordOpenstackOperationMetric("create_v1_volume", timeTaken, err) - if err != nil { - return "", "", err - } - return vol.ID, vol.AvailabilityZone, nil -} - -func (volumes *VolumesV2) createVolume(opts volumeCreateOpts) (string, string, error) { - startTime := time.Now() - - createOpts := volumes_v2.CreateOpts{ - Name: opts.Name, - Size: opts.Size, - VolumeType: opts.VolumeType, - AvailabilityZone: opts.Availability, - Metadata: opts.Metadata, - } - - vol, err := volumes_v2.Create(volumes.blockstorage, createOpts).Extract() - timeTaken := time.Since(startTime).Seconds() - recordOpenstackOperationMetric("create_v2_volume", timeTaken, err) - if err != nil { - return "", "", err - } - return vol.ID, vol.AvailabilityZone, nil -} - -func (volumes *VolumesV3) createVolume(opts volumeCreateOpts) (string, string, error) { - startTime := time.Now() - - createOpts := 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, createOpts).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() - timeTaken := time.Since(startTime).Seconds() - recordOpenstackOperationMetric("get_v1_volume", timeTaken, err) - if err != nil { - if isNotFound(err) { - return Volume{}, ErrNotFound - } - return Volume{}, fmt.Errorf("error occurred getting volume by ID: %s, err: %v", volumeID, err) - } - - volume := Volume{ - AvailabilityZone: volumeV1.AvailabilityZone, - ID: volumeV1.ID, - Name: volumeV1.Name, - Status: volumeV1.Status, - Size: volumeV1.Size, - } - - if len(volumeV1.Attachments) > 0 && volumeV1.Attachments[0]["server_id"] != nil { - volume.AttachedServerID = volumeV1.Attachments[0]["server_id"].(string) - volume.AttachedDevice = volumeV1.Attachments[0]["device"].(string) - } - - return volume, nil -} - -func (volumes *VolumesV2) getVolume(volumeID string) (Volume, error) { - startTime := time.Now() - volumeV2, err := volumes_v2.Get(volumes.blockstorage, volumeID).Extract() - timeTaken := time.Since(startTime).Seconds() - recordOpenstackOperationMetric("get_v2_volume", timeTaken, err) - if err != nil { - if isNotFound(err) { - return Volume{}, ErrNotFound - } - return Volume{}, fmt.Errorf("error occurred getting volume by ID: %s, err: %v", volumeID, err) - } - - volume := Volume{ - AvailabilityZone: volumeV2.AvailabilityZone, - ID: volumeV2.ID, - Name: volumeV2.Name, - Status: volumeV2.Status, - Size: volumeV2.Size, - } - - if len(volumeV2.Attachments) > 0 { - volume.AttachedServerID = volumeV2.Attachments[0].ServerID - volume.AttachedDevice = volumeV2.Attachments[0].Device - } - - 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 { - if isNotFound(err) { - return Volume{}, ErrNotFound - } - return Volume{}, fmt.Errorf("error occurred getting volume by ID: %s, err: %v", volumeID, err) - } - - volume := Volume{ - AvailabilityZone: volumeV3.AvailabilityZone, - ID: volumeV3.ID, - Name: volumeV3.Name, - Status: volumeV3.Status, - Size: volumeV3.Size, - } - - 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() - timeTaken := time.Since(startTime).Seconds() - recordOpenstackOperationMetric("delete_v1_volume", timeTaken, err) - return err -} - -func (volumes *VolumesV2) deleteVolume(volumeID string) error { - startTime := time.Now() - err := volumes_v2.Delete(volumes.blockstorage, volumeID, nil).ExtractErr() - timeTaken := time.Since(startTime).Seconds() - recordOpenstackOperationMetric("delete_v2_volume", timeTaken, err) - return err -} - -func (volumes *VolumesV3) deleteVolume(volumeID string) error { - startTime := time.Now() - err := volumes_v3.Delete(volumes.blockstorage, volumeID, nil).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() - createOpts := volumeexpand.ExtendSizeOpts{ - NewSize: newSize, - } - err := volumeexpand.ExtendSize(volumes.blockstorage, volumeID, createOpts).ExtractErr() - timeTaken := time.Since(startTime).Seconds() - recordOpenstackOperationMetric("expand_volume", timeTaken, err) - return err -} - -func (volumes *VolumesV2) expandVolume(volumeID string, newSize int) error { - startTime := time.Now() - createOpts := volumeexpand.ExtendSizeOpts{ - NewSize: newSize, - } - err := volumeexpand.ExtendSize(volumes.blockstorage, volumeID, createOpts).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() - createOpts := volumeexpand.ExtendSizeOpts{ - NewSize: newSize, - } - err := volumeexpand.ExtendSize(volumes.blockstorage, volumeID, createOpts).ExtractErr() - timeTaken := time.Since(startTime).Seconds() - recordOpenstackOperationMetric("expand_volume", timeTaken, err) - return err -} - -// OperationPending checks if there is an operation pending on a volume -func (os *OpenStack) OperationPending(diskName string) (bool, string, error) { - volume, err := os.getVolume(diskName) - if err != nil { - return false, "", err - } - volumeStatus := volume.Status - if volumeStatus == volumeErrorStatus { - err = fmt.Errorf("status of volume %s is %s", diskName, volumeStatus) - return false, volumeStatus, err - } - if volumeStatus == volumeAvailableStatus || volumeStatus == volumeInUseStatus || volumeStatus == volumeDeletedStatus { - return false, volume.Status, nil - } - return true, volumeStatus, nil -} - -// AttachDisk attaches given cinder volume to the compute running kubelet -func (os *OpenStack) AttachDisk(instanceID, volumeID string) (string, error) { - volume, err := os.getVolume(volumeID) - if err != nil { - return "", err - } - - cClient, err := os.NewComputeV2() - if err != nil { - return "", err - } - - if volume.AttachedServerID != "" { - if instanceID == volume.AttachedServerID { - klog.V(4).Infof("Disk %s is already attached to instance %s", volumeID, instanceID) - return volume.ID, nil - } - nodeName, err := os.GetNodeNameByID(volume.AttachedServerID) - attachErr := fmt.Sprintf("disk %s path %s is attached to a different instance (%s)", volumeID, volume.AttachedDevice, volume.AttachedServerID) - if err != nil { - klog.Error(attachErr) - return "", errors.New(attachErr) - } - // using volume.AttachedDevice may cause problems because cinder does not report device path correctly see issue #33128 - devicePath := volume.AttachedDevice - danglingErr := volerr.NewDanglingError(attachErr, nodeName, devicePath) - klog.V(2).Infof("Found dangling volume %s attached to node %s", volumeID, nodeName) - return "", danglingErr - } - - startTime := time.Now() - // add read only flag here if possible spothanis - _, err = volumeattach.Create(cClient, instanceID, &volumeattach.CreateOpts{ - VolumeID: volume.ID, - }).Extract() - timeTaken := time.Since(startTime).Seconds() - recordOpenstackOperationMetric("attach_disk", timeTaken, err) - if err != nil { - return "", fmt.Errorf("failed to attach %s volume to %s compute: %v", volumeID, instanceID, err) - } - klog.V(2).Infof("Successfully attached %s volume to %s compute", volumeID, instanceID) - return volume.ID, nil -} - -// DetachDisk detaches given cinder volume from the compute running kubelet -func (os *OpenStack) DetachDisk(instanceID, volumeID string) error { - volume, err := os.getVolume(volumeID) - if err != nil { - return err - } - if volume.Status == volumeAvailableStatus { - // "available" is fine since that means the volume is detached from instance already. - klog.V(2).Infof("volume: %s has been detached from compute: %s ", volume.ID, instanceID) - return nil - } - - if volume.Status != volumeInUseStatus { - return fmt.Errorf("can not detach volume %s, its status is %s", volume.Name, volume.Status) - } - cClient, err := os.NewComputeV2() - if err != nil { - return err - } - if volume.AttachedServerID != instanceID { - return fmt.Errorf("disk: %s has no attachments or is not attached to compute: %s", volume.Name, instanceID) - } - - startTime := time.Now() - // This is a blocking call and effects kubelet's performance directly. - // We should consider kicking it out into a separate routine, if it is bad. - err = volumeattach.Delete(cClient, instanceID, volume.ID).ExtractErr() - timeTaken := time.Since(startTime).Seconds() - recordOpenstackOperationMetric("detach_disk", timeTaken, err) - if err != nil { - return fmt.Errorf("failed to delete volume %s from compute %s attached %v", volume.ID, instanceID, err) - } - klog.V(2).Infof("Successfully detached volume: %s from compute: %s", volume.ID, instanceID) - - return nil -} - -// ExpandVolume expands the size of specific cinder volume (in GiB) -func (os *OpenStack) ExpandVolume(volumeID string, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) { - volume, err := os.getVolume(volumeID) - if err != nil { - return oldSize, err - } - if volume.Status != volumeAvailableStatus { - // cinder volume can not be expanded if its status is not available - if volume.Status == volumeInUseStatus { - // Send a nice event when the volume is used - return oldSize, fmt.Errorf("PVC used by a Pod can not be expanded, please ensure the PVC is not used by any Pod and is fully detached from a node") - } - // Send not so nice event when the volume is in any other state (deleted, error) - return oldSize, fmt.Errorf("volume in state %q can not be expanded, it must be \"available\"", volume.Status) - } - - // Cinder works with gigabytes, convert to GiB with rounding up - volSizeGiB, err := volumehelpers.RoundUpToGiBInt(newSize) - if err != nil { - return oldSize, err - } - newSizeQuant := resource.MustParse(fmt.Sprintf("%dGi", volSizeGiB)) - - // if volume size equals to or greater than the newSize, return nil - if volume.Size >= volSizeGiB { - return newSizeQuant, nil - } - - volumes, err := os.volumeService("") - if err != nil { - return oldSize, err - } - - err = volumes.expandVolume(volumeID, volSizeGiB) - if err != nil { - return oldSize, err - } - return newSizeQuant, nil -} - -// getVolume retrieves Volume by its ID. -func (os *OpenStack) getVolume(volumeID string) (Volume, error) { - volumes, err := os.volumeService("") - if err != nil { - return Volume{}, fmt.Errorf("unable to initialize cinder client for region: %s, err: %v", os.region, err) - } - return volumes.getVolume(volumeID) -} - -// CreateVolume creates a volume of given size (in GiB) -func (os *OpenStack) CreateVolume(name string, size int, vtype, availability string, tags *map[string]string) (string, string, string, bool, error) { - volumes, err := os.volumeService("") - if err != nil { - return "", "", "", os.bsOpts.IgnoreVolumeAZ, fmt.Errorf("unable to initialize cinder client for region: %s, err: %v", os.region, err) - } - - opts := volumeCreateOpts{ - Name: name, - Size: size, - VolumeType: vtype, - Availability: availability, - } - if tags != nil { - opts.Metadata = *tags - } - - volumeID, volumeAZ, err := volumes.createVolume(opts) - - if err != nil { - return "", "", "", os.bsOpts.IgnoreVolumeAZ, fmt.Errorf("failed to create a %d GB volume: %v", size, err) - } - - klog.Infof("Created volume %v in Availability Zone: %v Region: %v Ignore volume AZ: %v", volumeID, volumeAZ, os.region, os.bsOpts.IgnoreVolumeAZ) - return volumeID, volumeAZ, os.region, os.bsOpts.IgnoreVolumeAZ, nil -} - -// GetDevicePathBySerialID returns the path of an attached block storage volume, specified by its id. -func (os *OpenStack) GetDevicePathBySerialID(volumeID string) string { - // Build a list of candidate device paths. - // Certain Nova drivers will set the disk serial ID, including the Cinder volume id. - // Newer OpenStacks may not truncate the volumeID to 20 chars. - candidateDeviceNodes := []string{ - // KVM - fmt.Sprintf("virtio-%s", volumeID[:20]), - fmt.Sprintf("virtio-%s", volumeID), - // KVM virtio-scsi - fmt.Sprintf("scsi-0QEMU_QEMU_HARDDISK_%s", volumeID[:20]), - fmt.Sprintf("scsi-0QEMU_QEMU_HARDDISK_%s", volumeID), - // ESXi - fmt.Sprintf("wwn-0x%s", strings.Replace(volumeID, "-", "", -1)), - } - - files, _ := ioutil.ReadDir("/dev/disk/by-id/") - - for _, f := range files { - for _, c := range candidateDeviceNodes { - if c == f.Name() { - klog.V(4).Infof("Found disk attached as %q; full devicepath: %s\n", f.Name(), path.Join("/dev/disk/by-id/", f.Name())) - return path.Join("/dev/disk/by-id/", f.Name()) - } - } - } - - klog.V(4).Infof("Failed to find device for the volumeID: %q by serial ID", volumeID) - return "" -} - -func (os *OpenStack) getDevicePathFromInstanceMetadata(volumeID string) string { - // Nova Hyper-V hosts cannot override disk SCSI IDs. In order to locate - // volumes, we're querying the metadata service. Note that the Hyper-V - // driver will include device metadata for untagged volumes as well. - // - // We're avoiding using cached metadata (or the configdrive), - // relying on the metadata service. - instanceMetadata, err := getMetadataFromMetadataService( - newtonMetadataVersion) - - if err != nil { - klog.V(4).Infof( - "Could not retrieve instance metadata. Error: %v", err) - return "" - } - - for _, device := range instanceMetadata.Devices { - if device.Type == "disk" && device.Serial == volumeID { - klog.V(4).Infof( - "Found disk metadata for volumeID %q. Bus: %q, Address: %q", - volumeID, device.Bus, device.Address) - - diskPattern := fmt.Sprintf( - "/dev/disk/by-path/*-%s-%s", - device.Bus, device.Address) - diskPaths, err := filepath.Glob(diskPattern) - if err != nil { - klog.Errorf( - "could not retrieve disk path for volumeID: %q. Error filepath.Glob(%q): %v", - volumeID, diskPattern, err) - return "" - } - - if len(diskPaths) == 1 { - return diskPaths[0] - } - - klog.Errorf( - "expecting to find one disk path for volumeID %q, found %d: %v", - volumeID, len(diskPaths), diskPaths) - return "" - } - } - - klog.V(4).Infof( - "Could not retrieve device metadata for volumeID: %q", volumeID) - return "" -} - -// GetDevicePath returns the path of an attached block storage volume, specified by its id. -func (os *OpenStack) GetDevicePath(volumeID string) string { - devicePath := os.GetDevicePathBySerialID(volumeID) - - if devicePath == "" { - devicePath = os.getDevicePathFromInstanceMetadata(volumeID) - } - - if devicePath == "" { - klog.Warningf("Failed to find device for the volumeID: %q", volumeID) - } - - return devicePath -} - -// DeleteVolume deletes a volume given volume name. -func (os *OpenStack) DeleteVolume(volumeID string) error { - used, err := os.diskIsUsed(volumeID) - if err != nil { - return err - } - if used { - msg := fmt.Sprintf("Cannot delete the volume %q, it's still attached to a node", volumeID) - return volerr.NewDeletedVolumeInUseError(msg) - } - - volumes, err := os.volumeService("") - if err != nil { - return fmt.Errorf("unable to initialize cinder client for region: %s, err: %v", os.region, err) - } - - err = volumes.deleteVolume(volumeID) - return err - -} - -// GetAttachmentDiskPath gets device path of attached volume to the compute running kubelet, as known by cinder -func (os *OpenStack) GetAttachmentDiskPath(instanceID, volumeID string) (string, error) { - // See issue #33128 - Cinder does not always tell you the right device path, as such - // we must only use this value as a last resort. - volume, err := os.getVolume(volumeID) - if err != nil { - return "", err - } - if volume.Status != volumeInUseStatus { - return "", fmt.Errorf("can not get device path of volume %s, its status is %s ", volume.Name, volume.Status) - } - if volume.AttachedServerID != "" { - if instanceID == volume.AttachedServerID { - // Attachment[0]["device"] points to the device path - // see http://developer.openstack.org/api-ref-blockstorage-v1.html - return volume.AttachedDevice, nil - } - return "", fmt.Errorf("disk %q is attached to a different compute: %q, should be detached before proceeding", volumeID, volume.AttachedServerID) - } - return "", fmt.Errorf("volume %s has no ServerId", volumeID) -} - -// DiskIsAttached queries if a volume is attached to a compute instance -func (os *OpenStack) DiskIsAttached(instanceID, volumeID string) (bool, error) { - if instanceID == "" { - klog.Warningf("calling DiskIsAttached with empty instanceid: %s %s", instanceID, volumeID) - } - volume, err := os.getVolume(volumeID) - if err != nil { - if err == ErrNotFound { - // Volume does not exists, it can't be attached. - return false, nil - } - return false, err - } - - return instanceID == volume.AttachedServerID, nil -} - -// DiskIsAttachedByName queries if a volume is attached to a compute instance by name -func (os *OpenStack) DiskIsAttachedByName(nodeName types.NodeName, volumeID string) (bool, string, error) { - cClient, err := os.NewComputeV2() - if err != nil { - return false, "", err - } - srv, err := getServerByName(cClient, nodeName) - if err != nil { - if err == ErrNotFound { - // instance not found anymore in cloudprovider, assume that cinder is detached - return false, "", nil - } - return false, "", err - } - instanceID := "/" + srv.ID - if ind := strings.LastIndex(instanceID, "/"); ind >= 0 { - instanceID = instanceID[(ind + 1):] - } - attached, err := os.DiskIsAttached(instanceID, volumeID) - return attached, instanceID, err -} - -// DisksAreAttached queries if a list of volumes are attached to a compute instance -func (os *OpenStack) DisksAreAttached(instanceID string, volumeIDs []string) (map[string]bool, error) { - attached := make(map[string]bool) - for _, volumeID := range volumeIDs { - isAttached, err := os.DiskIsAttached(instanceID, volumeID) - if err != nil && err != ErrNotFound { - attached[volumeID] = true - continue - } - attached[volumeID] = isAttached - } - return attached, nil -} - -// DisksAreAttachedByName queries if a list of volumes are attached to a compute instance by name -func (os *OpenStack) DisksAreAttachedByName(nodeName types.NodeName, volumeIDs []string) (map[string]bool, error) { - attached := make(map[string]bool) - cClient, err := os.NewComputeV2() - if err != nil { - return attached, err - } - srv, err := getServerByName(cClient, nodeName) - if err != nil { - if err == ErrNotFound { - // instance not found anymore, mark all volumes as detached - for _, volumeID := range volumeIDs { - attached[volumeID] = false - } - return attached, nil - } - return attached, err - } - instanceID := "/" + srv.ID - if ind := strings.LastIndex(instanceID, "/"); ind >= 0 { - instanceID = instanceID[(ind + 1):] - } - return os.DisksAreAttached(instanceID, volumeIDs) -} - -// diskIsUsed returns true a disk is attached to any node. -func (os *OpenStack) diskIsUsed(volumeID string) (bool, error) { - volume, err := os.getVolume(volumeID) - if err != nil { - return false, err - } - return volume.AttachedServerID != "", nil -} - -// ShouldTrustDevicePath queries if we should trust the cinder provide deviceName, See issue #33128 -func (os *OpenStack) ShouldTrustDevicePath() bool { - return os.bsOpts.TrustDevicePath -} - -// NodeVolumeAttachLimit specifies number of cinder volumes that can be attached to this node. -func (os *OpenStack) NodeVolumeAttachLimit() int { - return os.bsOpts.NodeVolumeAttachLimit -} - -// GetLabelsForVolume implements PVLabeler.GetLabelsForVolume -func (os *OpenStack) GetLabelsForVolume(ctx context.Context, pv *v1.PersistentVolume) (map[string]string, error) { - // Ignore if not Cinder. - if pv.Spec.Cinder == nil { - return nil, nil - } - - // Ignore any volumes that are being provisioned - if pv.Spec.Cinder.VolumeID == cloudvolume.ProvisionedVolumeName { - return nil, nil - } - - // if volume az is to be ignored we should return nil from here - if os.bsOpts.IgnoreVolumeAZ { - return nil, nil - } - - // Get Volume - volume, err := os.getVolume(pv.Spec.Cinder.VolumeID) - if err != nil { - return nil, err - } - - // Construct Volume Labels - labels := make(map[string]string) - if volume.AvailabilityZone != "" { - labels[v1.LabelTopologyZone] = volume.AvailabilityZone - } - if os.region != "" { - labels[v1.LabelTopologyRegion] = os.region - } - klog.V(4).Infof("The Volume %s has labels %v", pv.Spec.Cinder.VolumeID, labels) - - return labels, nil -} - -// recordOpenstackOperationMetric records openstack operation metrics -func recordOpenstackOperationMetric(operation string, timeTaken float64, err error) { - if err != nil { - openstackAPIRequestErrors.With(metrics.Labels{"request": operation}).Inc() - } else { - openstackOperationsLatency.With(metrics.Labels{"request": operation}).Observe(timeTaken) - } -} diff --git a/staging/src/k8s.io/pod-security-admission/policy/check_restrictedVolumes.go b/staging/src/k8s.io/pod-security-admission/policy/check_restrictedVolumes.go index e171cdd60f1..f33cf4c7b69 100644 --- a/staging/src/k8s.io/pod-security-admission/policy/check_restrictedVolumes.go +++ b/staging/src/k8s.io/pod-security-admission/policy/check_restrictedVolumes.go @@ -122,8 +122,6 @@ func restrictedVolumes_1_0(podMetadata *metav1.ObjectMeta, podSpec *corev1.PodSp badVolumeTypes.Insert("rbd") case volume.FlexVolume != nil: badVolumeTypes.Insert("flexVolume") - case volume.Cinder != nil: - badVolumeTypes.Insert("cinder") case volume.CephFS != nil: badVolumeTypes.Insert("cephfs") case volume.Flocker != nil: diff --git a/staging/src/k8s.io/pod-security-admission/policy/check_restrictedVolumes_test.go b/staging/src/k8s.io/pod-security-admission/policy/check_restrictedVolumes_test.go index 45b08235bdb..b7fdda4338f 100644 --- a/staging/src/k8s.io/pod-security-admission/policy/check_restrictedVolumes_test.go +++ b/staging/src/k8s.io/pod-security-admission/policy/check_restrictedVolumes_test.go @@ -53,7 +53,6 @@ func TestRestrictedVolumes(t *testing.T) { {Name: "b7", VolumeSource: corev1.VolumeSource{Glusterfs: &corev1.GlusterfsVolumeSource{}}}, {Name: "b8", VolumeSource: corev1.VolumeSource{RBD: &corev1.RBDVolumeSource{}}}, {Name: "b9", VolumeSource: corev1.VolumeSource{FlexVolume: &corev1.FlexVolumeSource{}}}, - {Name: "b10", VolumeSource: corev1.VolumeSource{Cinder: &corev1.CinderVolumeSource{}}}, {Name: "b11", VolumeSource: corev1.VolumeSource{CephFS: &corev1.CephFSVolumeSource{}}}, {Name: "b12", VolumeSource: corev1.VolumeSource{Flocker: &corev1.FlockerVolumeSource{}}}, {Name: "b13", VolumeSource: corev1.VolumeSource{FC: &corev1.FCVolumeSource{}}}, @@ -72,9 +71,9 @@ func TestRestrictedVolumes(t *testing.T) { }}, expectReason: `restricted volume types`, expectDetail: `volumes ` + - `"b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "b10", "b11", "b12", "b13", "b14", "b15", "b16", "b17", "b18", "b19", "b20", "b21", "c1"` + + `"b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "b11", "b12", "b13", "b14", "b15", "b16", "b17", "b18", "b19", "b20", "b21", "c1"` + ` use restricted volume types ` + - `"awsElasticBlockStore", "azureDisk", "azureFile", "cephfs", "cinder", "fc", "flexVolume", "flocker", "gcePersistentDisk", "gitRepo", "glusterfs", ` + + `"awsElasticBlockStore", "azureDisk", "azureFile", "cephfs", "fc", "flexVolume", "flocker", "gcePersistentDisk", "gitRepo", "glusterfs", ` + `"hostPath", "iscsi", "nfs", "photonPersistentDisk", "portworxVolume", "quobyte", "rbd", "scaleIO", "storageos", "unknown", "vsphereVolume"`, }, } diff --git a/test/e2e/common/storage/volumes.go b/test/e2e/common/storage/volumes.go index 2420b3b90e6..1833be74e1a 100644 --- a/test/e2e/common/storage/volumes.go +++ b/test/e2e/common/storage/volumes.go @@ -31,8 +31,8 @@ limitations under the License. * Note that the server containers are for testing purposes only and should not * be used in production. * - * 2) With server outside of Kubernetes (Cinder, ...) - * Appropriate server (e.g. OpenStack Cinder) must exist somewhere outside + * 2) With server outside of Kubernetes + * Appropriate server exist somewhere outside * the tested Kubernetes cluster. The test itself creates a new volume, * and checks, that Kubernetes can use it as a volume. */ diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index b9df43a52d9..ad2ba30ce11 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -56,7 +56,6 @@ import ( _ "k8s.io/kubernetes/test/e2e/framework/providers/azure" _ "k8s.io/kubernetes/test/e2e/framework/providers/gce" _ "k8s.io/kubernetes/test/e2e/framework/providers/kubemark" - _ "k8s.io/kubernetes/test/e2e/framework/providers/openstack" _ "k8s.io/kubernetes/test/e2e/framework/providers/vsphere" // Ensure that logging flags are part of the command line. diff --git a/test/e2e/framework/providers/openstack/openstack.go b/test/e2e/framework/providers/openstack/openstack.go deleted file mode 100644 index 784c2f709f6..00000000000 --- a/test/e2e/framework/providers/openstack/openstack.go +++ /dev/null @@ -1,34 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors. - -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. -*/ - -package openstack - -import ( - "k8s.io/kubernetes/test/e2e/framework" -) - -func init() { - framework.RegisterProvider("openstack", newProvider) -} - -func newProvider() (framework.ProviderInterface, error) { - return &Provider{}, nil -} - -// Provider is a structure to handle OpenStack clouds for e2e testing -type Provider struct { - framework.NullProvider -} diff --git a/test/e2e/framework/test_context.go b/test/e2e/framework/test_context.go index 6d8e1c7e12e..9399395f2b6 100644 --- a/test/e2e/framework/test_context.go +++ b/test/e2e/framework/test_context.go @@ -256,7 +256,7 @@ type CloudConfig struct { ClusterIPRange string ClusterTag string Network string - ConfigFile string // for azure and openstack + ConfigFile string // for azure NodeTag string MasterTag string diff --git a/test/e2e/framework/volume/fixtures.go b/test/e2e/framework/volume/fixtures.go index ff1a7bebda7..7278de48f3a 100644 --- a/test/e2e/framework/volume/fixtures.go +++ b/test/e2e/framework/volume/fixtures.go @@ -31,8 +31,8 @@ limitations under the License. * Note that the server containers are for testing purposes only and should not * be used in production. * - * 2) With server outside of Kubernetes (Cinder, ...) - * Appropriate server (e.g. OpenStack Cinder) must exist somewhere outside + * 2) With server outside of Kubernetes + * Appropriate server must exist somewhere outside * the tested Kubernetes cluster. The test itself creates a new volume, * and checks, that Kubernetes can use it as a volume. */ diff --git a/test/e2e/storage/drivers/csi.go b/test/e2e/storage/drivers/csi.go index 51f8d3e0299..61566c0bd32 100644 --- a/test/e2e/storage/drivers/csi.go +++ b/test/e2e/storage/drivers/csi.go @@ -27,7 +27,7 @@ limitations under the License. * Note that the server containers are for testing purposes only and should not * be used in production. * - * 2) With server or cloud provider outside of Kubernetes (Cinder, GCE, AWS, Azure, ...) + * 2) With server or cloud provider outside of Kubernetes (GCE, AWS, Azure, ...) * Appropriate server or cloud provider must exist somewhere outside * the tested Kubernetes cluster. CreateVolume will create a new volume to be * used in the TestSuites for inlineVolume or DynamicPV tests. diff --git a/test/e2e/storage/drivers/in_tree.go b/test/e2e/storage/drivers/in_tree.go index 76c5cda123d..0733197e5dd 100644 --- a/test/e2e/storage/drivers/in_tree.go +++ b/test/e2e/storage/drivers/in_tree.go @@ -27,7 +27,7 @@ limitations under the License. * Note that the server containers are for testing purposes only and should not * be used in production. * - * 2) With server or cloud provider outside of Kubernetes (Cinder, GCE, AWS, Azure, ...) + * 2) With server or cloud provider outside of Kubernetes (GCE, AWS, Azure, ...) * Appropriate server or cloud provider must exist somewhere outside * the tested Kubernetes cluster. CreateVolume will create a new volume to be * used in the TestSuites for inlineVolume or DynamicPV tests. @@ -38,7 +38,6 @@ package drivers import ( "context" "fmt" - "os/exec" "strconv" "strings" "time" @@ -1036,179 +1035,6 @@ func (e *emptydirDriver) PrepareTest(f *framework.Framework) (*storageframework. }, func() {} } -// Cinder -// This driver assumes that OpenStack client tools are installed -// (/usr/bin/nova, /usr/bin/cinder and /usr/bin/keystone) -// and that the usual OpenStack authentication env. variables are set -// (OS_USERNAME, OS_PASSWORD, OS_TENANT_NAME at least). -type cinderDriver struct { - driverInfo storageframework.DriverInfo -} - -type cinderVolume struct { - volumeName string - volumeID string -} - -var _ storageframework.TestDriver = &cinderDriver{} -var _ storageframework.PreprovisionedVolumeTestDriver = &cinderDriver{} -var _ storageframework.InlineVolumeTestDriver = &cinderDriver{} -var _ storageframework.PreprovisionedPVTestDriver = &cinderDriver{} -var _ storageframework.DynamicPVTestDriver = &cinderDriver{} - -// InitCinderDriver returns cinderDriver that implements TestDriver interface -func InitCinderDriver() storageframework.TestDriver { - return &cinderDriver{ - driverInfo: storageframework.DriverInfo{ - Name: "cinder", - InTreePluginName: "kubernetes.io/cinder", - MaxFileSize: storageframework.FileSizeMedium, - SupportedSizeRange: e2evolume.SizeRange{ - Min: "1Gi", - }, - SupportedFsType: sets.NewString( - "", // Default fsType - ), - TopologyKeys: []string{v1.LabelFailureDomainBetaZone}, - Capabilities: map[storageframework.Capability]bool{ - storageframework.CapPersistence: true, - storageframework.CapFsGroup: true, - storageframework.CapExec: true, - storageframework.CapBlock: true, - // Cinder supports volume limits, but the test creates large - // number of volumes and times out test suites. - storageframework.CapVolumeLimits: false, - storageframework.CapTopology: true, - }, - }, - } -} - -func (c *cinderDriver) GetDriverInfo() *storageframework.DriverInfo { - return &c.driverInfo -} - -func (c *cinderDriver) SkipUnsupportedTest(pattern storageframework.TestPattern) { - e2eskipper.SkipUnlessProviderIs("openstack") -} - -func (c *cinderDriver) GetVolumeSource(readOnly bool, fsType string, e2evolume storageframework.TestVolume) *v1.VolumeSource { - cv, ok := e2evolume.(*cinderVolume) - framework.ExpectEqual(ok, true, "Failed to cast test volume to Cinder test volume") - - volSource := v1.VolumeSource{ - Cinder: &v1.CinderVolumeSource{ - VolumeID: cv.volumeID, - ReadOnly: readOnly, - }, - } - if fsType != "" { - volSource.Cinder.FSType = fsType - } - return &volSource -} - -func (c *cinderDriver) GetPersistentVolumeSource(readOnly bool, fsType string, e2evolume storageframework.TestVolume) (*v1.PersistentVolumeSource, *v1.VolumeNodeAffinity) { - cv, ok := e2evolume.(*cinderVolume) - framework.ExpectEqual(ok, true, "Failed to cast test volume to Cinder test volume") - - pvSource := v1.PersistentVolumeSource{ - Cinder: &v1.CinderPersistentVolumeSource{ - VolumeID: cv.volumeID, - ReadOnly: readOnly, - }, - } - if fsType != "" { - pvSource.Cinder.FSType = fsType - } - return &pvSource, nil -} - -func (c *cinderDriver) GetDynamicProvisionStorageClass(config *storageframework.PerTestConfig, fsType string) *storagev1.StorageClass { - provisioner := "kubernetes.io/cinder" - parameters := map[string]string{} - if fsType != "" { - parameters["fsType"] = fsType - } - ns := config.Framework.Namespace.Name - - return storageframework.GetStorageClass(provisioner, parameters, nil, ns) -} - -func (c *cinderDriver) PrepareTest(f *framework.Framework) (*storageframework.PerTestConfig, func()) { - return &storageframework.PerTestConfig{ - Driver: c, - Prefix: "cinder", - Framework: f, - }, func() {} -} - -func (c *cinderDriver) CreateVolume(config *storageframework.PerTestConfig, volType storageframework.TestVolType) storageframework.TestVolume { - f := config.Framework - ns := f.Namespace - - // We assume that namespace.Name is a random string - volumeName := ns.Name - ginkgo.By("creating a test Cinder volume") - output, err := exec.Command("cinder", "create", "--display-name="+volumeName, "1").CombinedOutput() - outputString := string(output[:]) - framework.Logf("cinder output:\n%s", outputString) - framework.ExpectNoError(err) - - // Parse 'id'' from stdout. Expected format: - // | attachments | [] | - // | availability_zone | nova | - // ... - // | id | 1d6ff08f-5d1c-41a4-ad72-4ef872cae685 | - volumeID := "" - for _, line := range strings.Split(outputString, "\n") { - fields := strings.Fields(line) - if len(fields) != 5 { - continue - } - if fields[1] != "id" { - continue - } - volumeID = fields[3] - break - } - framework.Logf("Volume ID: %s", volumeID) - framework.ExpectNotEqual(volumeID, "") - return &cinderVolume{ - volumeName: volumeName, - volumeID: volumeID, - } -} - -func (v *cinderVolume) DeleteVolume() { - id := v.volumeID - name := v.volumeName - - // Try to delete the volume for several seconds - it takes - // a while for the plugin to detach it. - var output []byte - var err error - timeout := time.Second * 120 - - framework.Logf("Waiting up to %v for removal of cinder volume %s / %s", timeout, id, name) - for start := time.Now(); time.Since(start) < timeout; time.Sleep(5 * time.Second) { - output, err = exec.Command("cinder", "delete", id).CombinedOutput() - if err == nil { - framework.Logf("Cinder volume %s deleted", id) - return - } - framework.Logf("Failed to delete volume %s / %s: %v\n%s", id, name, err, string(output)) - } - // Timed out, try to get "cinder show " output for easier debugging - showOutput, showErr := exec.Command("cinder", "show", id).CombinedOutput() - if showErr != nil { - framework.Logf("Failed to show volume %s / %s: %v\n%s", id, name, showErr, string(showOutput)) - } else { - framework.Logf("Volume %s / %s:\n%s", id, name, string(showOutput)) - } - framework.Failf("Failed to delete pre-provisioned volume %s / %s: %v\n%s", id, name, err, string(output[:])) -} - // GCE type gcePdDriver struct { driverInfo storageframework.DriverInfo diff --git a/test/e2e/storage/in_tree_volumes.go b/test/e2e/storage/in_tree_volumes.go index 5526e586b4f..1118f4114c8 100644 --- a/test/e2e/storage/in_tree_volumes.go +++ b/test/e2e/storage/in_tree_volumes.go @@ -37,7 +37,6 @@ var testDrivers = []func() storageframework.TestDriver{ drivers.InitHostPathDriver, drivers.InitHostPathSymlinkDriver, drivers.InitEmptydirDriver, - drivers.InitCinderDriver, drivers.InitVSphereDriver, drivers.InitAzureDiskDriver, drivers.InitAzureFileDriver, diff --git a/test/e2e/storage/testsuites/volumelimits.go b/test/e2e/storage/testsuites/volumelimits.go index 4860144cc8e..b73d63f54fc 100644 --- a/test/e2e/storage/testsuites/volumelimits.go +++ b/test/e2e/storage/testsuites/volumelimits.go @@ -374,8 +374,6 @@ func getInTreeNodeLimits(cs clientset.Interface, nodeName string, driverInfo *st allocatableKey = volumeutil.EBSVolumeLimitKey case migrationplugins.GCEPDInTreePluginName: allocatableKey = volumeutil.GCEVolumeLimitKey - case migrationplugins.CinderInTreePluginName: - allocatableKey = volumeutil.CinderVolumeLimitKey case migrationplugins.AzureDiskInTreePluginName: allocatableKey = volumeutil.AzureVolumeLimitKey default: diff --git a/test/e2e/storage/volume_provisioning.go b/test/e2e/storage/volume_provisioning.go index e8f778867ba..17a00a89c93 100644 --- a/test/e2e/storage/volume_provisioning.go +++ b/test/e2e/storage/volume_provisioning.go @@ -286,34 +286,6 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { framework.ExpectNoError(err, "checkAWSEBS gp2 encrypted") }, }, - // OpenStack generic tests (works on all OpenStack deployments) - { - Name: "generic Cinder volume on OpenStack", - CloudProviders: []string{"openstack"}, - Timeouts: f.Timeouts, - Provisioner: "kubernetes.io/cinder", - Parameters: map[string]string{}, - ClaimSize: "1.5Gi", - ExpectedSize: "2Gi", - PvCheck: func(claim *v1.PersistentVolumeClaim) { - testsuites.PVWriteReadSingleNodeCheck(c, f.Timeouts, claim, e2epod.NodeSelection{}) - }, - }, - { - Name: "Cinder volume with empty volume type and zone on OpenStack", - CloudProviders: []string{"openstack"}, - Timeouts: f.Timeouts, - Provisioner: "kubernetes.io/cinder", - Parameters: map[string]string{ - "type": "", - "availability": "", - }, - ClaimSize: "1.5Gi", - ExpectedSize: "2Gi", - PvCheck: func(claim *v1.PersistentVolumeClaim) { - testsuites.PVWriteReadSingleNodeCheck(c, f.Timeouts, claim, e2epod.NodeSelection{}) - }, - }, // vSphere generic test { Name: "generic vSphere volume", @@ -429,7 +401,7 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { // not being deleted. // NOTE: Polls until no PVs are detected, times out at 5 minutes. - e2eskipper.SkipUnlessProviderIs("openstack", "gce", "aws", "gke", "vsphere", "azure") + e2eskipper.SkipUnlessProviderIs("gce", "aws", "gke", "vsphere", "azure") const raceAttempts int = 100 var residualPVs []*v1.PersistentVolume @@ -605,7 +577,7 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { ginkgo.Describe("DynamicProvisioner Default", func() { ginkgo.It("should create and delete default persistent volumes [Slow]", func() { - e2eskipper.SkipUnlessProviderIs("openstack", "gce", "aws", "gke", "vsphere", "azure") + e2eskipper.SkipUnlessProviderIs("gce", "aws", "gke", "vsphere", "azure") e2epv.SkipIfNoDefaultStorageClass(c) ginkgo.By("creating a claim with no annotation") @@ -631,7 +603,7 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { // Modifying the default storage class can be disruptive to other tests that depend on it ginkgo.It("should be disabled by changing the default annotation [Serial] [Disruptive]", func() { - e2eskipper.SkipUnlessProviderIs("openstack", "gce", "aws", "gke", "vsphere", "azure") + e2eskipper.SkipUnlessProviderIs("gce", "aws", "gke", "vsphere", "azure") e2epv.SkipIfNoDefaultStorageClass(c) scName, scErr := e2epv.GetDefaultStorageClassName(c) @@ -670,7 +642,7 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() { // Modifying the default storage class can be disruptive to other tests that depend on it ginkgo.It("should be disabled by removing the default annotation [Serial] [Disruptive]", func() { - e2eskipper.SkipUnlessProviderIs("openstack", "gce", "aws", "gke", "vsphere", "azure") + e2eskipper.SkipUnlessProviderIs("gce", "aws", "gke", "vsphere", "azure") e2epv.SkipIfNoDefaultStorageClass(c) scName, scErr := e2epv.GetDefaultStorageClassName(c) @@ -844,8 +816,6 @@ func getDefaultPluginName() string { return "kubernetes.io/gce-pd" case framework.ProviderIs("aws"): return "kubernetes.io/aws-ebs" - case framework.ProviderIs("openstack"): - return "kubernetes.io/cinder" case framework.ProviderIs("vsphere"): return "kubernetes.io/vsphere-volume" case framework.ProviderIs("azure"): diff --git a/test/e2e/upgrades/storage/persistent_volumes.go b/test/e2e/upgrades/storage/persistent_volumes.go index c292b59008b..3fe87029bc4 100644 --- a/test/e2e/upgrades/storage/persistent_volumes.go +++ b/test/e2e/upgrades/storage/persistent_volumes.go @@ -47,7 +47,7 @@ const ( func (t *PersistentVolumeUpgradeTest) Setup(f *framework.Framework) { var err error - e2eskipper.SkipUnlessProviderIs("gce", "gke", "openstack", "aws", "vsphere", "azure") + e2eskipper.SkipUnlessProviderIs("gce", "gke", "aws", "vsphere", "azure") ns := f.Namespace.Name diff --git a/test/e2e/upgrades/storage/volume_mode.go b/test/e2e/upgrades/storage/volume_mode.go index 4cde7f6f0a3..52a068cb308 100644 --- a/test/e2e/upgrades/storage/volume_mode.go +++ b/test/e2e/upgrades/storage/volume_mode.go @@ -52,7 +52,7 @@ func (VolumeModeDowngradeTest) Name() string { // Skip returns true when this test can be skipped. func (t *VolumeModeDowngradeTest) Skip(upgCtx upgrades.UpgradeContext) bool { - if !framework.ProviderIs("openstack", "gce", "aws", "gke", "vsphere", "azure") { + if !framework.ProviderIs("gce", "aws", "gke", "vsphere", "azure") { return true } diff --git a/vendor/github.com/gophercloud/gophercloud/.gitignore b/vendor/github.com/gophercloud/gophercloud/.gitignore deleted file mode 100644 index dd91ed20559..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -**/*.swp -.idea -.vscode diff --git a/vendor/github.com/gophercloud/gophercloud/.travis.yml b/vendor/github.com/gophercloud/gophercloud/.travis.yml deleted file mode 100644 index 9153a00fc55..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -language: go -sudo: false -install: -- GO111MODULE=off go get golang.org/x/crypto/ssh -- GO111MODULE=off go get -v -tags 'fixtures acceptance' ./... -- GO111MODULE=off go get github.com/wadey/gocovmerge -- GO111MODULE=off go get github.com/mattn/goveralls -- GO111MODULE=off go get golang.org/x/tools/cmd/goimports -go: -- "1.10" -- "1.11" -- "1.12" -- "tip" -env: - global: - - secure: "xSQsAG5wlL9emjbCdxzz/hYQsSpJ/bABO1kkbwMSISVcJ3Nk0u4ywF+LS4bgeOnwPfmFvNTOqVDu3RwEvMeWXSI76t1piCPcObutb2faKLVD/hLoAS76gYX+Z8yGWGHrSB7Do5vTPj1ERe2UljdrnsSeOXzoDwFxYRaZLX4bBOB4AyoGvRniil5QXPATiA1tsWX1VMicj8a4F8X+xeESzjt1Q5Iy31e7vkptu71bhvXCaoo5QhYwT+pLR9dN0S1b7Ro0KVvkRefmr1lUOSYd2e74h6Lc34tC1h3uYZCS4h47t7v5cOXvMNxinEj2C51RvbjvZI1RLVdkuAEJD1Iz4+Ote46nXbZ//6XRZMZz/YxQ13l7ux1PFjgEB6HAapmF5Xd8PRsgeTU9LRJxpiTJ3P5QJ3leS1va8qnziM5kYipj/Rn+V8g2ad/rgkRox9LSiR9VYZD2Pe45YCb1mTKSl2aIJnV7nkOqsShY5LNB4JZSg7xIffA+9YVDktw8dJlATjZqt7WvJJ49g6A61mIUV4C15q2JPGKTkZzDiG81NtmS7hFa7k0yaE2ELgYocbcuyUcAahhxntYTC0i23nJmEHVNiZmBO3u7EgpWe4KGVfumU+lt12tIn5b3dZRBBUk3QakKKozSK1QPHGpk/AZGrhu7H6l8to6IICKWtDcyMPQ=" - - GO111MODULE=on -before_script: -- go vet ./... -script: -- ./script/coverage -- ./script/unittest -- ./script/format -after_success: -- $HOME/gopath/bin/goveralls -service=travis-ci -coverprofile=cover.out diff --git a/vendor/github.com/gophercloud/gophercloud/.zuul.yaml b/vendor/github.com/gophercloud/gophercloud/.zuul.yaml deleted file mode 100644 index 135e3b203a8..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/.zuul.yaml +++ /dev/null @@ -1,114 +0,0 @@ -- job: - name: gophercloud-unittest - parent: golang-test - description: | - Run gophercloud unit test - run: .zuul/playbooks/gophercloud-unittest/run.yaml - nodeset: ubuntu-xenial-ut - -- job: - name: gophercloud-acceptance-test - parent: golang-test - description: | - Run gophercloud acceptance test on master branch - run: .zuul/playbooks/gophercloud-acceptance-test/run.yaml - -- job: - name: gophercloud-acceptance-test-ironic - parent: golang-test - description: | - Run gophercloud ironic acceptance test on master branch - run: .zuul/playbooks/gophercloud-acceptance-test-ironic/run.yaml - -- job: - name: gophercloud-acceptance-test-stein - parent: gophercloud-acceptance-test - description: | - Run gophercloud acceptance test on stein branch - vars: - global_env: - OS_BRANCH: stable/stein - -- job: - name: gophercloud-acceptance-test-rocky - parent: gophercloud-acceptance-test - description: | - Run gophercloud acceptance test on rocky branch - vars: - global_env: - OS_BRANCH: stable/rocky - -- job: - name: gophercloud-acceptance-test-queens - parent: gophercloud-acceptance-test - description: | - Run gophercloud acceptance test on queens branch - vars: - global_env: - OS_BRANCH: stable/queens - -- job: - name: gophercloud-acceptance-test-pike - parent: gophercloud-acceptance-test - description: | - Run gophercloud acceptance test on pike branch - vars: - global_env: - OS_BRANCH: stable/pike - -- job: - name: gophercloud-acceptance-test-ocata - parent: gophercloud-acceptance-test - description: | - Run gophercloud acceptance test on ocata branch - vars: - global_env: - OS_BRANCH: stable/ocata - -- job: - name: gophercloud-acceptance-test-newton - parent: gophercloud-acceptance-test - description: | - Run gophercloud acceptance test on newton branch - vars: - global_env: - OS_BRANCH: stable/newton - -- job: - name: gophercloud-acceptance-test-mitaka - parent: gophercloud-acceptance-test - description: | - Run gophercloud acceptance test on mitaka branch - vars: - global_env: - OS_BRANCH: stable/mitaka - nodeset: ubuntu-trusty - -- project: - name: gophercloud/gophercloud - check: - jobs: - - gophercloud-unittest - - gophercloud-acceptance-test - - gophercloud-acceptance-test-ironic - recheck-mitaka: - jobs: - - gophercloud-acceptance-test-mitaka - recheck-newton: - jobs: - - gophercloud-acceptance-test-newton - recheck-ocata: - jobs: - - gophercloud-acceptance-test-ocata - recheck-pike: - jobs: - - gophercloud-acceptance-test-pike - recheck-queens: - jobs: - - gophercloud-acceptance-test-queens - recheck-rocky: - jobs: - - gophercloud-acceptance-test-rocky - recheck-stein: - jobs: - - gophercloud-acceptance-test-stein diff --git a/vendor/github.com/gophercloud/gophercloud/CHANGELOG.md b/vendor/github.com/gophercloud/gophercloud/CHANGELOG.md deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/vendor/github.com/gophercloud/gophercloud/LICENSE b/vendor/github.com/gophercloud/gophercloud/LICENSE deleted file mode 100644 index fbbbc9e4cba..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ -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 diff --git a/vendor/github.com/gophercloud/gophercloud/README.md b/vendor/github.com/gophercloud/gophercloud/README.md deleted file mode 100644 index ad29041d9bf..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/README.md +++ /dev/null @@ -1,159 +0,0 @@ -# Gophercloud: an OpenStack SDK for Go -[![Build Status](https://travis-ci.org/gophercloud/gophercloud.svg?branch=master)](https://travis-ci.org/gophercloud/gophercloud) -[![Coverage Status](https://coveralls.io/repos/github/gophercloud/gophercloud/badge.svg?branch=master)](https://coveralls.io/github/gophercloud/gophercloud?branch=master) - -Gophercloud is an OpenStack Go SDK. - -## Useful links - -* [Reference documentation](http://godoc.org/github.com/gophercloud/gophercloud) -* [Effective Go](https://golang.org/doc/effective_go.html) - -## How to install - -Before installing, you need to ensure that your [GOPATH environment variable](https://golang.org/doc/code.html#GOPATH) -is pointing to an appropriate directory where you want to install Gophercloud: - -```bash -mkdir $HOME/go -export GOPATH=$HOME/go -``` - -To protect yourself against changes in your dependencies, we highly recommend choosing a -[dependency management solution](https://github.com/golang/go/wiki/PackageManagementTools) for -your projects, such as [godep](https://github.com/tools/godep). Once this is set up, you can install -Gophercloud as a dependency like so: - -```bash -go get github.com/gophercloud/gophercloud - -# Edit your code to import relevant packages from "github.com/gophercloud/gophercloud" - -godep save ./... -``` - -This will install all the source files you need into a `Godeps/_workspace` directory, which is -referenceable from your own source files when you use the `godep go` command. - -## Getting started - -### Credentials - -Because you'll be hitting an API, you will need to retrieve your OpenStack -credentials and either store them as environment variables or in your local Go -files. The first method is recommended because it decouples credential -information from source code, allowing you to push the latter to your version -control system without any security risk. - -You will need to retrieve the following: - -* username -* password -* a valid Keystone identity URL - -For users that have the OpenStack dashboard installed, there's a shortcut. If -you visit the `project/access_and_security` path in Horizon and click on the -"Download OpenStack RC File" button at the top right hand corner, you will -download a bash file that exports all of your access details to environment -variables. To execute the file, run `source admin-openrc.sh` and you will be -prompted for your password. - -### Authentication - -Once you have access to your credentials, you can begin plugging them into -Gophercloud. The next step is authentication, and this is handled by a base -"Provider" struct. To get one, you can either pass in your credentials -explicitly, or tell Gophercloud to use environment variables: - -```go -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack" - "github.com/gophercloud/gophercloud/openstack/utils" -) - -// Option 1: Pass in the values yourself -opts := gophercloud.AuthOptions{ - IdentityEndpoint: "https://openstack.example.com:5000/v2.0", - Username: "{username}", - Password: "{password}", -} - -// Option 2: Use a utility function to retrieve all your environment variables -opts, err := openstack.AuthOptionsFromEnv() -``` - -Once you have the `opts` variable, you can pass it in and get back a -`ProviderClient` struct: - -```go -provider, err := openstack.AuthenticatedClient(opts) -``` - -The `ProviderClient` is the top-level client that all of your OpenStack services -derive from. The provider contains all of the authentication details that allow -your Go code to access the API - such as the base URL and token ID. - -### Provision a server - -Once we have a base Provider, we inject it as a dependency into each OpenStack -service. In order to work with the Compute API, we need a Compute service -client; which can be created like so: - -```go -client, err := openstack.NewComputeV2(provider, gophercloud.EndpointOpts{ - Region: os.Getenv("OS_REGION_NAME"), -}) -``` - -We then use this `client` for any Compute API operation we want. In our case, -we want to provision a new server - so we invoke the `Create` method and pass -in the flavor ID (hardware specification) and image ID (operating system) we're -interested in: - -```go -import "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" - -server, err := servers.Create(client, servers.CreateOpts{ - Name: "My new server!", - FlavorRef: "flavor_id", - ImageRef: "image_id", -}).Extract() -``` - -The above code sample creates a new server with the parameters, and embodies the -new resource in the `server` variable (a -[`servers.Server`](http://godoc.org/github.com/gophercloud/gophercloud) struct). - -## Advanced Usage - -Have a look at the [FAQ](./docs/FAQ.md) for some tips on customizing the way Gophercloud works. - -## Backwards-Compatibility Guarantees - -None. Vendor it and write tests covering the parts you use. - -## Contributing - -See the [contributing guide](./.github/CONTRIBUTING.md). - -## Help and feedback - -If you're struggling with something or have spotted a potential bug, feel free -to submit an issue to our [bug tracker](https://github.com/gophercloud/gophercloud/issues). - -## Thank You - -We'd like to extend special thanks and appreciation to the following: - -### OpenLab - - - -OpenLab is providing a full CI environment to test each PR and merge for a variety of OpenStack releases. - -### VEXXHOST - - - -VEXXHOST is providing their services to assist with the development and testing of Gophercloud. diff --git a/vendor/github.com/gophercloud/gophercloud/auth_options.go b/vendor/github.com/gophercloud/gophercloud/auth_options.go deleted file mode 100644 index 5ffa8d1e0a7..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/auth_options.go +++ /dev/null @@ -1,437 +0,0 @@ -package gophercloud - -/* -AuthOptions stores information needed to authenticate to an OpenStack Cloud. -You can populate one manually, or use a provider's AuthOptionsFromEnv() function -to read relevant information from the standard environment variables. Pass one -to a provider's AuthenticatedClient function to authenticate and obtain a -ProviderClient representing an active session on that provider. - -Its fields are the union of those recognized by each identity implementation and -provider. - -An example of manually providing authentication information: - - opts := gophercloud.AuthOptions{ - IdentityEndpoint: "https://openstack.example.com:5000/v2.0", - Username: "{username}", - Password: "{password}", - TenantID: "{tenant_id}", - } - - provider, err := openstack.AuthenticatedClient(opts) - -An example of using AuthOptionsFromEnv(), where the environment variables can -be read from a file, such as a standard openrc file: - - opts, err := openstack.AuthOptionsFromEnv() - provider, err := openstack.AuthenticatedClient(opts) -*/ -type AuthOptions struct { - // IdentityEndpoint specifies the HTTP endpoint that is required to work with - // the Identity API of the appropriate version. While it's ultimately needed by - // all of the identity services, it will often be populated by a provider-level - // function. - // - // The IdentityEndpoint is typically referred to as the "auth_url" or - // "OS_AUTH_URL" in the information provided by the cloud operator. - IdentityEndpoint string `json:"-"` - - // Username is required if using Identity V2 API. Consult with your provider's - // control panel to discover your account's username. In Identity V3, either - // UserID or a combination of Username and DomainID or DomainName are needed. - Username string `json:"username,omitempty"` - UserID string `json:"-"` - - Password string `json:"password,omitempty"` - - // At most one of DomainID and DomainName must be provided if using Username - // with Identity V3. Otherwise, either are optional. - DomainID string `json:"-"` - DomainName string `json:"name,omitempty"` - - // The TenantID and TenantName fields are optional for the Identity V2 API. - // The same fields are known as project_id and project_name in the Identity - // V3 API, but are collected as TenantID and TenantName here in both cases. - // Some providers allow you to specify a TenantName instead of the TenantId. - // Some require both. Your provider's authentication policies will determine - // how these fields influence authentication. - // If DomainID or DomainName are provided, they will also apply to TenantName. - // It is not currently possible to authenticate with Username and a Domain - // and scope to a Project in a different Domain by using TenantName. To - // accomplish that, the ProjectID will need to be provided as the TenantID - // option. - TenantID string `json:"tenantId,omitempty"` - TenantName string `json:"tenantName,omitempty"` - - // AllowReauth should be set to true if you grant permission for Gophercloud to - // cache your credentials in memory, and to allow Gophercloud to attempt to - // re-authenticate automatically if/when your token expires. If you set it to - // false, it will not cache these settings, but re-authentication will not be - // possible. This setting defaults to false. - // - // NOTE: The reauth function will try to re-authenticate endlessly if left - // unchecked. The way to limit the number of attempts is to provide a custom - // HTTP client to the provider client and provide a transport that implements - // the RoundTripper interface and stores the number of failed retries. For an - // example of this, see here: - // https://github.com/rackspace/rack/blob/1.0.0/auth/clients.go#L311 - AllowReauth bool `json:"-"` - - // TokenID allows users to authenticate (possibly as another user) with an - // authentication token ID. - TokenID string `json:"-"` - - // Scope determines the scoping of the authentication request. - Scope *AuthScope `json:"-"` - - // Authentication through Application Credentials requires supplying name, project and secret - // For project we can use TenantID - ApplicationCredentialID string `json:"-"` - ApplicationCredentialName string `json:"-"` - ApplicationCredentialSecret string `json:"-"` -} - -// AuthScope allows a created token to be limited to a specific domain or project. -type AuthScope struct { - ProjectID string - ProjectName string - DomainID string - DomainName string -} - -// ToTokenV2CreateMap allows AuthOptions to satisfy the AuthOptionsBuilder -// interface in the v2 tokens package -func (opts AuthOptions) ToTokenV2CreateMap() (map[string]interface{}, error) { - // Populate the request map. - authMap := make(map[string]interface{}) - - if opts.Username != "" { - if opts.Password != "" { - authMap["passwordCredentials"] = map[string]interface{}{ - "username": opts.Username, - "password": opts.Password, - } - } else { - return nil, ErrMissingInput{Argument: "Password"} - } - } else if opts.TokenID != "" { - authMap["token"] = map[string]interface{}{ - "id": opts.TokenID, - } - } else { - return nil, ErrMissingInput{Argument: "Username"} - } - - if opts.TenantID != "" { - authMap["tenantId"] = opts.TenantID - } - if opts.TenantName != "" { - authMap["tenantName"] = opts.TenantName - } - - return map[string]interface{}{"auth": authMap}, nil -} - -func (opts *AuthOptions) ToTokenV3CreateMap(scope map[string]interface{}) (map[string]interface{}, error) { - type domainReq struct { - ID *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - } - - type projectReq struct { - Domain *domainReq `json:"domain,omitempty"` - Name *string `json:"name,omitempty"` - ID *string `json:"id,omitempty"` - } - - type userReq struct { - ID *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Password string `json:"password,omitempty"` - Domain *domainReq `json:"domain,omitempty"` - } - - type passwordReq struct { - User userReq `json:"user"` - } - - type tokenReq struct { - ID string `json:"id"` - } - - type applicationCredentialReq struct { - ID *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - User *userReq `json:"user,omitempty"` - Secret *string `json:"secret,omitempty"` - } - - type identityReq struct { - Methods []string `json:"methods"` - Password *passwordReq `json:"password,omitempty"` - Token *tokenReq `json:"token,omitempty"` - ApplicationCredential *applicationCredentialReq `json:"application_credential,omitempty"` - } - - type authReq struct { - Identity identityReq `json:"identity"` - } - - type request struct { - Auth authReq `json:"auth"` - } - - // Populate the request structure based on the provided arguments. Create and return an error - // if insufficient or incompatible information is present. - var req request - - if opts.Password == "" { - if opts.TokenID != "" { - // Because we aren't using password authentication, it's an error to also provide any of the user-based authentication - // parameters. - if opts.Username != "" { - return nil, ErrUsernameWithToken{} - } - if opts.UserID != "" { - return nil, ErrUserIDWithToken{} - } - if opts.DomainID != "" { - return nil, ErrDomainIDWithToken{} - } - if opts.DomainName != "" { - return nil, ErrDomainNameWithToken{} - } - - // Configure the request for Token authentication. - req.Auth.Identity.Methods = []string{"token"} - req.Auth.Identity.Token = &tokenReq{ - ID: opts.TokenID, - } - - } else if opts.ApplicationCredentialID != "" { - // Configure the request for ApplicationCredentialID authentication. - // https://github.com/openstack/keystoneauth/blob/stable/rocky/keystoneauth1/identity/v3/application_credential.py#L48-L67 - // There are three kinds of possible application_credential requests - // 1. application_credential id + secret - // 2. application_credential name + secret + user_id - // 3. application_credential name + secret + username + domain_id / domain_name - if opts.ApplicationCredentialSecret == "" { - return nil, ErrAppCredMissingSecret{} - } - req.Auth.Identity.Methods = []string{"application_credential"} - req.Auth.Identity.ApplicationCredential = &applicationCredentialReq{ - ID: &opts.ApplicationCredentialID, - Secret: &opts.ApplicationCredentialSecret, - } - } else if opts.ApplicationCredentialName != "" { - if opts.ApplicationCredentialSecret == "" { - return nil, ErrAppCredMissingSecret{} - } - - var userRequest *userReq - - if opts.UserID != "" { - // UserID could be used without the domain information - userRequest = &userReq{ - ID: &opts.UserID, - } - } - - if userRequest == nil && opts.Username == "" { - // Make sure that Username or UserID are provided - return nil, ErrUsernameOrUserID{} - } - - if userRequest == nil && opts.DomainID != "" { - userRequest = &userReq{ - Name: &opts.Username, - Domain: &domainReq{ID: &opts.DomainID}, - } - } - - if userRequest == nil && opts.DomainName != "" { - userRequest = &userReq{ - Name: &opts.Username, - Domain: &domainReq{Name: &opts.DomainName}, - } - } - - // Make sure that DomainID or DomainName are provided among Username - if userRequest == nil { - return nil, ErrDomainIDOrDomainName{} - } - - req.Auth.Identity.Methods = []string{"application_credential"} - req.Auth.Identity.ApplicationCredential = &applicationCredentialReq{ - Name: &opts.ApplicationCredentialName, - User: userRequest, - Secret: &opts.ApplicationCredentialSecret, - } - } else { - // If no password or token ID or ApplicationCredential are available, authentication can't continue. - return nil, ErrMissingPassword{} - } - } else { - // Password authentication. - req.Auth.Identity.Methods = []string{"password"} - - // At least one of Username and UserID must be specified. - if opts.Username == "" && opts.UserID == "" { - return nil, ErrUsernameOrUserID{} - } - - if opts.Username != "" { - // If Username is provided, UserID may not be provided. - if opts.UserID != "" { - return nil, ErrUsernameOrUserID{} - } - - // Either DomainID or DomainName must also be specified. - if opts.DomainID == "" && opts.DomainName == "" { - return nil, ErrDomainIDOrDomainName{} - } - - if opts.DomainID != "" { - if opts.DomainName != "" { - return nil, ErrDomainIDOrDomainName{} - } - - // Configure the request for Username and Password authentication with a DomainID. - req.Auth.Identity.Password = &passwordReq{ - User: userReq{ - Name: &opts.Username, - Password: opts.Password, - Domain: &domainReq{ID: &opts.DomainID}, - }, - } - } - - if opts.DomainName != "" { - // Configure the request for Username and Password authentication with a DomainName. - req.Auth.Identity.Password = &passwordReq{ - User: userReq{ - Name: &opts.Username, - Password: opts.Password, - Domain: &domainReq{Name: &opts.DomainName}, - }, - } - } - } - - if opts.UserID != "" { - // If UserID is specified, neither DomainID nor DomainName may be. - if opts.DomainID != "" { - return nil, ErrDomainIDWithUserID{} - } - if opts.DomainName != "" { - return nil, ErrDomainNameWithUserID{} - } - - // Configure the request for UserID and Password authentication. - req.Auth.Identity.Password = &passwordReq{ - User: userReq{ID: &opts.UserID, Password: opts.Password}, - } - } - } - - b, err := BuildRequestBody(req, "") - if err != nil { - return nil, err - } - - if len(scope) != 0 { - b["auth"].(map[string]interface{})["scope"] = scope - } - - return b, nil -} - -func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) { - // For backwards compatibility. - // If AuthOptions.Scope was not set, try to determine it. - // This works well for common scenarios. - if opts.Scope == nil { - opts.Scope = new(AuthScope) - if opts.TenantID != "" { - opts.Scope.ProjectID = opts.TenantID - } else { - if opts.TenantName != "" { - opts.Scope.ProjectName = opts.TenantName - opts.Scope.DomainID = opts.DomainID - opts.Scope.DomainName = opts.DomainName - } - } - } - - if opts.Scope.ProjectName != "" { - // ProjectName provided: either DomainID or DomainName must also be supplied. - // ProjectID may not be supplied. - if opts.Scope.DomainID == "" && opts.Scope.DomainName == "" { - return nil, ErrScopeDomainIDOrDomainName{} - } - if opts.Scope.ProjectID != "" { - return nil, ErrScopeProjectIDOrProjectName{} - } - - if opts.Scope.DomainID != "" { - // ProjectName + DomainID - return map[string]interface{}{ - "project": map[string]interface{}{ - "name": &opts.Scope.ProjectName, - "domain": map[string]interface{}{"id": &opts.Scope.DomainID}, - }, - }, nil - } - - if opts.Scope.DomainName != "" { - // ProjectName + DomainName - return map[string]interface{}{ - "project": map[string]interface{}{ - "name": &opts.Scope.ProjectName, - "domain": map[string]interface{}{"name": &opts.Scope.DomainName}, - }, - }, nil - } - } else if opts.Scope.ProjectID != "" { - // ProjectID provided. ProjectName, DomainID, and DomainName may not be provided. - if opts.Scope.DomainID != "" { - return nil, ErrScopeProjectIDAlone{} - } - if opts.Scope.DomainName != "" { - return nil, ErrScopeProjectIDAlone{} - } - - // ProjectID - return map[string]interface{}{ - "project": map[string]interface{}{ - "id": &opts.Scope.ProjectID, - }, - }, nil - } else if opts.Scope.DomainID != "" { - // DomainID provided. ProjectID, ProjectName, and DomainName may not be provided. - if opts.Scope.DomainName != "" { - return nil, ErrScopeDomainIDOrDomainName{} - } - - // DomainID - return map[string]interface{}{ - "domain": map[string]interface{}{ - "id": &opts.Scope.DomainID, - }, - }, nil - } else if opts.Scope.DomainName != "" { - // DomainName - return map[string]interface{}{ - "domain": map[string]interface{}{ - "name": &opts.Scope.DomainName, - }, - }, nil - } - - return nil, nil -} - -func (opts AuthOptions) CanReauth() bool { - return opts.AllowReauth -} diff --git a/vendor/github.com/gophercloud/gophercloud/auth_result.go b/vendor/github.com/gophercloud/gophercloud/auth_result.go deleted file mode 100644 index 2e4699b978c..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/auth_result.go +++ /dev/null @@ -1,52 +0,0 @@ -package gophercloud - -/* -AuthResult is the result from the request that was used to obtain a provider -client's Keystone token. It is returned from ProviderClient.GetAuthResult(). - -The following types satisfy this interface: - - github.com/gophercloud/gophercloud/openstack/identity/v2/tokens.CreateResult - github.com/gophercloud/gophercloud/openstack/identity/v3/tokens.CreateResult - -Usage example: - - import ( - "github.com/gophercloud/gophercloud" - tokens2 "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens" - tokens3 "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens" - ) - - func GetAuthenticatedUserID(providerClient *gophercloud.ProviderClient) (string, error) { - r := providerClient.GetAuthResult() - if r == nil { - //ProviderClient did not use openstack.Authenticate(), e.g. because token - //was set manually with ProviderClient.SetToken() - return "", errors.New("no AuthResult available") - } - switch r := r.(type) { - case tokens2.CreateResult: - u, err := r.ExtractUser() - if err != nil { - return "", err - } - return u.ID, nil - case tokens3.CreateResult: - u, err := r.ExtractUser() - if err != nil { - return "", err - } - return u.ID, nil - default: - panic(fmt.Sprintf("got unexpected AuthResult type %t", r)) - } - } - -Both implementing types share a lot of methods by name, like ExtractUser() in -this example. But those methods cannot be part of the AuthResult interface -because the return types are different (in this case, type tokens2.User vs. -type tokens3.User). -*/ -type AuthResult interface { - ExtractTokenID() (string, error) -} diff --git a/vendor/github.com/gophercloud/gophercloud/doc.go b/vendor/github.com/gophercloud/gophercloud/doc.go deleted file mode 100644 index 953ca822a97..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/doc.go +++ /dev/null @@ -1,110 +0,0 @@ -/* -Package gophercloud provides a multi-vendor interface to OpenStack-compatible -clouds. The library has a three-level hierarchy: providers, services, and -resources. - -Authenticating with Providers - -Provider structs represent the cloud providers that offer and manage a -collection of services. You will generally want to create one Provider -client per OpenStack cloud. - - It is now recommended to use the `clientconfig` package found at - https://github.com/gophercloud/utils/tree/master/openstack/clientconfig - for all authentication purposes. - - The below documentation is still relevant. clientconfig simply implements - the below and presents it in an easier and more flexible way. - -Use your OpenStack credentials to create a Provider client. The -IdentityEndpoint is typically refered to as "auth_url" or "OS_AUTH_URL" in -information provided by the cloud operator. Additionally, the cloud may refer to -TenantID or TenantName as project_id and project_name. Credentials are -specified like so: - - opts := gophercloud.AuthOptions{ - IdentityEndpoint: "https://openstack.example.com:5000/v2.0", - Username: "{username}", - Password: "{password}", - TenantID: "{tenant_id}", - } - - provider, err := openstack.AuthenticatedClient(opts) - -You can authenticate with a token by doing: - - opts := gophercloud.AuthOptions{ - IdentityEndpoint: "https://openstack.example.com:5000/v2.0", - TokenID: "{token_id}", - TenantID: "{tenant_id}", - } - - provider, err := openstack.AuthenticatedClient(opts) - -You may also use the openstack.AuthOptionsFromEnv() helper function. This -function reads in standard environment variables frequently found in an -OpenStack `openrc` file. Again note that Gophercloud currently uses "tenant" -instead of "project". - - opts, err := openstack.AuthOptionsFromEnv() - provider, err := openstack.AuthenticatedClient(opts) - -Service Clients - -Service structs are specific to a provider and handle all of the logic and -operations for a particular OpenStack service. Examples of services include: -Compute, Object Storage, Block Storage. In order to define one, you need to -pass in the parent provider, like so: - - opts := gophercloud.EndpointOpts{Region: "RegionOne"} - - client, err := openstack.NewComputeV2(provider, opts) - -Resources - -Resource structs are the domain models that services make use of in order -to work with and represent the state of API resources: - - server, err := servers.Get(client, "{serverId}").Extract() - -Intermediate Result structs are returned for API operations, which allow -generic access to the HTTP headers, response body, and any errors associated -with the network transaction. To turn a result into a usable resource struct, -you must call the Extract method which is chained to the response, or an -Extract function from an applicable extension: - - result := servers.Get(client, "{serverId}") - - // Attempt to extract the disk configuration from the OS-DCF disk config - // extension: - config, err := diskconfig.ExtractGet(result) - -All requests that enumerate a collection return a Pager struct that is used to -iterate through the results one page at a time. Use the EachPage method on that -Pager to handle each successive Page in a closure, then use the appropriate -extraction method from that request's package to interpret that Page as a slice -of results: - - err := servers.List(client, nil).EachPage(func (page pagination.Page) (bool, error) { - s, err := servers.ExtractServers(page) - if err != nil { - return false, err - } - - // Handle the []servers.Server slice. - - // Return "false" or an error to prematurely stop fetching new pages. - return true, nil - }) - -If you want to obtain the entire collection of pages without doing any -intermediary processing on each page, you can use the AllPages method: - - allPages, err := servers.List(client, nil).AllPages() - allServers, err := servers.ExtractServers(allPages) - -This top-level package contains utility functions and data types that are used -throughout the provider and service packages. Of particular note for end users -are the AuthOptions and EndpointOpts structs. -*/ -package gophercloud diff --git a/vendor/github.com/gophercloud/gophercloud/endpoint_search.go b/vendor/github.com/gophercloud/gophercloud/endpoint_search.go deleted file mode 100644 index 2fbc3c97f14..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/endpoint_search.go +++ /dev/null @@ -1,76 +0,0 @@ -package gophercloud - -// Availability indicates to whom a specific service endpoint is accessible: -// the internet at large, internal networks only, or only to administrators. -// Different identity services use different terminology for these. Identity v2 -// lists them as different kinds of URLs within the service catalog ("adminURL", -// "internalURL", and "publicURL"), while v3 lists them as "Interfaces" in an -// endpoint's response. -type Availability string - -const ( - // AvailabilityAdmin indicates that an endpoint is only available to - // administrators. - AvailabilityAdmin Availability = "admin" - - // AvailabilityPublic indicates that an endpoint is available to everyone on - // the internet. - AvailabilityPublic Availability = "public" - - // AvailabilityInternal indicates that an endpoint is only available within - // the cluster's internal network. - AvailabilityInternal Availability = "internal" -) - -// EndpointOpts specifies search criteria used by queries against an -// OpenStack service catalog. The options must contain enough information to -// unambiguously identify one, and only one, endpoint within the catalog. -// -// Usually, these are passed to service client factory functions in a provider -// package, like "openstack.NewComputeV2()". -type EndpointOpts struct { - // Type [required] is the service type for the client (e.g., "compute", - // "object-store"). Generally, this will be supplied by the service client - // function, but a user-given value will be honored if provided. - Type string - - // Name [optional] is the service name for the client (e.g., "nova") as it - // appears in the service catalog. Services can have the same Type but a - // different Name, which is why both Type and Name are sometimes needed. - Name string - - // Region [required] is the geographic region in which the endpoint resides, - // generally specifying which datacenter should house your resources. - // Required only for services that span multiple regions. - Region string - - // Availability [optional] is the visibility of the endpoint to be returned. - // Valid types include the constants AvailabilityPublic, AvailabilityInternal, - // or AvailabilityAdmin from this package. - // - // Availability is not required, and defaults to AvailabilityPublic. Not all - // providers or services offer all Availability options. - Availability Availability -} - -/* -EndpointLocator is an internal function to be used by provider implementations. - -It provides an implementation that locates a single endpoint from a service -catalog for a specific ProviderClient based on user-provided EndpointOpts. The -provider then uses it to discover related ServiceClients. -*/ -type EndpointLocator func(EndpointOpts) (string, error) - -// ApplyDefaults is an internal method to be used by provider implementations. -// -// It sets EndpointOpts fields if not already set, including a default type. -// Currently, EndpointOpts.Availability defaults to the public endpoint. -func (eo *EndpointOpts) ApplyDefaults(t string) { - if eo.Type == "" { - eo.Type = t - } - if eo.Availability == "" { - eo.Availability = AvailabilityPublic - } -} diff --git a/vendor/github.com/gophercloud/gophercloud/errors.go b/vendor/github.com/gophercloud/gophercloud/errors.go deleted file mode 100644 index 0bcb3af7f00..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/errors.go +++ /dev/null @@ -1,471 +0,0 @@ -package gophercloud - -import ( - "fmt" - "strings" -) - -// BaseError is an error type that all other error types embed. -type BaseError struct { - DefaultErrString string - Info string -} - -func (e BaseError) Error() string { - e.DefaultErrString = "An error occurred while executing a Gophercloud request." - return e.choseErrString() -} - -func (e BaseError) choseErrString() string { - if e.Info != "" { - return e.Info - } - return e.DefaultErrString -} - -// ErrMissingInput is the error when input is required in a particular -// situation but not provided by the user -type ErrMissingInput struct { - BaseError - Argument string -} - -func (e ErrMissingInput) Error() string { - e.DefaultErrString = fmt.Sprintf("Missing input for argument [%s]", e.Argument) - return e.choseErrString() -} - -// ErrInvalidInput is an error type used for most non-HTTP Gophercloud errors. -type ErrInvalidInput struct { - ErrMissingInput - Value interface{} -} - -func (e ErrInvalidInput) Error() string { - e.DefaultErrString = fmt.Sprintf("Invalid input provided for argument [%s]: [%+v]", e.Argument, e.Value) - return e.choseErrString() -} - -// ErrMissingEnvironmentVariable is the error when environment variable is required -// in a particular situation but not provided by the user -type ErrMissingEnvironmentVariable struct { - BaseError - EnvironmentVariable string -} - -func (e ErrMissingEnvironmentVariable) Error() string { - e.DefaultErrString = fmt.Sprintf("Missing environment variable [%s]", e.EnvironmentVariable) - return e.choseErrString() -} - -// ErrMissingAnyoneOfEnvironmentVariables is the error when anyone of the environment variables -// is required in a particular situation but not provided by the user -type ErrMissingAnyoneOfEnvironmentVariables struct { - BaseError - EnvironmentVariables []string -} - -func (e ErrMissingAnyoneOfEnvironmentVariables) Error() string { - e.DefaultErrString = fmt.Sprintf( - "Missing one of the following environment variables [%s]", - strings.Join(e.EnvironmentVariables, ", "), - ) - return e.choseErrString() -} - -// ErrUnexpectedResponseCode is returned by the Request method when a response code other than -// those listed in OkCodes is encountered. -type ErrUnexpectedResponseCode struct { - BaseError - URL string - Method string - Expected []int - Actual int - Body []byte -} - -func (e ErrUnexpectedResponseCode) Error() string { - e.DefaultErrString = fmt.Sprintf( - "Expected HTTP response code %v when accessing [%s %s], but got %d instead\n%s", - e.Expected, e.Method, e.URL, e.Actual, e.Body, - ) - return e.choseErrString() -} - -// ErrDefault400 is the default error type returned on a 400 HTTP response code. -type ErrDefault400 struct { - ErrUnexpectedResponseCode -} - -// ErrDefault401 is the default error type returned on a 401 HTTP response code. -type ErrDefault401 struct { - ErrUnexpectedResponseCode -} - -// ErrDefault403 is the default error type returned on a 403 HTTP response code. -type ErrDefault403 struct { - ErrUnexpectedResponseCode -} - -// ErrDefault404 is the default error type returned on a 404 HTTP response code. -type ErrDefault404 struct { - ErrUnexpectedResponseCode -} - -// ErrDefault405 is the default error type returned on a 405 HTTP response code. -type ErrDefault405 struct { - ErrUnexpectedResponseCode -} - -// ErrDefault408 is the default error type returned on a 408 HTTP response code. -type ErrDefault408 struct { - ErrUnexpectedResponseCode -} - -// ErrDefault409 is the default error type returned on a 409 HTTP response code. -type ErrDefault409 struct { - ErrUnexpectedResponseCode -} - -// ErrDefault429 is the default error type returned on a 429 HTTP response code. -type ErrDefault429 struct { - ErrUnexpectedResponseCode -} - -// ErrDefault500 is the default error type returned on a 500 HTTP response code. -type ErrDefault500 struct { - ErrUnexpectedResponseCode -} - -// ErrDefault503 is the default error type returned on a 503 HTTP response code. -type ErrDefault503 struct { - ErrUnexpectedResponseCode -} - -func (e ErrDefault400) Error() string { - e.DefaultErrString = fmt.Sprintf( - "Bad request with: [%s %s], error message: %s", - e.Method, e.URL, e.Body, - ) - return e.choseErrString() -} -func (e ErrDefault401) Error() string { - return "Authentication failed" -} -func (e ErrDefault403) Error() string { - e.DefaultErrString = fmt.Sprintf( - "Request forbidden: [%s %s], error message: %s", - e.Method, e.URL, e.Body, - ) - return e.choseErrString() -} -func (e ErrDefault404) Error() string { - return "Resource not found" -} -func (e ErrDefault405) Error() string { - return "Method not allowed" -} -func (e ErrDefault408) Error() string { - return "The server timed out waiting for the request" -} -func (e ErrDefault429) Error() string { - return "Too many requests have been sent in a given amount of time. Pause" + - " requests, wait up to one minute, and try again." -} -func (e ErrDefault500) Error() string { - return "Internal Server Error" -} -func (e ErrDefault503) Error() string { - return "The service is currently unable to handle the request due to a temporary" + - " overloading or maintenance. This is a temporary condition. Try again later." -} - -// Err400er is the interface resource error types implement to override the error message -// from a 400 error. -type Err400er interface { - Error400(ErrUnexpectedResponseCode) error -} - -// Err401er is the interface resource error types implement to override the error message -// from a 401 error. -type Err401er interface { - Error401(ErrUnexpectedResponseCode) error -} - -// Err403er is the interface resource error types implement to override the error message -// from a 403 error. -type Err403er interface { - Error403(ErrUnexpectedResponseCode) error -} - -// Err404er is the interface resource error types implement to override the error message -// from a 404 error. -type Err404er interface { - Error404(ErrUnexpectedResponseCode) error -} - -// Err405er is the interface resource error types implement to override the error message -// from a 405 error. -type Err405er interface { - Error405(ErrUnexpectedResponseCode) error -} - -// Err408er is the interface resource error types implement to override the error message -// from a 408 error. -type Err408er interface { - Error408(ErrUnexpectedResponseCode) error -} - -// Err409er is the interface resource error types implement to override the error message -// from a 409 error. -type Err409er interface { - Error409(ErrUnexpectedResponseCode) error -} - -// Err429er is the interface resource error types implement to override the error message -// from a 429 error. -type Err429er interface { - Error429(ErrUnexpectedResponseCode) error -} - -// Err500er is the interface resource error types implement to override the error message -// from a 500 error. -type Err500er interface { - Error500(ErrUnexpectedResponseCode) error -} - -// Err503er is the interface resource error types implement to override the error message -// from a 503 error. -type Err503er interface { - Error503(ErrUnexpectedResponseCode) error -} - -// ErrTimeOut is the error type returned when an operations times out. -type ErrTimeOut struct { - BaseError -} - -func (e ErrTimeOut) Error() string { - e.DefaultErrString = "A time out occurred" - return e.choseErrString() -} - -// ErrUnableToReauthenticate is the error type returned when reauthentication fails. -type ErrUnableToReauthenticate struct { - BaseError - ErrOriginal error -} - -func (e ErrUnableToReauthenticate) Error() string { - e.DefaultErrString = fmt.Sprintf("Unable to re-authenticate: %s", e.ErrOriginal) - return e.choseErrString() -} - -// ErrErrorAfterReauthentication is the error type returned when reauthentication -// succeeds, but an error occurs afterword (usually an HTTP error). -type ErrErrorAfterReauthentication struct { - BaseError - ErrOriginal error -} - -func (e ErrErrorAfterReauthentication) Error() string { - e.DefaultErrString = fmt.Sprintf("Successfully re-authenticated, but got error executing request: %s", e.ErrOriginal) - return e.choseErrString() -} - -// ErrServiceNotFound is returned when no service in a service catalog matches -// the provided EndpointOpts. This is generally returned by provider service -// factory methods like "NewComputeV2()" and can mean that a service is not -// enabled for your account. -type ErrServiceNotFound struct { - BaseError -} - -func (e ErrServiceNotFound) Error() string { - e.DefaultErrString = "No suitable service could be found in the service catalog." - return e.choseErrString() -} - -// ErrEndpointNotFound is returned when no available endpoints match the -// provided EndpointOpts. This is also generally returned by provider service -// factory methods, and usually indicates that a region was specified -// incorrectly. -type ErrEndpointNotFound struct { - BaseError -} - -func (e ErrEndpointNotFound) Error() string { - e.DefaultErrString = "No suitable endpoint could be found in the service catalog." - return e.choseErrString() -} - -// ErrResourceNotFound is the error when trying to retrieve a resource's -// ID by name and the resource doesn't exist. -type ErrResourceNotFound struct { - BaseError - Name string - ResourceType string -} - -func (e ErrResourceNotFound) Error() string { - e.DefaultErrString = fmt.Sprintf("Unable to find %s with name %s", e.ResourceType, e.Name) - return e.choseErrString() -} - -// ErrMultipleResourcesFound is the error when trying to retrieve a resource's -// ID by name and multiple resources have the user-provided name. -type ErrMultipleResourcesFound struct { - BaseError - Name string - Count int - ResourceType string -} - -func (e ErrMultipleResourcesFound) Error() string { - e.DefaultErrString = fmt.Sprintf("Found %d %ss matching %s", e.Count, e.ResourceType, e.Name) - return e.choseErrString() -} - -// ErrUnexpectedType is the error when an unexpected type is encountered -type ErrUnexpectedType struct { - BaseError - Expected string - Actual string -} - -func (e ErrUnexpectedType) Error() string { - e.DefaultErrString = fmt.Sprintf("Expected %s but got %s", e.Expected, e.Actual) - return e.choseErrString() -} - -func unacceptedAttributeErr(attribute string) string { - return fmt.Sprintf("The base Identity V3 API does not accept authentication by %s", attribute) -} - -func redundantWithTokenErr(attribute string) string { - return fmt.Sprintf("%s may not be provided when authenticating with a TokenID", attribute) -} - -func redundantWithUserID(attribute string) string { - return fmt.Sprintf("%s may not be provided when authenticating with a UserID", attribute) -} - -// ErrAPIKeyProvided indicates that an APIKey was provided but can't be used. -type ErrAPIKeyProvided struct{ BaseError } - -func (e ErrAPIKeyProvided) Error() string { - return unacceptedAttributeErr("APIKey") -} - -// ErrTenantIDProvided indicates that a TenantID was provided but can't be used. -type ErrTenantIDProvided struct{ BaseError } - -func (e ErrTenantIDProvided) Error() string { - return unacceptedAttributeErr("TenantID") -} - -// ErrTenantNameProvided indicates that a TenantName was provided but can't be used. -type ErrTenantNameProvided struct{ BaseError } - -func (e ErrTenantNameProvided) Error() string { - return unacceptedAttributeErr("TenantName") -} - -// ErrUsernameWithToken indicates that a Username was provided, but token authentication is being used instead. -type ErrUsernameWithToken struct{ BaseError } - -func (e ErrUsernameWithToken) Error() string { - return redundantWithTokenErr("Username") -} - -// ErrUserIDWithToken indicates that a UserID was provided, but token authentication is being used instead. -type ErrUserIDWithToken struct{ BaseError } - -func (e ErrUserIDWithToken) Error() string { - return redundantWithTokenErr("UserID") -} - -// ErrDomainIDWithToken indicates that a DomainID was provided, but token authentication is being used instead. -type ErrDomainIDWithToken struct{ BaseError } - -func (e ErrDomainIDWithToken) Error() string { - return redundantWithTokenErr("DomainID") -} - -// ErrDomainNameWithToken indicates that a DomainName was provided, but token authentication is being used instead.s -type ErrDomainNameWithToken struct{ BaseError } - -func (e ErrDomainNameWithToken) Error() string { - return redundantWithTokenErr("DomainName") -} - -// ErrUsernameOrUserID indicates that neither username nor userID are specified, or both are at once. -type ErrUsernameOrUserID struct{ BaseError } - -func (e ErrUsernameOrUserID) Error() string { - return "Exactly one of Username and UserID must be provided for password authentication" -} - -// ErrDomainIDWithUserID indicates that a DomainID was provided, but unnecessary because a UserID is being used. -type ErrDomainIDWithUserID struct{ BaseError } - -func (e ErrDomainIDWithUserID) Error() string { - return redundantWithUserID("DomainID") -} - -// ErrDomainNameWithUserID indicates that a DomainName was provided, but unnecessary because a UserID is being used. -type ErrDomainNameWithUserID struct{ BaseError } - -func (e ErrDomainNameWithUserID) Error() string { - return redundantWithUserID("DomainName") -} - -// ErrDomainIDOrDomainName indicates that a username was provided, but no domain to scope it. -// It may also indicate that both a DomainID and a DomainName were provided at once. -type ErrDomainIDOrDomainName struct{ BaseError } - -func (e ErrDomainIDOrDomainName) Error() string { - return "You must provide exactly one of DomainID or DomainName to authenticate by Username" -} - -// ErrMissingPassword indicates that no password was provided and no token is available. -type ErrMissingPassword struct{ BaseError } - -func (e ErrMissingPassword) Error() string { - return "You must provide a password to authenticate" -} - -// ErrScopeDomainIDOrDomainName indicates that a domain ID or Name was required in a Scope, but not present. -type ErrScopeDomainIDOrDomainName struct{ BaseError } - -func (e ErrScopeDomainIDOrDomainName) Error() string { - return "You must provide exactly one of DomainID or DomainName in a Scope with ProjectName" -} - -// ErrScopeProjectIDOrProjectName indicates that both a ProjectID and a ProjectName were provided in a Scope. -type ErrScopeProjectIDOrProjectName struct{ BaseError } - -func (e ErrScopeProjectIDOrProjectName) Error() string { - return "You must provide at most one of ProjectID or ProjectName in a Scope" -} - -// ErrScopeProjectIDAlone indicates that a ProjectID was provided with other constraints in a Scope. -type ErrScopeProjectIDAlone struct{ BaseError } - -func (e ErrScopeProjectIDAlone) Error() string { - return "ProjectID must be supplied alone in a Scope" -} - -// ErrScopeEmpty indicates that no credentials were provided in a Scope. -type ErrScopeEmpty struct{ BaseError } - -func (e ErrScopeEmpty) Error() string { - return "You must provide either a Project or Domain in a Scope" -} - -// ErrAppCredMissingSecret indicates that no Application Credential Secret was provided with Application Credential ID or Name -type ErrAppCredMissingSecret struct{ BaseError } - -func (e ErrAppCredMissingSecret) Error() string { - return "You must provide an Application Credential Secret" -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/auth_env.go b/vendor/github.com/gophercloud/gophercloud/openstack/auth_env.go deleted file mode 100644 index 0e8d90ff826..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/auth_env.go +++ /dev/null @@ -1,125 +0,0 @@ -package openstack - -import ( - "os" - - "github.com/gophercloud/gophercloud" -) - -var nilOptions = gophercloud.AuthOptions{} - -/* -AuthOptionsFromEnv fills out an identity.AuthOptions structure with the -settings found on the various OpenStack OS_* environment variables. - -The following variables provide sources of truth: OS_AUTH_URL, OS_USERNAME, -OS_PASSWORD and OS_PROJECT_ID. - -Of these, OS_USERNAME, OS_PASSWORD, and OS_AUTH_URL must have settings, -or an error will result. OS_PROJECT_ID, is optional. - -OS_TENANT_ID and OS_TENANT_NAME are deprecated forms of OS_PROJECT_ID and -OS_PROJECT_NAME and the latter are expected against a v3 auth api. - -If OS_PROJECT_ID and OS_PROJECT_NAME are set, they will still be referred -as "tenant" in Gophercloud. - -If OS_PROJECT_NAME is set, it requires OS_PROJECT_ID to be set as well to -handle projects not on the default domain. - -To use this function, first set the OS_* environment variables (for example, -by sourcing an `openrc` file), then: - - opts, err := openstack.AuthOptionsFromEnv() - provider, err := openstack.AuthenticatedClient(opts) -*/ -func AuthOptionsFromEnv() (gophercloud.AuthOptions, error) { - authURL := os.Getenv("OS_AUTH_URL") - username := os.Getenv("OS_USERNAME") - userID := os.Getenv("OS_USERID") - password := os.Getenv("OS_PASSWORD") - tenantID := os.Getenv("OS_TENANT_ID") - tenantName := os.Getenv("OS_TENANT_NAME") - domainID := os.Getenv("OS_DOMAIN_ID") - domainName := os.Getenv("OS_DOMAIN_NAME") - applicationCredentialID := os.Getenv("OS_APPLICATION_CREDENTIAL_ID") - applicationCredentialName := os.Getenv("OS_APPLICATION_CREDENTIAL_NAME") - applicationCredentialSecret := os.Getenv("OS_APPLICATION_CREDENTIAL_SECRET") - - // If OS_PROJECT_ID is set, overwrite tenantID with the value. - if v := os.Getenv("OS_PROJECT_ID"); v != "" { - tenantID = v - } - - // If OS_PROJECT_NAME is set, overwrite tenantName with the value. - if v := os.Getenv("OS_PROJECT_NAME"); v != "" { - tenantName = v - } - - if authURL == "" { - err := gophercloud.ErrMissingEnvironmentVariable{ - EnvironmentVariable: "OS_AUTH_URL", - } - return nilOptions, err - } - - if userID == "" && username == "" { - // Empty username and userID could be ignored, when applicationCredentialID and applicationCredentialSecret are set - if applicationCredentialID == "" && applicationCredentialSecret == "" { - err := gophercloud.ErrMissingAnyoneOfEnvironmentVariables{ - EnvironmentVariables: []string{"OS_USERID", "OS_USERNAME"}, - } - return nilOptions, err - } - } - - if password == "" && applicationCredentialID == "" && applicationCredentialName == "" { - err := gophercloud.ErrMissingEnvironmentVariable{ - EnvironmentVariable: "OS_PASSWORD", - } - return nilOptions, err - } - - if (applicationCredentialID != "" || applicationCredentialName != "") && applicationCredentialSecret == "" { - err := gophercloud.ErrMissingEnvironmentVariable{ - EnvironmentVariable: "OS_APPLICATION_CREDENTIAL_SECRET", - } - return nilOptions, err - } - - if domainID == "" && domainName == "" && tenantID == "" && tenantName != "" { - err := gophercloud.ErrMissingEnvironmentVariable{ - EnvironmentVariable: "OS_PROJECT_ID", - } - return nilOptions, err - } - - if applicationCredentialID == "" && applicationCredentialName != "" && applicationCredentialSecret != "" { - if userID == "" && username == "" { - return nilOptions, gophercloud.ErrMissingAnyoneOfEnvironmentVariables{ - EnvironmentVariables: []string{"OS_USERID", "OS_USERNAME"}, - } - } - if username != "" && domainID == "" && domainName == "" { - return nilOptions, gophercloud.ErrMissingAnyoneOfEnvironmentVariables{ - EnvironmentVariables: []string{"OS_DOMAIN_ID", "OS_DOMAIN_NAME"}, - } - } - } - - ao := gophercloud.AuthOptions{ - IdentityEndpoint: authURL, - UserID: userID, - Username: username, - Password: password, - TenantID: tenantID, - TenantName: tenantName, - DomainID: domainID, - DomainName: domainName, - ApplicationCredentialID: applicationCredentialID, - ApplicationCredentialName: applicationCredentialName, - ApplicationCredentialSecret: applicationCredentialSecret, - } - - return ao, nil -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions/doc.go deleted file mode 100644 index a78d3d0482c..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions/doc.go +++ /dev/null @@ -1,86 +0,0 @@ -/* -Package volumeactions 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. - -Example of Attaching a Volume to an Instance - - attachOpts := volumeactions.AttachOpts{ - MountPoint: "/mnt", - Mode: "rw", - InstanceUUID: server.ID, - } - - err := volumeactions.Attach(client, volume.ID, attachOpts).ExtractErr() - if err != nil { - panic(err) - } - - detachOpts := volumeactions.DetachOpts{ - AttachmentID: volume.Attachments[0].AttachmentID, - } - - err = volumeactions.Detach(client, volume.ID, detachOpts).ExtractErr() - if err != nil { - panic(err) - } - - -Example of Creating an Image from a Volume - - uploadImageOpts := volumeactions.UploadImageOpts{ - ImageName: "my_vol", - Force: true, - } - - volumeImage, err := volumeactions.UploadImage(client, volume.ID, uploadImageOpts).Extract() - if err != nil { - panic(err) - } - - fmt.Printf("%+v\n", volumeImage) - -Example of Extending a Volume's Size - - extendOpts := volumeactions.ExtendSizeOpts{ - NewSize: 100, - } - - err := volumeactions.ExtendSize(client, volume.ID, extendOpts).ExtractErr() - if err != nil { - panic(err) - } - -Example of Initializing a Volume Connection - - connectOpts := &volumeactions.InitializeConnectionOpts{ - IP: "127.0.0.1", - Host: "stack", - Initiator: "iqn.1994-05.com.redhat:17cf566367d2", - Multipath: gophercloud.Disabled, - Platform: "x86_64", - OSType: "linux2", - } - - connectionInfo, err := volumeactions.InitializeConnection(client, volume.ID, connectOpts).Extract() - if err != nil { - panic(err) - } - - fmt.Printf("%+v\n", connectionInfo["data"]) - - terminateOpts := &volumeactions.InitializeConnectionOpts{ - IP: "127.0.0.1", - Host: "stack", - Initiator: "iqn.1994-05.com.redhat:17cf566367d2", - Multipath: gophercloud.Disabled, - Platform: "x86_64", - OSType: "linux2", - } - - err = volumeactions.TerminateConnection(client, volume.ID, terminateOpts).ExtractErr() - if err != nil { - panic(err) - } -*/ -package volumeactions diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions/requests.go deleted file mode 100644 index d18bff555b5..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions/requests.go +++ /dev/null @@ -1,269 +0,0 @@ -package volumeactions - -import ( - "github.com/gophercloud/gophercloud" -) - -// AttachOptsBuilder allows extensions to add additional parameters to the -// Attach request. -type AttachOptsBuilder interface { - ToVolumeAttachMap() (map[string]interface{}, error) -} - -// AttachMode describes the attachment mode for volumes. -type AttachMode string - -// These constants determine how a volume is attached. -const ( - ReadOnly AttachMode = "ro" - ReadWrite AttachMode = "rw" -) - -// AttachOpts contains options for attaching a Volume. -type AttachOpts struct { - // The mountpoint of this volume. - MountPoint string `json:"mountpoint,omitempty"` - - // The nova instance ID, can't set simultaneously with HostName. - InstanceUUID string `json:"instance_uuid,omitempty"` - - // The hostname of baremetal host, can't set simultaneously with InstanceUUID. - HostName string `json:"host_name,omitempty"` - - // Mount mode of this volume. - Mode AttachMode `json:"mode,omitempty"` -} - -// ToVolumeAttachMap assembles a request body based on the contents of a -// AttachOpts. -func (opts AttachOpts) ToVolumeAttachMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "os-attach") -} - -// Attach will attach a volume based on the values in AttachOpts. -func Attach(client *gophercloud.ServiceClient, id string, opts AttachOptsBuilder) (r AttachResult) { - b, err := opts.ToVolumeAttachMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{ - OkCodes: []int{202}, - }) - return -} - -// BeginDetach will mark the volume as detaching. -func BeginDetaching(client *gophercloud.ServiceClient, id string) (r BeginDetachingResult) { - b := map[string]interface{}{"os-begin_detaching": make(map[string]interface{})} - _, r.Err = client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{ - OkCodes: []int{202}, - }) - return -} - -// DetachOptsBuilder allows extensions to add additional parameters to the -// Detach request. -type DetachOptsBuilder interface { - ToVolumeDetachMap() (map[string]interface{}, error) -} - -// DetachOpts contains options for detaching a Volume. -type DetachOpts struct { - // AttachmentID is the ID of the attachment between a volume and instance. - AttachmentID string `json:"attachment_id,omitempty"` -} - -// ToVolumeDetachMap assembles a request body based on the contents of a -// DetachOpts. -func (opts DetachOpts) ToVolumeDetachMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "os-detach") -} - -// Detach will detach a volume based on volume ID. -func Detach(client *gophercloud.ServiceClient, id string, opts DetachOptsBuilder) (r DetachResult) { - b, err := opts.ToVolumeDetachMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{ - OkCodes: []int{202}, - }) - return -} - -// Reserve will reserve a volume based on volume ID. -func Reserve(client *gophercloud.ServiceClient, id string) (r ReserveResult) { - b := map[string]interface{}{"os-reserve": make(map[string]interface{})} - _, r.Err = client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{ - OkCodes: []int{200, 201, 202}, - }) - return -} - -// Unreserve will unreserve a volume based on volume ID. -func Unreserve(client *gophercloud.ServiceClient, id string) (r UnreserveResult) { - b := map[string]interface{}{"os-unreserve": make(map[string]interface{})} - _, r.Err = client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{ - OkCodes: []int{200, 201, 202}, - }) - return -} - -// InitializeConnectionOptsBuilder allows extensions to add additional parameters to the -// InitializeConnection request. -type InitializeConnectionOptsBuilder interface { - ToVolumeInitializeConnectionMap() (map[string]interface{}, error) -} - -// InitializeConnectionOpts hosts options for InitializeConnection. -// The fields are specific to the storage driver in use and the destination -// attachment. -type InitializeConnectionOpts struct { - IP string `json:"ip,omitempty"` - Host string `json:"host,omitempty"` - Initiator string `json:"initiator,omitempty"` - Wwpns []string `json:"wwpns,omitempty"` - Wwnns string `json:"wwnns,omitempty"` - Multipath *bool `json:"multipath,omitempty"` - Platform string `json:"platform,omitempty"` - OSType string `json:"os_type,omitempty"` -} - -// ToVolumeInitializeConnectionMap assembles a request body based on the contents of a -// InitializeConnectionOpts. -func (opts InitializeConnectionOpts) ToVolumeInitializeConnectionMap() (map[string]interface{}, error) { - b, err := gophercloud.BuildRequestBody(opts, "connector") - return map[string]interface{}{"os-initialize_connection": b}, err -} - -// InitializeConnection initializes an iSCSI connection by volume ID. -func InitializeConnection(client *gophercloud.ServiceClient, id string, opts InitializeConnectionOptsBuilder) (r InitializeConnectionResult) { - b, err := opts.ToVolumeInitializeConnectionMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(actionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200, 201, 202}, - }) - return -} - -// TerminateConnectionOptsBuilder allows extensions to add additional parameters to the -// TerminateConnection request. -type TerminateConnectionOptsBuilder interface { - ToVolumeTerminateConnectionMap() (map[string]interface{}, error) -} - -// TerminateConnectionOpts hosts options for TerminateConnection. -type TerminateConnectionOpts struct { - IP string `json:"ip,omitempty"` - Host string `json:"host,omitempty"` - Initiator string `json:"initiator,omitempty"` - Wwpns []string `json:"wwpns,omitempty"` - Wwnns string `json:"wwnns,omitempty"` - Multipath *bool `json:"multipath,omitempty"` - Platform string `json:"platform,omitempty"` - OSType string `json:"os_type,omitempty"` -} - -// ToVolumeTerminateConnectionMap assembles a request body based on the contents of a -// TerminateConnectionOpts. -func (opts TerminateConnectionOpts) ToVolumeTerminateConnectionMap() (map[string]interface{}, error) { - b, err := gophercloud.BuildRequestBody(opts, "connector") - return map[string]interface{}{"os-terminate_connection": b}, err -} - -// TerminateConnection terminates an iSCSI connection by volume ID. -func TerminateConnection(client *gophercloud.ServiceClient, id string, opts TerminateConnectionOptsBuilder) (r TerminateConnectionResult) { - b, err := opts.ToVolumeTerminateConnectionMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{ - OkCodes: []int{202}, - }) - return -} - -// ExtendSizeOptsBuilder allows extensions to add additional parameters to the -// ExtendSize request. -type ExtendSizeOptsBuilder interface { - ToVolumeExtendSizeMap() (map[string]interface{}, error) -} - -// ExtendSizeOpts contains options for extending the size of an existing Volume. -// This object is passed to the volumes.ExtendSize function. -type ExtendSizeOpts struct { - // NewSize is the new size of the volume, in GB. - NewSize int `json:"new_size" required:"true"` -} - -// ToVolumeExtendSizeMap assembles a request body based on the contents of an -// ExtendSizeOpts. -func (opts ExtendSizeOpts) ToVolumeExtendSizeMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "os-extend") -} - -// ExtendSize will extend the size of the volume based on the provided information. -// This operation does not return a response body. -func ExtendSize(client *gophercloud.ServiceClient, id string, opts ExtendSizeOptsBuilder) (r ExtendSizeResult) { - b, err := opts.ToVolumeExtendSizeMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{ - OkCodes: []int{202}, - }) - return -} - -// UploadImageOptsBuilder allows extensions to add additional parameters to the -// UploadImage request. -type UploadImageOptsBuilder interface { - ToVolumeUploadImageMap() (map[string]interface{}, error) -} - -// UploadImageOpts contains options for uploading a Volume to image storage. -type UploadImageOpts struct { - // Container format, may be bare, ofv, ova, etc. - ContainerFormat string `json:"container_format,omitempty"` - - // Disk format, may be raw, qcow2, vhd, vdi, vmdk, etc. - DiskFormat string `json:"disk_format,omitempty"` - - // The name of image that will be stored in glance. - ImageName string `json:"image_name,omitempty"` - - // Force image creation, usable if volume attached to instance. - Force bool `json:"force,omitempty"` -} - -// ToVolumeUploadImageMap assembles a request body based on the contents of a -// UploadImageOpts. -func (opts UploadImageOpts) ToVolumeUploadImageMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "os-volume_upload_image") -} - -// UploadImage will upload an image based on the values in UploadImageOptsBuilder. -func UploadImage(client *gophercloud.ServiceClient, id string, opts UploadImageOptsBuilder) (r UploadImageResult) { - b, err := opts.ToVolumeUploadImageMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(actionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{202}, - }) - return -} - -// ForceDelete will delete the volume regardless of state. -func ForceDelete(client *gophercloud.ServiceClient, id string) (r ForceDeleteResult) { - _, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"os-force_delete": ""}, nil, nil) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions/results.go deleted file mode 100644 index 5cadd360f20..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions/results.go +++ /dev/null @@ -1,191 +0,0 @@ -package volumeactions - -import ( - "encoding/json" - "time" - - "github.com/gophercloud/gophercloud" -) - -// AttachResult contains the response body and error from an Attach request. -type AttachResult struct { - gophercloud.ErrResult -} - -// BeginDetachingResult contains the response body and error from a BeginDetach -// request. -type BeginDetachingResult struct { - gophercloud.ErrResult -} - -// DetachResult contains the response body and error from a Detach request. -type DetachResult struct { - gophercloud.ErrResult -} - -// UploadImageResult contains the response body and error from an UploadImage -// request. -type UploadImageResult struct { - gophercloud.Result -} - -// ReserveResult contains the response body and error from a Reserve request. -type ReserveResult struct { - gophercloud.ErrResult -} - -// UnreserveResult contains the response body and error from an Unreserve -// request. -type UnreserveResult struct { - gophercloud.ErrResult -} - -// TerminateConnectionResult contains the response body and error from a -// TerminateConnection request. -type TerminateConnectionResult struct { - gophercloud.ErrResult -} - -// InitializeConnectionResult contains the response body and error from an -// InitializeConnection request. -type InitializeConnectionResult struct { - gophercloud.Result -} - -// ExtendSizeResult contains the response body and error from an ExtendSize request. -type ExtendSizeResult struct { - gophercloud.ErrResult -} - -// Extract will get the connection information out of the -// InitializeConnectionResult object. -// -// This will be a generic map[string]interface{} and the results will be -// dependent on the type of connection made. -func (r InitializeConnectionResult) Extract() (map[string]interface{}, error) { - var s struct { - ConnectionInfo map[string]interface{} `json:"connection_info"` - } - err := r.ExtractInto(&s) - return s.ConnectionInfo, err -} - -// ImageVolumeType contains volume type information obtained from UploadImage -// action. -type ImageVolumeType struct { - // The ID of a volume type. - ID string `json:"id"` - - // Human-readable display name for the volume type. - Name string `json:"name"` - - // Human-readable description for the volume type. - Description string `json:"display_description"` - - // Flag for public access. - IsPublic bool `json:"is_public"` - - // Extra specifications for volume type. - ExtraSpecs map[string]interface{} `json:"extra_specs"` - - // ID of quality of service specs. - QosSpecsID string `json:"qos_specs_id"` - - // Flag for deletion status of volume type. - Deleted bool `json:"deleted"` - - // The date when volume type was deleted. - DeletedAt time.Time `json:"-"` - - // The date when volume type was created. - CreatedAt time.Time `json:"-"` - - // The date when this volume was last updated. - UpdatedAt time.Time `json:"-"` -} - -func (r *ImageVolumeType) UnmarshalJSON(b []byte) error { - type tmp ImageVolumeType - var s struct { - tmp - CreatedAt gophercloud.JSONRFC3339MilliNoZ `json:"created_at"` - UpdatedAt gophercloud.JSONRFC3339MilliNoZ `json:"updated_at"` - DeletedAt gophercloud.JSONRFC3339MilliNoZ `json:"deleted_at"` - } - err := json.Unmarshal(b, &s) - if err != nil { - return err - } - *r = ImageVolumeType(s.tmp) - - r.CreatedAt = time.Time(s.CreatedAt) - r.UpdatedAt = time.Time(s.UpdatedAt) - r.DeletedAt = time.Time(s.DeletedAt) - - return err -} - -// VolumeImage contains information about volume uploaded to an image service. -type VolumeImage struct { - // The ID of a volume an image is created from. - VolumeID string `json:"id"` - - // Container format, may be bare, ofv, ova, etc. - ContainerFormat string `json:"container_format"` - - // Disk format, may be raw, qcow2, vhd, vdi, vmdk, etc. - DiskFormat string `json:"disk_format"` - - // Human-readable description for the volume. - Description string `json:"display_description"` - - // The ID of the created image. - ImageID string `json:"image_id"` - - // Human-readable display name for the image. - ImageName string `json:"image_name"` - - // Size of the volume in GB. - Size int `json:"size"` - - // Current status of the volume. - Status string `json:"status"` - - // The date when this volume was last updated. - UpdatedAt time.Time `json:"-"` - - // Volume type object of used volume. - VolumeType ImageVolumeType `json:"volume_type"` -} - -func (r *VolumeImage) UnmarshalJSON(b []byte) error { - type tmp VolumeImage - var s struct { - tmp - UpdatedAt gophercloud.JSONRFC3339MilliNoZ `json:"updated_at"` - } - err := json.Unmarshal(b, &s) - if err != nil { - return err - } - *r = VolumeImage(s.tmp) - - r.UpdatedAt = time.Time(s.UpdatedAt) - - return err -} - -// Extract will get an object with info about the uploaded image out of the -// UploadImageResult object. -func (r UploadImageResult) Extract() (VolumeImage, error) { - var s struct { - VolumeImage VolumeImage `json:"os-volume_upload_image"` - } - err := r.ExtractInto(&s) - return s.VolumeImage, err -} - -// ForceDeleteResult contains the response body and error from a ForceDelete request. -type ForceDeleteResult struct { - gophercloud.ErrResult -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions/urls.go deleted file mode 100644 index 20486ed7194..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions/urls.go +++ /dev/null @@ -1,7 +0,0 @@ -package volumeactions - -import "github.com/gophercloud/gophercloud" - -func actionURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL("volumes", id, "action") -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/doc.go deleted file mode 100644 index 307b8b12d2f..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// 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/v1/volumes/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/requests.go deleted file mode 100644 index 1da94238b9c..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/requests.go +++ /dev/null @@ -1,172 +0,0 @@ -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 { - Size int `json:"size" required:"true"` - AvailabilityZone string `json:"availability_zone,omitempty"` - Description string `json:"display_description,omitempty"` - Metadata map[string]string `json:"metadata,omitempty"` - Name string `json:"display_name,omitempty"` - SnapshotID string `json:"snapshot_id,omitempty"` - SourceVolID string `json:"source_volid,omitempty"` - ImageID string `json:"imageRef,omitempty"` - 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{200, 201}, - }) - 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:"display_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:"display_name,omitempty"` - Description *string `json:"display_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 := "" - - listOpts := ListOpts{ - Name: name, - } - - pages, err := List(client, listOpts).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/v1/volumes/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/results.go deleted file mode 100644 index 7f68d148639..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/results.go +++ /dev/null @@ -1,109 +0,0 @@ -package volumes - -import ( - "encoding/json" - "time" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// Volume contains all the information associated with an OpenStack Volume. -type Volume struct { - // Current status of the volume. - Status string `json:"status"` - // Human-readable display name for the volume. - Name string `json:"display_name"` - // Instances onto which the volume is attached. - Attachments []map[string]interface{} `json:"attachments"` - // This parameter is no longer used. - AvailabilityZone string `json:"availability_zone"` - // Indicates whether this is a bootable volume. - Bootable string `json:"bootable"` - // The date when this volume was created. - CreatedAt time.Time `json:"-"` - // Human-readable description for the volume. - Description string `json:"display_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"` - // Unique identifier for the volume. - ID string `json:"id"` - // Size of the volume in GB. - Size int `json:"size"` -} - -func (r *Volume) UnmarshalJSON(b []byte) error { - type tmp Volume - var s struct { - tmp - CreatedAt gophercloud.JSONRFC3339MilliNoZ `json:"created_at"` - } - err := json.Unmarshal(b, &s) - if err != nil { - return err - } - *r = Volume(s.tmp) - - r.CreatedAt = time.Time(s.CreatedAt) - - return err -} - -// 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 -} - -// DeleteResult contains the response body and error from a Delete request. -type DeleteResult struct { - gophercloud.ErrResult -} - -// 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 VolumePage 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 struct { - Volumes []Volume `json:"volumes"` - } - err := (r.(VolumePage)).ExtractInto(&s) - return s.Volumes, err -} - -// UpdateResult contains the response body and error from an Update request. -type UpdateResult struct { - commonResult -} - -type commonResult struct { - gophercloud.Result -} - -// Extract will get the Volume object out of the commonResult object. -func (r commonResult) Extract() (*Volume, error) { - var s struct { - Volume *Volume `json:"volume"` - } - err := r.ExtractInto(&s) - return s.Volume, err -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/urls.go deleted file mode 100644 index 8a00f97e98c..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/urls.go +++ /dev/null @@ -1,23 +0,0 @@ -package volumes - -import "github.com/gophercloud/gophercloud" - -func createURL(c *gophercloud.ServiceClient) string { - return c.ServiceURL("volumes") -} - -func listURL(c *gophercloud.ServiceClient) string { - return createURL(c) -} - -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/v1/volumes/util.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/util.go deleted file mode 100644 index e86c1b4b4ee..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/util.go +++ /dev/null @@ -1,22 +0,0 @@ -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/blockstorage/v2/volumes/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/doc.go deleted file mode 100644 index 307b8b12d2f..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// 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/v2/volumes/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/requests.go deleted file mode 100644 index c27ddbf67c3..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/requests.go +++ /dev/null @@ -1,235 +0,0 @@ -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 -} - -// DeleteOptsBuilder allows extensions to add additional parameters to the -// Delete request. -type DeleteOptsBuilder interface { - ToVolumeDeleteQuery() (string, error) -} - -// DeleteOpts contains options for deleting a Volume. This object is passed to -// the volumes.Delete function. -type DeleteOpts struct { - // Delete all snapshots of this volume as well. - Cascade bool `q:"cascade"` -} - -// ToLoadBalancerDeleteQuery formats a DeleteOpts into a query string. -func (opts DeleteOpts) ToVolumeDeleteQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - return q.String(), err -} - -// Delete will delete the existing Volume with the provided ID. -func Delete(client *gophercloud.ServiceClient, id string, opts DeleteOptsBuilder) (r DeleteResult) { - url := deleteURL(client, id) - if opts != nil { - query, err := opts.ToVolumeDeleteQuery() - if err != nil { - r.Err = err - return - } - url += query - } - _, r.Err = client.Delete(url, 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 { - // AllTenants will retrieve volumes of all tenants/projects. - AllTenants bool `q:"all_tenants"` - - // Metadata will filter results based on specified metadata. - Metadata map[string]string `q:"metadata"` - - // Name will filter by the specified volume name. - Name string `q:"name"` - - // Status will filter by the specified status. - Status string `q:"status"` - - // TenantID will filter by a specific tenant/project ID. - // Setting AllTenants is required for this. - TenantID string `q:"project_id"` - - // Comma-separated list of sort keys and optional sort directions in the - // form of [:]. - Sort string `q:"sort"` - - // Requests a page size of items. - Limit int `q:"limit"` - - // Used in conjunction with limit to return a slice of items. - Offset int `q:"offset"` - - // The ID of the last-seen item. - Marker string `q:"marker"` -} - -// 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.LinkedPageBase{PageResult: 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 := "" - - listOpts := ListOpts{ - Name: name, - } - - pages, err := List(client, listOpts).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/v2/volumes/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/results.go deleted file mode 100644 index 96572b01b45..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/results.go +++ /dev/null @@ -1,167 +0,0 @@ -package volumes - -import ( - "encoding/json" - "time" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -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"` -} - -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"` -} - -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.LinkedPageBase -} - -// IsEmpty returns true if a ListResult contains no Volumes. -func (r VolumePage) IsEmpty() (bool, error) { - volumes, err := ExtractVolumes(r) - return len(volumes) == 0, err -} - -// NextPageURL uses the response's embedded link reference to navigate to the -// next page of results. -func (r VolumePage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"volumes_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// 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 -} - -func (r commonResult) ExtractInto(v interface{}) error { - return r.Result.ExtractIntoStructPtr(v, "volume") -} - -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/v2/volumes/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/urls.go deleted file mode 100644 index 170724905ab..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/urls.go +++ /dev/null @@ -1,23 +0,0 @@ -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/v2/volumes/util.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/util.go deleted file mode 100644 index e86c1b4b4ee..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/util.go +++ /dev/null @@ -1,22 +0,0 @@ -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/blockstorage/v3/volumes/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/doc.go deleted file mode 100644 index 307b8b12d2f..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// 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 deleted file mode 100644 index 25f70b27c1a..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/requests.go +++ /dev/null @@ -1,237 +0,0 @@ -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"` - // Multiattach denotes if the volume is multi-attach capable. - Multiattach bool `json:"multiattach,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 -} - -// DeleteOptsBuilder allows extensions to add additional parameters to the -// Delete request. -type DeleteOptsBuilder interface { - ToVolumeDeleteQuery() (string, error) -} - -// DeleteOpts contains options for deleting a Volume. This object is passed to -// the volumes.Delete function. -type DeleteOpts struct { - // Delete all snapshots of this volume as well. - Cascade bool `q:"cascade"` -} - -// ToLoadBalancerDeleteQuery formats a DeleteOpts into a query string. -func (opts DeleteOpts) ToVolumeDeleteQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - return q.String(), err -} - -// Delete will delete the existing Volume with the provided ID. -func Delete(client *gophercloud.ServiceClient, id string, opts DeleteOptsBuilder) (r DeleteResult) { - url := deleteURL(client, id) - if opts != nil { - query, err := opts.ToVolumeDeleteQuery() - if err != nil { - r.Err = err - return - } - url += query - } - _, r.Err = client.Delete(url, 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 { - // AllTenants will retrieve volumes of all tenants/projects. - AllTenants bool `q:"all_tenants"` - - // Metadata will filter results based on specified metadata. - Metadata map[string]string `q:"metadata"` - - // Name will filter by the specified volume name. - Name string `q:"name"` - - // Status will filter by the specified status. - Status string `q:"status"` - - // TenantID will filter by a specific tenant/project ID. - // Setting AllTenants is required for this. - TenantID string `q:"project_id"` - - // Comma-separated list of sort keys and optional sort directions in the - // form of [:]. - Sort string `q:"sort"` - - // Requests a page size of items. - Limit int `q:"limit"` - - // Used in conjunction with limit to return a slice of items. - Offset int `q:"offset"` - - // The ID of the last-seen item. - Marker string `q:"marker"` -} - -// 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.LinkedPageBase{PageResult: 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 := "" - - listOpts := ListOpts{ - Name: name, - } - - pages, err := List(client, listOpts).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 deleted file mode 100644 index 3a33b5864bb..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/results.go +++ /dev/null @@ -1,172 +0,0 @@ -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"` - // Image metadata entries, only included for volumes that were created from an image, or from a snapshot of a volume originally created from an image. - VolumeImageMetadata map[string]string `json:"volume_image_metadata"` -} - -// 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.LinkedPageBase -} - -// IsEmpty returns true if a ListResult contains no Volumes. -func (r VolumePage) IsEmpty() (bool, error) { - volumes, err := ExtractVolumes(r) - return len(volumes) == 0, err -} - -func (page VolumePage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"volumes_links"` - } - err := page.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// 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 deleted file mode 100644 index 170724905ab..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/urls.go +++ /dev/null @@ -1,23 +0,0 @@ -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 deleted file mode 100644 index e86c1b4b4ee..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes/util.go +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index 50f239711e7..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/client.go +++ /dev/null @@ -1,438 +0,0 @@ -package openstack - -import ( - "fmt" - "reflect" - - "github.com/gophercloud/gophercloud" - tokens2 "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens" - tokens3 "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens" - "github.com/gophercloud/gophercloud/openstack/utils" -) - -const ( - // v2 represents Keystone v2. - // It should never increase beyond 2.0. - v2 = "v2.0" - - // v3 represents Keystone v3. - // The version can be anything from v3 to v3.x. - v3 = "v3" -) - -/* -NewClient prepares an unauthenticated ProviderClient instance. -Most users will probably prefer using the AuthenticatedClient function -instead. - -This is useful if you wish to explicitly control the version of the identity -service that's used for authentication explicitly, for example. - -A basic example of using this would be: - - ao, err := openstack.AuthOptionsFromEnv() - provider, err := openstack.NewClient(ao.IdentityEndpoint) - client, err := openstack.NewIdentityV3(provider, gophercloud.EndpointOpts{}) -*/ -func NewClient(endpoint string) (*gophercloud.ProviderClient, error) { - base, err := utils.BaseEndpoint(endpoint) - if err != nil { - return nil, err - } - - endpoint = gophercloud.NormalizeURL(endpoint) - base = gophercloud.NormalizeURL(base) - - p := new(gophercloud.ProviderClient) - p.IdentityBase = base - p.IdentityEndpoint = endpoint - p.UseTokenLock() - - return p, nil -} - -/* -AuthenticatedClient logs in to an OpenStack cloud found at the identity endpoint -specified by the options, acquires a token, and returns a Provider Client -instance that's ready to operate. - -If the full path to a versioned identity endpoint was specified (example: -http://example.com:5000/v3), that path will be used as the endpoint to query. - -If a versionless endpoint was specified (example: http://example.com:5000/), -the endpoint will be queried to determine which versions of the identity service -are available, then chooses the most recent or most supported version. - -Example: - - ao, err := openstack.AuthOptionsFromEnv() - provider, err := openstack.AuthenticatedClient(ao) - client, err := openstack.NewNetworkV2(client, gophercloud.EndpointOpts{ - Region: os.Getenv("OS_REGION_NAME"), - }) -*/ -func AuthenticatedClient(options gophercloud.AuthOptions) (*gophercloud.ProviderClient, error) { - client, err := NewClient(options.IdentityEndpoint) - if err != nil { - return nil, err - } - - err = Authenticate(client, options) - if err != nil { - return nil, err - } - return client, nil -} - -// Authenticate or re-authenticate against the most recent identity service -// supported at the provided endpoint. -func Authenticate(client *gophercloud.ProviderClient, options gophercloud.AuthOptions) error { - versions := []*utils.Version{ - {ID: v2, Priority: 20, Suffix: "/v2.0/"}, - {ID: v3, Priority: 30, Suffix: "/v3/"}, - } - - chosen, endpoint, err := utils.ChooseVersion(client, versions) - if err != nil { - return err - } - - switch chosen.ID { - case v2: - return v2auth(client, endpoint, options, gophercloud.EndpointOpts{}) - case v3: - return v3auth(client, endpoint, &options, gophercloud.EndpointOpts{}) - default: - // The switch statement must be out of date from the versions list. - return fmt.Errorf("Unrecognized identity version: %s", chosen.ID) - } -} - -// AuthenticateV2 explicitly authenticates against the identity v2 endpoint. -func AuthenticateV2(client *gophercloud.ProviderClient, options gophercloud.AuthOptions, eo gophercloud.EndpointOpts) error { - return v2auth(client, "", options, eo) -} - -func v2auth(client *gophercloud.ProviderClient, endpoint string, options gophercloud.AuthOptions, eo gophercloud.EndpointOpts) error { - v2Client, err := NewIdentityV2(client, eo) - if err != nil { - return err - } - - if endpoint != "" { - v2Client.Endpoint = endpoint - } - - v2Opts := tokens2.AuthOptions{ - IdentityEndpoint: options.IdentityEndpoint, - Username: options.Username, - Password: options.Password, - TenantID: options.TenantID, - TenantName: options.TenantName, - AllowReauth: options.AllowReauth, - TokenID: options.TokenID, - } - - result := tokens2.Create(v2Client, v2Opts) - - err = client.SetTokenAndAuthResult(result) - if err != nil { - return err - } - - catalog, err := result.ExtractServiceCatalog() - if err != nil { - return err - } - - if options.AllowReauth { - // here we're creating a throw-away client (tac). it's a copy of the user's provider client, but - // with the token and reauth func zeroed out. combined with setting `AllowReauth` to `false`, - // this should retry authentication only once - tac := *client - tac.SetThrowaway(true) - tac.ReauthFunc = nil - tac.SetTokenAndAuthResult(nil) - tao := options - tao.AllowReauth = false - client.ReauthFunc = func() error { - err := v2auth(&tac, endpoint, tao, eo) - if err != nil { - return err - } - client.CopyTokenFrom(&tac) - return nil - } - } - client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) { - return V2EndpointURL(catalog, opts) - } - - return nil -} - -// AuthenticateV3 explicitly authenticates against the identity v3 service. -func AuthenticateV3(client *gophercloud.ProviderClient, options tokens3.AuthOptionsBuilder, eo gophercloud.EndpointOpts) error { - return v3auth(client, "", options, eo) -} - -func v3auth(client *gophercloud.ProviderClient, endpoint string, opts tokens3.AuthOptionsBuilder, eo gophercloud.EndpointOpts) error { - // Override the generated service endpoint with the one returned by the version endpoint. - v3Client, err := NewIdentityV3(client, eo) - if err != nil { - return err - } - - if endpoint != "" { - v3Client.Endpoint = endpoint - } - - result := tokens3.Create(v3Client, opts) - - err = client.SetTokenAndAuthResult(result) - if err != nil { - return err - } - - catalog, err := result.ExtractServiceCatalog() - if err != nil { - return err - } - - if opts.CanReauth() { - // here we're creating a throw-away client (tac). it's a copy of the user's provider client, but - // with the token and reauth func zeroed out. combined with setting `AllowReauth` to `false`, - // this should retry authentication only once - tac := *client - tac.SetThrowaway(true) - tac.ReauthFunc = nil - tac.SetTokenAndAuthResult(nil) - var tao tokens3.AuthOptionsBuilder - switch ot := opts.(type) { - case *gophercloud.AuthOptions: - o := *ot - o.AllowReauth = false - tao = &o - case *tokens3.AuthOptions: - o := *ot - o.AllowReauth = false - tao = &o - default: - tao = opts - } - client.ReauthFunc = func() error { - err := v3auth(&tac, endpoint, tao, eo) - if err != nil { - return err - } - client.CopyTokenFrom(&tac) - return nil - } - } - client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) { - return V3EndpointURL(catalog, opts) - } - - return nil -} - -// NewIdentityV2 creates a ServiceClient that may be used to interact with the -// v2 identity service. -func NewIdentityV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - endpoint := client.IdentityBase + "v2.0/" - clientType := "identity" - var err error - if !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) { - eo.ApplyDefaults(clientType) - endpoint, err = client.EndpointLocator(eo) - if err != nil { - return nil, err - } - } - - return &gophercloud.ServiceClient{ - ProviderClient: client, - Endpoint: endpoint, - Type: clientType, - }, nil -} - -// NewIdentityV3 creates a ServiceClient that may be used to access the v3 -// identity service. -func NewIdentityV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - endpoint := client.IdentityBase + "v3/" - clientType := "identity" - var err error - if !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) { - eo.ApplyDefaults(clientType) - endpoint, err = client.EndpointLocator(eo) - if err != nil { - return nil, err - } - } - - // Ensure endpoint still has a suffix of v3. - // This is because EndpointLocator might have found a versionless - // endpoint or the published endpoint is still /v2.0. In both - // cases, we need to fix the endpoint to point to /v3. - base, err := utils.BaseEndpoint(endpoint) - if err != nil { - return nil, err - } - - base = gophercloud.NormalizeURL(base) - - endpoint = base + "v3/" - - return &gophercloud.ServiceClient{ - ProviderClient: client, - Endpoint: endpoint, - Type: clientType, - }, nil -} - -func initClientOpts(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts, clientType string) (*gophercloud.ServiceClient, error) { - sc := new(gophercloud.ServiceClient) - eo.ApplyDefaults(clientType) - url, err := client.EndpointLocator(eo) - if err != nil { - return sc, err - } - sc.ProviderClient = client - sc.Endpoint = url - sc.Type = clientType - return sc, nil -} - -// NewBareMetalV1 creates a ServiceClient that may be used with the v1 -// bare metal package. -func NewBareMetalV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "baremetal") -} - -// NewBareMetalIntrospectionV1 creates a ServiceClient that may be used with the v1 -// bare metal introspection package. -func NewBareMetalIntrospectionV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "baremetal-inspector") -} - -// NewObjectStorageV1 creates a ServiceClient that may be used with the v1 -// object storage package. -func NewObjectStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "object-store") -} - -// NewComputeV2 creates a ServiceClient that may be used with the v2 compute -// package. -func NewComputeV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "compute") -} - -// NewNetworkV2 creates a ServiceClient that may be used with the v2 network -// package. -func NewNetworkV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - sc, err := initClientOpts(client, eo, "network") - sc.ResourceBase = sc.Endpoint + "v2.0/" - return sc, err -} - -// NewBlockStorageV1 creates a ServiceClient that may be used to access the v1 -// block storage service. -func NewBlockStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "volume") -} - -// NewBlockStorageV2 creates a ServiceClient that may be used to access the v2 -// block storage service. -func NewBlockStorageV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "volumev2") -} - -// 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") -} - -// NewCDNV1 creates a ServiceClient that may be used to access the OpenStack v1 -// CDN service. -func NewCDNV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "cdn") -} - -// NewOrchestrationV1 creates a ServiceClient that may be used to access the v1 -// orchestration service. -func NewOrchestrationV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "orchestration") -} - -// NewDBV1 creates a ServiceClient that may be used to access the v1 DB service. -func NewDBV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "database") -} - -// NewDNSV2 creates a ServiceClient that may be used to access the v2 DNS -// service. -func NewDNSV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - sc, err := initClientOpts(client, eo, "dns") - sc.ResourceBase = sc.Endpoint + "v2/" - return sc, err -} - -// NewImageServiceV2 creates a ServiceClient that may be used to access the v2 -// image service. -func NewImageServiceV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - sc, err := initClientOpts(client, eo, "image") - sc.ResourceBase = sc.Endpoint + "v2/" - return sc, err -} - -// NewLoadBalancerV2 creates a ServiceClient that may be used to access the v2 -// load balancer service. -func NewLoadBalancerV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - sc, err := initClientOpts(client, eo, "load-balancer") - sc.ResourceBase = sc.Endpoint + "v2.0/" - return sc, err -} - -// NewClusteringV1 creates a ServiceClient that may be used with the v1 clustering -// package. -func NewClusteringV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "clustering") -} - -// NewMessagingV2 creates a ServiceClient that may be used with the v2 messaging -// service. -func NewMessagingV2(client *gophercloud.ProviderClient, clientID string, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - sc, err := initClientOpts(client, eo, "messaging") - sc.MoreHeaders = map[string]string{"Client-ID": clientID} - return sc, err -} - -// NewContainerV1 creates a ServiceClient that may be used with v1 container package -func NewContainerV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "container") -} - -// NewKeyManagerV1 creates a ServiceClient that may be used with the v1 key -// manager service. -func NewKeyManagerV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - sc, err := initClientOpts(client, eo, "key-manager") - sc.ResourceBase = sc.Endpoint + "v1/" - return sc, err -} - -// NewContainerInfraV1 creates a ServiceClient that may be used with the v1 container infra management -// package. -func NewContainerInfraV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "container-infra") -} - -// NewWorkflowV2 creates a ServiceClient that may be used with the v2 workflow management package. -func NewWorkflowV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "workflowv2") -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/common/extensions/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/common/extensions/doc.go deleted file mode 100644 index 5510f265395..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/common/extensions/doc.go +++ /dev/null @@ -1,52 +0,0 @@ -/* -Package extensions provides information and interaction with the different -extensions available for an OpenStack service. - -The purpose of OpenStack API extensions is to: - -- Introduce new features in the API without requiring a version change. -- Introduce vendor-specific niche functionality. -- Act as a proving ground for experimental functionalities that might be -included in a future version of the API. - -Extensions usually have tags that prevent conflicts with other extensions that -define attributes or resources with the same names, and with core resources and -attributes. Because an extension might not be supported by all plug-ins, its -availability varies with deployments and the specific plug-in. - -The results of this package vary depending on the type of Service Client used. -In the following examples, note how the only difference is the creation of the -Service Client. - -Example of Retrieving Compute Extensions - - ao, err := openstack.AuthOptionsFromEnv() - provider, err := openstack.AuthenticatedClient(ao) - computeClient, err := openstack.NewComputeV2(provider, gophercloud.EndpointOpts{ - Region: os.Getenv("OS_REGION_NAME"), - }) - - allPages, err := extensions.List(computeClient).Allpages() - allExtensions, err := extensions.ExtractExtensions(allPages) - - for _, extension := range allExtensions{ - fmt.Println("%+v\n", extension) - } - - -Example of Retrieving Network Extensions - - ao, err := openstack.AuthOptionsFromEnv() - provider, err := openstack.AuthenticatedClient(ao) - networkClient, err := openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{ - Region: os.Getenv("OS_REGION_NAME"), - }) - - allPages, err := extensions.List(networkClient).Allpages() - allExtensions, err := extensions.ExtractExtensions(allPages) - - for _, extension := range allExtensions{ - fmt.Println("%+v\n", extension) - } -*/ -package extensions diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/common/extensions/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/common/extensions/requests.go deleted file mode 100644 index 46b7d60cd69..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/common/extensions/requests.go +++ /dev/null @@ -1,20 +0,0 @@ -package extensions - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// Get retrieves information for a specific extension using its alias. -func Get(c *gophercloud.ServiceClient, alias string) (r GetResult) { - _, r.Err = c.Get(ExtensionURL(c, alias), &r.Body, nil) - return -} - -// List returns a Pager which allows you to iterate over the full collection of extensions. -// It does not accept query parameters. -func List(c *gophercloud.ServiceClient) pagination.Pager { - return pagination.NewPager(c, ListExtensionURL(c), func(r pagination.PageResult) pagination.Page { - return ExtensionPage{pagination.SinglePageBase(r)} - }) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/common/extensions/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/common/extensions/results.go deleted file mode 100644 index 8a26edd1c59..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/common/extensions/results.go +++ /dev/null @@ -1,53 +0,0 @@ -package extensions - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// GetResult temporarily stores the result of a Get call. -// Use its Extract() method to interpret it as an Extension. -type GetResult struct { - gophercloud.Result -} - -// Extract interprets a GetResult as an Extension. -func (r GetResult) Extract() (*Extension, error) { - var s struct { - Extension *Extension `json:"extension"` - } - err := r.ExtractInto(&s) - return s.Extension, err -} - -// Extension is a struct that represents an OpenStack extension. -type Extension struct { - Updated string `json:"updated"` - Name string `json:"name"` - Links []interface{} `json:"links"` - Namespace string `json:"namespace"` - Alias string `json:"alias"` - Description string `json:"description"` -} - -// ExtensionPage is the page returned by a pager when traversing over a collection of extensions. -type ExtensionPage struct { - pagination.SinglePageBase -} - -// IsEmpty checks whether an ExtensionPage struct is empty. -func (r ExtensionPage) IsEmpty() (bool, error) { - is, err := ExtractExtensions(r) - return len(is) == 0, err -} - -// ExtractExtensions accepts a Page struct, specifically an ExtensionPage -// struct, and extracts the elements into a slice of Extension structs. -// In other words, a generic collection is mapped into a relevant slice. -func ExtractExtensions(r pagination.Page) ([]Extension, error) { - var s struct { - Extensions []Extension `json:"extensions"` - } - err := (r.(ExtensionPage)).ExtractInto(&s) - return s.Extensions, err -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/common/extensions/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/common/extensions/urls.go deleted file mode 100644 index eaf38b2d191..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/common/extensions/urls.go +++ /dev/null @@ -1,13 +0,0 @@ -package extensions - -import "github.com/gophercloud/gophercloud" - -// ExtensionURL generates the URL for an extension resource by name. -func ExtensionURL(c *gophercloud.ServiceClient, name string) string { - return c.ServiceURL("extensions", name) -} - -// ListExtensionURL generates the URL for the extensions resource collection. -func ListExtensionURL(c *gophercloud.ServiceClient) string { - return c.ServiceURL("extensions") -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces/doc.go deleted file mode 100644 index 3653122bf30..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces/doc.go +++ /dev/null @@ -1,52 +0,0 @@ -/* -Package attachinterfaces provides the ability to retrieve and manage network -interfaces through Nova. - -Example of Listing a Server's Interfaces - - serverID := "b07e7a3b-d951-4efc-a4f9-ac9f001afb7f" - allPages, err := attachinterfaces.List(computeClient, serverID).AllPages() - if err != nil { - panic(err) - } - - allInterfaces, err := attachinterfaces.ExtractInterfaces(allPages) - if err != nil { - panic(err) - } - - for _, interface := range allInterfaces { - fmt.Printf("%+v\n", interface) - } - -Example to Get a Server's Interface - - portID = "0dde1598-b374-474e-986f-5b8dd1df1d4e" - serverID := "b07e7a3b-d951-4efc-a4f9-ac9f001afb7f" - interface, err := attachinterfaces.Get(computeClient, serverID, portID).Extract() - if err != nil { - panic(err) - } - -Example to Create a new Interface attachment on the Server - - networkID := "8a5fe506-7e9f-4091-899b-96336909d93c" - serverID := "b07e7a3b-d951-4efc-a4f9-ac9f001afb7f" - attachOpts := attachinterfaces.CreateOpts{ - NetworkID: networkID, - } - interface, err := attachinterfaces.Create(computeClient, serverID, attachOpts).Extract() - if err != nil { - panic(err) - } - -Example to Delete an Interface attachment from the Server - - portID = "0dde1598-b374-474e-986f-5b8dd1df1d4e" - serverID := "b07e7a3b-d951-4efc-a4f9-ac9f001afb7f" - err := attachinterfaces.Delete(computeClient, serverID, portID).ExtractErr() - if err != nil { - panic(err) - } -*/ -package attachinterfaces diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces/requests.go deleted file mode 100644 index 874f7a61ec4..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces/requests.go +++ /dev/null @@ -1,72 +0,0 @@ -package attachinterfaces - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// List makes a request against the nova API to list the server's interfaces. -func List(client *gophercloud.ServiceClient, serverID string) pagination.Pager { - return pagination.NewPager(client, listInterfaceURL(client, serverID), func(r pagination.PageResult) pagination.Page { - return InterfacePage{pagination.SinglePageBase(r)} - }) -} - -// Get requests details on a single interface attachment by the server and port IDs. -func Get(client *gophercloud.ServiceClient, serverID, portID string) (r GetResult) { - _, r.Err = client.Get(getInterfaceURL(client, serverID, portID), &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// CreateOptsBuilder allows extensions to add additional parameters to the -// Create request. -type CreateOptsBuilder interface { - ToAttachInterfacesCreateMap() (map[string]interface{}, error) -} - -// CreateOpts specifies parameters of a new interface attachment. -type CreateOpts struct { - // PortID is the ID of the port for which you want to create an interface. - // The NetworkID and PortID parameters are mutually exclusive. - // If you do not specify the PortID parameter, the OpenStack Networking API - // v2.0 allocates a port and creates an interface for it on the network. - PortID string `json:"port_id,omitempty"` - - // NetworkID is the ID of the network for which you want to create an interface. - // The NetworkID and PortID parameters are mutually exclusive. - // If you do not specify the NetworkID parameter, the OpenStack Networking - // API v2.0 uses the network information cache that is associated with the instance. - NetworkID string `json:"net_id,omitempty"` - - // Slice of FixedIPs. If you request a specific FixedIP address without a - // NetworkID, the request returns a Bad Request (400) response code. - // Note: this uses the FixedIP struct, but only the IPAddress field can be used. - FixedIPs []FixedIP `json:"fixed_ips,omitempty"` -} - -// ToAttachInterfacesCreateMap constructs a request body from CreateOpts. -func (opts CreateOpts) ToAttachInterfacesCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "interfaceAttachment") -} - -// Create requests the creation of a new interface attachment on the server. -func Create(client *gophercloud.ServiceClient, serverID string, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToAttachInterfacesCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(createInterfaceURL(client, serverID), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// Delete makes a request against the nova API to detach a single interface from the server. -// It needs server and port IDs to make a such request. -func Delete(client *gophercloud.ServiceClient, serverID, portID string) (r DeleteResult) { - _, r.Err = client.Delete(deleteInterfaceURL(client, serverID, portID), nil) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces/results.go deleted file mode 100644 index 7d15e1ecb4b..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces/results.go +++ /dev/null @@ -1,80 +0,0 @@ -package attachinterfaces - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -type attachInterfaceResult struct { - gophercloud.Result -} - -// Extract interprets any attachInterfaceResult as an Interface, if possible. -func (r attachInterfaceResult) Extract() (*Interface, error) { - var s struct { - Interface *Interface `json:"interfaceAttachment"` - } - err := r.ExtractInto(&s) - return s.Interface, err -} - -// GetResult is the response from a Get operation. Call its Extract -// method to interpret it as an Interface. -type GetResult struct { - attachInterfaceResult -} - -// CreateResult is the response from a Create operation. Call its Extract -// method to interpret it as an Interface. -type CreateResult struct { - attachInterfaceResult -} - -// DeleteResult is the response from a Delete operation. Call its ExtractErr -// method to determine if the call succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} - -// FixedIP represents a Fixed IP Address. -// This struct is also used when creating an attachment, -// but it is not possible to specify a SubnetID. -type FixedIP struct { - SubnetID string `json:"subnet_id,omitempty"` - IPAddress string `json:"ip_address"` -} - -// Interface represents a network interface on a server. -type Interface struct { - PortState string `json:"port_state"` - FixedIPs []FixedIP `json:"fixed_ips"` - PortID string `json:"port_id"` - NetID string `json:"net_id"` - MACAddr string `json:"mac_addr"` -} - -// InterfacePage abstracts the raw results of making a List() request against -// the API. -// -// As OpenStack extensions may freely alter the response bodies of structures -// returned to the client, you may only safely access the data provided through -// the ExtractInterfaces call. -type InterfacePage struct { - pagination.SinglePageBase -} - -// IsEmpty returns true if an InterfacePage contains no interfaces. -func (r InterfacePage) IsEmpty() (bool, error) { - interfaces, err := ExtractInterfaces(r) - return len(interfaces) == 0, err -} - -// ExtractInterfaces interprets the results of a single page from a List() call, -// producing a slice of Interface structs. -func ExtractInterfaces(r pagination.Page) ([]Interface, error) { - var s struct { - Interfaces []Interface `json:"interfaceAttachments"` - } - err := (r.(InterfacePage)).ExtractInto(&s) - return s.Interfaces, err -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces/urls.go deleted file mode 100644 index 50292e8b5a5..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces/urls.go +++ /dev/null @@ -1,18 +0,0 @@ -package attachinterfaces - -import "github.com/gophercloud/gophercloud" - -func listInterfaceURL(client *gophercloud.ServiceClient, serverID string) string { - return client.ServiceURL("servers", serverID, "os-interface") -} - -func getInterfaceURL(client *gophercloud.ServiceClient, serverID, portID string) string { - return client.ServiceURL("servers", serverID, "os-interface", portID) -} - -func createInterfaceURL(client *gophercloud.ServiceClient, serverID string) string { - return client.ServiceURL("servers", serverID, "os-interface") -} -func deleteInterfaceURL(client *gophercloud.ServiceClient, serverID, portID string) string { - return client.ServiceURL("servers", serverID, "os-interface", portID) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/doc.go deleted file mode 100644 index 484eb20000c..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/doc.go +++ /dev/null @@ -1,30 +0,0 @@ -/* -Package volumeattach provides the ability to attach and detach volumes -from servers. - -Example to Attach a Volume - - serverID := "7ac8686c-de71-4acb-9600-ec18b1a1ed6d" - volumeID := "87463836-f0e2-4029-abf6-20c8892a3103" - - createOpts := volumeattach.CreateOpts{ - Device: "/dev/vdc", - VolumeID: volumeID, - } - - result, err := volumeattach.Create(computeClient, serverID, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to Detach a Volume - - serverID := "7ac8686c-de71-4acb-9600-ec18b1a1ed6d" - attachmentID := "ed081613-1c9b-4231-aa5e-ebfd4d87f983" - - err := volumeattach.Delete(computeClient, serverID, attachmentID).ExtractErr() - if err != nil { - panic(err) - } -*/ -package volumeattach diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/requests.go deleted file mode 100644 index 6a262c212e1..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/requests.go +++ /dev/null @@ -1,60 +0,0 @@ -package volumeattach - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// List returns a Pager that allows you to iterate over a collection of -// VolumeAttachments. -func List(client *gophercloud.ServiceClient, serverID string) pagination.Pager { - return pagination.NewPager(client, listURL(client, serverID), func(r pagination.PageResult) pagination.Page { - return VolumeAttachmentPage{pagination.SinglePageBase(r)} - }) -} - -// CreateOptsBuilder allows extensions to add parameters to the Create request. -type CreateOptsBuilder interface { - ToVolumeAttachmentCreateMap() (map[string]interface{}, error) -} - -// CreateOpts specifies volume attachment creation or import parameters. -type CreateOpts struct { - // Device is the device that the volume will attach to the instance as. - // Omit for "auto". - Device string `json:"device,omitempty"` - - // VolumeID is the ID of the volume to attach to the instance. - VolumeID string `json:"volumeId" required:"true"` -} - -// ToVolumeAttachmentCreateMap constructs a request body from CreateOpts. -func (opts CreateOpts) ToVolumeAttachmentCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "volumeAttachment") -} - -// Create requests the creation of a new volume attachment on the server. -func Create(client *gophercloud.ServiceClient, serverID string, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToVolumeAttachmentCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(createURL(client, serverID), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// Get returns public data about a previously created VolumeAttachment. -func Get(client *gophercloud.ServiceClient, serverID, attachmentID string) (r GetResult) { - _, r.Err = client.Get(getURL(client, serverID, attachmentID), &r.Body, nil) - return -} - -// Delete requests the deletion of a previous stored VolumeAttachment from -// the server. -func Delete(client *gophercloud.ServiceClient, serverID, attachmentID string) (r DeleteResult) { - _, r.Err = client.Delete(deleteURL(client, serverID, attachmentID), nil) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/results.go deleted file mode 100644 index 56d50347291..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/results.go +++ /dev/null @@ -1,77 +0,0 @@ -package volumeattach - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// VolumeAttachment contains attachment information between a volume -// and server. -type VolumeAttachment struct { - // ID is a unique id of the attachment. - ID string `json:"id"` - - // Device is what device the volume is attached as. - Device string `json:"device"` - - // VolumeID is the ID of the attached volume. - VolumeID string `json:"volumeId"` - - // ServerID is the ID of the instance that has the volume attached. - ServerID string `json:"serverId"` -} - -// VolumeAttachmentPage stores a single page all of VolumeAttachment -// results from a List call. -type VolumeAttachmentPage struct { - pagination.SinglePageBase -} - -// IsEmpty determines whether or not a VolumeAttachmentPage is empty. -func (page VolumeAttachmentPage) IsEmpty() (bool, error) { - va, err := ExtractVolumeAttachments(page) - return len(va) == 0, err -} - -// ExtractVolumeAttachments interprets a page of results as a slice of -// VolumeAttachment. -func ExtractVolumeAttachments(r pagination.Page) ([]VolumeAttachment, error) { - var s struct { - VolumeAttachments []VolumeAttachment `json:"volumeAttachments"` - } - err := (r.(VolumeAttachmentPage)).ExtractInto(&s) - return s.VolumeAttachments, err -} - -// VolumeAttachmentResult is the result from a volume attachment operation. -type VolumeAttachmentResult struct { - gophercloud.Result -} - -// Extract is a method that attempts to interpret any VolumeAttachment resource -// response as a VolumeAttachment struct. -func (r VolumeAttachmentResult) Extract() (*VolumeAttachment, error) { - var s struct { - VolumeAttachment *VolumeAttachment `json:"volumeAttachment"` - } - err := r.ExtractInto(&s) - return s.VolumeAttachment, err -} - -// CreateResult is the response from a Create operation. Call its Extract method -// to interpret it as a VolumeAttachment. -type CreateResult struct { - VolumeAttachmentResult -} - -// GetResult is the response from a Get operation. Call its Extract method to -// interpret it as a VolumeAttachment. -type GetResult struct { - VolumeAttachmentResult -} - -// DeleteResult is the response from a Delete operation. Call its ExtractErr -// method to determine if the call succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/urls.go deleted file mode 100644 index 083f8dc4554..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/urls.go +++ /dev/null @@ -1,25 +0,0 @@ -package volumeattach - -import "github.com/gophercloud/gophercloud" - -const resourcePath = "os-volume_attachments" - -func resourceURL(c *gophercloud.ServiceClient, serverID string) string { - return c.ServiceURL("servers", serverID, resourcePath) -} - -func listURL(c *gophercloud.ServiceClient, serverID string) string { - return resourceURL(c, serverID) -} - -func createURL(c *gophercloud.ServiceClient, serverID string) string { - return resourceURL(c, serverID) -} - -func getURL(c *gophercloud.ServiceClient, serverID, aID string) string { - return c.ServiceURL("servers", serverID, resourcePath, aID) -} - -func deleteURL(c *gophercloud.ServiceClient, serverID, aID string) string { - return getURL(c, serverID, aID) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/doc.go deleted file mode 100644 index 34d8764fadb..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/doc.go +++ /dev/null @@ -1,137 +0,0 @@ -/* -Package flavors provides information and interaction with the flavor API -in the OpenStack Compute service. - -A flavor is an available hardware configuration for a server. Each flavor -has a unique combination of disk space, memory capacity and priority for CPU -time. - -Example to List Flavors - - listOpts := flavors.ListOpts{ - AccessType: flavors.PublicAccess, - } - - allPages, err := flavors.ListDetail(computeClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - allFlavors, err := flavors.ExtractFlavors(allPages) - if err != nil { - panic(err) - } - - for _, flavor := range allFlavors { - fmt.Printf("%+v\n", flavor) - } - -Example to Create a Flavor - - createOpts := flavors.CreateOpts{ - ID: "1", - Name: "m1.tiny", - Disk: gophercloud.IntToPointer(1), - RAM: 512, - VCPUs: 1, - RxTxFactor: 1.0, - } - - flavor, err := flavors.Create(computeClient, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to List Flavor Access - - flavorID := "e91758d6-a54a-4778-ad72-0c73a1cb695b" - - allPages, err := flavors.ListAccesses(computeClient, flavorID).AllPages() - if err != nil { - panic(err) - } - - allAccesses, err := flavors.ExtractAccesses(allPages) - if err != nil { - panic(err) - } - - for _, access := range allAccesses { - fmt.Printf("%+v", access) - } - -Example to Grant Access to a Flavor - - flavorID := "e91758d6-a54a-4778-ad72-0c73a1cb695b" - - accessOpts := flavors.AddAccessOpts{ - Tenant: "15153a0979884b59b0592248ef947921", - } - - accessList, err := flavors.AddAccess(computeClient, flavor.ID, accessOpts).Extract() - if err != nil { - panic(err) - } - -Example to Remove/Revoke Access to a Flavor - - flavorID := "e91758d6-a54a-4778-ad72-0c73a1cb695b" - - accessOpts := flavors.RemoveAccessOpts{ - Tenant: "15153a0979884b59b0592248ef947921", - } - - accessList, err := flavors.RemoveAccess(computeClient, flavor.ID, accessOpts).Extract() - if err != nil { - panic(err) - } - -Example to Create Extra Specs for a Flavor - - flavorID := "e91758d6-a54a-4778-ad72-0c73a1cb695b" - - createOpts := flavors.ExtraSpecsOpts{ - "hw:cpu_policy": "CPU-POLICY", - "hw:cpu_thread_policy": "CPU-THREAD-POLICY", - } - createdExtraSpecs, err := flavors.CreateExtraSpecs(computeClient, flavorID, createOpts).Extract() - if err != nil { - panic(err) - } - - fmt.Printf("%+v", createdExtraSpecs) - -Example to Get Extra Specs for a Flavor - - flavorID := "e91758d6-a54a-4778-ad72-0c73a1cb695b" - - extraSpecs, err := flavors.ListExtraSpecs(computeClient, flavorID).Extract() - if err != nil { - panic(err) - } - - fmt.Printf("%+v", extraSpecs) - -Example to Update Extra Specs for a Flavor - - flavorID := "e91758d6-a54a-4778-ad72-0c73a1cb695b" - - updateOpts := flavors.ExtraSpecsOpts{ - "hw:cpu_thread_policy": "CPU-THREAD-POLICY-UPDATED", - } - updatedExtraSpec, err := flavors.UpdateExtraSpec(computeClient, flavorID, updateOpts).Extract() - if err != nil { - panic(err) - } - - fmt.Printf("%+v", updatedExtraSpec) - -Example to Delete an Extra Spec for a Flavor - - flavorID := "e91758d6-a54a-4778-ad72-0c73a1cb695b" - err := flavors.DeleteExtraSpec(computeClient, flavorID, "hw:cpu_thread_policy").ExtractErr() - if err != nil { - panic(err) - } -*/ -package flavors diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/requests.go deleted file mode 100644 index 753024a18b7..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/requests.go +++ /dev/null @@ -1,357 +0,0 @@ -package flavors - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// ListOptsBuilder allows extensions to add additional parameters to the -// List request. -type ListOptsBuilder interface { - ToFlavorListQuery() (string, error) -} - -/* - AccessType maps to OpenStack's Flavor.is_public field. Although the is_public - field is boolean, the request options are ternary, which is why AccessType is - a string. The following values are allowed: - - The AccessType arguement is optional, and if it is not supplied, OpenStack - returns the PublicAccess flavors. -*/ -type AccessType string - -const ( - // PublicAccess returns public flavors and private flavors associated with - // that project. - PublicAccess AccessType = "true" - - // PrivateAccess (admin only) returns private flavors, across all projects. - PrivateAccess AccessType = "false" - - // AllAccess (admin only) returns public and private flavors across all - // projects. - AllAccess AccessType = "None" -) - -/* - ListOpts filters the results returned by the List() function. - For example, a flavor with a minDisk field of 10 will not be returned if you - specify MinDisk set to 20. - - Typically, software will use the last ID of the previous call to List to set - the Marker for the current call. -*/ -type ListOpts struct { - // ChangesSince, if provided, instructs List to return only those things which - // have changed since the timestamp provided. - ChangesSince string `q:"changes-since"` - - // MinDisk and MinRAM, if provided, elides flavors which do not meet your - // criteria. - MinDisk int `q:"minDisk"` - MinRAM int `q:"minRam"` - - // SortDir allows to select sort direction. - // It can be "asc" or "desc" (default). - SortDir string `q:"sort_dir"` - - // SortKey allows to sort by one of the flavors attributes. - // Default is flavorid. - SortKey string `q:"sort_key"` - - // Marker and Limit control paging. - // Marker instructs List where to start listing from. - Marker string `q:"marker"` - - // Limit instructs List to refrain from sending excessively large lists of - // flavors. - Limit int `q:"limit"` - - // AccessType, if provided, instructs List which set of flavors to return. - // If IsPublic not provided, flavors for the current project are returned. - AccessType AccessType `q:"is_public"` -} - -// ToFlavorListQuery formats a ListOpts into a query string. -func (opts ListOpts) ToFlavorListQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - return q.String(), err -} - -// ListDetail instructs OpenStack to provide a list of flavors. -// You may provide criteria by which List curtails its results for easier -// processing. -func ListDetail(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { - url := listURL(client) - if opts != nil { - query, err := opts.ToFlavorListQuery() - if err != nil { - return pagination.Pager{Err: err} - } - url += query - } - return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { - return FlavorPage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -type CreateOptsBuilder interface { - ToFlavorCreateMap() (map[string]interface{}, error) -} - -// CreateOpts specifies parameters used for creating a flavor. -type CreateOpts struct { - // Name is the name of the flavor. - Name string `json:"name" required:"true"` - - // RAM is the memory of the flavor, measured in MB. - RAM int `json:"ram" required:"true"` - - // VCPUs is the number of vcpus for the flavor. - VCPUs int `json:"vcpus" required:"true"` - - // Disk the amount of root disk space, measured in GB. - Disk *int `json:"disk" required:"true"` - - // ID is a unique ID for the flavor. - ID string `json:"id,omitempty"` - - // Swap is the amount of swap space for the flavor, measured in MB. - Swap *int `json:"swap,omitempty"` - - // RxTxFactor alters the network bandwidth of a flavor. - RxTxFactor float64 `json:"rxtx_factor,omitempty"` - - // IsPublic flags a flavor as being available to all projects or not. - IsPublic *bool `json:"os-flavor-access:is_public,omitempty"` - - // Ephemeral is the amount of ephemeral disk space, measured in GB. - Ephemeral *int `json:"OS-FLV-EXT-DATA:ephemeral,omitempty"` -} - -// ToFlavorCreateMap constructs a request body from CreateOpts. -func (opts CreateOpts) ToFlavorCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "flavor") -} - -// Create requests the creation of a new flavor. -func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToFlavorCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200, 201}, - }) - return -} - -// Get retrieves details of a single flavor. Use Extract to convert its -// result into a Flavor. -func Get(client *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = client.Get(getURL(client, id), &r.Body, nil) - return -} - -// Delete deletes the specified flavor ID. -func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = client.Delete(deleteURL(client, id), nil) - return -} - -// ListAccesses retrieves the tenants which have access to a flavor. -func ListAccesses(client *gophercloud.ServiceClient, id string) pagination.Pager { - url := accessURL(client, id) - - return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { - return AccessPage{pagination.SinglePageBase(r)} - }) -} - -// AddAccessOptsBuilder allows extensions to add additional parameters to the -// AddAccess requests. -type AddAccessOptsBuilder interface { - ToFlavorAddAccessMap() (map[string]interface{}, error) -} - -// AddAccessOpts represents options for adding access to a flavor. -type AddAccessOpts struct { - // Tenant is the project/tenant ID to grant access. - Tenant string `json:"tenant"` -} - -// ToFlavorAddAccessMap constructs a request body from AddAccessOpts. -func (opts AddAccessOpts) ToFlavorAddAccessMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "addTenantAccess") -} - -// AddAccess grants a tenant/project access to a flavor. -func AddAccess(client *gophercloud.ServiceClient, id string, opts AddAccessOptsBuilder) (r AddAccessResult) { - b, err := opts.ToFlavorAddAccessMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(accessActionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// RemoveAccessOptsBuilder allows extensions to add additional parameters to the -// RemoveAccess requests. -type RemoveAccessOptsBuilder interface { - ToFlavorRemoveAccessMap() (map[string]interface{}, error) -} - -// RemoveAccessOpts represents options for removing access to a flavor. -type RemoveAccessOpts struct { - // Tenant is the project/tenant ID to grant access. - Tenant string `json:"tenant"` -} - -// ToFlavorRemoveAccessMap constructs a request body from RemoveAccessOpts. -func (opts RemoveAccessOpts) ToFlavorRemoveAccessMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "removeTenantAccess") -} - -// RemoveAccess removes/revokes a tenant/project access to a flavor. -func RemoveAccess(client *gophercloud.ServiceClient, id string, opts RemoveAccessOptsBuilder) (r RemoveAccessResult) { - b, err := opts.ToFlavorRemoveAccessMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(accessActionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// ExtraSpecs requests all the extra-specs for the given flavor ID. -func ListExtraSpecs(client *gophercloud.ServiceClient, flavorID string) (r ListExtraSpecsResult) { - _, r.Err = client.Get(extraSpecsListURL(client, flavorID), &r.Body, nil) - return -} - -func GetExtraSpec(client *gophercloud.ServiceClient, flavorID string, key string) (r GetExtraSpecResult) { - _, r.Err = client.Get(extraSpecsGetURL(client, flavorID, key), &r.Body, nil) - return -} - -// CreateExtraSpecsOptsBuilder allows extensions to add additional parameters to the -// CreateExtraSpecs requests. -type CreateExtraSpecsOptsBuilder interface { - ToFlavorExtraSpecsCreateMap() (map[string]interface{}, error) -} - -// ExtraSpecsOpts is a map that contains key-value pairs. -type ExtraSpecsOpts map[string]string - -// ToFlavorExtraSpecsCreateMap assembles a body for a Create request based on -// the contents of ExtraSpecsOpts. -func (opts ExtraSpecsOpts) ToFlavorExtraSpecsCreateMap() (map[string]interface{}, error) { - return map[string]interface{}{"extra_specs": opts}, nil -} - -// CreateExtraSpecs will create or update the extra-specs key-value pairs for -// the specified Flavor. -func CreateExtraSpecs(client *gophercloud.ServiceClient, flavorID string, opts CreateExtraSpecsOptsBuilder) (r CreateExtraSpecsResult) { - b, err := opts.ToFlavorExtraSpecsCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(extraSpecsCreateURL(client, flavorID), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// UpdateExtraSpecOptsBuilder allows extensions to add additional parameters to -// the Update request. -type UpdateExtraSpecOptsBuilder interface { - ToFlavorExtraSpecUpdateMap() (map[string]string, string, error) -} - -// ToFlavorExtraSpecUpdateMap assembles a body for an Update request based on -// the contents of a ExtraSpecOpts. -func (opts ExtraSpecsOpts) ToFlavorExtraSpecUpdateMap() (map[string]string, string, error) { - if len(opts) != 1 { - err := gophercloud.ErrInvalidInput{} - err.Argument = "flavors.ExtraSpecOpts" - err.Info = "Must have 1 and only one key-value pair" - return nil, "", err - } - - var key string - for k := range opts { - key = k - } - - return opts, key, nil -} - -// UpdateExtraSpec will updates the value of the specified flavor's extra spec -// for the key in opts. -func UpdateExtraSpec(client *gophercloud.ServiceClient, flavorID string, opts UpdateExtraSpecOptsBuilder) (r UpdateExtraSpecResult) { - b, key, err := opts.ToFlavorExtraSpecUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Put(extraSpecUpdateURL(client, flavorID, key), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// DeleteExtraSpec will delete the key-value pair with the given key for the given -// flavor ID. -func DeleteExtraSpec(client *gophercloud.ServiceClient, flavorID, key string) (r DeleteExtraSpecResult) { - _, r.Err = client.Delete(extraSpecDeleteURL(client, flavorID, key), &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// IDFromName is a convienience function that returns a flavor's ID given its -// name. -func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) { - count := 0 - id := "" - allPages, err := ListDetail(client, nil).AllPages() - if err != nil { - return "", err - } - - all, err := ExtractFlavors(allPages) - if err != nil { - return "", err - } - - for _, f := range all { - if f.Name == name { - count++ - id = f.ID - } - } - - switch count { - case 0: - err := &gophercloud.ErrResourceNotFound{} - err.ResourceType = "flavor" - err.Name = name - return "", err - case 1: - return id, nil - default: - err := &gophercloud.ErrMultipleResourcesFound{} - err.ResourceType = "flavor" - err.Name = name - err.Count = count - return "", err - } -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/results.go deleted file mode 100644 index 92fe1b1809d..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/results.go +++ /dev/null @@ -1,252 +0,0 @@ -package flavors - -import ( - "encoding/json" - "strconv" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -type commonResult struct { - gophercloud.Result -} - -// CreateResult is the response of a Get operations. Call its Extract method to -// interpret it as a Flavor. -type CreateResult struct { - commonResult -} - -// GetResult is the response of a Get operations. Call its Extract method to -// interpret it as a Flavor. -type GetResult struct { - commonResult -} - -// DeleteResult is the result from a Delete operation. Call its ExtractErr -// method to determine if the call succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} - -// Extract provides access to the individual Flavor returned by the Get and -// Create functions. -func (r commonResult) Extract() (*Flavor, error) { - var s struct { - Flavor *Flavor `json:"flavor"` - } - err := r.ExtractInto(&s) - return s.Flavor, err -} - -// Flavor represent (virtual) hardware configurations for server resources -// in a region. -type Flavor struct { - // ID is the flavor's unique ID. - ID string `json:"id"` - - // Disk is the amount of root disk, measured in GB. - Disk int `json:"disk"` - - // RAM is the amount of memory, measured in MB. - RAM int `json:"ram"` - - // Name is the name of the flavor. - Name string `json:"name"` - - // RxTxFactor describes bandwidth alterations of the flavor. - RxTxFactor float64 `json:"rxtx_factor"` - - // Swap is the amount of swap space, measured in MB. - Swap int `json:"-"` - - // VCPUs indicates how many (virtual) CPUs are available for this flavor. - VCPUs int `json:"vcpus"` - - // IsPublic indicates whether the flavor is public. - IsPublic bool `json:"os-flavor-access:is_public"` - - // Ephemeral is the amount of ephemeral disk space, measured in GB. - Ephemeral int `json:"OS-FLV-EXT-DATA:ephemeral"` -} - -func (r *Flavor) UnmarshalJSON(b []byte) error { - type tmp Flavor - var s struct { - tmp - Swap interface{} `json:"swap"` - } - err := json.Unmarshal(b, &s) - if err != nil { - return err - } - - *r = Flavor(s.tmp) - - switch t := s.Swap.(type) { - case float64: - r.Swap = int(t) - case string: - switch t { - case "": - r.Swap = 0 - default: - swap, err := strconv.ParseFloat(t, 64) - if err != nil { - return err - } - r.Swap = int(swap) - } - } - - return nil -} - -// FlavorPage contains a single page of all flavors from a ListDetails call. -type FlavorPage struct { - pagination.LinkedPageBase -} - -// IsEmpty determines if a FlavorPage contains any results. -func (page FlavorPage) IsEmpty() (bool, error) { - flavors, err := ExtractFlavors(page) - return len(flavors) == 0, err -} - -// NextPageURL uses the response's embedded link reference to navigate to the -// next page of results. -func (page FlavorPage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"flavors_links"` - } - err := page.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// ExtractFlavors provides access to the list of flavors in a page acquired -// from the ListDetail operation. -func ExtractFlavors(r pagination.Page) ([]Flavor, error) { - var s struct { - Flavors []Flavor `json:"flavors"` - } - err := (r.(FlavorPage)).ExtractInto(&s) - return s.Flavors, err -} - -// AccessPage contains a single page of all FlavorAccess entries for a flavor. -type AccessPage struct { - pagination.SinglePageBase -} - -// IsEmpty indicates whether an AccessPage is empty. -func (page AccessPage) IsEmpty() (bool, error) { - v, err := ExtractAccesses(page) - return len(v) == 0, err -} - -// ExtractAccesses interprets a page of results as a slice of FlavorAccess. -func ExtractAccesses(r pagination.Page) ([]FlavorAccess, error) { - var s struct { - FlavorAccesses []FlavorAccess `json:"flavor_access"` - } - err := (r.(AccessPage)).ExtractInto(&s) - return s.FlavorAccesses, err -} - -type accessResult struct { - gophercloud.Result -} - -// AddAccessResult is the response of an AddAccess operation. Call its -// Extract method to interpret it as a slice of FlavorAccess. -type AddAccessResult struct { - accessResult -} - -// RemoveAccessResult is the response of a RemoveAccess operation. Call its -// Extract method to interpret it as a slice of FlavorAccess. -type RemoveAccessResult struct { - accessResult -} - -// Extract provides access to the result of an access create or delete. -// The result will be all accesses that the flavor has. -func (r accessResult) Extract() ([]FlavorAccess, error) { - var s struct { - FlavorAccesses []FlavorAccess `json:"flavor_access"` - } - err := r.ExtractInto(&s) - return s.FlavorAccesses, err -} - -// FlavorAccess represents an ACL of tenant access to a specific Flavor. -type FlavorAccess struct { - // FlavorID is the unique ID of the flavor. - FlavorID string `json:"flavor_id"` - - // TenantID is the unique ID of the tenant. - TenantID string `json:"tenant_id"` -} - -// Extract interprets any extraSpecsResult as ExtraSpecs, if possible. -func (r extraSpecsResult) Extract() (map[string]string, error) { - var s struct { - ExtraSpecs map[string]string `json:"extra_specs"` - } - err := r.ExtractInto(&s) - return s.ExtraSpecs, err -} - -// extraSpecsResult contains the result of a call for (potentially) multiple -// key-value pairs. Call its Extract method to interpret it as a -// map[string]interface. -type extraSpecsResult struct { - gophercloud.Result -} - -// ListExtraSpecsResult contains the result of a Get operation. Call its Extract -// method to interpret it as a map[string]interface. -type ListExtraSpecsResult struct { - extraSpecsResult -} - -// CreateExtraSpecResult contains the result of a Create operation. Call its -// Extract method to interpret it as a map[string]interface. -type CreateExtraSpecsResult struct { - extraSpecsResult -} - -// extraSpecResult contains the result of a call for individual a single -// key-value pair. -type extraSpecResult struct { - gophercloud.Result -} - -// GetExtraSpecResult contains the result of a Get operation. Call its Extract -// method to interpret it as a map[string]interface. -type GetExtraSpecResult struct { - extraSpecResult -} - -// UpdateExtraSpecResult contains the result of an Update operation. Call its -// Extract method to interpret it as a map[string]interface. -type UpdateExtraSpecResult struct { - extraSpecResult -} - -// DeleteExtraSpecResult contains the result of a Delete operation. Call its -// ExtractErr method to determine if the call succeeded or failed. -type DeleteExtraSpecResult struct { - gophercloud.ErrResult -} - -// Extract interprets any extraSpecResult as an ExtraSpec, if possible. -func (r extraSpecResult) Extract() (map[string]string, error) { - var s map[string]string - err := r.ExtractInto(&s) - return s, err -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/urls.go deleted file mode 100644 index 8620dd78ad0..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/urls.go +++ /dev/null @@ -1,49 +0,0 @@ -package flavors - -import ( - "github.com/gophercloud/gophercloud" -) - -func getURL(client *gophercloud.ServiceClient, id string) string { - return client.ServiceURL("flavors", id) -} - -func listURL(client *gophercloud.ServiceClient) string { - return client.ServiceURL("flavors", "detail") -} - -func createURL(client *gophercloud.ServiceClient) string { - return client.ServiceURL("flavors") -} - -func deleteURL(client *gophercloud.ServiceClient, id string) string { - return client.ServiceURL("flavors", id) -} - -func accessURL(client *gophercloud.ServiceClient, id string) string { - return client.ServiceURL("flavors", id, "os-flavor-access") -} - -func accessActionURL(client *gophercloud.ServiceClient, id string) string { - return client.ServiceURL("flavors", id, "action") -} - -func extraSpecsListURL(client *gophercloud.ServiceClient, id string) string { - return client.ServiceURL("flavors", id, "os-extra_specs") -} - -func extraSpecsGetURL(client *gophercloud.ServiceClient, id, key string) string { - return client.ServiceURL("flavors", id, "os-extra_specs", key) -} - -func extraSpecsCreateURL(client *gophercloud.ServiceClient, id string) string { - return client.ServiceURL("flavors", id, "os-extra_specs") -} - -func extraSpecUpdateURL(client *gophercloud.ServiceClient, id, key string) string { - return client.ServiceURL("flavors", id, "os-extra_specs", key) -} - -func extraSpecDeleteURL(client *gophercloud.ServiceClient, id, key string) string { - return client.ServiceURL("flavors", id, "os-extra_specs", key) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/doc.go deleted file mode 100644 index 22410a79a27..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/doc.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Package images provides information and interaction with the images through -the OpenStack Compute service. - -This API is deprecated and will be removed from a future version of the Nova -API service. - -An image is a collection of files used to create or rebuild a server. -Operators provide a number of pre-built OS images by default. You may also -create custom images from cloud servers you have launched. - -Example to List Images - - listOpts := images.ListOpts{ - Limit: 2, - } - - allPages, err := images.ListDetail(computeClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - allImages, err := images.ExtractImages(allPages) - if err != nil { - panic(err) - } - - for _, image := range allImages { - fmt.Printf("%+v\n", image) - } -*/ -package images diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/requests.go deleted file mode 100644 index 558b481b9e7..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/requests.go +++ /dev/null @@ -1,109 +0,0 @@ -package images - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// ListOptsBuilder allows extensions to add additional parameters to the -// ListDetail request. -type ListOptsBuilder interface { - ToImageListQuery() (string, error) -} - -// ListOpts contain options filtering Images returned from a call to ListDetail. -type ListOpts struct { - // ChangesSince filters Images based on the last changed status (in date-time - // format). - ChangesSince string `q:"changes-since"` - - // Limit limits the number of Images to return. - Limit int `q:"limit"` - - // Mark is an Image UUID at which to set a marker. - Marker string `q:"marker"` - - // Name is the name of the Image. - Name string `q:"name"` - - // Server is the name of the Server (in URL format). - Server string `q:"server"` - - // Status is the current status of the Image. - Status string `q:"status"` - - // Type is the type of image (e.g. BASE, SERVER, ALL). - Type string `q:"type"` -} - -// ToImageListQuery formats a ListOpts into a query string. -func (opts ListOpts) ToImageListQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - return q.String(), err -} - -// ListDetail enumerates the available images. -func ListDetail(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { - url := listDetailURL(client) - if opts != nil { - query, err := opts.ToImageListQuery() - if err != nil { - return pagination.Pager{Err: err} - } - url += query - } - return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { - return ImagePage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -// Get returns data about a specific image by its ID. -func Get(client *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = client.Get(getURL(client, id), &r.Body, nil) - return -} - -// Delete deletes the specified image ID. -func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = client.Delete(deleteURL(client, id), nil) - return -} - -// IDFromName is a convienience function that returns an image's ID given its -// name. -func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) { - count := 0 - id := "" - allPages, err := ListDetail(client, nil).AllPages() - if err != nil { - return "", err - } - - all, err := ExtractImages(allPages) - if err != nil { - return "", err - } - - for _, f := range all { - if f.Name == name { - count++ - id = f.ID - } - } - - switch count { - case 0: - err := &gophercloud.ErrResourceNotFound{} - err.ResourceType = "image" - err.Name = name - return "", err - case 1: - return id, nil - default: - err := &gophercloud.ErrMultipleResourcesFound{} - err.ResourceType = "image" - err.Name = name - err.Count = count - return "", err - } -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/results.go deleted file mode 100644 index 70d1018c721..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/results.go +++ /dev/null @@ -1,95 +0,0 @@ -package images - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// GetResult is the response from a Get operation. Call its Extract method to -// interpret it as an Image. -type GetResult struct { - gophercloud.Result -} - -// DeleteResult is the result from a Delete operation. Call its ExtractErr -// method to determine if the call succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} - -// Extract interprets a GetResult as an Image. -func (r GetResult) Extract() (*Image, error) { - var s struct { - Image *Image `json:"image"` - } - err := r.ExtractInto(&s) - return s.Image, err -} - -// Image represents an Image returned by the Compute API. -type Image struct { - // ID is the unique ID of an image. - ID string - - // Created is the date when the image was created. - Created string - - // MinDisk is the minimum amount of disk a flavor must have to be able - // to create a server based on the image, measured in GB. - MinDisk int - - // MinRAM is the minimum amount of RAM a flavor must have to be able - // to create a server based on the image, measured in MB. - MinRAM int - - // Name provides a human-readable moniker for the OS image. - Name string - - // The Progress and Status fields indicate image-creation status. - Progress int - - // Status is the current status of the image. - Status string - - // Update is the date when the image was updated. - Updated string - - // Metadata provides free-form key/value pairs that further describe the - // image. - Metadata map[string]interface{} -} - -// ImagePage contains a single page of all Images returne from a ListDetail -// operation. Use ExtractImages to convert it into a slice of usable structs. -type ImagePage struct { - pagination.LinkedPageBase -} - -// IsEmpty returns true if an ImagePage contains no Image results. -func (page ImagePage) IsEmpty() (bool, error) { - images, err := ExtractImages(page) - return len(images) == 0, err -} - -// NextPageURL uses the response's embedded link reference to navigate to the -// next page of results. -func (page ImagePage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"images_links"` - } - err := page.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// ExtractImages converts a page of List results into a slice of usable Image -// structs. -func ExtractImages(r pagination.Page) ([]Image, error) { - var s struct { - Images []Image `json:"images"` - } - err := (r.(ImagePage)).ExtractInto(&s) - return s.Images, err -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/urls.go deleted file mode 100644 index 57787fb725e..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/urls.go +++ /dev/null @@ -1,15 +0,0 @@ -package images - -import "github.com/gophercloud/gophercloud" - -func listDetailURL(client *gophercloud.ServiceClient) string { - return client.ServiceURL("images", "detail") -} - -func getURL(client *gophercloud.ServiceClient, id string) string { - return client.ServiceURL("images", id) -} - -func deleteURL(client *gophercloud.ServiceClient, id string) string { - return client.ServiceURL("images", id) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/doc.go deleted file mode 100644 index 3b0ab783626..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/doc.go +++ /dev/null @@ -1,115 +0,0 @@ -/* -Package servers provides information and interaction with the server API -resource in the OpenStack Compute service. - -A server is a virtual machine instance in the compute system. In order for -one to be provisioned, a valid flavor and image are required. - -Example to List Servers - - listOpts := servers.ListOpts{ - AllTenants: true, - } - - allPages, err := servers.List(computeClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - allServers, err := servers.ExtractServers(allPages) - if err != nil { - panic(err) - } - - for _, server := range allServers { - fmt.Printf("%+v\n", server) - } - -Example to Create a Server - - createOpts := servers.CreateOpts{ - Name: "server_name", - ImageRef: "image-uuid", - FlavorRef: "flavor-uuid", - } - - server, err := servers.Create(computeClient, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to Delete a Server - - serverID := "d9072956-1560-487c-97f2-18bdf65ec749" - err := servers.Delete(computeClient, serverID).ExtractErr() - if err != nil { - panic(err) - } - -Example to Force Delete a Server - - serverID := "d9072956-1560-487c-97f2-18bdf65ec749" - err := servers.ForceDelete(computeClient, serverID).ExtractErr() - if err != nil { - panic(err) - } - -Example to Reboot a Server - - rebootOpts := servers.RebootOpts{ - Type: servers.SoftReboot, - } - - serverID := "d9072956-1560-487c-97f2-18bdf65ec749" - - err := servers.Reboot(computeClient, serverID, rebootOpts).ExtractErr() - if err != nil { - panic(err) - } - -Example to Rebuild a Server - - rebuildOpts := servers.RebuildOpts{ - Name: "new_name", - ImageID: "image-uuid", - } - - serverID := "d9072956-1560-487c-97f2-18bdf65ec749" - - server, err := servers.Rebuilt(computeClient, serverID, rebuildOpts).Extract() - if err != nil { - panic(err) - } - -Example to Resize a Server - - resizeOpts := servers.ResizeOpts{ - FlavorRef: "flavor-uuid", - } - - serverID := "d9072956-1560-487c-97f2-18bdf65ec749" - - err := servers.Resize(computeClient, serverID, resizeOpts).ExtractErr() - if err != nil { - panic(err) - } - - err = servers.ConfirmResize(computeClient, serverID).ExtractErr() - if err != nil { - panic(err) - } - -Example to Snapshot a Server - - snapshotOpts := servers.CreateImageOpts{ - Name: "snapshot_name", - } - - serverID := "d9072956-1560-487c-97f2-18bdf65ec749" - - image, err := servers.CreateImage(computeClient, serverID, snapshotOpts).ExtractImageID() - if err != nil { - panic(err) - } -*/ -package servers diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/errors.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/errors.go deleted file mode 100644 index c9f0e3c20b5..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/errors.go +++ /dev/null @@ -1,71 +0,0 @@ -package servers - -import ( - "fmt" - - "github.com/gophercloud/gophercloud" -) - -// ErrNeitherImageIDNorImageNameProvided is the error when neither the image -// ID nor the image name is provided for a server operation -type ErrNeitherImageIDNorImageNameProvided struct{ gophercloud.ErrMissingInput } - -func (e ErrNeitherImageIDNorImageNameProvided) Error() string { - return "One and only one of the image ID and the image name must be provided." -} - -// ErrNeitherFlavorIDNorFlavorNameProvided is the error when neither the flavor -// ID nor the flavor name is provided for a server operation -type ErrNeitherFlavorIDNorFlavorNameProvided struct{ gophercloud.ErrMissingInput } - -func (e ErrNeitherFlavorIDNorFlavorNameProvided) Error() string { - return "One and only one of the flavor ID and the flavor name must be provided." -} - -type ErrNoClientProvidedForIDByName struct{ gophercloud.ErrMissingInput } - -func (e ErrNoClientProvidedForIDByName) Error() string { - return "A service client must be provided to find a resource ID by name." -} - -// ErrInvalidHowParameterProvided is the error when an unknown value is given -// for the `how` argument -type ErrInvalidHowParameterProvided struct{ gophercloud.ErrInvalidInput } - -// ErrNoAdminPassProvided is the error when an administrative password isn't -// provided for a server operation -type ErrNoAdminPassProvided struct{ gophercloud.ErrMissingInput } - -// ErrNoImageIDProvided is the error when an image ID isn't provided for a server -// operation -type ErrNoImageIDProvided struct{ gophercloud.ErrMissingInput } - -// ErrNoIDProvided is the error when a server ID isn't provided for a server -// operation -type ErrNoIDProvided struct{ gophercloud.ErrMissingInput } - -// ErrServer is a generic error type for servers HTTP operations. -type ErrServer struct { - gophercloud.ErrUnexpectedResponseCode - ID string -} - -func (se ErrServer) Error() string { - return fmt.Sprintf("Error while executing HTTP request for server [%s]", se.ID) -} - -// Error404 overrides the generic 404 error message. -func (se ErrServer) Error404(e gophercloud.ErrUnexpectedResponseCode) error { - se.ErrUnexpectedResponseCode = e - return &ErrServerNotFound{se} -} - -// ErrServerNotFound is the error when a 404 is received during server HTTP -// operations. -type ErrServerNotFound struct { - ErrServer -} - -func (e ErrServerNotFound) Error() string { - return fmt.Sprintf("I couldn't find server [%s]", e.ID) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/microversions.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/microversions.go deleted file mode 100644 index 84ec9f31d35..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/microversions.go +++ /dev/null @@ -1,11 +0,0 @@ -package servers - -// ExtractTags will extract the tags of a server. -// This requires the client to be set to microversion 2.26 or later. -func (r serverResult) ExtractTags() ([]string, error) { - var s struct { - Tags []string `json:"tags"` - } - err := r.ExtractInto(&s) - return s.Tags, err -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/requests.go deleted file mode 100644 index ee8e93b1dcb..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/requests.go +++ /dev/null @@ -1,812 +0,0 @@ -package servers - -import ( - "encoding/base64" - "encoding/json" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/compute/v2/flavors" - "github.com/gophercloud/gophercloud/openstack/compute/v2/images" - "github.com/gophercloud/gophercloud/pagination" -) - -// ListOptsBuilder allows extensions to add additional parameters to the -// List request. -type ListOptsBuilder interface { - ToServerListQuery() (string, error) -} - -// ListOpts allows the filtering and sorting of paginated collections through -// the API. Filtering is achieved by passing in struct field values that map to -// the server attributes you want to see returned. Marker and Limit are used -// for pagination. -type ListOpts struct { - // ChangesSince is a time/date stamp for when the server last changed status. - ChangesSince string `q:"changes-since"` - - // Image is the name of the image in URL format. - Image string `q:"image"` - - // Flavor is the name of the flavor in URL format. - Flavor string `q:"flavor"` - - // Name of the server as a string; can be queried with regular expressions. - // Realize that ?name=bob returns both bob and bobb. If you need to match bob - // only, you can use a regular expression matching the syntax of the - // underlying database server implemented for Compute. - Name string `q:"name"` - - // Status is the value of the status of the server so that you can filter on - // "ACTIVE" for example. - Status string `q:"status"` - - // Host is the name of the host as a string. - Host string `q:"host"` - - // Marker is a UUID of the server at which you want to set a marker. - Marker string `q:"marker"` - - // Limit is an integer value for the limit of values to return. - Limit int `q:"limit"` - - // AllTenants is a bool to show all tenants. - AllTenants bool `q:"all_tenants"` - - // TenantID lists servers for a particular tenant. - // Setting "AllTenants = true" is required. - TenantID string `q:"tenant_id"` -} - -// ToServerListQuery formats a ListOpts into a query string. -func (opts ListOpts) ToServerListQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - return q.String(), err -} - -// List makes a request against the API to list servers accessible to you. -func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { - url := listDetailURL(client) - if opts != nil { - query, err := opts.ToServerListQuery() - if err != nil { - return pagination.Pager{Err: err} - } - url += query - } - return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { - return ServerPage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -// CreateOptsBuilder allows extensions to add additional parameters to the -// Create request. -type CreateOptsBuilder interface { - ToServerCreateMap() (map[string]interface{}, error) -} - -// Network is used within CreateOpts to control a new server's network -// attachments. -type Network struct { - // UUID of a network to attach to the newly provisioned server. - // Required unless Port is provided. - UUID string - - // Port of a neutron network to attach to the newly provisioned server. - // Required unless UUID is provided. - Port string - - // FixedIP specifies a fixed IPv4 address to be used on this network. - FixedIP string -} - -// Personality is an array of files that are injected into the server at launch. -type Personality []*File - -// File is used within CreateOpts and RebuildOpts to inject a file into the -// server at launch. -// File implements the json.Marshaler interface, so when a Create or Rebuild -// operation is requested, json.Marshal will call File's MarshalJSON method. -type File struct { - // Path of the file. - Path string - - // Contents of the file. Maximum content size is 255 bytes. - Contents []byte -} - -// MarshalJSON marshals the escaped file, base64 encoding the contents. -func (f *File) MarshalJSON() ([]byte, error) { - file := struct { - Path string `json:"path"` - Contents string `json:"contents"` - }{ - Path: f.Path, - Contents: base64.StdEncoding.EncodeToString(f.Contents), - } - return json.Marshal(file) -} - -// CreateOpts specifies server creation parameters. -type CreateOpts struct { - // Name is the name to assign to the newly launched server. - Name string `json:"name" required:"true"` - - // ImageRef [optional; required if ImageName is not provided] is the ID or - // full URL to the image that contains the server's OS and initial state. - // Also optional if using the boot-from-volume extension. - ImageRef string `json:"imageRef"` - - // ImageName [optional; required if ImageRef is not provided] is the name of - // the image that contains the server's OS and initial state. - // Also optional if using the boot-from-volume extension. - ImageName string `json:"-"` - - // FlavorRef [optional; required if FlavorName is not provided] is the ID or - // full URL to the flavor that describes the server's specs. - FlavorRef string `json:"flavorRef"` - - // FlavorName [optional; required if FlavorRef is not provided] is the name of - // the flavor that describes the server's specs. - FlavorName string `json:"-"` - - // SecurityGroups lists the names of the security groups to which this server - // should belong. - SecurityGroups []string `json:"-"` - - // UserData contains configuration information or scripts to use upon launch. - // Create will base64-encode it for you, if it isn't already. - UserData []byte `json:"-"` - - // AvailabilityZone in which to launch the server. - AvailabilityZone string `json:"availability_zone,omitempty"` - - // Networks dictates how this server will be attached to available networks. - // By default, the server will be attached to all isolated networks for the - // tenant. - Networks []Network `json:"-"` - - // Metadata contains key-value pairs (up to 255 bytes each) to attach to the - // server. - Metadata map[string]string `json:"metadata,omitempty"` - - // Personality includes files to inject into the server at launch. - // Create will base64-encode file contents for you. - Personality Personality `json:"personality,omitempty"` - - // ConfigDrive enables metadata injection through a configuration drive. - ConfigDrive *bool `json:"config_drive,omitempty"` - - // AdminPass sets the root user password. If not set, a randomly-generated - // password will be created and returned in the response. - AdminPass string `json:"adminPass,omitempty"` - - // AccessIPv4 specifies an IPv4 address for the instance. - AccessIPv4 string `json:"accessIPv4,omitempty"` - - // AccessIPv6 specifies an IPv6 address for the instance. - AccessIPv6 string `json:"accessIPv6,omitempty"` - - // Min specifies Minimum number of servers to launch. - Min int `json:"min_count,omitempty"` - - // Max specifies Maximum number of servers to launch. - Max int `json:"max_count,omitempty"` - - // ServiceClient will allow calls to be made to retrieve an image or - // flavor ID by name. - ServiceClient *gophercloud.ServiceClient `json:"-"` - - // Tags allows a server to be tagged with single-word metadata. - // Requires microversion 2.52 or later. - Tags []string `json:"tags,omitempty"` -} - -// ToServerCreateMap assembles a request body based on the contents of a -// CreateOpts. -func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) { - sc := opts.ServiceClient - opts.ServiceClient = nil - b, err := gophercloud.BuildRequestBody(opts, "") - if err != nil { - return nil, err - } - - if opts.UserData != nil { - var userData string - if _, err := base64.StdEncoding.DecodeString(string(opts.UserData)); err != nil { - userData = base64.StdEncoding.EncodeToString(opts.UserData) - } else { - userData = string(opts.UserData) - } - b["user_data"] = &userData - } - - if len(opts.SecurityGroups) > 0 { - securityGroups := make([]map[string]interface{}, len(opts.SecurityGroups)) - for i, groupName := range opts.SecurityGroups { - securityGroups[i] = map[string]interface{}{"name": groupName} - } - b["security_groups"] = securityGroups - } - - if len(opts.Networks) > 0 { - networks := make([]map[string]interface{}, len(opts.Networks)) - for i, net := range opts.Networks { - networks[i] = make(map[string]interface{}) - if net.UUID != "" { - networks[i]["uuid"] = net.UUID - } - if net.Port != "" { - networks[i]["port"] = net.Port - } - if net.FixedIP != "" { - networks[i]["fixed_ip"] = net.FixedIP - } - } - b["networks"] = networks - } - - // If ImageRef isn't provided, check if ImageName was provided to ascertain - // the image ID. - if opts.ImageRef == "" { - if opts.ImageName != "" { - if sc == nil { - err := ErrNoClientProvidedForIDByName{} - err.Argument = "ServiceClient" - return nil, err - } - imageID, err := images.IDFromName(sc, opts.ImageName) - if err != nil { - return nil, err - } - b["imageRef"] = imageID - } - } - - // If FlavorRef isn't provided, use FlavorName to ascertain the flavor ID. - if opts.FlavorRef == "" { - if opts.FlavorName == "" { - err := ErrNeitherFlavorIDNorFlavorNameProvided{} - err.Argument = "FlavorRef/FlavorName" - return nil, err - } - if sc == nil { - err := ErrNoClientProvidedForIDByName{} - err.Argument = "ServiceClient" - return nil, err - } - flavorID, err := flavors.IDFromName(sc, opts.FlavorName) - if err != nil { - return nil, err - } - b["flavorRef"] = flavorID - } - - if opts.Min != 0 { - b["min_count"] = opts.Min - } - - if opts.Max != 0 { - b["max_count"] = opts.Max - } - - return map[string]interface{}{"server": b}, nil -} - -// Create requests a server to be provisioned to the user in the current tenant. -func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - reqBody, err := opts.ToServerCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(listURL(client), reqBody, &r.Body, nil) - return -} - -// Delete requests that a server previously provisioned be removed from your -// account. -func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = client.Delete(deleteURL(client, id), nil) - return -} - -// ForceDelete forces the deletion of a server. -func ForceDelete(client *gophercloud.ServiceClient, id string) (r ActionResult) { - _, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"forceDelete": ""}, nil, nil) - return -} - -// Get requests details on a single server, by ID. -func Get(client *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = client.Get(getURL(client, id), &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200, 203}, - }) - return -} - -// UpdateOptsBuilder allows extensions to add additional attributes to the -// Update request. -type UpdateOptsBuilder interface { - ToServerUpdateMap() (map[string]interface{}, error) -} - -// UpdateOpts specifies the base attributes that may be updated on an existing -// server. -type UpdateOpts struct { - // Name changes the displayed name of the server. - // The server host name will *not* change. - // Server names are not constrained to be unique, even within the same tenant. - Name string `json:"name,omitempty"` - - // AccessIPv4 provides a new IPv4 address for the instance. - AccessIPv4 string `json:"accessIPv4,omitempty"` - - // AccessIPv6 provides a new IPv6 address for the instance. - AccessIPv6 string `json:"accessIPv6,omitempty"` -} - -// ToServerUpdateMap formats an UpdateOpts structure into a request body. -func (opts UpdateOpts) ToServerUpdateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "server") -} - -// Update requests that various attributes of the indicated server be changed. -func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { - b, err := opts.ToServerUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Put(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// ChangeAdminPassword alters the administrator or root password for a specified -// server. -func ChangeAdminPassword(client *gophercloud.ServiceClient, id, newPassword string) (r ActionResult) { - b := map[string]interface{}{ - "changePassword": map[string]string{ - "adminPass": newPassword, - }, - } - _, r.Err = client.Post(actionURL(client, id), b, nil, nil) - return -} - -// RebootMethod describes the mechanisms by which a server reboot can be requested. -type RebootMethod string - -// These constants determine how a server should be rebooted. -// See the Reboot() function for further details. -const ( - SoftReboot RebootMethod = "SOFT" - HardReboot RebootMethod = "HARD" - OSReboot = SoftReboot - PowerCycle = HardReboot -) - -// RebootOptsBuilder allows extensions to add additional parameters to the -// reboot request. -type RebootOptsBuilder interface { - ToServerRebootMap() (map[string]interface{}, error) -} - -// RebootOpts provides options to the reboot request. -type RebootOpts struct { - // Type is the type of reboot to perform on the server. - Type RebootMethod `json:"type" required:"true"` -} - -// ToServerRebootMap builds a body for the reboot request. -func (opts RebootOpts) ToServerRebootMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "reboot") -} - -/* - Reboot requests that a given server reboot. - - Two methods exist for rebooting a server: - - HardReboot (aka PowerCycle) starts the server instance by physically cutting - power to the machine, or if a VM, terminating it at the hypervisor level. - It's done. Caput. Full stop. - Then, after a brief while, power is rtored or the VM instance restarted. - - SoftReboot (aka OSReboot) simply tells the OS to restart under its own - procedure. - E.g., in Linux, asking it to enter runlevel 6, or executing - "sudo shutdown -r now", or by asking Windows to rtart the machine. -*/ -func Reboot(client *gophercloud.ServiceClient, id string, opts RebootOptsBuilder) (r ActionResult) { - b, err := opts.ToServerRebootMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(actionURL(client, id), b, nil, nil) - return -} - -// RebuildOptsBuilder allows extensions to provide additional parameters to the -// rebuild request. -type RebuildOptsBuilder interface { - ToServerRebuildMap() (map[string]interface{}, error) -} - -// RebuildOpts represents the configuration options used in a server rebuild -// operation. -type RebuildOpts struct { - // AdminPass is the server's admin password - AdminPass string `json:"adminPass,omitempty"` - - // ImageID is the ID of the image you want your server to be provisioned on. - ImageID string `json:"imageRef"` - - // ImageName is readable name of an image. - ImageName string `json:"-"` - - // Name to set the server to - Name string `json:"name,omitempty"` - - // AccessIPv4 [optional] provides a new IPv4 address for the instance. - AccessIPv4 string `json:"accessIPv4,omitempty"` - - // AccessIPv6 [optional] provides a new IPv6 address for the instance. - AccessIPv6 string `json:"accessIPv6,omitempty"` - - // Metadata [optional] contains key-value pairs (up to 255 bytes each) - // to attach to the server. - Metadata map[string]string `json:"metadata,omitempty"` - - // Personality [optional] includes files to inject into the server at launch. - // Rebuild will base64-encode file contents for you. - Personality Personality `json:"personality,omitempty"` - - // ServiceClient will allow calls to be made to retrieve an image or - // flavor ID by name. - ServiceClient *gophercloud.ServiceClient `json:"-"` -} - -// ToServerRebuildMap formats a RebuildOpts struct into a map for use in JSON -func (opts RebuildOpts) ToServerRebuildMap() (map[string]interface{}, error) { - b, err := gophercloud.BuildRequestBody(opts, "") - if err != nil { - return nil, err - } - - // If ImageRef isn't provided, check if ImageName was provided to ascertain - // the image ID. - if opts.ImageID == "" { - if opts.ImageName != "" { - if opts.ServiceClient == nil { - err := ErrNoClientProvidedForIDByName{} - err.Argument = "ServiceClient" - return nil, err - } - imageID, err := images.IDFromName(opts.ServiceClient, opts.ImageName) - if err != nil { - return nil, err - } - b["imageRef"] = imageID - } - } - - return map[string]interface{}{"rebuild": b}, nil -} - -// Rebuild will reprovision the server according to the configuration options -// provided in the RebuildOpts struct. -func Rebuild(client *gophercloud.ServiceClient, id string, opts RebuildOptsBuilder) (r RebuildResult) { - b, err := opts.ToServerRebuildMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(actionURL(client, id), b, &r.Body, nil) - return -} - -// ResizeOptsBuilder allows extensions to add additional parameters to the -// resize request. -type ResizeOptsBuilder interface { - ToServerResizeMap() (map[string]interface{}, error) -} - -// ResizeOpts represents the configuration options used to control a Resize -// operation. -type ResizeOpts struct { - // FlavorRef is the ID of the flavor you wish your server to become. - FlavorRef string `json:"flavorRef" required:"true"` -} - -// ToServerResizeMap formats a ResizeOpts as a map that can be used as a JSON -// request body for the Resize request. -func (opts ResizeOpts) ToServerResizeMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "resize") -} - -// Resize instructs the provider to change the flavor of the server. -// -// Note that this implies rebuilding it. -// -// Unfortunately, one cannot pass rebuild parameters to the resize function. -// When the resize completes, the server will be in VERIFY_RESIZE state. -// While in this state, you can explore the use of the new server's -// configuration. If you like it, call ConfirmResize() to commit the resize -// permanently. Otherwise, call RevertResize() to restore the old configuration. -func Resize(client *gophercloud.ServiceClient, id string, opts ResizeOptsBuilder) (r ActionResult) { - b, err := opts.ToServerResizeMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(actionURL(client, id), b, nil, nil) - return -} - -// ConfirmResize confirms a previous resize operation on a server. -// See Resize() for more details. -func ConfirmResize(client *gophercloud.ServiceClient, id string) (r ActionResult) { - _, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"confirmResize": nil}, nil, &gophercloud.RequestOpts{ - OkCodes: []int{201, 202, 204}, - }) - return -} - -// RevertResize cancels a previous resize operation on a server. -// See Resize() for more details. -func RevertResize(client *gophercloud.ServiceClient, id string) (r ActionResult) { - _, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"revertResize": nil}, nil, nil) - return -} - -// ResetMetadataOptsBuilder allows extensions to add additional parameters to -// the Reset request. -type ResetMetadataOptsBuilder interface { - ToMetadataResetMap() (map[string]interface{}, error) -} - -// MetadataOpts is a map that contains key-value pairs. -type MetadataOpts map[string]string - -// ToMetadataResetMap assembles a body for a Reset request based on the contents -// of a MetadataOpts. -func (opts MetadataOpts) ToMetadataResetMap() (map[string]interface{}, error) { - return map[string]interface{}{"metadata": opts}, nil -} - -// ToMetadataUpdateMap assembles a body for an Update request based on the -// contents of a MetadataOpts. -func (opts MetadataOpts) ToMetadataUpdateMap() (map[string]interface{}, error) { - return map[string]interface{}{"metadata": opts}, nil -} - -// ResetMetadata will create multiple new key-value pairs for the given server -// ID. -// Note: Using this operation will erase any already-existing metadata and -// create the new metadata provided. To keep any already-existing metadata, -// use the UpdateMetadatas or UpdateMetadata function. -func ResetMetadata(client *gophercloud.ServiceClient, id string, opts ResetMetadataOptsBuilder) (r ResetMetadataResult) { - b, err := opts.ToMetadataResetMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Put(metadataURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// Metadata requests all the metadata for the given server ID. -func Metadata(client *gophercloud.ServiceClient, id string) (r GetMetadataResult) { - _, r.Err = client.Get(metadataURL(client, id), &r.Body, nil) - return -} - -// UpdateMetadataOptsBuilder allows extensions to add additional parameters to -// the Create request. -type UpdateMetadataOptsBuilder interface { - ToMetadataUpdateMap() (map[string]interface{}, error) -} - -// UpdateMetadata updates (or creates) all the metadata specified by opts for -// the given server ID. This operation does not affect already-existing metadata -// that is not specified by opts. -func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts UpdateMetadataOptsBuilder) (r UpdateMetadataResult) { - b, err := opts.ToMetadataUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(metadataURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// MetadatumOptsBuilder allows extensions to add additional parameters to the -// Create request. -type MetadatumOptsBuilder interface { - ToMetadatumCreateMap() (map[string]interface{}, string, error) -} - -// MetadatumOpts is a map of length one that contains a key-value pair. -type MetadatumOpts map[string]string - -// ToMetadatumCreateMap assembles a body for a Create request based on the -// contents of a MetadataumOpts. -func (opts MetadatumOpts) ToMetadatumCreateMap() (map[string]interface{}, string, error) { - if len(opts) != 1 { - err := gophercloud.ErrInvalidInput{} - err.Argument = "servers.MetadatumOpts" - err.Info = "Must have 1 and only 1 key-value pair" - return nil, "", err - } - metadatum := map[string]interface{}{"meta": opts} - var key string - for k := range metadatum["meta"].(MetadatumOpts) { - key = k - } - return metadatum, key, nil -} - -// CreateMetadatum will create or update the key-value pair with the given key -// for the given server ID. -func CreateMetadatum(client *gophercloud.ServiceClient, id string, opts MetadatumOptsBuilder) (r CreateMetadatumResult) { - b, key, err := opts.ToMetadatumCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Put(metadatumURL(client, id, key), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// Metadatum requests the key-value pair with the given key for the given -// server ID. -func Metadatum(client *gophercloud.ServiceClient, id, key string) (r GetMetadatumResult) { - _, r.Err = client.Get(metadatumURL(client, id, key), &r.Body, nil) - return -} - -// DeleteMetadatum will delete the key-value pair with the given key for the -// given server ID. -func DeleteMetadatum(client *gophercloud.ServiceClient, id, key string) (r DeleteMetadatumResult) { - _, r.Err = client.Delete(metadatumURL(client, id, key), nil) - return -} - -// ListAddresses makes a request against the API to list the servers IP -// addresses. -func ListAddresses(client *gophercloud.ServiceClient, id string) pagination.Pager { - return pagination.NewPager(client, listAddressesURL(client, id), func(r pagination.PageResult) pagination.Page { - return AddressPage{pagination.SinglePageBase(r)} - }) -} - -// ListAddressesByNetwork makes a request against the API to list the servers IP -// addresses for the given network. -func ListAddressesByNetwork(client *gophercloud.ServiceClient, id, network string) pagination.Pager { - return pagination.NewPager(client, listAddressesByNetworkURL(client, id, network), func(r pagination.PageResult) pagination.Page { - return NetworkAddressPage{pagination.SinglePageBase(r)} - }) -} - -// CreateImageOptsBuilder allows extensions to add additional parameters to the -// CreateImage request. -type CreateImageOptsBuilder interface { - ToServerCreateImageMap() (map[string]interface{}, error) -} - -// CreateImageOpts provides options to pass to the CreateImage request. -type CreateImageOpts struct { - // Name of the image/snapshot. - Name string `json:"name" required:"true"` - - // Metadata contains key-value pairs (up to 255 bytes each) to attach to - // the created image. - Metadata map[string]string `json:"metadata,omitempty"` -} - -// ToServerCreateImageMap formats a CreateImageOpts structure into a request -// body. -func (opts CreateImageOpts) ToServerCreateImageMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "createImage") -} - -// CreateImage makes a request against the nova API to schedule an image to be -// created of the server -func CreateImage(client *gophercloud.ServiceClient, id string, opts CreateImageOptsBuilder) (r CreateImageResult) { - b, err := opts.ToServerCreateImageMap() - if err != nil { - r.Err = err - return - } - resp, err := client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{ - OkCodes: []int{202}, - }) - r.Err = err - r.Header = resp.Header - 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 := "" - - listOpts := ListOpts{ - Name: name, - } - - allPages, err := List(client, listOpts).AllPages() - if err != nil { - return "", err - } - - all, err := ExtractServers(allPages) - if err != nil { - return "", err - } - - for _, f := range all { - if f.Name == name { - count++ - id = f.ID - } - } - - switch count { - case 0: - return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "server"} - case 1: - return id, nil - default: - return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "server"} - } -} - -// GetPassword makes a request against the nova API to get the encrypted -// administrative password. -func GetPassword(client *gophercloud.ServiceClient, serverId string) (r GetPasswordResult) { - _, r.Err = client.Get(passwordURL(client, serverId), &r.Body, nil) - return -} - -// ShowConsoleOutputOptsBuilder is the interface types must satisfy in order to be -// used as ShowConsoleOutput options -type ShowConsoleOutputOptsBuilder interface { - ToServerShowConsoleOutputMap() (map[string]interface{}, error) -} - -// ShowConsoleOutputOpts satisfies the ShowConsoleOutputOptsBuilder -type ShowConsoleOutputOpts struct { - // The number of lines to fetch from the end of console log. - // All lines will be returned if this is not specified. - Length int `json:"length,omitempty"` -} - -// ToServerShowConsoleOutputMap formats a ShowConsoleOutputOpts structure into a request body. -func (opts ShowConsoleOutputOpts) ToServerShowConsoleOutputMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "os-getConsoleOutput") -} - -// ShowConsoleOutput makes a request against the nova API to get console log from the server -func ShowConsoleOutput(client *gophercloud.ServiceClient, id string, opts ShowConsoleOutputOptsBuilder) (r ShowConsoleOutputResult) { - b, err := opts.ToServerShowConsoleOutputMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(actionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/results.go deleted file mode 100644 index f973d1ea0e1..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/results.go +++ /dev/null @@ -1,414 +0,0 @@ -package servers - -import ( - "crypto/rsa" - "encoding/base64" - "encoding/json" - "fmt" - "net/url" - "path" - "time" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -type serverResult struct { - gophercloud.Result -} - -// Extract interprets any serverResult as a Server, if possible. -func (r serverResult) Extract() (*Server, error) { - var s Server - err := r.ExtractInto(&s) - return &s, err -} - -func (r serverResult) ExtractInto(v interface{}) error { - return r.Result.ExtractIntoStructPtr(v, "server") -} - -func ExtractServersInto(r pagination.Page, v interface{}) error { - return r.(ServerPage).Result.ExtractIntoSlicePtr(v, "servers") -} - -// CreateResult is the response from a Create operation. Call its Extract -// method to interpret it as a Server. -type CreateResult struct { - serverResult -} - -// GetResult is the response from a Get operation. Call its Extract -// method to interpret it as a Server. -type GetResult struct { - serverResult -} - -// UpdateResult is the response from an Update operation. Call its Extract -// method to interpret it as a Server. -type UpdateResult struct { - serverResult -} - -// DeleteResult is the response from a Delete operation. Call its ExtractErr -// method to determine if the call succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} - -// RebuildResult is the response from a Rebuild operation. Call its Extract -// method to interpret it as a Server. -type RebuildResult struct { - serverResult -} - -// ActionResult represents the result of server action operations, like reboot. -// Call its ExtractErr method to determine if the action succeeded or failed. -type ActionResult struct { - gophercloud.ErrResult -} - -// CreateImageResult is the response from a CreateImage operation. Call its -// ExtractImageID method to retrieve the ID of the newly created image. -type CreateImageResult struct { - gophercloud.Result -} - -// ShowConsoleOutputResult represents the result of console output from a server -type ShowConsoleOutputResult struct { - gophercloud.Result -} - -// Extract will return the console output from a ShowConsoleOutput request. -func (r ShowConsoleOutputResult) Extract() (string, error) { - var s struct { - Output string `json:"output"` - } - - err := r.ExtractInto(&s) - return s.Output, err -} - -// GetPasswordResult represent the result of a get os-server-password operation. -// Call its ExtractPassword method to retrieve the password. -type GetPasswordResult struct { - gophercloud.Result -} - -// ExtractPassword gets the encrypted password. -// If privateKey != nil the password is decrypted with the private key. -// If privateKey == nil the encrypted password is returned and can be decrypted -// with: -// echo '' | base64 -D | openssl rsautl -decrypt -inkey -func (r GetPasswordResult) ExtractPassword(privateKey *rsa.PrivateKey) (string, error) { - var s struct { - Password string `json:"password"` - } - err := r.ExtractInto(&s) - if err == nil && privateKey != nil && s.Password != "" { - return decryptPassword(s.Password, privateKey) - } - return s.Password, err -} - -func decryptPassword(encryptedPassword string, privateKey *rsa.PrivateKey) (string, error) { - b64EncryptedPassword := make([]byte, base64.StdEncoding.DecodedLen(len(encryptedPassword))) - - n, err := base64.StdEncoding.Decode(b64EncryptedPassword, []byte(encryptedPassword)) - if err != nil { - return "", fmt.Errorf("Failed to base64 decode encrypted password: %s", err) - } - password, err := rsa.DecryptPKCS1v15(nil, privateKey, b64EncryptedPassword[0:n]) - if err != nil { - return "", fmt.Errorf("Failed to decrypt password: %s", err) - } - - return string(password), nil -} - -// ExtractImageID gets the ID of the newly created server image from the header. -func (r CreateImageResult) ExtractImageID() (string, error) { - if r.Err != nil { - return "", r.Err - } - // Get the image id from the header - u, err := url.ParseRequestURI(r.Header.Get("Location")) - if err != nil { - return "", err - } - imageID := path.Base(u.Path) - if imageID == "." || imageID == "/" { - return "", fmt.Errorf("Failed to parse the ID of newly created image: %s", u) - } - return imageID, nil -} - -// Server represents a server/instance in the OpenStack cloud. -type Server struct { - // ID uniquely identifies this server amongst all other servers, - // including those not accessible to the current tenant. - ID string `json:"id"` - - // TenantID identifies the tenant owning this server resource. - TenantID string `json:"tenant_id"` - - // UserID uniquely identifies the user account owning the tenant. - UserID string `json:"user_id"` - - // Name contains the human-readable name for the server. - Name string `json:"name"` - - // Updated and Created contain ISO-8601 timestamps of when the state of the - // server last changed, and when it was created. - Updated time.Time `json:"updated"` - Created time.Time `json:"created"` - - // HostID is the host where the server is located in the cloud. - HostID string `json:"hostid"` - - // Status contains the current operational status of the server, - // such as IN_PROGRESS or ACTIVE. - Status string `json:"status"` - - // Progress ranges from 0..100. - // A request made against the server completes only once Progress reaches 100. - Progress int `json:"progress"` - - // AccessIPv4 and AccessIPv6 contain the IP addresses of the server, - // suitable for remote access for administration. - AccessIPv4 string `json:"accessIPv4"` - AccessIPv6 string `json:"accessIPv6"` - - // Image refers to a JSON object, which itself indicates the OS image used to - // deploy the server. - Image map[string]interface{} `json:"-"` - - // Flavor refers to a JSON object, which itself indicates the hardware - // configuration of the deployed server. - Flavor map[string]interface{} `json:"flavor"` - - // Addresses includes a list of all IP addresses assigned to the server, - // keyed by pool. - Addresses map[string]interface{} `json:"addresses"` - - // Metadata includes a list of all user-specified key-value pairs attached - // to the server. - Metadata map[string]string `json:"metadata"` - - // Links includes HTTP references to the itself, useful for passing along to - // other APIs that might want a server reference. - Links []interface{} `json:"links"` - - // KeyName indicates which public key was injected into the server on launch. - KeyName string `json:"key_name"` - - // AdminPass will generally be empty (""). However, it will contain the - // administrative password chosen when provisioning a new server without a - // set AdminPass setting in the first place. - // Note that this is the ONLY time this field will be valid. - AdminPass string `json:"adminPass"` - - // SecurityGroups includes the security groups that this instance has applied - // to it. - SecurityGroups []map[string]interface{} `json:"security_groups"` - - // Fault contains failure information about a server. - Fault Fault `json:"fault"` -} - -type Fault struct { - Code int `json:"code"` - Created time.Time `json:"created"` - Details string `json:"details"` - Message string `json:"message"` -} - -func (r *Server) UnmarshalJSON(b []byte) error { - type tmp Server - var s struct { - tmp - Image interface{} `json:"image"` - } - err := json.Unmarshal(b, &s) - if err != nil { - return err - } - - *r = Server(s.tmp) - - switch t := s.Image.(type) { - case map[string]interface{}: - r.Image = t - case string: - switch t { - case "": - r.Image = nil - } - } - - return err -} - -// ServerPage abstracts the raw results of making a List() request against -// the API. As OpenStack extensions may freely alter the response bodies of -// structures returned to the client, you may only safely access the data -// provided through the ExtractServers call. -type ServerPage struct { - pagination.LinkedPageBase -} - -// IsEmpty returns true if a page contains no Server results. -func (r ServerPage) IsEmpty() (bool, error) { - s, err := ExtractServers(r) - return len(s) == 0, err -} - -// NextPageURL uses the response's embedded link reference to navigate to the -// next page of results. -func (r ServerPage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"servers_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// ExtractServers interprets the results of a single page from a List() call, -// producing a slice of Server entities. -func ExtractServers(r pagination.Page) ([]Server, error) { - var s []Server - err := ExtractServersInto(r, &s) - return s, err -} - -// MetadataResult contains the result of a call for (potentially) multiple -// key-value pairs. Call its Extract method to interpret it as a -// map[string]interface. -type MetadataResult struct { - gophercloud.Result -} - -// GetMetadataResult contains the result of a Get operation. Call its Extract -// method to interpret it as a map[string]interface. -type GetMetadataResult struct { - MetadataResult -} - -// ResetMetadataResult contains the result of a Reset operation. Call its -// Extract method to interpret it as a map[string]interface. -type ResetMetadataResult struct { - MetadataResult -} - -// UpdateMetadataResult contains the result of an Update operation. Call its -// Extract method to interpret it as a map[string]interface. -type UpdateMetadataResult struct { - MetadataResult -} - -// MetadatumResult contains the result of a call for individual a single -// key-value pair. -type MetadatumResult struct { - gophercloud.Result -} - -// GetMetadatumResult contains the result of a Get operation. Call its Extract -// method to interpret it as a map[string]interface. -type GetMetadatumResult struct { - MetadatumResult -} - -// CreateMetadatumResult contains the result of a Create operation. Call its -// Extract method to interpret it as a map[string]interface. -type CreateMetadatumResult struct { - MetadatumResult -} - -// DeleteMetadatumResult contains the result of a Delete operation. Call its -// ExtractErr method to determine if the call succeeded or failed. -type DeleteMetadatumResult struct { - gophercloud.ErrResult -} - -// Extract interprets any MetadataResult as a Metadata, if possible. -func (r MetadataResult) Extract() (map[string]string, error) { - var s struct { - Metadata map[string]string `json:"metadata"` - } - err := r.ExtractInto(&s) - return s.Metadata, err -} - -// Extract interprets any MetadatumResult as a Metadatum, if possible. -func (r MetadatumResult) Extract() (map[string]string, error) { - var s struct { - Metadatum map[string]string `json:"meta"` - } - err := r.ExtractInto(&s) - return s.Metadatum, err -} - -// Address represents an IP address. -type Address struct { - Version int `json:"version"` - Address string `json:"addr"` -} - -// AddressPage abstracts the raw results of making a ListAddresses() request -// against the API. As OpenStack extensions may freely alter the response bodies -// of structures returned to the client, you may only safely access the data -// provided through the ExtractAddresses call. -type AddressPage struct { - pagination.SinglePageBase -} - -// IsEmpty returns true if an AddressPage contains no networks. -func (r AddressPage) IsEmpty() (bool, error) { - addresses, err := ExtractAddresses(r) - return len(addresses) == 0, err -} - -// ExtractAddresses interprets the results of a single page from a -// ListAddresses() call, producing a map of addresses. -func ExtractAddresses(r pagination.Page) (map[string][]Address, error) { - var s struct { - Addresses map[string][]Address `json:"addresses"` - } - err := (r.(AddressPage)).ExtractInto(&s) - return s.Addresses, err -} - -// NetworkAddressPage abstracts the raw results of making a -// ListAddressesByNetwork() request against the API. -// As OpenStack extensions may freely alter the response bodies of structures -// returned to the client, you may only safely access the data provided through -// the ExtractAddresses call. -type NetworkAddressPage struct { - pagination.SinglePageBase -} - -// IsEmpty returns true if a NetworkAddressPage contains no addresses. -func (r NetworkAddressPage) IsEmpty() (bool, error) { - addresses, err := ExtractNetworkAddresses(r) - return len(addresses) == 0, err -} - -// ExtractNetworkAddresses interprets the results of a single page from a -// ListAddressesByNetwork() call, producing a slice of addresses. -func ExtractNetworkAddresses(r pagination.Page) ([]Address, error) { - var s map[string][]Address - err := (r.(NetworkAddressPage)).ExtractInto(&s) - if err != nil { - return nil, err - } - - var key string - for k := range s { - key = k - } - - return s[key], err -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/urls.go deleted file mode 100644 index e892e8d9259..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/urls.go +++ /dev/null @@ -1,51 +0,0 @@ -package servers - -import "github.com/gophercloud/gophercloud" - -func createURL(client *gophercloud.ServiceClient) string { - return client.ServiceURL("servers") -} - -func listURL(client *gophercloud.ServiceClient) string { - return createURL(client) -} - -func listDetailURL(client *gophercloud.ServiceClient) string { - return client.ServiceURL("servers", "detail") -} - -func deleteURL(client *gophercloud.ServiceClient, id string) string { - return client.ServiceURL("servers", id) -} - -func getURL(client *gophercloud.ServiceClient, id string) string { - return deleteURL(client, id) -} - -func updateURL(client *gophercloud.ServiceClient, id string) string { - return deleteURL(client, id) -} - -func actionURL(client *gophercloud.ServiceClient, id string) string { - return client.ServiceURL("servers", id, "action") -} - -func metadatumURL(client *gophercloud.ServiceClient, id, key string) string { - return client.ServiceURL("servers", id, "metadata", key) -} - -func metadataURL(client *gophercloud.ServiceClient, id string) string { - return client.ServiceURL("servers", id, "metadata") -} - -func listAddressesURL(client *gophercloud.ServiceClient, id string) string { - return client.ServiceURL("servers", id, "ips") -} - -func listAddressesByNetworkURL(client *gophercloud.ServiceClient, id, network string) string { - return client.ServiceURL("servers", id, "ips", network) -} - -func passwordURL(client *gophercloud.ServiceClient, id string) string { - return client.ServiceURL("servers", id, "os-server-password") -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/util.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/util.go deleted file mode 100644 index cadef054506..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/util.go +++ /dev/null @@ -1,21 +0,0 @@ -package servers - -import "github.com/gophercloud/gophercloud" - -// WaitForStatus will continually poll a server until it successfully -// transitions to a specified status. It will do this for at most the number -// of seconds specified. -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/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/doc.go deleted file mode 100644 index cedf1f4d3a3..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/doc.go +++ /dev/null @@ -1,14 +0,0 @@ -/* -Package openstack contains resources for the individual OpenStack projects -supported in Gophercloud. It also includes functions to authenticate to an -OpenStack cloud and for provisioning various service-level clients. - -Example of Creating a Service Client - - ao, err := openstack.AuthOptionsFromEnv() - provider, err := openstack.AuthenticatedClient(ao) - client, err := openstack.NewNetworkV2(client, gophercloud.EndpointOpts{ - Region: os.Getenv("OS_REGION_NAME"), - }) -*/ -package openstack diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/endpoint_location.go b/vendor/github.com/gophercloud/gophercloud/openstack/endpoint_location.go deleted file mode 100644 index 12c8aebcf77..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/endpoint_location.go +++ /dev/null @@ -1,107 +0,0 @@ -package openstack - -import ( - "github.com/gophercloud/gophercloud" - tokens2 "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens" - tokens3 "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens" -) - -/* -V2EndpointURL discovers the endpoint URL for a specific service from a -ServiceCatalog acquired during the v2 identity service. - -The specified EndpointOpts are used to identify a unique, unambiguous endpoint -to return. It's an error both when multiple endpoints match the provided -criteria and when none do. The minimum that can be specified is a Type, but you -will also often need to specify a Name and/or a Region depending on what's -available on your OpenStack deployment. -*/ -func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) { - // Extract Endpoints from the catalog entries that match the requested Type, Name if provided, and Region if provided. - var endpoints = make([]tokens2.Endpoint, 0, 1) - for _, entry := range catalog.Entries { - if (entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) { - for _, endpoint := range entry.Endpoints { - if opts.Region == "" || endpoint.Region == opts.Region { - endpoints = append(endpoints, endpoint) - } - } - } - } - - // Report an error if the options were ambiguous. - if len(endpoints) > 1 { - err := &ErrMultipleMatchingEndpointsV2{} - err.Endpoints = endpoints - return "", err - } - - // Extract the appropriate URL from the matching Endpoint. - for _, endpoint := range endpoints { - switch opts.Availability { - case gophercloud.AvailabilityPublic: - return gophercloud.NormalizeURL(endpoint.PublicURL), nil - case gophercloud.AvailabilityInternal: - return gophercloud.NormalizeURL(endpoint.InternalURL), nil - case gophercloud.AvailabilityAdmin: - return gophercloud.NormalizeURL(endpoint.AdminURL), nil - default: - err := &ErrInvalidAvailabilityProvided{} - err.Argument = "Availability" - err.Value = opts.Availability - return "", err - } - } - - // Report an error if there were no matching endpoints. - err := &gophercloud.ErrEndpointNotFound{} - return "", err -} - -/* -V3EndpointURL discovers the endpoint URL for a specific service from a Catalog -acquired during the v3 identity service. - -The specified EndpointOpts are used to identify a unique, unambiguous endpoint -to return. It's an error both when multiple endpoints match the provided -criteria and when none do. The minimum that can be specified is a Type, but you -will also often need to specify a Name and/or a Region depending on what's -available on your OpenStack deployment. -*/ -func V3EndpointURL(catalog *tokens3.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) { - // Extract Endpoints from the catalog entries that match the requested Type, Interface, - // Name if provided, and Region if provided. - var endpoints = make([]tokens3.Endpoint, 0, 1) - for _, entry := range catalog.Entries { - if (entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) { - for _, endpoint := range entry.Endpoints { - if opts.Availability != gophercloud.AvailabilityAdmin && - opts.Availability != gophercloud.AvailabilityPublic && - opts.Availability != gophercloud.AvailabilityInternal { - err := &ErrInvalidAvailabilityProvided{} - err.Argument = "Availability" - err.Value = opts.Availability - return "", err - } - if (opts.Availability == gophercloud.Availability(endpoint.Interface)) && - (opts.Region == "" || endpoint.Region == opts.Region || endpoint.RegionID == opts.Region) { - endpoints = append(endpoints, endpoint) - } - } - } - } - - // Report an error if the options were ambiguous. - if len(endpoints) > 1 { - return "", ErrMultipleMatchingEndpointsV3{Endpoints: endpoints} - } - - // Extract the URL from the matching Endpoint. - for _, endpoint := range endpoints { - return gophercloud.NormalizeURL(endpoint.URL), nil - } - - // Report an error if there were no matching endpoints. - err := &gophercloud.ErrEndpointNotFound{} - return "", err -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/errors.go b/vendor/github.com/gophercloud/gophercloud/openstack/errors.go deleted file mode 100644 index df410b1c611..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/errors.go +++ /dev/null @@ -1,71 +0,0 @@ -package openstack - -import ( - "fmt" - - "github.com/gophercloud/gophercloud" - tokens2 "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens" - tokens3 "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens" -) - -// ErrEndpointNotFound is the error when no suitable endpoint can be found -// in the user's catalog -type ErrEndpointNotFound struct{ gophercloud.BaseError } - -func (e ErrEndpointNotFound) Error() string { - return "No suitable endpoint could be found in the service catalog." -} - -// ErrInvalidAvailabilityProvided is the error when an invalid endpoint -// availability is provided -type ErrInvalidAvailabilityProvided struct{ gophercloud.ErrInvalidInput } - -func (e ErrInvalidAvailabilityProvided) Error() string { - return fmt.Sprintf("Unexpected availability in endpoint query: %s", e.Value) -} - -// ErrMultipleMatchingEndpointsV2 is the error when more than one endpoint -// for the given options is found in the v2 catalog -type ErrMultipleMatchingEndpointsV2 struct { - gophercloud.BaseError - Endpoints []tokens2.Endpoint -} - -func (e ErrMultipleMatchingEndpointsV2) Error() string { - return fmt.Sprintf("Discovered %d matching endpoints: %#v", len(e.Endpoints), e.Endpoints) -} - -// ErrMultipleMatchingEndpointsV3 is the error when more than one endpoint -// for the given options is found in the v3 catalog -type ErrMultipleMatchingEndpointsV3 struct { - gophercloud.BaseError - Endpoints []tokens3.Endpoint -} - -func (e ErrMultipleMatchingEndpointsV3) Error() string { - return fmt.Sprintf("Discovered %d matching endpoints: %#v", len(e.Endpoints), e.Endpoints) -} - -// ErrNoAuthURL is the error when the OS_AUTH_URL environment variable is not -// found -type ErrNoAuthURL struct{ gophercloud.ErrInvalidInput } - -func (e ErrNoAuthURL) Error() string { - return "Environment variable OS_AUTH_URL needs to be set." -} - -// ErrNoUsername is the error when the OS_USERNAME environment variable is not -// found -type ErrNoUsername struct{ gophercloud.ErrInvalidInput } - -func (e ErrNoUsername) Error() string { - return "Environment variable OS_USERNAME needs to be set." -} - -// ErrNoPassword is the error when the OS_PASSWORD environment variable is not -// found -type ErrNoPassword struct{ gophercloud.ErrInvalidInput } - -func (e ErrNoPassword) Error() string { - return "Environment variable OS_PASSWORD needs to be set." -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/doc.go deleted file mode 100644 index 45623369e18..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/doc.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Package tenants provides information and interaction with the -tenants API resource for the OpenStack Identity service. - -See http://developer.openstack.org/api-ref-identity-v2.html#identity-auth-v2 -and http://developer.openstack.org/api-ref-identity-v2.html#admin-tenants -for more information. - -Example to List Tenants - - listOpts := tenants.ListOpts{ - Limit: 2, - } - - allPages, err := tenants.List(identityClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - allTenants, err := tenants.ExtractTenants(allPages) - if err != nil { - panic(err) - } - - for _, tenant := range allTenants { - fmt.Printf("%+v\n", tenant) - } - -Example to Create a Tenant - - createOpts := tenants.CreateOpts{ - Name: "tenant_name", - Description: "this is a tenant", - Enabled: gophercloud.Enabled, - } - - tenant, err := tenants.Create(identityClient, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to Update a Tenant - - tenantID := "e6db6ed6277c461a853458589063b295" - - updateOpts := tenants.UpdateOpts{ - Description: "this is a new description", - Enabled: gophercloud.Disabled, - } - - tenant, err := tenants.Update(identityClient, tenantID, updateOpts).Extract() - if err != nil { - panic(err) - } - -Example to Delete a Tenant - - tenantID := "e6db6ed6277c461a853458589063b295" - - err := tenants.Delete(identitYClient, tenantID).ExtractErr() - if err != nil { - panic(err) - } -*/ -package tenants diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/requests.go deleted file mode 100644 index f21a58f10c8..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/requests.go +++ /dev/null @@ -1,116 +0,0 @@ -package tenants - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// ListOpts filters the Tenants that are returned by the List call. -type ListOpts struct { - // Marker is the ID of the last Tenant on the previous page. - Marker string `q:"marker"` - - // Limit specifies the page size. - Limit int `q:"limit"` -} - -// List enumerates the Tenants to which the current token has access. -func List(client *gophercloud.ServiceClient, opts *ListOpts) pagination.Pager { - url := listURL(client) - if opts != nil { - q, err := gophercloud.BuildQueryString(opts) - if err != nil { - return pagination.Pager{Err: err} - } - url += q.String() - } - return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { - return TenantPage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -// CreateOpts represents the options needed when creating new tenant. -type CreateOpts struct { - // Name is the name of the tenant. - Name string `json:"name" required:"true"` - - // Description is the description of the tenant. - Description string `json:"description,omitempty"` - - // Enabled sets the tenant status to enabled or disabled. - Enabled *bool `json:"enabled,omitempty"` -} - -// CreateOptsBuilder enables extensions to add additional parameters to the -// Create request. -type CreateOptsBuilder interface { - ToTenantCreateMap() (map[string]interface{}, error) -} - -// ToTenantCreateMap assembles a request body based on the contents of -// a CreateOpts. -func (opts CreateOpts) ToTenantCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "tenant") -} - -// Create is the operation responsible for creating new tenant. -func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToTenantCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200, 201}, - }) - return -} - -// Get requests details on a single tenant by ID. -func Get(client *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = client.Get(getURL(client, id), &r.Body, nil) - return -} - -// UpdateOptsBuilder allows extensions to add additional parameters to the -// Update request. -type UpdateOptsBuilder interface { - ToTenantUpdateMap() (map[string]interface{}, error) -} - -// UpdateOpts specifies the base attributes that may be updated on an existing -// tenant. -type UpdateOpts struct { - // Name is the name of the tenant. - Name string `json:"name,omitempty"` - - // Description is the description of the tenant. - Description *string `json:"description,omitempty"` - - // Enabled sets the tenant status to enabled or disabled. - Enabled *bool `json:"enabled,omitempty"` -} - -// ToTenantUpdateMap formats an UpdateOpts structure into a request body. -func (opts UpdateOpts) ToTenantUpdateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "tenant") -} - -// Update is the operation responsible for updating exist tenants by their TenantID. -func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { - b, err := opts.ToTenantUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Put(updateURL(client, id), &b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// Delete is the operation responsible for permanently deleting a tenant. -func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = client.Delete(deleteURL(client, id), nil) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/results.go deleted file mode 100644 index bb6c2c6b08a..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/results.go +++ /dev/null @@ -1,91 +0,0 @@ -package tenants - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// Tenant is a grouping of users in the identity service. -type Tenant struct { - // ID is a unique identifier for this tenant. - ID string `json:"id"` - - // Name is a friendlier user-facing name for this tenant. - Name string `json:"name"` - - // Description is a human-readable explanation of this Tenant's purpose. - Description string `json:"description"` - - // Enabled indicates whether or not a tenant is active. - Enabled bool `json:"enabled"` -} - -// TenantPage is a single page of Tenant results. -type TenantPage struct { - pagination.LinkedPageBase -} - -// IsEmpty determines whether or not a page of Tenants contains any results. -func (r TenantPage) IsEmpty() (bool, error) { - tenants, err := ExtractTenants(r) - return len(tenants) == 0, err -} - -// NextPageURL extracts the "next" link from the tenants_links section of the result. -func (r TenantPage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"tenants_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// ExtractTenants returns a slice of Tenants contained in a single page of -// results. -func ExtractTenants(r pagination.Page) ([]Tenant, error) { - var s struct { - Tenants []Tenant `json:"tenants"` - } - err := (r.(TenantPage)).ExtractInto(&s) - return s.Tenants, err -} - -type tenantResult struct { - gophercloud.Result -} - -// Extract interprets any tenantResults as a Tenant. -func (r tenantResult) Extract() (*Tenant, error) { - var s struct { - Tenant *Tenant `json:"tenant"` - } - err := r.ExtractInto(&s) - return s.Tenant, err -} - -// GetResult is the response from a Get request. Call its Extract method to -// interpret it as a Tenant. -type GetResult struct { - tenantResult -} - -// CreateResult is the response from a Create request. Call its Extract method -// to interpret it as a Tenant. -type CreateResult struct { - tenantResult -} - -// DeleteResult is the response from a Get request. Call its ExtractErr method -// to determine if the call succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} - -// UpdateResult is the response from a Update request. Call its Extract method -// to interpret it as a Tenant. -type UpdateResult struct { - tenantResult -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/urls.go deleted file mode 100644 index 0f026690790..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/urls.go +++ /dev/null @@ -1,23 +0,0 @@ -package tenants - -import "github.com/gophercloud/gophercloud" - -func listURL(client *gophercloud.ServiceClient) string { - return client.ServiceURL("tenants") -} - -func getURL(client *gophercloud.ServiceClient, tenantID string) string { - return client.ServiceURL("tenants", tenantID) -} - -func createURL(client *gophercloud.ServiceClient) string { - return client.ServiceURL("tenants") -} - -func deleteURL(client *gophercloud.ServiceClient, tenantID string) string { - return client.ServiceURL("tenants", tenantID) -} - -func updateURL(client *gophercloud.ServiceClient, tenantID string) string { - return client.ServiceURL("tenants", tenantID) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/doc.go deleted file mode 100644 index 5375eea8726..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/doc.go +++ /dev/null @@ -1,46 +0,0 @@ -/* -Package tokens provides information and interaction with the token API -resource for the OpenStack Identity service. - -For more information, see: -http://developer.openstack.org/api-ref-identity-v2.html#identity-auth-v2 - -Example to Create an Unscoped Token from a Password - - authOpts := gophercloud.AuthOptions{ - Username: "user", - Password: "pass" - } - - token, err := tokens.Create(identityClient, authOpts).ExtractToken() - if err != nil { - panic(err) - } - -Example to Create a Token from a Tenant ID and Password - - authOpts := gophercloud.AuthOptions{ - Username: "user", - Password: "password", - TenantID: "fc394f2ab2df4114bde39905f800dc57" - } - - token, err := tokens.Create(identityClient, authOpts).ExtractToken() - if err != nil { - panic(err) - } - -Example to Create a Token from a Tenant Name and Password - - authOpts := gophercloud.AuthOptions{ - Username: "user", - Password: "password", - TenantName: "tenantname" - } - - token, err := tokens.Create(identityClient, authOpts).ExtractToken() - if err != nil { - panic(err) - } -*/ -package tokens diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/requests.go deleted file mode 100644 index ab32368cc6e..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/requests.go +++ /dev/null @@ -1,103 +0,0 @@ -package tokens - -import "github.com/gophercloud/gophercloud" - -// PasswordCredentialsV2 represents the required options to authenticate -// with a username and password. -type PasswordCredentialsV2 struct { - Username string `json:"username" required:"true"` - Password string `json:"password" required:"true"` -} - -// TokenCredentialsV2 represents the required options to authenticate -// with a token. -type TokenCredentialsV2 struct { - ID string `json:"id,omitempty" required:"true"` -} - -// AuthOptionsV2 wraps a gophercloud AuthOptions in order to adhere to the -// AuthOptionsBuilder interface. -type AuthOptionsV2 struct { - PasswordCredentials *PasswordCredentialsV2 `json:"passwordCredentials,omitempty" xor:"TokenCredentials"` - - // The TenantID and TenantName fields are optional for the Identity V2 API. - // Some providers allow you to specify a TenantName instead of the TenantId. - // Some require both. Your provider's authentication policies will determine - // how these fields influence authentication. - TenantID string `json:"tenantId,omitempty"` - TenantName string `json:"tenantName,omitempty"` - - // TokenCredentials allows users to authenticate (possibly as another user) - // with an authentication token ID. - TokenCredentials *TokenCredentialsV2 `json:"token,omitempty" xor:"PasswordCredentials"` -} - -// AuthOptionsBuilder allows extensions to add additional parameters to the -// token create request. -type AuthOptionsBuilder interface { - // ToTokenCreateMap assembles the Create request body, returning an error - // if parameters are missing or inconsistent. - ToTokenV2CreateMap() (map[string]interface{}, error) -} - -// AuthOptions are the valid options for Openstack Identity v2 authentication. -// For field descriptions, see gophercloud.AuthOptions. -type AuthOptions struct { - IdentityEndpoint string `json:"-"` - Username string `json:"username,omitempty"` - Password string `json:"password,omitempty"` - TenantID string `json:"tenantId,omitempty"` - TenantName string `json:"tenantName,omitempty"` - AllowReauth bool `json:"-"` - TokenID string -} - -// ToTokenV2CreateMap builds a token request body from the given AuthOptions. -func (opts AuthOptions) ToTokenV2CreateMap() (map[string]interface{}, error) { - v2Opts := AuthOptionsV2{ - TenantID: opts.TenantID, - TenantName: opts.TenantName, - } - - if opts.Password != "" { - v2Opts.PasswordCredentials = &PasswordCredentialsV2{ - Username: opts.Username, - Password: opts.Password, - } - } else { - v2Opts.TokenCredentials = &TokenCredentialsV2{ - ID: opts.TokenID, - } - } - - b, err := gophercloud.BuildRequestBody(v2Opts, "auth") - if err != nil { - return nil, err - } - return b, nil -} - -// Create authenticates to the identity service and attempts to acquire a Token. -// Generally, rather than interact with this call directly, end users should -// call openstack.AuthenticatedClient(), which abstracts all of the gory details -// about navigating service catalogs and such. -func Create(client *gophercloud.ServiceClient, auth AuthOptionsBuilder) (r CreateResult) { - b, err := auth.ToTokenV2CreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(CreateURL(client), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200, 203}, - MoreHeaders: map[string]string{"X-Auth-Token": ""}, - }) - return -} - -// Get validates and retrieves information for user's token. -func Get(client *gophercloud.ServiceClient, token string) (r GetResult) { - _, r.Err = client.Get(GetURL(client, token), &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200, 203}, - }) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/results.go deleted file mode 100644 index ee5da37f465..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/results.go +++ /dev/null @@ -1,174 +0,0 @@ -package tokens - -import ( - "time" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants" -) - -// Token provides only the most basic information related to an authentication -// token. -type Token struct { - // ID provides the primary means of identifying a user to the OpenStack API. - // OpenStack defines this field as an opaque value, so do not depend on its - // content. It is safe, however, to compare for equality. - ID string - - // ExpiresAt provides a timestamp in ISO 8601 format, indicating when the - // authentication token becomes invalid. After this point in time, future - // API requests made using this authentication token will respond with - // errors. Either the caller will need to reauthenticate manually, or more - // preferably, the caller should exploit automatic re-authentication. - // See the AuthOptions structure for more details. - ExpiresAt time.Time - - // Tenant provides information about the tenant to which this token grants - // access. - Tenant tenants.Tenant -} - -// Role is a role for a user. -type Role struct { - Name string `json:"name"` -} - -// User is an OpenStack user. -type User struct { - ID string `json:"id"` - Name string `json:"name"` - UserName string `json:"username"` - Roles []Role `json:"roles"` -} - -// Endpoint represents a single API endpoint offered by a service. -// It provides the public and internal URLs, if supported, along with a region -// specifier, again if provided. -// -// The significance of the Region field will depend upon your provider. -// -// In addition, the interface offered by the service will have version -// information associated with it through the VersionId, VersionInfo, and -// VersionList fields, if provided or supported. -// -// In all cases, fields which aren't supported by the provider and service -// combined will assume a zero-value (""). -type Endpoint struct { - TenantID string `json:"tenantId"` - PublicURL string `json:"publicURL"` - InternalURL string `json:"internalURL"` - AdminURL string `json:"adminURL"` - Region string `json:"region"` - VersionID string `json:"versionId"` - VersionInfo string `json:"versionInfo"` - VersionList string `json:"versionList"` -} - -// CatalogEntry provides a type-safe interface to an Identity API V2 service -// catalog listing. -// -// Each class of service, such as cloud DNS or block storage services, will have -// a single CatalogEntry representing it. -// -// Note: when looking for the desired service, try, whenever possible, to key -// off the type field. Otherwise, you'll tie the representation of the service -// to a specific provider. -type CatalogEntry struct { - // Name will contain the provider-specified name for the service. - Name string `json:"name"` - - // Type will contain a type string if OpenStack defines a type for the - // service. Otherwise, for provider-specific services, the provider may assign - // their own type strings. - Type string `json:"type"` - - // Endpoints will let the caller iterate over all the different endpoints that - // may exist for the service. - Endpoints []Endpoint `json:"endpoints"` -} - -// ServiceCatalog provides a view into the service catalog from a previous, -// successful authentication. -type ServiceCatalog struct { - Entries []CatalogEntry -} - -// CreateResult is the response from a Create request. Use ExtractToken() to -// interpret it as a Token, or ExtractServiceCatalog() to interpret it as a -// service catalog. -type CreateResult struct { - gophercloud.Result -} - -// GetResult is the deferred response from a Get call, which is the same with a -// Created token. Use ExtractUser() to interpret it as a User. -type GetResult struct { - CreateResult -} - -// ExtractToken returns the just-created Token from a CreateResult. -func (r CreateResult) ExtractToken() (*Token, error) { - var s struct { - Access struct { - Token struct { - Expires string `json:"expires"` - ID string `json:"id"` - Tenant tenants.Tenant `json:"tenant"` - } `json:"token"` - } `json:"access"` - } - - err := r.ExtractInto(&s) - if err != nil { - return nil, err - } - - expiresTs, err := time.Parse(gophercloud.RFC3339Milli, s.Access.Token.Expires) - if err != nil { - return nil, err - } - - return &Token{ - ID: s.Access.Token.ID, - ExpiresAt: expiresTs, - Tenant: s.Access.Token.Tenant, - }, nil -} - -// ExtractTokenID implements the gophercloud.AuthResult interface. The returned -// string is the same as the ID field of the Token struct returned from -// ExtractToken(). -func (r CreateResult) ExtractTokenID() (string, error) { - var s struct { - Access struct { - Token struct { - ID string `json:"id"` - } `json:"token"` - } `json:"access"` - } - err := r.ExtractInto(&s) - return s.Access.Token.ID, err -} - -// ExtractServiceCatalog returns the ServiceCatalog that was generated along -// with the user's Token. -func (r CreateResult) ExtractServiceCatalog() (*ServiceCatalog, error) { - var s struct { - Access struct { - Entries []CatalogEntry `json:"serviceCatalog"` - } `json:"access"` - } - err := r.ExtractInto(&s) - return &ServiceCatalog{Entries: s.Access.Entries}, err -} - -// ExtractUser returns the User from a GetResult. -func (r GetResult) ExtractUser() (*User, error) { - var s struct { - Access struct { - User User `json:"user"` - } `json:"access"` - } - err := r.ExtractInto(&s) - return &s.Access.User, err -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/urls.go deleted file mode 100644 index ee0a28f2004..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/urls.go +++ /dev/null @@ -1,13 +0,0 @@ -package tokens - -import "github.com/gophercloud/gophercloud" - -// CreateURL generates the URL used to create new Tokens. -func CreateURL(client *gophercloud.ServiceClient) string { - return client.ServiceURL("tokens") -} - -// GetURL generates the URL used to Validate Tokens. -func GetURL(client *gophercloud.ServiceClient, token string) string { - return client.ServiceURL("tokens", token) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts/doc.go deleted file mode 100644 index 8db7724f2b0..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts/doc.go +++ /dev/null @@ -1,26 +0,0 @@ -/* -Package trusts enables management of OpenStack Identity Trusts. - -Example to Create a Token with Username, Password, and Trust ID - - var trustToken struct { - tokens.Token - trusts.TokenExt - } - - authOptions := tokens.AuthOptions{ - UserID: "username", - Password: "password", - } - - createOpts := trusts.AuthOptsExt{ - AuthOptionsBuilder: authOptions, - TrustID: "de0945a", - } - - err := tokens.Create(identityClient, createOpts).ExtractInto(&trustToken) - if err != nil { - panic(err) - } -*/ -package trusts diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts/requests.go deleted file mode 100644 index 438fba61de5..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts/requests.go +++ /dev/null @@ -1,39 +0,0 @@ -package trusts - -import "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens" - -// AuthOptsExt extends the base Identity v3 tokens AuthOpts with a TrustID. -type AuthOptsExt struct { - tokens.AuthOptionsBuilder - - // TrustID is the ID of the trust. - TrustID string `json:"id"` -} - -// ToTokenV3CreateMap builds a create request body from the AuthOpts. -func (opts AuthOptsExt) ToTokenV3CreateMap(scope map[string]interface{}) (map[string]interface{}, error) { - return opts.AuthOptionsBuilder.ToTokenV3CreateMap(scope) -} - -// ToTokenV3ScopeMap builds a scope from AuthOpts. -func (opts AuthOptsExt) ToTokenV3ScopeMap() (map[string]interface{}, error) { - b, err := opts.AuthOptionsBuilder.ToTokenV3ScopeMap() - if err != nil { - return nil, err - } - - if opts.TrustID != "" { - if b == nil { - b = make(map[string]interface{}) - } - b["OS-TRUST:trust"] = map[string]interface{}{ - "id": opts.TrustID, - } - } - - return b, nil -} - -func (opts AuthOptsExt) CanReauth() bool { - return opts.AuthOptionsBuilder.CanReauth() -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts/results.go deleted file mode 100644 index e6912e612c2..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts/results.go +++ /dev/null @@ -1,27 +0,0 @@ -package trusts - -// TrusteeUser represents the trusted user ID of a trust. -type TrusteeUser struct { - ID string `json:"id"` -} - -// TrustorUser represents the trusting user ID of a trust. -type TrustorUser struct { - ID string `json:"id"` -} - -// Trust represents a delegated authorization request between two -// identities. -type Trust struct { - ID string `json:"id"` - Impersonation bool `json:"impersonation"` - TrusteeUser TrusteeUser `json:"trustee_user"` - TrustorUser TrustorUser `json:"trustor_user"` - RedelegatedTrustID string `json:"redelegated_trust_id"` - RedelegationCount int `json:"redelegation_count"` -} - -// TokenExt represents an extension of the base token result. -type TokenExt struct { - Trust Trust `json:"OS-TRUST:trust"` -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/doc.go deleted file mode 100644 index 966e128f128..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/doc.go +++ /dev/null @@ -1,108 +0,0 @@ -/* -Package tokens provides information and interaction with the token API -resource for the OpenStack Identity service. - -For more information, see: -http://developer.openstack.org/api-ref-identity-v3.html#tokens-v3 - -Example to Create a Token From a Username and Password - - authOptions := tokens.AuthOptions{ - UserID: "username", - Password: "password", - } - - token, err := tokens.Create(identityClient, authOptions).ExtractToken() - if err != nil { - panic(err) - } - -Example to Create a Token From a Username, Password, and Domain - - authOptions := tokens.AuthOptions{ - UserID: "username", - Password: "password", - DomainID: "default", - } - - token, err := tokens.Create(identityClient, authOptions).ExtractToken() - if err != nil { - panic(err) - } - - authOptions = tokens.AuthOptions{ - UserID: "username", - Password: "password", - DomainName: "default", - } - - token, err = tokens.Create(identityClient, authOptions).ExtractToken() - if err != nil { - panic(err) - } - -Example to Create a Token From a Token - - authOptions := tokens.AuthOptions{ - TokenID: "token_id", - } - - token, err := tokens.Create(identityClient, authOptions).ExtractToken() - if err != nil { - panic(err) - } - -Example to Create a Token from a Username and Password with Project ID Scope - - scope := tokens.Scope{ - ProjectID: "0fe36e73809d46aeae6705c39077b1b3", - } - - authOptions := tokens.AuthOptions{ - Scope: &scope, - UserID: "username", - Password: "password", - } - - token, err = tokens.Create(identityClient, authOptions).ExtractToken() - if err != nil { - panic(err) - } - -Example to Create a Token from a Username and Password with Domain ID Scope - - scope := tokens.Scope{ - DomainID: "default", - } - - authOptions := tokens.AuthOptions{ - Scope: &scope, - UserID: "username", - Password: "password", - } - - token, err = tokens.Create(identityClient, authOptions).ExtractToken() - if err != nil { - panic(err) - } - -Example to Create a Token from a Username and Password with Project Name Scope - - scope := tokens.Scope{ - ProjectName: "project_name", - DomainID: "default", - } - - authOptions := tokens.AuthOptions{ - Scope: &scope, - UserID: "username", - Password: "password", - } - - token, err = tokens.Create(identityClient, authOptions).ExtractToken() - if err != nil { - panic(err) - } - -*/ -package tokens diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/requests.go deleted file mode 100644 index e4d766b2327..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/requests.go +++ /dev/null @@ -1,162 +0,0 @@ -package tokens - -import "github.com/gophercloud/gophercloud" - -// Scope allows a created token to be limited to a specific domain or project. -type Scope struct { - ProjectID string - ProjectName string - DomainID string - DomainName string -} - -// AuthOptionsBuilder provides the ability for extensions to add additional -// parameters to AuthOptions. Extensions must satisfy all required methods. -type AuthOptionsBuilder interface { - // ToTokenV3CreateMap assembles the Create request body, returning an error - // if parameters are missing or inconsistent. - ToTokenV3CreateMap(map[string]interface{}) (map[string]interface{}, error) - ToTokenV3ScopeMap() (map[string]interface{}, error) - CanReauth() bool -} - -// AuthOptions represents options for authenticating a user. -type AuthOptions struct { - // IdentityEndpoint specifies the HTTP endpoint that is required to work with - // the Identity API of the appropriate version. While it's ultimately needed - // by all of the identity services, it will often be populated by a - // provider-level function. - IdentityEndpoint string `json:"-"` - - // Username is required if using Identity V2 API. Consult with your provider's - // control panel to discover your account's username. In Identity V3, either - // UserID or a combination of Username and DomainID or DomainName are needed. - Username string `json:"username,omitempty"` - UserID string `json:"id,omitempty"` - - Password string `json:"password,omitempty"` - - // At most one of DomainID and DomainName must be provided if using Username - // with Identity V3. Otherwise, either are optional. - DomainID string `json:"-"` - DomainName string `json:"name,omitempty"` - - // AllowReauth should be set to true if you grant permission for Gophercloud - // to cache your credentials in memory, and to allow Gophercloud to attempt - // to re-authenticate automatically if/when your token expires. If you set - // it to false, it will not cache these settings, but re-authentication will - // not be possible. This setting defaults to false. - AllowReauth bool `json:"-"` - - // TokenID allows users to authenticate (possibly as another user) with an - // authentication token ID. - TokenID string `json:"-"` - - // Authentication through Application Credentials requires supplying name, project and secret - // For project we can use TenantID - ApplicationCredentialID string `json:"-"` - ApplicationCredentialName string `json:"-"` - ApplicationCredentialSecret string `json:"-"` - - Scope Scope `json:"-"` -} - -// ToTokenV3CreateMap builds a request body from AuthOptions. -func (opts *AuthOptions) ToTokenV3CreateMap(scope map[string]interface{}) (map[string]interface{}, error) { - gophercloudAuthOpts := gophercloud.AuthOptions{ - Username: opts.Username, - UserID: opts.UserID, - Password: opts.Password, - DomainID: opts.DomainID, - DomainName: opts.DomainName, - AllowReauth: opts.AllowReauth, - TokenID: opts.TokenID, - ApplicationCredentialID: opts.ApplicationCredentialID, - ApplicationCredentialName: opts.ApplicationCredentialName, - ApplicationCredentialSecret: opts.ApplicationCredentialSecret, - } - - return gophercloudAuthOpts.ToTokenV3CreateMap(scope) -} - -// ToTokenV3CreateMap builds a scope request body from AuthOptions. -func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) { - scope := gophercloud.AuthScope(opts.Scope) - - gophercloudAuthOpts := gophercloud.AuthOptions{ - Scope: &scope, - DomainID: opts.DomainID, - DomainName: opts.DomainName, - } - - return gophercloudAuthOpts.ToTokenV3ScopeMap() -} - -func (opts *AuthOptions) CanReauth() bool { - return opts.AllowReauth -} - -func subjectTokenHeaders(c *gophercloud.ServiceClient, subjectToken string) map[string]string { - return map[string]string{ - "X-Subject-Token": subjectToken, - } -} - -// Create authenticates and either generates a new token, or changes the Scope -// of an existing token. -func Create(c *gophercloud.ServiceClient, opts AuthOptionsBuilder) (r CreateResult) { - scope, err := opts.ToTokenV3ScopeMap() - if err != nil { - r.Err = err - return - } - - b, err := opts.ToTokenV3CreateMap(scope) - if err != nil { - r.Err = err - return - } - - resp, err := c.Post(tokenURL(c), b, &r.Body, &gophercloud.RequestOpts{ - MoreHeaders: map[string]string{"X-Auth-Token": ""}, - }) - r.Err = err - if resp != nil { - r.Header = resp.Header - } - return -} - -// Get validates and retrieves information about another token. -func Get(c *gophercloud.ServiceClient, token string) (r GetResult) { - resp, err := c.Get(tokenURL(c), &r.Body, &gophercloud.RequestOpts{ - MoreHeaders: subjectTokenHeaders(c, token), - OkCodes: []int{200, 203}, - }) - if resp != nil { - r.Header = resp.Header - } - r.Err = err - return -} - -// Validate determines if a specified token is valid or not. -func Validate(c *gophercloud.ServiceClient, token string) (bool, error) { - resp, err := c.Head(tokenURL(c), &gophercloud.RequestOpts{ - MoreHeaders: subjectTokenHeaders(c, token), - OkCodes: []int{200, 204, 404}, - }) - if err != nil { - return false, err - } - - return resp.StatusCode == 200 || resp.StatusCode == 204, nil -} - -// Revoke immediately makes specified token invalid. -func Revoke(c *gophercloud.ServiceClient, token string) (r RevokeResult) { - _, r.Err = c.Delete(tokenURL(c), &gophercloud.RequestOpts{ - MoreHeaders: subjectTokenHeaders(c, token), - }) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/results.go deleted file mode 100644 index 6f26c96bcdc..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/results.go +++ /dev/null @@ -1,178 +0,0 @@ -package tokens - -import ( - "time" - - "github.com/gophercloud/gophercloud" -) - -// Endpoint represents a single API endpoint offered by a service. -// It matches either a public, internal or admin URL. -// If supported, it contains a region specifier, again if provided. -// The significance of the Region field will depend upon your provider. -type Endpoint struct { - ID string `json:"id"` - Region string `json:"region"` - RegionID string `json:"region_id"` - Interface string `json:"interface"` - URL string `json:"url"` -} - -// CatalogEntry provides a type-safe interface to an Identity API V3 service -// catalog listing. Each class of service, such as cloud DNS or block storage -// services, could have multiple CatalogEntry representing it (one by interface -// type, e.g public, admin or internal). -// -// Note: when looking for the desired service, try, whenever possible, to key -// off the type field. Otherwise, you'll tie the representation of the service -// to a specific provider. -type CatalogEntry struct { - // Service ID - ID string `json:"id"` - - // Name will contain the provider-specified name for the service. - Name string `json:"name"` - - // Type will contain a type string if OpenStack defines a type for the - // service. Otherwise, for provider-specific services, the provider may - // assign their own type strings. - Type string `json:"type"` - - // Endpoints will let the caller iterate over all the different endpoints that - // may exist for the service. - Endpoints []Endpoint `json:"endpoints"` -} - -// ServiceCatalog provides a view into the service catalog from a previous, -// successful authentication. -type ServiceCatalog struct { - Entries []CatalogEntry `json:"catalog"` -} - -// Domain provides information about the domain to which this token grants -// access. -type Domain struct { - ID string `json:"id"` - Name string `json:"name"` -} - -// User represents a user resource that exists in the Identity Service. -type User struct { - Domain Domain `json:"domain"` - ID string `json:"id"` - Name string `json:"name"` -} - -// Role provides information about roles to which User is authorized. -type Role struct { - ID string `json:"id"` - Name string `json:"name"` -} - -// Project provides information about project to which User is authorized. -type Project struct { - Domain Domain `json:"domain"` - ID string `json:"id"` - Name string `json:"name"` -} - -// commonResult is the response from a request. A commonResult has various -// methods which can be used to extract different details about the result. -type commonResult struct { - gophercloud.Result -} - -// Extract is a shortcut for ExtractToken. -// This function is deprecated and still present for backward compatibility. -func (r commonResult) Extract() (*Token, error) { - return r.ExtractToken() -} - -// ExtractToken interprets a commonResult as a Token. -func (r commonResult) ExtractToken() (*Token, error) { - var s Token - err := r.ExtractInto(&s) - if err != nil { - return nil, err - } - - // Parse the token itself from the stored headers. - s.ID = r.Header.Get("X-Subject-Token") - - return &s, err -} - -// ExtractTokenID implements the gophercloud.AuthResult interface. The returned -// string is the same as the ID field of the Token struct returned from -// ExtractToken(). -func (r CreateResult) ExtractTokenID() (string, error) { - return r.Header.Get("X-Subject-Token"), r.Err -} - -// ExtractServiceCatalog returns the ServiceCatalog that was generated along -// with the user's Token. -func (r commonResult) ExtractServiceCatalog() (*ServiceCatalog, error) { - var s ServiceCatalog - err := r.ExtractInto(&s) - return &s, err -} - -// ExtractUser returns the User that is the owner of the Token. -func (r commonResult) ExtractUser() (*User, error) { - var s struct { - User *User `json:"user"` - } - err := r.ExtractInto(&s) - return s.User, err -} - -// ExtractRoles returns Roles to which User is authorized. -func (r commonResult) ExtractRoles() ([]Role, error) { - var s struct { - Roles []Role `json:"roles"` - } - err := r.ExtractInto(&s) - return s.Roles, err -} - -// ExtractProject returns Project to which User is authorized. -func (r commonResult) ExtractProject() (*Project, error) { - var s struct { - Project *Project `json:"project"` - } - err := r.ExtractInto(&s) - return s.Project, err -} - -// CreateResult is the response from a Create request. Use ExtractToken() -// to interpret it as a Token, or ExtractServiceCatalog() to interpret it -// as a service catalog. -type CreateResult struct { - commonResult -} - -// GetResult is the response from a Get request. Use ExtractToken() -// to interpret it as a Token, or ExtractServiceCatalog() to interpret it -// as a service catalog. -type GetResult struct { - commonResult -} - -// RevokeResult is response from a Revoke request. -type RevokeResult struct { - commonResult -} - -// Token is a string that grants a user access to a controlled set of services -// in an OpenStack provider. Each Token is valid for a set length of time. -type Token struct { - // ID is the issued token. - ID string `json:"id"` - - // ExpiresAt is the timestamp at which this token will no longer be accepted. - ExpiresAt time.Time `json:"expires_at"` -} - -func (r commonResult) ExtractInto(v interface{}) error { - return r.ExtractIntoStructPtr(v, "token") -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/urls.go deleted file mode 100644 index 2f864a31c8b..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/urls.go +++ /dev/null @@ -1,7 +0,0 @@ -package tokens - -import "github.com/gophercloud/gophercloud" - -func tokenURL(c *gophercloud.ServiceClient) string { - return c.ServiceURL("auth", "tokens") -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/delegate.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/delegate.go deleted file mode 100644 index 0c43689bb80..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/delegate.go +++ /dev/null @@ -1,41 +0,0 @@ -package extensions - -import ( - "github.com/gophercloud/gophercloud" - common "github.com/gophercloud/gophercloud/openstack/common/extensions" - "github.com/gophercloud/gophercloud/pagination" -) - -// Extension is a single OpenStack extension. -type Extension struct { - common.Extension -} - -// GetResult wraps a GetResult from common. -type GetResult struct { - common.GetResult -} - -// ExtractExtensions interprets a Page as a slice of Extensions. -func ExtractExtensions(page pagination.Page) ([]Extension, error) { - inner, err := common.ExtractExtensions(page) - if err != nil { - return nil, err - } - outer := make([]Extension, len(inner)) - for index, ext := range inner { - outer[index] = Extension{ext} - } - return outer, nil -} - -// Get retrieves information for a specific extension using its alias. -func Get(c *gophercloud.ServiceClient, alias string) GetResult { - return GetResult{common.Get(c, alias)} -} - -// List returns a Pager which allows you to iterate over the full collection of extensions. -// It does not accept query parameters. -func List(c *gophercloud.ServiceClient) pagination.Pager { - return common.List(c) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external/doc.go deleted file mode 100644 index eda010cb0c8..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external/doc.go +++ /dev/null @@ -1,53 +0,0 @@ -/* -Package external provides information and interaction with the external -extension for the OpenStack Networking service. - -Example to List Networks with External Information - - iTrue := true - networkListOpts := networks.ListOpts{} - listOpts := external.ListOptsExt{ - ListOptsBuilder: networkListOpts, - External: &iTrue, - } - - type NetworkWithExternalExt struct { - networks.Network - external.NetworkExternalExt - } - - var allNetworks []NetworkWithExternalExt - - allPages, err := networks.List(networkClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - err = networks.ExtractNetworksInto(allPages, &allNetworks) - if err != nil { - panic(err) - } - - for _, network := range allNetworks { - fmt.Println("%+v\n", network) - } - -Example to Create a Network with External Information - - iTrue := true - networkCreateOpts := networks.CreateOpts{ - Name: "private", - AdminStateUp: &iTrue, - } - - createOpts := external.CreateOptsExt{ - networkCreateOpts, - &iTrue, - } - - network, err := networks.Create(networkClient, createOpts).Extract() - if err != nil { - panic(err) - } -*/ -package external diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external/requests.go deleted file mode 100644 index ced5efed8d9..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external/requests.go +++ /dev/null @@ -1,84 +0,0 @@ -package external - -import ( - "net/url" - "strconv" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" -) - -// ListOptsExt adds the external network options to the base ListOpts. -type ListOptsExt struct { - networks.ListOptsBuilder - External *bool `q:"router:external"` -} - -// ToNetworkListQuery adds the router:external option to the base network -// list options. -func (opts ListOptsExt) ToNetworkListQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts.ListOptsBuilder) - if err != nil { - return "", err - } - - params := q.Query() - if opts.External != nil { - v := strconv.FormatBool(*opts.External) - params.Add("router:external", v) - } - - q = &url.URL{RawQuery: params.Encode()} - return q.String(), err -} - -// CreateOptsExt is the structure used when creating new external network -// resources. It embeds networks.CreateOpts and so inherits all of its required -// and optional fields, with the addition of the External field. -type CreateOptsExt struct { - networks.CreateOptsBuilder - External *bool `json:"router:external,omitempty"` -} - -// ToNetworkCreateMap adds the router:external options to the base network -// creation options. -func (opts CreateOptsExt) ToNetworkCreateMap() (map[string]interface{}, error) { - base, err := opts.CreateOptsBuilder.ToNetworkCreateMap() - if err != nil { - return nil, err - } - - if opts.External == nil { - return base, nil - } - - networkMap := base["network"].(map[string]interface{}) - networkMap["router:external"] = opts.External - - return base, nil -} - -// UpdateOptsExt is the structure used when updating existing external network -// resources. It embeds networks.UpdateOpts and so inherits all of its required -// and optional fields, with the addition of the External field. -type UpdateOptsExt struct { - networks.UpdateOptsBuilder - External *bool `json:"router:external,omitempty"` -} - -// ToNetworkUpdateMap casts an UpdateOpts struct to a map. -func (opts UpdateOptsExt) ToNetworkUpdateMap() (map[string]interface{}, error) { - base, err := opts.UpdateOptsBuilder.ToNetworkUpdateMap() - if err != nil { - return nil, err - } - - if opts.External == nil { - return base, nil - } - - networkMap := base["network"].(map[string]interface{}) - networkMap["router:external"] = opts.External - - return base, nil -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external/results.go deleted file mode 100644 index 7cbbffdcf8a..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external/results.go +++ /dev/null @@ -1,8 +0,0 @@ -package external - -// NetworkExternalExt represents a decorated form of a Network with based on the -// "external-net" extension. -type NetworkExternalExt struct { - // Specifies whether the network is an external network or not. - External bool `json:"router:external"` -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/doc.go deleted file mode 100644 index a71a3ec88a9..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/doc.go +++ /dev/null @@ -1,71 +0,0 @@ -/* -package floatingips enables management and retrieval of Floating IPs from the -OpenStack Networking service. - -Example to List Floating IPs - - listOpts := floatingips.ListOpts{ - FloatingNetworkID: "a6917946-38ab-4ffd-a55a-26c0980ce5ee", - } - - allPages, err := floatingips.List(networkClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - allFIPs, err := floatingips.ExtractFloatingIPs(allPages) - if err != nil { - panic(err) - } - - for _, fip := range allFIPs { - fmt.Printf("%+v\n", fip) - } - -Example to Create a Floating IP - - createOpts := floatingips.CreateOpts{ - FloatingNetworkID: "a6917946-38ab-4ffd-a55a-26c0980ce5ee", - } - - fip, err := floatingips.Create(networkingClient, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to Update a Floating IP - - fipID := "2f245a7b-796b-4f26-9cf9-9e82d248fda7" - portID := "76d0a61b-b8e5-490c-9892-4cf674f2bec8" - - updateOpts := floatingips.UpdateOpts{ - PortID: &portID, - } - - fip, err := floatingips.Update(networkingClient, fipID, updateOpts).Extract() - if err != nil { - panic(err) - } - -Example to Disassociate a Floating IP with a Port - - fipID := "2f245a7b-796b-4f26-9cf9-9e82d248fda7" - - updateOpts := floatingips.UpdateOpts{ - PortID: new(string), - } - - fip, err := floatingips.Update(networkingClient, fipID, updateOpts).Extract() - if err != nil { - panic(err) - } - -Example to Delete a Floating IP - - fipID := "2f245a7b-796b-4f26-9cf9-9e82d248fda7" - err := floatingips.Delete(networkClient, fipID).ExtractErr() - if err != nil { - panic(err) - } -*/ -package floatingips diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/requests.go deleted file mode 100644 index 0c0db64d8d3..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/requests.go +++ /dev/null @@ -1,182 +0,0 @@ -package floatingips - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// ListOptsBuilder allows extensions to add additional parameters to the -// List request. -type ListOptsBuilder interface { - ToFloatingIPListQuery() (string, error) -} - -// ListOpts allows the filtering and sorting of paginated collections through -// the API. Filtering is achieved by passing in struct field values that map to -// the floating IP attributes you want to see returned. SortKey allows you to -// sort by a particular network attribute. SortDir sets the direction, and is -// either `asc' or `desc'. Marker and Limit are used for pagination. -type ListOpts struct { - ID string `q:"id"` - Description string `q:"description"` - FloatingNetworkID string `q:"floating_network_id"` - PortID string `q:"port_id"` - FixedIP string `q:"fixed_ip_address"` - FloatingIP string `q:"floating_ip_address"` - TenantID string `q:"tenant_id"` - ProjectID string `q:"project_id"` - Limit int `q:"limit"` - Marker string `q:"marker"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` - RouterID string `q:"router_id"` - Status string `q:"status"` - Tags string `q:"tags"` - TagsAny string `q:"tags-any"` - NotTags string `q:"not-tags"` - NotTagsAny string `q:"not-tags-any"` -} - -// ToNetworkListQuery formats a ListOpts into a query string. -func (opts ListOpts) ToFloatingIPListQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - return q.String(), err -} - -// List returns a Pager which allows you to iterate over a collection of -// floating IP resources. It accepts a ListOpts struct, which allows you to -// filter and sort the returned collection for greater efficiency. -func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { - url := rootURL(c) - if opts != nil { - query, err := opts.ToFloatingIPListQuery() - if err != nil { - return pagination.Pager{Err: err} - } - url += query - } - return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { - return FloatingIPPage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -// CreateOptsBuilder allows extensions to add additional parameters to the -// Create request. -type CreateOptsBuilder interface { - ToFloatingIPCreateMap() (map[string]interface{}, error) -} - -// CreateOpts contains all the values needed to create a new floating IP -// resource. The only required fields are FloatingNetworkID and PortID which -// refer to the external network and internal port respectively. -type CreateOpts struct { - Description string `json:"description,omitempty"` - FloatingNetworkID string `json:"floating_network_id" required:"true"` - FloatingIP string `json:"floating_ip_address,omitempty"` - PortID string `json:"port_id,omitempty"` - FixedIP string `json:"fixed_ip_address,omitempty"` - SubnetID string `json:"subnet_id,omitempty"` - TenantID string `json:"tenant_id,omitempty"` - ProjectID string `json:"project_id,omitempty"` -} - -// ToFloatingIPCreateMap allows CreateOpts to satisfy the CreateOptsBuilder -// interface -func (opts CreateOpts) ToFloatingIPCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "floatingip") -} - -// Create accepts a CreateOpts struct and uses the values provided to create a -// new floating IP resource. You can create floating IPs on external networks -// only. If you provide a FloatingNetworkID which refers to a network that is -// not external (i.e. its `router:external' attribute is False), the operation -// will fail and return a 400 error. -// -// If you do not specify a FloatingIP address value, the operation will -// automatically allocate an available address for the new resource. If you do -// choose to specify one, it must fall within the subnet range for the external -// network - otherwise the operation returns a 400 error. If the FloatingIP -// address is already in use, the operation returns a 409 error code. -// -// You can associate the new resource with an internal port by using the PortID -// field. If you specify a PortID that is not valid, the operation will fail and -// return 404 error code. -// -// You must also configure an IP address for the port associated with the PortID -// you have provided - this is what the FixedIP refers to: an IP fixed to a -// port. Because a port might be associated with multiple IP addresses, you can -// use the FixedIP field to associate a particular IP address rather than have -// the API assume for you. If you specify an IP address that is not valid, the -// operation will fail and return a 400 error code. If the PortID and FixedIP -// are already associated with another resource, the operation will fail and -// returns a 409 error code. -func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToFloatingIPCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Post(rootURL(c), b, &r.Body, nil) - return -} - -// Get retrieves a particular floating IP resource based on its unique ID. -func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) - return -} - -// UpdateOptsBuilder allows extensions to add additional parameters to the -// Update request. -type UpdateOptsBuilder interface { - ToFloatingIPUpdateMap() (map[string]interface{}, error) -} - -// UpdateOpts contains the values used when updating a floating IP resource. The -// only value that can be updated is which internal port the floating IP is -// linked to. To associate the floating IP with a new internal port, provide its -// ID. To disassociate the floating IP from all ports, provide an empty string. -type UpdateOpts struct { - Description *string `json:"description,omitempty"` - PortID *string `json:"port_id,omitempty"` - FixedIP string `json:"fixed_ip_address,omitempty"` -} - -// ToFloatingIPUpdateMap allows UpdateOpts to satisfy the UpdateOptsBuilder -// interface -func (opts UpdateOpts) ToFloatingIPUpdateMap() (map[string]interface{}, error) { - b, err := gophercloud.BuildRequestBody(opts, "floatingip") - if err != nil { - return nil, err - } - - if m := b["floatingip"].(map[string]interface{}); m["port_id"] == "" { - m["port_id"] = nil - } - - return b, nil -} - -// Update allows floating IP resources to be updated. Currently, the only way to -// "update" a floating IP is to associate it with a new internal port, or -// disassociated it from all ports. See UpdateOpts for instructions of how to -// do this. -func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { - b, err := opts.ToFloatingIPUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// Delete will permanently delete a particular floating IP resource. Please -// ensure this is what you want - you can also disassociate the IP from existing -// internal ports. -func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = c.Delete(resourceURL(c, id), nil) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/results.go deleted file mode 100644 index a9709ccec3f..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/results.go +++ /dev/null @@ -1,131 +0,0 @@ -package floatingips - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// FloatingIP represents a floating IP resource. A floating IP is an external -// IP address that is mapped to an internal port and, optionally, a specific -// IP address on a private network. In other words, it enables access to an -// instance on a private network from an external network. For this reason, -// floating IPs can only be defined on networks where the `router:external' -// attribute (provided by the external network extension) is set to True. -type FloatingIP struct { - // ID is the unique identifier for the floating IP instance. - ID string `json:"id"` - - // Description for the floating IP instance. - Description string `json:"description"` - - // FloatingNetworkID is the UUID of the external network where the floating - // IP is to be created. - FloatingNetworkID string `json:"floating_network_id"` - - // FloatingIP is the address of the floating IP on the external network. - FloatingIP string `json:"floating_ip_address"` - - // PortID is the UUID of the port on an internal network that is associated - // with the floating IP. - PortID string `json:"port_id"` - - // FixedIP is the specific IP address of the internal port which should be - // associated with the floating IP. - FixedIP string `json:"fixed_ip_address"` - - // TenantID is the project owner of the floating IP. Only admin users can - // specify a project identifier other than its own. - TenantID string `json:"tenant_id"` - - // ProjectID is the project owner of the floating IP. - ProjectID string `json:"project_id"` - - // Status is the condition of the API resource. - Status string `json:"status"` - - // RouterID is the ID of the router used for this floating IP. - RouterID string `json:"router_id"` - - // Tags optionally set via extensions/attributestags - Tags []string `json:"tags"` -} - -type commonResult struct { - gophercloud.Result -} - -// Extract will extract a FloatingIP resource from a result. -func (r commonResult) Extract() (*FloatingIP, error) { - var s FloatingIP - err := r.ExtractInto(&s) - return &s, err -} - -func (r commonResult) ExtractInto(v interface{}) error { - return r.Result.ExtractIntoStructPtr(v, "floatingip") -} - -// CreateResult represents the result of a create operation. Call its Extract -// method to interpret it as a FloatingIP. -type CreateResult struct { - commonResult -} - -// GetResult represents the result of a get operation. Call its Extract -// method to interpret it as a FloatingIP. -type GetResult struct { - commonResult -} - -// UpdateResult represents the result of an update operation. Call its Extract -// method to interpret it as a FloatingIP. -type UpdateResult struct { - commonResult -} - -// DeleteResult represents the result of an update operation. Call its -// ExtractErr method to determine if the request succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} - -// FloatingIPPage is the page returned by a pager when traversing over a -// collection of floating IPs. -type FloatingIPPage struct { - pagination.LinkedPageBase -} - -// NextPageURL is invoked when a paginated collection of floating IPs has -// reached the end of a page and the pager seeks to traverse over a new one. -// In order to do this, it needs to construct the next page's URL. -func (r FloatingIPPage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"floatingips_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// IsEmpty checks whether a FloatingIPPage struct is empty. -func (r FloatingIPPage) IsEmpty() (bool, error) { - is, err := ExtractFloatingIPs(r) - return len(is) == 0, err -} - -// ExtractFloatingIPs accepts a Page struct, specifically a FloatingIPPage -// struct, and extracts the elements into a slice of FloatingIP structs. In -// other words, a generic collection is mapped into a relevant slice. -func ExtractFloatingIPs(r pagination.Page) ([]FloatingIP, error) { - var s struct { - FloatingIPs []FloatingIP `json:"floatingips"` - } - err := (r.(FloatingIPPage)).ExtractInto(&s) - return s.FloatingIPs, err -} - -func ExtractFloatingIPsInto(r pagination.Page, v interface{}) error { - return r.(FloatingIPPage).Result.ExtractIntoSlicePtr(v, "floatingips") -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/urls.go deleted file mode 100644 index 1318a184caa..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/urls.go +++ /dev/null @@ -1,13 +0,0 @@ -package floatingips - -import "github.com/gophercloud/gophercloud" - -const resourcePath = "floatingips" - -func rootURL(c *gophercloud.ServiceClient) string { - return c.ServiceURL(resourcePath) -} - -func resourceURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL(resourcePath, id) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/doc.go deleted file mode 100644 index 6ede7f5e171..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/doc.go +++ /dev/null @@ -1,108 +0,0 @@ -/* -Package routers enables management and retrieval of Routers from the OpenStack -Networking service. - -Example to List Routers - - listOpts := routers.ListOpts{} - allPages, err := routers.List(networkClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - allRouters, err := routers.ExtractRouters(allPages) - if err != nil { - panic(err) - } - - for _, router := range allRoutes { - fmt.Printf("%+v\n", router) - } - -Example to Create a Router - - iTrue := true - gwi := routers.GatewayInfo{ - NetworkID: "8ca37218-28ff-41cb-9b10-039601ea7e6b", - } - - createOpts := routers.CreateOpts{ - Name: "router_1", - AdminStateUp: &iTrue, - GatewayInfo: &gwi, - } - - router, err := routers.Create(networkClient, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to Update a Router - - routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" - - routes := []routers.Route{{ - DestinationCIDR: "40.0.1.0/24", - NextHop: "10.1.0.10", - }} - - updateOpts := routers.UpdateOpts{ - Name: "new_name", - Routes: routes, - } - - router, err := routers.Update(networkClient, routerID, updateOpts).Extract() - if err != nil { - panic(err) - } - -Example to Remove all Routes from a Router - - routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" - - routes := []routers.Route{} - - updateOpts := routers.UpdateOpts{ - Routes: routes, - } - - router, err := routers.Update(networkClient, routerID, updateOpts).Extract() - if err != nil { - panic(err) - } - -Example to Delete a Router - - routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" - err := routers.Delete(networkClient, routerID).ExtractErr() - if err != nil { - panic(err) - } - -Example to Add an Interface to a Router - - routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" - - intOpts := routers.AddInterfaceOpts{ - SubnetID: "a2f1f29d-571b-4533-907f-5803ab96ead1", - } - - interface, err := routers.AddInterface(networkClient, routerID, intOpts).Extract() - if err != nil { - panic(err) - } - -Example to Remove an Interface from a Router - - routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" - - intOpts := routers.RemoveInterfaceOpts{ - SubnetID: "a2f1f29d-571b-4533-907f-5803ab96ead1", - } - - interface, err := routers.RemoveInterface(networkClient, routerID, intOpts).Extract() - if err != nil { - panic(err) - } -*/ -package routers diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/requests.go deleted file mode 100644 index cf499f9873d..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/requests.go +++ /dev/null @@ -1,233 +0,0 @@ -package routers - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// ListOpts allows the filtering and sorting of paginated collections through -// the API. Filtering is achieved by passing in struct field values that map to -// the floating IP attributes you want to see returned. SortKey allows you to -// sort by a particular network attribute. SortDir sets the direction, and is -// either `asc' or `desc'. Marker and Limit are used for pagination. -type ListOpts struct { - ID string `q:"id"` - Name string `q:"name"` - Description string `q:"description"` - AdminStateUp *bool `q:"admin_state_up"` - Distributed *bool `q:"distributed"` - Status string `q:"status"` - TenantID string `q:"tenant_id"` - ProjectID string `q:"project_id"` - Limit int `q:"limit"` - Marker string `q:"marker"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` - Tags string `q:"tags"` - TagsAny string `q:"tags-any"` - NotTags string `q:"not-tags"` - NotTagsAny string `q:"not-tags-any"` -} - -// List returns a Pager which allows you to iterate over a collection of -// routers. It accepts a ListOpts struct, which allows you to filter and sort -// the returned collection for greater efficiency. -// -// Default policy settings return only those routers that are owned by the -// tenant who submits the request, unless an admin user submits the request. -func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager { - q, err := gophercloud.BuildQueryString(&opts) - if err != nil { - return pagination.Pager{Err: err} - } - u := rootURL(c) + q.String() - return pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page { - return RouterPage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -// CreateOptsBuilder allows extensions to add additional parameters to the -// Create request. -type CreateOptsBuilder interface { - ToRouterCreateMap() (map[string]interface{}, error) -} - -// CreateOpts contains all the values needed to create a new router. There are -// no required values. -type CreateOpts struct { - Name string `json:"name,omitempty"` - Description string `json:"description,omitempty"` - AdminStateUp *bool `json:"admin_state_up,omitempty"` - Distributed *bool `json:"distributed,omitempty"` - TenantID string `json:"tenant_id,omitempty"` - ProjectID string `json:"project_id,omitempty"` - GatewayInfo *GatewayInfo `json:"external_gateway_info,omitempty"` - AvailabilityZoneHints []string `json:"availability_zone_hints,omitempty"` -} - -// ToRouterCreateMap builds a create request body from CreateOpts. -func (opts CreateOpts) ToRouterCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "router") -} - -// Create accepts a CreateOpts struct and uses the values to create a new -// logical router. When it is created, the router does not have an internal -// interface - it is not associated to any subnet. -// -// You can optionally specify an external gateway for a router using the -// GatewayInfo struct. The external gateway for the router must be plugged into -// an external network (it is external if its `router:external' field is set to -// true). -func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToRouterCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Post(rootURL(c), b, &r.Body, nil) - return -} - -// Get retrieves a particular router based on its unique ID. -func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) - return -} - -// UpdateOptsBuilder allows extensions to add additional parameters to the -// Update request. -type UpdateOptsBuilder interface { - ToRouterUpdateMap() (map[string]interface{}, error) -} - -// UpdateOpts contains the values used when updating a router. -type UpdateOpts struct { - Name string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - AdminStateUp *bool `json:"admin_state_up,omitempty"` - Distributed *bool `json:"distributed,omitempty"` - GatewayInfo *GatewayInfo `json:"external_gateway_info,omitempty"` - Routes []Route `json:"routes"` -} - -// ToRouterUpdateMap builds an update body based on UpdateOpts. -func (opts UpdateOpts) ToRouterUpdateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "router") -} - -// Update allows routers to be updated. You can update the name, administrative -// state, and the external gateway. For more information about how to set the -// external gateway for a router, see Create. This operation does not enable -// the update of router interfaces. To do this, use the AddInterface and -// RemoveInterface functions. -func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { - b, err := opts.ToRouterUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// Delete will permanently delete a particular router based on its unique ID. -func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = c.Delete(resourceURL(c, id), nil) - return -} - -// AddInterfaceOptsBuilder allows extensions to add additional parameters to -// the AddInterface request. -type AddInterfaceOptsBuilder interface { - ToRouterAddInterfaceMap() (map[string]interface{}, error) -} - -// AddInterfaceOpts represents the options for adding an interface to a router. -type AddInterfaceOpts struct { - SubnetID string `json:"subnet_id,omitempty" xor:"PortID"` - PortID string `json:"port_id,omitempty" xor:"SubnetID"` -} - -// ToRouterAddInterfaceMap builds a request body from AddInterfaceOpts. -func (opts AddInterfaceOpts) ToRouterAddInterfaceMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "") -} - -// AddInterface attaches a subnet to an internal router interface. You must -// specify either a SubnetID or PortID in the request body. If you specify both, -// the operation will fail and an error will be returned. -// -// If you specify a SubnetID, the gateway IP address for that particular subnet -// is used to create the router interface. Alternatively, if you specify a -// PortID, the IP address associated with the port is used to create the router -// interface. -// -// If you reference a port that is associated with multiple IP addresses, or -// if the port is associated with zero IP addresses, the operation will fail and -// a 400 Bad Request error will be returned. -// -// If you reference a port already in use, the operation will fail and a 409 -// Conflict error will be returned. -// -// The PortID that is returned after using Extract() on the result of this -// operation can either be the same PortID passed in or, on the other hand, the -// identifier of a new port created by this operation. After the operation -// completes, the device ID of the port is set to the router ID, and the -// device owner attribute is set to `network:router_interface'. -func AddInterface(c *gophercloud.ServiceClient, id string, opts AddInterfaceOptsBuilder) (r InterfaceResult) { - b, err := opts.ToRouterAddInterfaceMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Put(addInterfaceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// RemoveInterfaceOptsBuilder allows extensions to add additional parameters to -// the RemoveInterface request. -type RemoveInterfaceOptsBuilder interface { - ToRouterRemoveInterfaceMap() (map[string]interface{}, error) -} - -// RemoveInterfaceOpts represents options for removing an interface from -// a router. -type RemoveInterfaceOpts struct { - SubnetID string `json:"subnet_id,omitempty" or:"PortID"` - PortID string `json:"port_id,omitempty" or:"SubnetID"` -} - -// ToRouterRemoveInterfaceMap builds a request body based on -// RemoveInterfaceOpts. -func (opts RemoveInterfaceOpts) ToRouterRemoveInterfaceMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "") -} - -// RemoveInterface removes an internal router interface, which detaches a -// subnet from the router. You must specify either a SubnetID or PortID, since -// these values are used to identify the router interface to remove. -// -// Unlike AddInterface, you can also specify both a SubnetID and PortID. If you -// choose to specify both, the subnet ID must correspond to the subnet ID of -// the first IP address on the port specified by the port ID. Otherwise, the -// operation will fail and return a 409 Conflict error. -// -// If the router, subnet or port which are referenced do not exist or are not -// visible to you, the operation will fail and a 404 Not Found error will be -// returned. After this operation completes, the port connecting the router -// with the subnet is removed from the subnet for the network. -func RemoveInterface(c *gophercloud.ServiceClient, id string, opts RemoveInterfaceOptsBuilder) (r InterfaceResult) { - b, err := opts.ToRouterRemoveInterfaceMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Put(removeInterfaceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/results.go deleted file mode 100644 index 857e1947e1f..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/results.go +++ /dev/null @@ -1,181 +0,0 @@ -package routers - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// GatewayInfo represents the information of an external gateway for any -// particular network router. -type GatewayInfo struct { - NetworkID string `json:"network_id,omitempty"` - EnableSNAT *bool `json:"enable_snat,omitempty"` - ExternalFixedIPs []ExternalFixedIP `json:"external_fixed_ips,omitempty"` -} - -// ExternalFixedIP is the IP address and subnet ID of the external gateway of a -// router. -type ExternalFixedIP struct { - IPAddress string `json:"ip_address,omitempty"` - SubnetID string `json:"subnet_id"` -} - -// Route is a possible route in a router. -type Route struct { - NextHop string `json:"nexthop"` - DestinationCIDR string `json:"destination"` -} - -// Router represents a Neutron router. A router is a logical entity that -// forwards packets across internal subnets and NATs (network address -// translation) them on external networks through an appropriate gateway. -// -// A router has an interface for each subnet with which it is associated. By -// default, the IP address of such interface is the subnet's gateway IP. Also, -// whenever a router is associated with a subnet, a port for that router -// interface is added to the subnet's network. -type Router struct { - // Status indicates whether or not a router is currently operational. - Status string `json:"status"` - - // GateayInfo provides information on external gateway for the router. - GatewayInfo GatewayInfo `json:"external_gateway_info"` - - // AdminStateUp is the administrative state of the router. - AdminStateUp bool `json:"admin_state_up"` - - // Distributed is whether router is disitrubted or not. - Distributed bool `json:"distributed"` - - // Name is the human readable name for the router. It does not have to be - // unique. - Name string `json:"name"` - - // Description for the router. - Description string `json:"description"` - - // ID is the unique identifier for the router. - ID string `json:"id"` - - // TenantID is the project owner of the router. Only admin users can - // specify a project identifier other than its own. - TenantID string `json:"tenant_id"` - - // ProjectID is the project owner of the router. - ProjectID string `json:"project_id"` - - // Routes are a collection of static routes that the router will host. - Routes []Route `json:"routes"` - - // Availability zone hints groups network nodes that run services like DHCP, L3, FW, and others. - // Used to make network resources highly available. - AvailabilityZoneHints []string `json:"availability_zone_hints"` - - // Tags optionally set via extensions/attributestags - Tags []string `json:"tags"` -} - -// RouterPage is the page returned by a pager when traversing over a -// collection of routers. -type RouterPage struct { - pagination.LinkedPageBase -} - -// NextPageURL is invoked when a paginated collection of routers has reached -// the end of a page and the pager seeks to traverse over a new one. In order -// to do this, it needs to construct the next page's URL. -func (r RouterPage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"routers_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// IsEmpty checks whether a RouterPage struct is empty. -func (r RouterPage) IsEmpty() (bool, error) { - is, err := ExtractRouters(r) - return len(is) == 0, err -} - -// ExtractRouters accepts a Page struct, specifically a RouterPage struct, -// and extracts the elements into a slice of Router structs. In other words, -// a generic collection is mapped into a relevant slice. -func ExtractRouters(r pagination.Page) ([]Router, error) { - var s struct { - Routers []Router `json:"routers"` - } - err := (r.(RouterPage)).ExtractInto(&s) - return s.Routers, err -} - -type commonResult struct { - gophercloud.Result -} - -// Extract is a function that accepts a result and extracts a router. -func (r commonResult) Extract() (*Router, error) { - var s struct { - Router *Router `json:"router"` - } - err := r.ExtractInto(&s) - return s.Router, err -} - -// CreateResult represents the result of a create operation. Call its Extract -// method to interpret it as a Router. -type CreateResult struct { - commonResult -} - -// GetResult represents the result of a get operation. Call its Extract -// method to interpret it as a Router. -type GetResult struct { - commonResult -} - -// UpdateResult represents the result of an update operation. Call its Extract -// method to interpret it as a Router. -type UpdateResult struct { - commonResult -} - -// DeleteResult represents the result of a delete operation. Call its ExtractErr -// method to determine if the request succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} - -// InterfaceInfo represents information about a particular router interface. As -// mentioned above, in order for a router to forward to a subnet, it needs an -// interface. -type InterfaceInfo struct { - // SubnetID is the ID of the subnet which this interface is associated with. - SubnetID string `json:"subnet_id"` - - // PortID is the ID of the port that is a part of the subnet. - PortID string `json:"port_id"` - - // ID is the UUID of the interface. - ID string `json:"id"` - - // TenantID is the owner of the interface. - TenantID string `json:"tenant_id"` -} - -// InterfaceResult represents the result of interface operations, such as -// AddInterface() and RemoveInterface(). Call its Extract method to interpret -// the result as a InterfaceInfo. -type InterfaceResult struct { - gophercloud.Result -} - -// Extract is a function that accepts a result and extracts an information struct. -func (r InterfaceResult) Extract() (*InterfaceInfo, error) { - var s InterfaceInfo - err := r.ExtractInto(&s) - return &s, err -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/urls.go deleted file mode 100644 index f9e9da32117..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/urls.go +++ /dev/null @@ -1,21 +0,0 @@ -package routers - -import "github.com/gophercloud/gophercloud" - -const resourcePath = "routers" - -func rootURL(c *gophercloud.ServiceClient) string { - return c.ServiceURL(resourcePath) -} - -func resourceURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL(resourcePath, id) -} - -func addInterfaceURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL(resourcePath, id, "add_router_interface") -} - -func removeInterfaceURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL(resourcePath, id, "remove_router_interface") -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies/doc.go deleted file mode 100644 index 813579905c2..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies/doc.go +++ /dev/null @@ -1,123 +0,0 @@ -/* -Package l7policies provides information and interaction with L7Policies and -Rules of the LBaaS v2 extension for the OpenStack Networking service. - -Example to Create a L7Policy - - createOpts := l7policies.CreateOpts{ - Name: "redirect-example.com", - ListenerID: "023f2e34-7806-443b-bfae-16c324569a3d", - Action: l7policies.ActionRedirectToURL, - RedirectURL: "http://www.example.com", - } - l7policy, err := l7policies.Create(lbClient, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to List L7Policies - - listOpts := l7policies.ListOpts{ - ListenerID: "c79a4468-d788-410c-bf79-9a8ef6354852", - } - allPages, err := l7policies.List(lbClient, listOpts).AllPages() - if err != nil { - panic(err) - } - allL7Policies, err := l7policies.ExtractL7Policies(allPages) - if err != nil { - panic(err) - } - for _, l7policy := range allL7Policies { - fmt.Printf("%+v\n", l7policy) - } - -Example to Get a L7Policy - - l7policy, err := l7policies.Get(lbClient, "023f2e34-7806-443b-bfae-16c324569a3d").Extract() - if err != nil { - panic(err) - } - -Example to Delete a L7Policy - - l7policyID := "d67d56a6-4a86-4688-a282-f46444705c64" - err := l7policies.Delete(lbClient, l7policyID).ExtractErr() - if err != nil { - panic(err) - } - -Example to Update a L7Policy - - l7policyID := "d67d56a6-4a86-4688-a282-f46444705c64" - name := "new-name" - updateOpts := l7policies.UpdateOpts{ - Name: &name, - } - l7policy, err := l7policies.Update(lbClient, l7policyID, updateOpts).Extract() - if err != nil { - panic(err) - } - -Example to Create a Rule - - l7policyID := "d67d56a6-4a86-4688-a282-f46444705c64" - createOpts := l7policies.CreateRuleOpts{ - RuleType: l7policies.TypePath, - CompareType: l7policies.CompareTypeRegex, - Value: "/images*", - } - rule, err := l7policies.CreateRule(lbClient, l7policyID, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to List L7 Rules - - l7policyID := "d67d56a6-4a86-4688-a282-f46444705c64" - listOpts := l7policies.ListRulesOpts{ - RuleType: l7policies.TypePath, - } - allPages, err := l7policies.ListRules(lbClient, l7policyID, listOpts).AllPages() - if err != nil { - panic(err) - } - allRules, err := l7policies.ExtractRules(allPages) - if err != nil { - panic(err) - } - for _, rule := allRules { - fmt.Printf("%+v\n", rule) - } - -Example to Get a l7 rule - - l7rule, err := l7policies.GetRule(lbClient, "023f2e34-7806-443b-bfae-16c324569a3d", "53ad8ab8-40fa-11e8-a508-00224d6b7bc1").Extract() - if err != nil { - panic(err) - } - -Example to Delete a l7 rule - - l7policyID := "d67d56a6-4a86-4688-a282-f46444705c64" - ruleID := "64dba99f-8af8-4200-8882-e32a0660f23e" - err := l7policies.DeleteRule(lbClient, l7policyID, ruleID).ExtractErr() - if err != nil { - panic(err) - } - -Example to Update a Rule - - l7policyID := "d67d56a6-4a86-4688-a282-f46444705c64" - ruleID := "64dba99f-8af8-4200-8882-e32a0660f23e" - updateOpts := l7policies.UpdateRuleOpts{ - RuleType: l7policies.TypePath, - CompareType: l7policies.CompareTypeRegex, - Value: "/images/special*", - } - rule, err := l7policies.UpdateRule(lbClient, l7policyID, ruleID, updateOpts).Extract() - if err != nil { - panic(err) - } -*/ -package l7policies diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies/requests.go deleted file mode 100644 index 9d2b3a0d351..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies/requests.go +++ /dev/null @@ -1,376 +0,0 @@ -package l7policies - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// CreateOptsBuilder allows extensions to add additional parameters to the -// Create request. -type CreateOptsBuilder interface { - ToL7PolicyCreateMap() (map[string]interface{}, error) -} - -type Action string -type RuleType string -type CompareType string - -const ( - ActionRedirectToPool Action = "REDIRECT_TO_POOL" - ActionRedirectToURL Action = "REDIRECT_TO_URL" - ActionReject Action = "REJECT" - - TypeCookie RuleType = "COOKIE" - TypeFileType RuleType = "FILE_TYPE" - TypeHeader RuleType = "HEADER" - TypeHostName RuleType = "HOST_NAME" - TypePath RuleType = "PATH" - - CompareTypeContains CompareType = "CONTAINS" - CompareTypeEndWith CompareType = "ENDS_WITH" - CompareTypeEqual CompareType = "EQUAL_TO" - CompareTypeRegex CompareType = "REGEX" - CompareTypeStartWith CompareType = "STARTS_WITH" -) - -// CreateOpts is the common options struct used in this package's Create -// operation. -type CreateOpts struct { - // Name of the L7 policy. - Name string `json:"name,omitempty"` - - // The ID of the listener. - ListenerID string `json:"listener_id" required:"true"` - - // The L7 policy action. One of REDIRECT_TO_POOL, REDIRECT_TO_URL, or REJECT. - Action Action `json:"action" required:"true"` - - // The position of this policy on the listener. - Position int32 `json:"position,omitempty"` - - // A human-readable description for the resource. - Description string `json:"description,omitempty"` - - // TenantID is the UUID of the tenant who owns the L7 policy in octavia. - // Only administrative users can specify a project UUID other than their own. - TenantID string `json:"tenant_id,omitempty"` - - // Requests matching this policy will be redirected to the pool with this ID. - // Only valid if action is REDIRECT_TO_POOL. - RedirectPoolID string `json:"redirect_pool_id,omitempty"` - - // Requests matching this policy will be redirected to this URL. - // Only valid if action is REDIRECT_TO_URL. - RedirectURL string `json:"redirect_url,omitempty"` - - // The administrative state of the Loadbalancer. A valid value is true (UP) - // or false (DOWN). - AdminStateUp *bool `json:"admin_state_up,omitempty"` -} - -// ToL7PolicyCreateMap builds a request body from CreateOpts. -func (opts CreateOpts) ToL7PolicyCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "l7policy") -} - -// Create accepts a CreateOpts struct and uses the values to create a new l7policy. -func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToL7PolicyCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Post(rootURL(c), b, &r.Body, nil) - return -} - -// ListOptsBuilder allows extensions to add additional parameters to the -// List request. -type ListOptsBuilder interface { - ToL7PolicyListQuery() (string, error) -} - -// ListOpts allows the filtering and sorting of paginated collections through -// the API. -type ListOpts struct { - Name string `q:"name"` - Description string `q:"description"` - ListenerID string `q:"listener_id"` - Action string `q:"action"` - TenantID string `q:"tenant_id"` - RedirectPoolID string `q:"redirect_pool_id"` - RedirectURL string `q:"redirect_url"` - Position int32 `q:"position"` - AdminStateUp bool `q:"admin_state_up"` - ID string `q:"id"` - Limit int `q:"limit"` - Marker string `q:"marker"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` -} - -// ToL7PolicyListQuery formats a ListOpts into a query string. -func (opts ListOpts) ToL7PolicyListQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - return q.String(), err -} - -// List returns a Pager which allows you to iterate over a collection of -// l7policies. It accepts a ListOpts struct, which allows you to filter and sort -// the returned collection for greater efficiency. -// -// Default policy settings return only those l7policies that are owned by the -// project who submits the request, unless an admin user submits the request. -func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { - url := rootURL(c) - if opts != nil { - query, err := opts.ToL7PolicyListQuery() - if err != nil { - return pagination.Pager{Err: err} - } - url += query - } - return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { - return L7PolicyPage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -// Get retrieves a particular l7policy based on its unique ID. -func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) - return -} - -// Delete will permanently delete a particular l7policy based on its unique ID. -func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = c.Delete(resourceURL(c, id), nil) - return -} - -// UpdateOptsBuilder allows extensions to add additional parameters to the -// Update request. -type UpdateOptsBuilder interface { - ToL7PolicyUpdateMap() (map[string]interface{}, error) -} - -// UpdateOpts is the common options struct used in this package's Update -// operation. -type UpdateOpts struct { - // Name of the L7 policy, empty string is allowed. - Name *string `json:"name,omitempty"` - - // The L7 policy action. One of REDIRECT_TO_POOL, REDIRECT_TO_URL, or REJECT. - Action Action `json:"action,omitempty"` - - // The position of this policy on the listener. - Position int32 `json:"position,omitempty"` - - // A human-readable description for the resource, empty string is allowed. - Description *string `json:"description,omitempty"` - - // Requests matching this policy will be redirected to the pool with this ID. - // Only valid if action is REDIRECT_TO_POOL. - RedirectPoolID *string `json:"redirect_pool_id,omitempty"` - - // Requests matching this policy will be redirected to this URL. - // Only valid if action is REDIRECT_TO_URL. - RedirectURL *string `json:"redirect_url,omitempty"` - - // The administrative state of the Loadbalancer. A valid value is true (UP) - // or false (DOWN). - AdminStateUp *bool `json:"admin_state_up,omitempty"` -} - -// ToL7PolicyUpdateMap builds a request body from UpdateOpts. -func (opts UpdateOpts) ToL7PolicyUpdateMap() (map[string]interface{}, error) { - b, err := gophercloud.BuildRequestBody(opts, "l7policy") - if err != nil { - return nil, err - } - - m := b["l7policy"].(map[string]interface{}) - - if m["redirect_pool_id"] == "" { - m["redirect_pool_id"] = nil - } - - if m["redirect_url"] == "" { - m["redirect_url"] = nil - } - - return b, nil -} - -// Update allows l7policy to be updated. -func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { - b, err := opts.ToL7PolicyUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// CreateRuleOpts is the common options struct used in this package's CreateRule -// operation. -type CreateRuleOpts struct { - // The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH. - RuleType RuleType `json:"type" required:"true"` - - // The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH, EQUAL_TO, REGEX, or STARTS_WITH. - CompareType CompareType `json:"compare_type" required:"true"` - - // The value to use for the comparison. For example, the file type to compare. - Value string `json:"value" required:"true"` - - // TenantID is the UUID of the tenant who owns the rule in octavia. - // Only administrative users can specify a project UUID other than their own. - TenantID string `json:"tenant_id,omitempty"` - - // The key to use for the comparison. For example, the name of the cookie to evaluate. - Key string `json:"key,omitempty"` - - // When true the logic of the rule is inverted. For example, with invert true, - // equal to would become not equal to. Default is false. - Invert bool `json:"invert,omitempty"` - - // The administrative state of the Loadbalancer. A valid value is true (UP) - // or false (DOWN). - AdminStateUp *bool `json:"admin_state_up,omitempty"` -} - -// ToRuleCreateMap builds a request body from CreateRuleOpts. -func (opts CreateRuleOpts) ToRuleCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "rule") -} - -// CreateRule will create and associate a Rule with a particular L7Policy. -func CreateRule(c *gophercloud.ServiceClient, policyID string, opts CreateRuleOpts) (r CreateRuleResult) { - b, err := opts.ToRuleCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Post(ruleRootURL(c, policyID), b, &r.Body, nil) - return -} - -// ListRulesOptsBuilder allows extensions to add additional parameters to the -// ListRules request. -type ListRulesOptsBuilder interface { - ToRulesListQuery() (string, error) -} - -// ListRulesOpts allows the filtering and sorting of paginated collections -// through the API. -type ListRulesOpts struct { - RuleType RuleType `q:"type"` - TenantID string `q:"tenant_id"` - CompareType CompareType `q:"compare_type"` - Value string `q:"value"` - Key string `q:"key"` - Invert bool `q:"invert"` - AdminStateUp bool `q:"admin_state_up"` - ID string `q:"id"` - Limit int `q:"limit"` - Marker string `q:"marker"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` -} - -// ToRulesListQuery formats a ListOpts into a query string. -func (opts ListRulesOpts) ToRulesListQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - return q.String(), err -} - -// ListRules returns a Pager which allows you to iterate over a collection of -// rules. It accepts a ListRulesOptsBuilder, which allows you to filter and -// sort the returned collection for greater efficiency. -// -// Default policy settings return only those rules that are owned by the -// project who submits the request, unless an admin user submits the request. -func ListRules(c *gophercloud.ServiceClient, policyID string, opts ListRulesOptsBuilder) pagination.Pager { - url := ruleRootURL(c, policyID) - if opts != nil { - query, err := opts.ToRulesListQuery() - if err != nil { - return pagination.Pager{Err: err} - } - url += query - } - return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { - return RulePage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -// GetRule retrieves a particular L7Policy Rule based on its unique ID. -func GetRule(c *gophercloud.ServiceClient, policyID string, ruleID string) (r GetRuleResult) { - _, r.Err = c.Get(ruleResourceURL(c, policyID, ruleID), &r.Body, nil) - return -} - -// DeleteRule will remove a Rule from a particular L7Policy. -func DeleteRule(c *gophercloud.ServiceClient, policyID string, ruleID string) (r DeleteRuleResult) { - _, r.Err = c.Delete(ruleResourceURL(c, policyID, ruleID), nil) - return -} - -// UpdateRuleOptsBuilder allows to add additional parameters to the PUT request. -type UpdateRuleOptsBuilder interface { - ToRuleUpdateMap() (map[string]interface{}, error) -} - -// UpdateRuleOpts is the common options struct used in this package's Update -// operation. -type UpdateRuleOpts struct { - // The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH. - RuleType RuleType `json:"type,omitempty"` - - // The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH, EQUAL_TO, REGEX, or STARTS_WITH. - CompareType CompareType `json:"compare_type,omitempty"` - - // The value to use for the comparison. For example, the file type to compare. - Value string `json:"value,omitempty"` - - // The key to use for the comparison. For example, the name of the cookie to evaluate. - Key *string `json:"key,omitempty"` - - // When true the logic of the rule is inverted. For example, with invert true, - // equal to would become not equal to. Default is false. - Invert *bool `json:"invert,omitempty"` - - // The administrative state of the Loadbalancer. A valid value is true (UP) - // or false (DOWN). - AdminStateUp *bool `json:"admin_state_up,omitempty"` -} - -// ToRuleUpdateMap builds a request body from UpdateRuleOpts. -func (opts UpdateRuleOpts) ToRuleUpdateMap() (map[string]interface{}, error) { - b, err := gophercloud.BuildRequestBody(opts, "rule") - if err != nil { - return nil, err - } - - if m := b["rule"].(map[string]interface{}); m["key"] == "" { - m["key"] = nil - } - - return b, nil -} - -// UpdateRule allows Rule to be updated. -func UpdateRule(c *gophercloud.ServiceClient, policyID string, ruleID string, opts UpdateRuleOptsBuilder) (r UpdateRuleResult) { - b, err := opts.ToRuleUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Put(ruleResourceURL(c, policyID, ruleID), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200, 201, 202}, - }) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies/results.go deleted file mode 100644 index 5153b1b90c8..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies/results.go +++ /dev/null @@ -1,245 +0,0 @@ -package l7policies - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// L7Policy is a collection of L7 rules associated with a Listener, and which -// may also have an association to a back-end pool. -type L7Policy struct { - // The unique ID for the L7 policy. - ID string `json:"id"` - - // Name of the L7 policy. - Name string `json:"name"` - - // The ID of the listener. - ListenerID string `json:"listener_id"` - - // The L7 policy action. One of REDIRECT_TO_POOL, REDIRECT_TO_URL, or REJECT. - Action string `json:"action"` - - // The position of this policy on the listener. - Position int32 `json:"position"` - - // A human-readable description for the resource. - Description string `json:"description"` - - // TenantID is the UUID of the tenant who owns the L7 policy in octavia. - // Only administrative users can specify a project UUID other than their own. - TenantID string `json:"tenant_id"` - - // Requests matching this policy will be redirected to the pool with this ID. - // Only valid if action is REDIRECT_TO_POOL. - RedirectPoolID string `json:"redirect_pool_id"` - - // Requests matching this policy will be redirected to this URL. - // Only valid if action is REDIRECT_TO_URL. - RedirectURL string `json:"redirect_url"` - - // The administrative state of the L7 policy, which is up (true) or down (false). - AdminStateUp bool `json:"admin_state_up"` - - // The provisioning status of the L7 policy. - // This value is ACTIVE, PENDING_* or ERROR. - // This field seems to only be returned during a call to a load balancer's /status - // see: https://github.com/gophercloud/gophercloud/issues/1362 - ProvisioningStatus string `json:"provisioning_status"` - - // The operating status of the L7 policy. - // This field seems to only be returned during a call to a load balancer's /status - // see: https://github.com/gophercloud/gophercloud/issues/1362 - OperatingStatus string `json:"operating_status"` - - // Rules are List of associated L7 rule IDs. - Rules []Rule `json:"rules"` -} - -// Rule represents layer 7 load balancing rule. -type Rule struct { - // The unique ID for the L7 rule. - ID string `json:"id"` - - // The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH. - RuleType string `json:"type"` - - // The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH, EQUAL_TO, REGEX, or STARTS_WITH. - CompareType string `json:"compare_type"` - - // The value to use for the comparison. For example, the file type to compare. - Value string `json:"value"` - - // TenantID is the UUID of the tenant who owns the rule in octavia. - // Only administrative users can specify a project UUID other than their own. - TenantID string `json:"tenant_id"` - - // The key to use for the comparison. For example, the name of the cookie to evaluate. - Key string `json:"key"` - - // When true the logic of the rule is inverted. For example, with invert true, - // equal to would become not equal to. Default is false. - Invert bool `json:"invert"` - - // The administrative state of the L7 rule, which is up (true) or down (false). - AdminStateUp bool `json:"admin_state_up"` - - // The provisioning status of the L7 rule. - // This value is ACTIVE, PENDING_* or ERROR. - // This field seems to only be returned during a call to a load balancer's /status - // see: https://github.com/gophercloud/gophercloud/issues/1362 - ProvisioningStatus string `json:"provisioning_status"` - - // The operating status of the L7 policy. - // This field seems to only be returned during a call to a load balancer's /status - // see: https://github.com/gophercloud/gophercloud/issues/1362 - OperatingStatus string `json:"operating_status"` -} - -type commonResult struct { - gophercloud.Result -} - -// Extract is a function that accepts a result and extracts a l7policy. -func (r commonResult) Extract() (*L7Policy, error) { - var s struct { - L7Policy *L7Policy `json:"l7policy"` - } - err := r.ExtractInto(&s) - return s.L7Policy, err -} - -// CreateResult represents the result of a Create operation. Call its Extract -// method to interpret the result as a L7Policy. -type CreateResult struct { - commonResult -} - -// L7PolicyPage is the page returned by a pager when traversing over a -// collection of l7policies. -type L7PolicyPage struct { - pagination.LinkedPageBase -} - -// NextPageURL is invoked when a paginated collection of l7policies has reached -// the end of a page and the pager seeks to traverse over a new one. In order -// to do this, it needs to construct the next page's URL. -func (r L7PolicyPage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"l7policies_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// IsEmpty checks whether a L7PolicyPage struct is empty. -func (r L7PolicyPage) IsEmpty() (bool, error) { - is, err := ExtractL7Policies(r) - return len(is) == 0, err -} - -// ExtractL7Policies accepts a Page struct, specifically a L7PolicyPage struct, -// and extracts the elements into a slice of L7Policy structs. In other words, -// a generic collection is mapped into a relevant slice. -func ExtractL7Policies(r pagination.Page) ([]L7Policy, error) { - var s struct { - L7Policies []L7Policy `json:"l7policies"` - } - err := (r.(L7PolicyPage)).ExtractInto(&s) - return s.L7Policies, err -} - -// GetResult represents the result of a Get operation. Call its Extract -// method to interpret the result as a L7Policy. -type GetResult struct { - commonResult -} - -// DeleteResult represents the result of a Delete operation. Call its -// ExtractErr method to determine if the request succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} - -// UpdateResult represents the result of an Update operation. Call its Extract -// method to interpret the result as a L7Policy. -type UpdateResult struct { - commonResult -} - -type commonRuleResult struct { - gophercloud.Result -} - -// Extract is a function that accepts a result and extracts a rule. -func (r commonRuleResult) Extract() (*Rule, error) { - var s struct { - Rule *Rule `json:"rule"` - } - err := r.ExtractInto(&s) - return s.Rule, err -} - -// CreateRuleResult represents the result of a CreateRule operation. -// Call its Extract method to interpret it as a Rule. -type CreateRuleResult struct { - commonRuleResult -} - -// RulePage is the page returned by a pager when traversing over a -// collection of Rules in a L7Policy. -type RulePage struct { - pagination.LinkedPageBase -} - -// NextPageURL is invoked when a paginated collection of rules has reached -// the end of a page and the pager seeks to traverse over a new one. In order -// to do this, it needs to construct the next page's URL. -func (r RulePage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"rules_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// IsEmpty checks whether a RulePage struct is empty. -func (r RulePage) IsEmpty() (bool, error) { - is, err := ExtractRules(r) - return len(is) == 0, err -} - -// ExtractRules accepts a Page struct, specifically a RulePage struct, -// and extracts the elements into a slice of Rules structs. In other words, -// a generic collection is mapped into a relevant slice. -func ExtractRules(r pagination.Page) ([]Rule, error) { - var s struct { - Rules []Rule `json:"rules"` - } - err := (r.(RulePage)).ExtractInto(&s) - return s.Rules, err -} - -// GetRuleResult represents the result of a GetRule operation. -// Call its Extract method to interpret it as a Rule. -type GetRuleResult struct { - commonRuleResult -} - -// DeleteRuleResult represents the result of a DeleteRule operation. -// Call its ExtractErr method to determine if the request succeeded or failed. -type DeleteRuleResult struct { - gophercloud.ErrResult -} - -// UpdateRuleResult represents the result of an UpdateRule operation. -// Call its Extract method to interpret it as a Rule. -type UpdateRuleResult struct { - commonRuleResult -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies/urls.go deleted file mode 100644 index ecb607a8e89..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies/urls.go +++ /dev/null @@ -1,25 +0,0 @@ -package l7policies - -import "github.com/gophercloud/gophercloud" - -const ( - rootPath = "lbaas" - resourcePath = "l7policies" - rulePath = "rules" -) - -func rootURL(c *gophercloud.ServiceClient) string { - return c.ServiceURL(rootPath, resourcePath) -} - -func resourceURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL(rootPath, resourcePath, id) -} - -func ruleRootURL(c *gophercloud.ServiceClient, policyID string) string { - return c.ServiceURL(rootPath, resourcePath, policyID, rulePath) -} - -func ruleResourceURL(c *gophercloud.ServiceClient, policyID string, ruleID string) string { - return c.ServiceURL(rootPath, resourcePath, policyID, rulePath, ruleID) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners/doc.go deleted file mode 100644 index 108cdb03d8b..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners/doc.go +++ /dev/null @@ -1,63 +0,0 @@ -/* -Package listeners provides information and interaction with Listeners of the -LBaaS v2 extension for the OpenStack Networking service. - -Example to List Listeners - - listOpts := listeners.ListOpts{ - LoadbalancerID : "ca430f80-1737-4712-8dc6-3f640d55594b", - } - - allPages, err := listeners.List(networkClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - allListeners, err := listeners.ExtractListeners(allPages) - if err != nil { - panic(err) - } - - for _, listener := range allListeners { - fmt.Printf("%+v\n", listener) - } - -Example to Create a Listener - - createOpts := listeners.CreateOpts{ - Protocol: "TCP", - Name: "db", - LoadbalancerID: "79e05663-7f03-45d2-a092-8b94062f22ab", - AdminStateUp: gophercloud.Enabled, - DefaultPoolID: "41efe233-7591-43c5-9cf7-923964759f9e", - ProtocolPort: 3306, - } - - listener, err := listeners.Create(networkClient, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to Update a Listener - - listenerID := "d67d56a6-4a86-4688-a282-f46444705c64" - - i1001 := 1001 - updateOpts := listeners.UpdateOpts{ - ConnLimit: &i1001, - } - - listener, err := listeners.Update(networkClient, listenerID, updateOpts).Extract() - if err != nil { - panic(err) - } - -Example to Delete a Listener - - listenerID := "d67d56a6-4a86-4688-a282-f46444705c64" - err := listeners.Delete(networkClient, listenerID).ExtractErr() - if err != nil { - panic(err) - } -*/ -package listeners diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners/requests.go deleted file mode 100644 index f2966b6c44a..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners/requests.go +++ /dev/null @@ -1,212 +0,0 @@ -package listeners - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// Type Protocol represents a listener protocol. -type Protocol string - -// Supported attributes for create/update operations. -const ( - ProtocolTCP Protocol = "TCP" - ProtocolHTTP Protocol = "HTTP" - ProtocolHTTPS Protocol = "HTTPS" - ProtocolTerminatedHTTPS Protocol = "TERMINATED_HTTPS" -) - -// ListOptsBuilder allows extensions to add additional parameters to the -// List request. -type ListOptsBuilder interface { - ToListenerListQuery() (string, error) -} - -// ListOpts allows the filtering and sorting of paginated collections through -// the API. Filtering is achieved by passing in struct field values that map to -// the floating IP attributes you want to see returned. SortKey allows you to -// sort by a particular listener attribute. SortDir sets the direction, and is -// either `asc' or `desc'. Marker and Limit are used for pagination. -type ListOpts struct { - ID string `q:"id"` - Name string `q:"name"` - AdminStateUp *bool `q:"admin_state_up"` - TenantID string `q:"tenant_id"` - ProjectID string `q:"project_id"` - LoadbalancerID string `q:"loadbalancer_id"` - DefaultPoolID string `q:"default_pool_id"` - Protocol string `q:"protocol"` - ProtocolPort int `q:"protocol_port"` - ConnectionLimit int `q:"connection_limit"` - Limit int `q:"limit"` - Marker string `q:"marker"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` -} - -// ToListenerListQuery formats a ListOpts into a query string. -func (opts ListOpts) ToListenerListQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - return q.String(), err -} - -// List returns a Pager which allows you to iterate over a collection of -// listeners. It accepts a ListOpts struct, which allows you to filter and sort -// the returned collection for greater efficiency. -// -// Default policy settings return only those listeners that are owned by the -// tenant who submits the request, unless an admin user submits the request. -func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { - url := rootURL(c) - if opts != nil { - query, err := opts.ToListenerListQuery() - if err != nil { - return pagination.Pager{Err: err} - } - url += query - } - return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { - return ListenerPage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -// CreateOptsBuilder allows extensions to add additional parameters to the -// Create request. -type CreateOptsBuilder interface { - ToListenerCreateMap() (map[string]interface{}, error) -} - -// CreateOpts represents options for creating a listener. -type CreateOpts struct { - // The load balancer on which to provision this listener. - LoadbalancerID string `json:"loadbalancer_id" required:"true"` - - // The protocol - can either be TCP, HTTP or HTTPS. - Protocol Protocol `json:"protocol" required:"true"` - - // The port on which to listen for client traffic. - ProtocolPort int `json:"protocol_port" required:"true"` - - // TenantID is only required if the caller has an admin role and wants - // to create a pool for another project. - TenantID string `json:"tenant_id,omitempty"` - - // ProjectID is only required if the caller has an admin role and wants - // to create a pool for another project. - ProjectID string `json:"project_id,omitempty"` - - // Human-readable name for the Listener. Does not have to be unique. - Name string `json:"name,omitempty"` - - // The ID of the default pool with which the Listener is associated. - DefaultPoolID string `json:"default_pool_id,omitempty"` - - // Human-readable description for the Listener. - Description string `json:"description,omitempty"` - - // The maximum number of connections allowed for the Listener. - ConnLimit *int `json:"connection_limit,omitempty"` - - // A reference to a Barbican container of TLS secrets. - DefaultTlsContainerRef string `json:"default_tls_container_ref,omitempty"` - - // A list of references to TLS secrets. - SniContainerRefs []string `json:"sni_container_refs,omitempty"` - - // The administrative state of the Listener. A valid value is true (UP) - // or false (DOWN). - AdminStateUp *bool `json:"admin_state_up,omitempty"` -} - -// ToListenerCreateMap builds a request body from CreateOpts. -func (opts CreateOpts) ToListenerCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "listener") -} - -// Create is an operation which provisions a new Listeners based on the -// configuration defined in the CreateOpts struct. Once the request is -// validated and progress has started on the provisioning process, a -// CreateResult will be returned. -// -// Users with an admin role can create Listeners on behalf of other tenants by -// specifying a TenantID attribute different than their own. -func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToListenerCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Post(rootURL(c), b, &r.Body, nil) - return -} - -// Get retrieves a particular Listeners based on its unique ID. -func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) - return -} - -// UpdateOptsBuilder allows extensions to add additional parameters to the -// Update request. -type UpdateOptsBuilder interface { - ToListenerUpdateMap() (map[string]interface{}, error) -} - -// UpdateOpts represents options for updating a Listener. -type UpdateOpts struct { - // Human-readable name for the Listener. Does not have to be unique. - Name *string `json:"name,omitempty"` - - // The ID of the default pool with which the Listener is associated. - DefaultPoolID *string `json:"default_pool_id,omitempty"` - - // Human-readable description for the Listener. - Description *string `json:"description,omitempty"` - - // The maximum number of connections allowed for the Listener. - ConnLimit *int `json:"connection_limit,omitempty"` - - // A reference to a Barbican container of TLS secrets. - DefaultTlsContainerRef string `json:"default_tls_container_ref,omitempty"` - - // A list of references to TLS secrets. - SniContainerRefs []string `json:"sni_container_refs,omitempty"` - - // The administrative state of the Listener. A valid value is true (UP) - // or false (DOWN). - AdminStateUp *bool `json:"admin_state_up,omitempty"` -} - -// ToListenerUpdateMap builds a request body from UpdateOpts. -func (opts UpdateOpts) ToListenerUpdateMap() (map[string]interface{}, error) { - b, err := gophercloud.BuildRequestBody(opts, "listener") - if err != nil { - return nil, err - } - - if m := b["listener"].(map[string]interface{}); m["default_pool_id"] == "" { - m["default_pool_id"] = nil - } - - return b, nil -} - -// Update is an operation which modifies the attributes of the specified -// Listener. -func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (r UpdateResult) { - b, err := opts.ToListenerUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200, 202}, - }) - return -} - -// Delete will permanently delete a particular Listeners based on its unique ID. -func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = c.Delete(resourceURL(c, id), nil) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners/results.go deleted file mode 100644 index ae105793225..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners/results.go +++ /dev/null @@ -1,141 +0,0 @@ -package listeners - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools" - "github.com/gophercloud/gophercloud/pagination" -) - -type LoadBalancerID struct { - ID string `json:"id"` -} - -// Listener is the primary load balancing configuration object that specifies -// the loadbalancer and port on which client traffic is received, as well -// as other details such as the load balancing method to be use, protocol, etc. -type Listener struct { - // The unique ID for the Listener. - ID string `json:"id"` - - // Owner of the Listener. - TenantID string `json:"tenant_id"` - - // Human-readable name for the Listener. Does not have to be unique. - Name string `json:"name"` - - // Human-readable description for the Listener. - Description string `json:"description"` - - // The protocol to loadbalance. A valid value is TCP, HTTP, or HTTPS. - Protocol string `json:"protocol"` - - // The port on which to listen to client traffic that is associated with the - // Loadbalancer. A valid value is from 0 to 65535. - ProtocolPort int `json:"protocol_port"` - - // The UUID of default pool. Must have compatible protocol with listener. - DefaultPoolID string `json:"default_pool_id"` - - // A list of load balancer IDs. - Loadbalancers []LoadBalancerID `json:"loadbalancers"` - - // The maximum number of connections allowed for the Loadbalancer. - // Default is -1, meaning no limit. - ConnLimit int `json:"connection_limit"` - - // The list of references to TLS secrets. - SniContainerRefs []string `json:"sni_container_refs"` - - // A reference to a Barbican container of TLS secrets. - DefaultTlsContainerRef string `json:"default_tls_container_ref"` - - // The administrative state of the Listener. A valid value is true (UP) or false (DOWN). - AdminStateUp bool `json:"admin_state_up"` - - // Pools are the pools which are part of this listener. - Pools []pools.Pool `json:"pools"` - - // L7policies are the L7 policies which are part of this listener. - // This field seems to only be returned during a call to a load balancer's /status - // see: https://github.com/gophercloud/gophercloud/issues/1352 - L7Policies []l7policies.L7Policy `json:"l7policies"` - - // The provisioning status of the listener. - // This value is ACTIVE, PENDING_* or ERROR. - ProvisioningStatus string `json:"provisioning_status"` -} - -// ListenerPage is the page returned by a pager when traversing over a -// collection of listeners. -type ListenerPage struct { - pagination.LinkedPageBase -} - -// NextPageURL is invoked when a paginated collection of listeners has reached -// the end of a page and the pager seeks to traverse over a new one. In order -// to do this, it needs to construct the next page's URL. -func (r ListenerPage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"listeners_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// IsEmpty checks whether a ListenerPage struct is empty. -func (r ListenerPage) IsEmpty() (bool, error) { - is, err := ExtractListeners(r) - return len(is) == 0, err -} - -// ExtractListeners accepts a Page struct, specifically a ListenerPage struct, -// and extracts the elements into a slice of Listener structs. In other words, -// a generic collection is mapped into a relevant slice. -func ExtractListeners(r pagination.Page) ([]Listener, error) { - var s struct { - Listeners []Listener `json:"listeners"` - } - err := (r.(ListenerPage)).ExtractInto(&s) - return s.Listeners, err -} - -type commonResult struct { - gophercloud.Result -} - -// Extract is a function that accepts a result and extracts a listener. -func (r commonResult) Extract() (*Listener, error) { - var s struct { - Listener *Listener `json:"listener"` - } - err := r.ExtractInto(&s) - return s.Listener, err -} - -// CreateResult represents the result of a create operation. Call its Extract -// method to interpret it as a Listener. -type CreateResult struct { - commonResult -} - -// GetResult represents the result of a get operation. Call its Extract -// method to interpret it as a Listener. -type GetResult struct { - commonResult -} - -// UpdateResult represents the result of an update operation. Call its Extract -// method to interpret it as a Listener. -type UpdateResult struct { - commonResult -} - -// DeleteResult represents the result of a delete operation. Call its -// ExtractErr method to determine if the request succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners/urls.go deleted file mode 100644 index 02fb1eb39ec..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners/urls.go +++ /dev/null @@ -1,16 +0,0 @@ -package listeners - -import "github.com/gophercloud/gophercloud" - -const ( - rootPath = "lbaas" - resourcePath = "listeners" -) - -func rootURL(c *gophercloud.ServiceClient) string { - return c.ServiceURL(rootPath, resourcePath) -} - -func resourceURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL(rootPath, resourcePath, id) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers/doc.go deleted file mode 100644 index c6d53a7b052..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers/doc.go +++ /dev/null @@ -1,79 +0,0 @@ -/* -Package loadbalancers provides information and interaction with Load Balancers -of the LBaaS v2 extension for the OpenStack Networking service. - -Example to List Load Balancers - - listOpts := loadbalancers.ListOpts{ - Provider: "haproxy", - } - - allPages, err := loadbalancers.List(networkClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - allLoadbalancers, err := loadbalancers.ExtractLoadBalancers(allPages) - if err != nil { - panic(err) - } - - for _, lb := range allLoadbalancers { - fmt.Printf("%+v\n", lb) - } - -Example to Create a Load Balancer - - createOpts := loadbalancers.CreateOpts{ - Name: "db_lb", - AdminStateUp: gophercloud.Enabled, - VipSubnetID: "9cedb85d-0759-4898-8a4b-fa5a5ea10086", - VipAddress: "10.30.176.48", - Flavor: "medium", - Provider: "haproxy", - } - - lb, err := loadbalancers.Create(networkClient, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to Update a Load Balancer - - lbID := "d67d56a6-4a86-4688-a282-f46444705c64" - - i1001 := 1001 - updateOpts := loadbalancers.UpdateOpts{ - Name: "new-name", - } - - lb, err := loadbalancers.Update(networkClient, lbID, updateOpts).Extract() - if err != nil { - panic(err) - } - -Example to Delete a Load Balancers - - lbID := "d67d56a6-4a86-4688-a282-f46444705c64" - err := loadbalancers.Delete(networkClient, lbID).ExtractErr() - if err != nil { - panic(err) - } - -Example to Get the Status of a Load Balancer - - lbID := "d67d56a6-4a86-4688-a282-f46444705c64" - status, err := loadbalancers.GetStatuses(networkClient, LBID).Extract() - if err != nil { - panic(err) - } - -Example to Get the Statistics of a Load Balancer - - lbID := "d67d56a6-4a86-4688-a282-f46444705c64" - stats, err := loadbalancers.GetStats(networkClient, LBID).Extract() - if err != nil { - panic(err) - } -*/ -package loadbalancers diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers/requests.go deleted file mode 100644 index f5b14134821..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers/requests.go +++ /dev/null @@ -1,204 +0,0 @@ -package loadbalancers - -import ( - "fmt" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// ListOptsBuilder allows extensions to add additional parameters to the -// List request. -type ListOptsBuilder interface { - ToLoadBalancerListQuery() (string, error) -} - -// ListOpts allows the filtering and sorting of paginated collections through -// the API. Filtering is achieved by passing in struct field values that map to -// the Loadbalancer attributes you want to see returned. SortKey allows you to -// sort by a particular attribute. SortDir sets the direction, and is -// either `asc' or `desc'. Marker and Limit are used for pagination. -type ListOpts struct { - Description string `q:"description"` - AdminStateUp *bool `q:"admin_state_up"` - TenantID string `q:"tenant_id"` - ProjectID string `q:"project_id"` - ProvisioningStatus string `q:"provisioning_status"` - VipAddress string `q:"vip_address"` - VipPortID string `q:"vip_port_id"` - VipSubnetID string `q:"vip_subnet_id"` - ID string `q:"id"` - OperatingStatus string `q:"operating_status"` - Name string `q:"name"` - Flavor string `q:"flavor"` - Provider string `q:"provider"` - Limit int `q:"limit"` - Marker string `q:"marker"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` -} - -// ToLoadBalancerListQuery formats a ListOpts into a query string. -func (opts ListOpts) ToLoadBalancerListQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - return q.String(), err -} - -// List returns a Pager which allows you to iterate over a collection of -// load balancers. It accepts a ListOpts struct, which allows you to filter -// and sort the returned collection for greater efficiency. -// -// Default policy settings return only those load balancers that are owned by -// the tenant who submits the request, unless an admin user submits the request. -func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { - url := rootURL(c) - if opts != nil { - query, err := opts.ToLoadBalancerListQuery() - if err != nil { - return pagination.Pager{Err: err} - } - url += query - } - return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { - return LoadBalancerPage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -// CreateOptsBuilder allows extensions to add additional parameters to the -// Create request. -type CreateOptsBuilder interface { - ToLoadBalancerCreateMap() (map[string]interface{}, error) -} - -// CreateOpts is the common options struct used in this package's Create -// operation. -type CreateOpts struct { - // Human-readable name for the Loadbalancer. Does not have to be unique. - Name string `json:"name,omitempty"` - - // Human-readable description for the Loadbalancer. - Description string `json:"description,omitempty"` - - // The network on which to allocate the Loadbalancer's address. A tenant can - // only create Loadbalancers on networks authorized by policy (e.g. networks - // that belong to them or networks that are shared). - VipSubnetID string `json:"vip_subnet_id" required:"true"` - - // TenantID is the UUID of the project who owns the Loadbalancer. - // Only administrative users can specify a project UUID other than their own. - TenantID string `json:"tenant_id,omitempty"` - - // ProjectID is the UUID of the project who owns the Loadbalancer. - // Only administrative users can specify a project UUID other than their own. - ProjectID string `json:"project_id,omitempty"` - - // The IP address of the Loadbalancer. - VipAddress string `json:"vip_address,omitempty"` - - // The administrative state of the Loadbalancer. A valid value is true (UP) - // or false (DOWN). - AdminStateUp *bool `json:"admin_state_up,omitempty"` - - // The UUID of a flavor. - Flavor string `json:"flavor,omitempty"` - - // The name of the provider. - Provider string `json:"provider,omitempty"` -} - -// ToLoadBalancerCreateMap builds a request body from CreateOpts. -func (opts CreateOpts) ToLoadBalancerCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "loadbalancer") -} - -// Create is an operation which provisions a new loadbalancer based on the -// configuration defined in the CreateOpts struct. Once the request is -// validated and progress has started on the provisioning process, a -// CreateResult will be returned. -func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToLoadBalancerCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Post(rootURL(c), b, &r.Body, nil) - return -} - -// Get retrieves a particular Loadbalancer based on its unique ID. -func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) - return -} - -// UpdateOptsBuilder allows extensions to add additional parameters to the -// Update request. -type UpdateOptsBuilder interface { - ToLoadBalancerUpdateMap() (map[string]interface{}, error) -} - -// UpdateOpts is the common options struct used in this package's Update -// operation. -type UpdateOpts struct { - // Human-readable name for the Loadbalancer. Does not have to be unique. - Name *string `json:"name,omitempty"` - - // Human-readable description for the Loadbalancer. - Description *string `json:"description,omitempty"` - - // The administrative state of the Loadbalancer. A valid value is true (UP) - // or false (DOWN). - AdminStateUp *bool `json:"admin_state_up,omitempty"` -} - -// ToLoadBalancerUpdateMap builds a request body from UpdateOpts. -func (opts UpdateOpts) ToLoadBalancerUpdateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "loadbalancer") -} - -// Update is an operation which modifies the attributes of the specified -// LoadBalancer. -func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (r UpdateResult) { - b, err := opts.ToLoadBalancerUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200, 202}, - }) - return -} - -// Delete will permanently delete a particular LoadBalancer based on its -// unique ID. -func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = c.Delete(resourceURL(c, id), nil) - return -} - -// CascadingDelete is like `Delete`, but will also delete any of the load balancer's -// children (listener, monitor, etc). -// NOTE: This function will only work with Octavia load balancers; Neutron does not -// support this. -func CascadingDelete(c *gophercloud.ServiceClient, id string) (r DeleteResult) { - if c.Type != "load-balancer" { - r.Err = fmt.Errorf("error prior to running cascade delete: only Octavia LBs supported") - return - } - u := fmt.Sprintf("%s?cascade=true", resourceURL(c, id)) - _, r.Err = c.Delete(u, nil) - return -} - -// GetStatuses will return the status of a particular LoadBalancer. -func GetStatuses(c *gophercloud.ServiceClient, id string) (r GetStatusesResult) { - _, r.Err = c.Get(statusRootURL(c, id), &r.Body, nil) - return -} - -// GetStats will return the shows the current statistics of a particular LoadBalancer. -func GetStats(c *gophercloud.ServiceClient, id string) (r StatsResult) { - _, r.Err = c.Get(statisticsRootURL(c, id), &r.Body, nil) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers/results.go deleted file mode 100644 index 7f423c933dd..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers/results.go +++ /dev/null @@ -1,186 +0,0 @@ -package loadbalancers - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools" - "github.com/gophercloud/gophercloud/pagination" -) - -// LoadBalancer is the primary load balancing configuration object that -// specifies the virtual IP address on which client traffic is received, as well -// as other details such as the load balancing method to be use, protocol, etc. -type LoadBalancer struct { - // Human-readable description for the Loadbalancer. - Description string `json:"description"` - - // The administrative state of the Loadbalancer. - // A valid value is true (UP) or false (DOWN). - AdminStateUp bool `json:"admin_state_up"` - - // Owner of the LoadBalancer. - TenantID string `json:"tenant_id"` - - // The provisioning status of the LoadBalancer. - // This value is ACTIVE, PENDING_CREATE or ERROR. - ProvisioningStatus string `json:"provisioning_status"` - - // The IP address of the Loadbalancer. - VipAddress string `json:"vip_address"` - - // The UUID of the port associated with the IP address. - VipPortID string `json:"vip_port_id"` - - // The UUID of the subnet on which to allocate the virtual IP for the - // Loadbalancer address. - VipSubnetID string `json:"vip_subnet_id"` - - // The unique ID for the LoadBalancer. - ID string `json:"id"` - - // The operating status of the LoadBalancer. This value is ONLINE or OFFLINE. - OperatingStatus string `json:"operating_status"` - - // Human-readable name for the LoadBalancer. Does not have to be unique. - Name string `json:"name"` - - // The UUID of a flavor if set. - Flavor string `json:"flavor"` - - // The name of the provider. - Provider string `json:"provider"` - - // Listeners are the listeners related to this Loadbalancer. - Listeners []listeners.Listener `json:"listeners"` - - // Pools are the pools related to this Loadbalancer. - Pools []pools.Pool `json:"pools"` -} - -// StatusTree represents the status of a loadbalancer. -type StatusTree struct { - Loadbalancer *LoadBalancer `json:"loadbalancer"` -} - -type Stats struct { - // The currently active connections. - ActiveConnections int `json:"active_connections"` - - // The total bytes received. - BytesIn int `json:"bytes_in"` - - // The total bytes sent. - BytesOut int `json:"bytes_out"` - - // The total requests that were unable to be fulfilled. - RequestErrors int `json:"request_errors"` - - // The total connections handled. - TotalConnections int `json:"total_connections"` -} - -// LoadBalancerPage is the page returned by a pager when traversing over a -// collection of load balancers. -type LoadBalancerPage struct { - pagination.LinkedPageBase -} - -// NextPageURL is invoked when a paginated collection of load balancers has -// reached the end of a page and the pager seeks to traverse over a new one. -// In order to do this, it needs to construct the next page's URL. -func (r LoadBalancerPage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"loadbalancers_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// IsEmpty checks whether a LoadBalancerPage struct is empty. -func (r LoadBalancerPage) IsEmpty() (bool, error) { - is, err := ExtractLoadBalancers(r) - return len(is) == 0, err -} - -// ExtractLoadBalancers accepts a Page struct, specifically a LoadbalancerPage -// struct, and extracts the elements into a slice of LoadBalancer structs. In -// other words, a generic collection is mapped into a relevant slice. -func ExtractLoadBalancers(r pagination.Page) ([]LoadBalancer, error) { - var s struct { - LoadBalancers []LoadBalancer `json:"loadbalancers"` - } - err := (r.(LoadBalancerPage)).ExtractInto(&s) - return s.LoadBalancers, err -} - -type commonResult struct { - gophercloud.Result -} - -// Extract is a function that accepts a result and extracts a loadbalancer. -func (r commonResult) Extract() (*LoadBalancer, error) { - var s struct { - LoadBalancer *LoadBalancer `json:"loadbalancer"` - } - err := r.ExtractInto(&s) - return s.LoadBalancer, err -} - -// GetStatusesResult represents the result of a GetStatuses operation. -// Call its Extract method to interpret it as a StatusTree. -type GetStatusesResult struct { - gophercloud.Result -} - -// Extract is a function that accepts a result and extracts the status of -// a Loadbalancer. -func (r GetStatusesResult) Extract() (*StatusTree, error) { - var s struct { - Statuses *StatusTree `json:"statuses"` - } - err := r.ExtractInto(&s) - return s.Statuses, err -} - -// StatsResult represents the result of a GetStats operation. -// Call its Extract method to interpret it as a Stats. -type StatsResult struct { - gophercloud.Result -} - -// Extract is a function that accepts a result and extracts the status of -// a Loadbalancer. -func (r StatsResult) Extract() (*Stats, error) { - var s struct { - Stats *Stats `json:"stats"` - } - err := r.ExtractInto(&s) - return s.Stats, err -} - -// CreateResult represents the result of a create operation. Call its Extract -// method to interpret it as a LoadBalancer. -type CreateResult struct { - commonResult -} - -// GetResult represents the result of a get operation. Call its Extract -// method to interpret it as a LoadBalancer. -type GetResult struct { - commonResult -} - -// UpdateResult represents the result of an update operation. Call its Extract -// method to interpret it as a LoadBalancer. -type UpdateResult struct { - commonResult -} - -// DeleteResult represents the result of a delete operation. Call its -// ExtractErr method to determine if the request succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers/urls.go deleted file mode 100644 index 2d2a99b7797..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers/urls.go +++ /dev/null @@ -1,26 +0,0 @@ -package loadbalancers - -import "github.com/gophercloud/gophercloud" - -const ( - rootPath = "lbaas" - resourcePath = "loadbalancers" - statusPath = "statuses" - statisticsPath = "stats" -) - -func rootURL(c *gophercloud.ServiceClient) string { - return c.ServiceURL(rootPath, resourcePath) -} - -func resourceURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL(rootPath, resourcePath, id) -} - -func statusRootURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL(rootPath, resourcePath, id, statusPath) -} - -func statisticsRootURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL(rootPath, resourcePath, id, statisticsPath) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors/doc.go deleted file mode 100644 index 6ed8c8fb5ff..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors/doc.go +++ /dev/null @@ -1,69 +0,0 @@ -/* -Package monitors provides information and interaction with Monitors -of the LBaaS v2 extension for the OpenStack Networking service. - -Example to List Monitors - - listOpts := monitors.ListOpts{ - PoolID: "c79a4468-d788-410c-bf79-9a8ef6354852", - } - - allPages, err := monitors.List(networkClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - allMonitors, err := monitors.ExtractMonitors(allPages) - if err != nil { - panic(err) - } - - for _, monitor := range allMonitors { - fmt.Printf("%+v\n", monitor) - } - -Example to Create a Monitor - - createOpts := monitors.CreateOpts{ - Type: "HTTP", - Name: "db", - PoolID: "84f1b61f-58c4-45bf-a8a9-2dafb9e5214d", - Delay: 20, - Timeout: 10, - MaxRetries: 5, - URLPath: "/check", - ExpectedCodes: "200-299", - } - - monitor, err := monitors.Create(networkClient, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to Update a Monitor - - monitorID := "d67d56a6-4a86-4688-a282-f46444705c64" - - updateOpts := monitors.UpdateOpts{ - Name: "NewHealthmonitorName", - Delay: 3, - Timeout: 20, - MaxRetries: 10, - URLPath: "/another_check", - ExpectedCodes: "301", - } - - monitor, err := monitors.Update(networkClient, monitorID, updateOpts).Extract() - if err != nil { - panic(err) - } - -Example to Delete a Monitor - - monitorID := "d67d56a6-4a86-4688-a282-f46444705c64" - err := monitors.Delete(networkClient, monitorID).ExtractErr() - if err != nil { - panic(err) - } -*/ -package monitors diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors/requests.go deleted file mode 100644 index f728f5a8237..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors/requests.go +++ /dev/null @@ -1,257 +0,0 @@ -package monitors - -import ( - "fmt" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// ListOptsBuilder allows extensions to add additional parameters to the -// List request. -type ListOptsBuilder interface { - ToMonitorListQuery() (string, error) -} - -// ListOpts allows the filtering and sorting of paginated collections through -// the API. Filtering is achieved by passing in struct field values that map to -// the Monitor attributes you want to see returned. SortKey allows you to -// sort by a particular Monitor attribute. SortDir sets the direction, and is -// either `asc' or `desc'. Marker and Limit are used for pagination. -type ListOpts struct { - ID string `q:"id"` - Name string `q:"name"` - TenantID string `q:"tenant_id"` - ProjectID string `q:"project_id"` - PoolID string `q:"pool_id"` - Type string `q:"type"` - Delay int `q:"delay"` - Timeout int `q:"timeout"` - MaxRetries int `q:"max_retries"` - HTTPMethod string `q:"http_method"` - URLPath string `q:"url_path"` - ExpectedCodes string `q:"expected_codes"` - AdminStateUp *bool `q:"admin_state_up"` - Status string `q:"status"` - Limit int `q:"limit"` - Marker string `q:"marker"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` -} - -// ToMonitorListQuery formats a ListOpts into a query string. -func (opts ListOpts) ToMonitorListQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - if err != nil { - return "", err - } - return q.String(), nil -} - -// List returns a Pager which allows you to iterate over a collection of -// health monitors. It accepts a ListOpts struct, which allows you to filter and sort -// the returned collection for greater efficiency. -// -// Default policy settings return only those health monitors that are owned by the -// tenant who submits the request, unless an admin user submits the request. -func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { - url := rootURL(c) - if opts != nil { - query, err := opts.ToMonitorListQuery() - if err != nil { - return pagination.Pager{Err: err} - } - url += query - } - return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { - return MonitorPage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -// Constants that represent approved monitoring types. -const ( - TypePING = "PING" - TypeTCP = "TCP" - TypeHTTP = "HTTP" - TypeHTTPS = "HTTPS" -) - -var ( - errDelayMustGETimeout = fmt.Errorf("Delay must be greater than or equal to timeout") -) - -// CreateOptsBuilder allows extensions to add additional parameters to the -// List request. -type CreateOptsBuilder interface { - ToMonitorCreateMap() (map[string]interface{}, error) -} - -// CreateOpts is the common options struct used in this package's Create -// operation. -type CreateOpts struct { - // The Pool to Monitor. - PoolID string `json:"pool_id" required:"true"` - - // The type of probe, which is PING, TCP, HTTP, or HTTPS, that is - // sent by the load balancer to verify the member state. - Type string `json:"type" required:"true"` - - // The time, in seconds, between sending probes to members. - Delay int `json:"delay" required:"true"` - - // Maximum number of seconds for a Monitor to wait for a ping reply - // before it times out. The value must be less than the delay value. - Timeout int `json:"timeout" required:"true"` - - // Number of permissible ping failures before changing the member's - // status to INACTIVE. Must be a number between 1 and 10. - MaxRetries int `json:"max_retries" required:"true"` - - // URI path that will be accessed if Monitor type is HTTP or HTTPS. - // Required for HTTP(S) types. - URLPath string `json:"url_path,omitempty"` - - // The HTTP method used for requests by the Monitor. If this attribute - // is not specified, it defaults to "GET". Required for HTTP(S) types. - HTTPMethod string `json:"http_method,omitempty"` - - // Expected HTTP codes for a passing HTTP(S) Monitor. You can either specify - // a single status like "200", or a range like "200-202". Required for HTTP(S) - // types. - ExpectedCodes string `json:"expected_codes,omitempty"` - - // TenantID is the UUID of the project who owns the Monitor. - // Only administrative users can specify a project UUID other than their own. - TenantID string `json:"tenant_id,omitempty"` - - // ProjectID is the UUID of the project who owns the Monitor. - // Only administrative users can specify a project UUID other than their own. - ProjectID string `json:"project_id,omitempty"` - - // The Name of the Monitor. - Name string `json:"name,omitempty"` - - // The administrative state of the Monitor. A valid value is true (UP) - // or false (DOWN). - AdminStateUp *bool `json:"admin_state_up,omitempty"` -} - -// ToMonitorCreateMap builds a request body from CreateOpts. -func (opts CreateOpts) ToMonitorCreateMap() (map[string]interface{}, error) { - b, err := gophercloud.BuildRequestBody(opts, "healthmonitor") - if err != nil { - return nil, err - } - - switch opts.Type { - case TypeHTTP, TypeHTTPS: - switch opts.URLPath { - case "": - return nil, fmt.Errorf("URLPath must be provided for HTTP and HTTPS") - } - switch opts.ExpectedCodes { - case "": - return nil, fmt.Errorf("ExpectedCodes must be provided for HTTP and HTTPS") - } - } - - return b, nil -} - -/* - Create is an operation which provisions a new Health Monitor. There are - different types of Monitor you can provision: PING, TCP or HTTP(S). Below - are examples of how to create each one. - - Here is an example config struct to use when creating a PING or TCP Monitor: - - CreateOpts{Type: TypePING, Delay: 20, Timeout: 10, MaxRetries: 3} - CreateOpts{Type: TypeTCP, Delay: 20, Timeout: 10, MaxRetries: 3} - - Here is an example config struct to use when creating a HTTP(S) Monitor: - - CreateOpts{Type: TypeHTTP, Delay: 20, Timeout: 10, MaxRetries: 3, - HttpMethod: "HEAD", ExpectedCodes: "200", PoolID: "2c946bfc-1804-43ab-a2ff-58f6a762b505"} -*/ -func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToMonitorCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Post(rootURL(c), b, &r.Body, nil) - return -} - -// Get retrieves a particular Health Monitor based on its unique ID. -func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) - return -} - -// UpdateOptsBuilder allows extensions to add additional parameters to the -// Update request. -type UpdateOptsBuilder interface { - ToMonitorUpdateMap() (map[string]interface{}, error) -} - -// UpdateOpts is the common options struct used in this package's Update -// operation. -type UpdateOpts struct { - // The time, in seconds, between sending probes to members. - Delay int `json:"delay,omitempty"` - - // Maximum number of seconds for a Monitor to wait for a ping reply - // before it times out. The value must be less than the delay value. - Timeout int `json:"timeout,omitempty"` - - // Number of permissible ping failures before changing the member's - // status to INACTIVE. Must be a number between 1 and 10. - MaxRetries int `json:"max_retries,omitempty"` - - // URI path that will be accessed if Monitor type is HTTP or HTTPS. - // Required for HTTP(S) types. - URLPath string `json:"url_path,omitempty"` - - // The HTTP method used for requests by the Monitor. If this attribute - // is not specified, it defaults to "GET". Required for HTTP(S) types. - HTTPMethod string `json:"http_method,omitempty"` - - // Expected HTTP codes for a passing HTTP(S) Monitor. You can either specify - // a single status like "200", or a range like "200-202". Required for HTTP(S) - // types. - ExpectedCodes string `json:"expected_codes,omitempty"` - - // The Name of the Monitor. - Name *string `json:"name,omitempty"` - - // The administrative state of the Monitor. A valid value is true (UP) - // or false (DOWN). - AdminStateUp *bool `json:"admin_state_up,omitempty"` -} - -// ToMonitorUpdateMap builds a request body from UpdateOpts. -func (opts UpdateOpts) ToMonitorUpdateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "healthmonitor") -} - -// Update is an operation which modifies the attributes of the specified -// Monitor. -func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { - b, err := opts.ToMonitorUpdateMap() - if err != nil { - r.Err = err - return - } - - _, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200, 202}, - }) - return -} - -// Delete will permanently delete a particular Monitor based on its unique ID. -func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = c.Delete(resourceURL(c, id), nil) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors/results.go deleted file mode 100644 index a78f7aeb0ff..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors/results.go +++ /dev/null @@ -1,153 +0,0 @@ -package monitors - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -type PoolID struct { - ID string `json:"id"` -} - -// Monitor represents a load balancer health monitor. A health monitor is used -// to determine whether or not back-end members of the VIP's pool are usable -// for processing a request. A pool can have several health monitors associated -// with it. There are different types of health monitors supported: -// -// PING: used to ping the members using ICMP. -// TCP: used to connect to the members using TCP. -// HTTP: used to send an HTTP request to the member. -// HTTPS: used to send a secure HTTP request to the member. -// -// When a pool has several monitors associated with it, each member of the pool -// is monitored by all these monitors. If any monitor declares the member as -// unhealthy, then the member status is changed to INACTIVE and the member -// won't participate in its pool's load balancing. In other words, ALL monitors -// must declare the member to be healthy for it to stay ACTIVE. -type Monitor struct { - // The unique ID for the Monitor. - ID string `json:"id"` - - // The Name of the Monitor. - Name string `json:"name"` - - // TenantID is the owner of the Monitor. - TenantID string `json:"tenant_id"` - - // The type of probe sent by the load balancer to verify the member state, - // which is PING, TCP, HTTP, or HTTPS. - Type string `json:"type"` - - // The time, in seconds, between sending probes to members. - Delay int `json:"delay"` - - // The maximum number of seconds for a monitor to wait for a connection to be - // established before it times out. This value must be less than the delay - // value. - Timeout int `json:"timeout"` - - // Number of allowed connection failures before changing the status of the - // member to INACTIVE. A valid value is from 1 to 10. - MaxRetries int `json:"max_retries"` - - // The HTTP method that the monitor uses for requests. - HTTPMethod string `json:"http_method"` - - // The HTTP path of the request sent by the monitor to test the health of a - // member. Must be a string beginning with a forward slash (/). - URLPath string `json:"url_path" ` - - // Expected HTTP codes for a passing HTTP(S) monitor. - ExpectedCodes string `json:"expected_codes"` - - // The administrative state of the health monitor, which is up (true) or - // down (false). - AdminStateUp bool `json:"admin_state_up"` - - // The status of the health monitor. Indicates whether the health monitor is - // operational. - Status string `json:"status"` - - // List of pools that are associated with the health monitor. - Pools []PoolID `json:"pools"` - - // The provisioning status of the monitor. - // This value is ACTIVE, PENDING_* or ERROR. - ProvisioningStatus string `json:"provisioning_status"` -} - -// MonitorPage is the page returned by a pager when traversing over a -// collection of health monitors. -type MonitorPage struct { - pagination.LinkedPageBase -} - -// NextPageURL is invoked when a paginated collection of monitors has reached -// the end of a page and the pager seeks to traverse over a new one. In order -// to do this, it needs to construct the next page's URL. -func (r MonitorPage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"healthmonitors_links"` - } - - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - - return gophercloud.ExtractNextURL(s.Links) -} - -// IsEmpty checks whether a MonitorPage struct is empty. -func (r MonitorPage) IsEmpty() (bool, error) { - is, err := ExtractMonitors(r) - return len(is) == 0, err -} - -// ExtractMonitors accepts a Page struct, specifically a MonitorPage struct, -// and extracts the elements into a slice of Monitor structs. In other words, -// a generic collection is mapped into a relevant slice. -func ExtractMonitors(r pagination.Page) ([]Monitor, error) { - var s struct { - Monitors []Monitor `json:"healthmonitors"` - } - err := (r.(MonitorPage)).ExtractInto(&s) - return s.Monitors, err -} - -type commonResult struct { - gophercloud.Result -} - -// Extract is a function that accepts a result and extracts a monitor. -func (r commonResult) Extract() (*Monitor, error) { - var s struct { - Monitor *Monitor `json:"healthmonitor"` - } - err := r.ExtractInto(&s) - return s.Monitor, err -} - -// CreateResult represents the result of a create operation. Call its Extract -// method to interpret it as a Monitor. -type CreateResult struct { - commonResult -} - -// GetResult represents the result of a get operation. Call its Extract -// method to interpret it as a Monitor. -type GetResult struct { - commonResult -} - -// UpdateResult represents the result of an update operation. Call its Extract -// method to interpret it as a Monitor. -type UpdateResult struct { - commonResult -} - -// DeleteResult represents the result of a delete operation. Call its -// ExtractErr method to determine if the result succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors/urls.go deleted file mode 100644 index a222e52a93d..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors/urls.go +++ /dev/null @@ -1,16 +0,0 @@ -package monitors - -import "github.com/gophercloud/gophercloud" - -const ( - rootPath = "lbaas" - resourcePath = "healthmonitors" -) - -func rootURL(c *gophercloud.ServiceClient) string { - return c.ServiceURL(rootPath, resourcePath) -} - -func resourceURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL(rootPath, resourcePath, id) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools/doc.go deleted file mode 100644 index 06971486806..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools/doc.go +++ /dev/null @@ -1,126 +0,0 @@ -/* -Package pools provides information and interaction with Pools and -Members of the LBaaS v2 extension for the OpenStack Networking service. - -Example to List Pools - - listOpts := pools.ListOpts{ - LoadbalancerID: "c79a4468-d788-410c-bf79-9a8ef6354852", - } - - allPages, err := pools.List(networkClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - allPools, err := pools.ExtractPools(allPages) - if err != nil { - panic(err) - } - - for _, pools := range allPools { - fmt.Printf("%+v\n", pool) - } - -Example to Create a Pool - - createOpts := pools.CreateOpts{ - LBMethod: pools.LBMethodRoundRobin, - Protocol: "HTTP", - Name: "Example pool", - LoadbalancerID: "79e05663-7f03-45d2-a092-8b94062f22ab", - } - - pool, err := pools.Create(networkClient, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to Update a Pool - - poolID := "d67d56a6-4a86-4688-a282-f46444705c64" - - updateOpts := pools.UpdateOpts{ - Name: "new-name", - } - - pool, err := pools.Update(networkClient, poolID, updateOpts).Extract() - if err != nil { - panic(err) - } - -Example to Delete a Pool - - poolID := "d67d56a6-4a86-4688-a282-f46444705c64" - err := pools.Delete(networkClient, poolID).ExtractErr() - if err != nil { - panic(err) - } - -Example to List Pool Members - - poolID := "d67d56a6-4a86-4688-a282-f46444705c64" - - listOpts := pools.ListMemberOpts{ - ProtocolPort: 80, - } - - allPages, err := pools.ListMembers(networkClient, poolID, listOpts).AllPages() - if err != nil { - panic(err) - } - - allMembers, err := pools.ExtractMembers(allPages) - if err != nil { - panic(err) - } - - for _, member := allMembers { - fmt.Printf("%+v\n", member) - } - -Example to Create a Member - - poolID := "d67d56a6-4a86-4688-a282-f46444705c64" - - weight := 10 - createOpts := pools.CreateMemberOpts{ - Name: "db", - SubnetID: "1981f108-3c48-48d2-b908-30f7d28532c9", - Address: "10.0.2.11", - ProtocolPort: 80, - Weight: &weight, - } - - member, err := pools.CreateMember(networkClient, poolID, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to Update a Member - - poolID := "d67d56a6-4a86-4688-a282-f46444705c64" - memberID := "64dba99f-8af8-4200-8882-e32a0660f23e" - - weight := 4 - updateOpts := pools.UpdateMemberOpts{ - Name: "new-name", - Weight: &weight, - } - - member, err := pools.UpdateMember(networkClient, poolID, memberID, updateOpts).Extract() - if err != nil { - panic(err) - } - -Example to Delete a Member - - poolID := "d67d56a6-4a86-4688-a282-f46444705c64" - memberID := "64dba99f-8af8-4200-8882-e32a0660f23e" - - err := pools.DeleteMember(networkClient, poolID, memberID).ExtractErr() - if err != nil { - panic(err) - } -*/ -package pools diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools/requests.go deleted file mode 100644 index f427ae7bf57..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools/requests.go +++ /dev/null @@ -1,356 +0,0 @@ -package pools - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// ListOptsBuilder allows extensions to add additional parameters to the -// List request. -type ListOptsBuilder interface { - ToPoolListQuery() (string, error) -} - -// ListOpts allows the filtering and sorting of paginated collections through -// the API. Filtering is achieved by passing in struct field values that map to -// the Pool attributes you want to see returned. SortKey allows you to -// sort by a particular Pool attribute. SortDir sets the direction, and is -// either `asc' or `desc'. Marker and Limit are used for pagination. -type ListOpts struct { - LBMethod string `q:"lb_algorithm"` - Protocol string `q:"protocol"` - TenantID string `q:"tenant_id"` - ProjectID string `q:"project_id"` - AdminStateUp *bool `q:"admin_state_up"` - Name string `q:"name"` - ID string `q:"id"` - LoadbalancerID string `q:"loadbalancer_id"` - ListenerID string `q:"listener_id"` - Limit int `q:"limit"` - Marker string `q:"marker"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` -} - -// ToPoolListQuery formats a ListOpts into a query string. -func (opts ListOpts) ToPoolListQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - return q.String(), err -} - -// List returns a Pager which allows you to iterate over a collection of -// pools. It accepts a ListOpts struct, which allows you to filter and sort -// the returned collection for greater efficiency. -// -// Default policy settings return only those pools that are owned by the -// tenant who submits the request, unless an admin user submits the request. -func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { - url := rootURL(c) - if opts != nil { - query, err := opts.ToPoolListQuery() - if err != nil { - return pagination.Pager{Err: err} - } - url += query - } - return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { - return PoolPage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -type LBMethod string -type Protocol string - -// Supported attributes for create/update operations. -const ( - LBMethodRoundRobin LBMethod = "ROUND_ROBIN" - LBMethodLeastConnections LBMethod = "LEAST_CONNECTIONS" - LBMethodSourceIp LBMethod = "SOURCE_IP" - - ProtocolTCP Protocol = "TCP" - ProtocolHTTP Protocol = "HTTP" - ProtocolHTTPS Protocol = "HTTPS" -) - -// CreateOptsBuilder allows extensions to add additional parameters to the -// Create request. -type CreateOptsBuilder interface { - ToPoolCreateMap() (map[string]interface{}, error) -} - -// CreateOpts is the common options struct used in this package's Create -// operation. -type CreateOpts struct { - // The algorithm used to distribute load between the members of the pool. The - // current specification supports LBMethodRoundRobin, LBMethodLeastConnections - // and LBMethodSourceIp as valid values for this attribute. - LBMethod LBMethod `json:"lb_algorithm" required:"true"` - - // The protocol used by the pool members, you can use either - // ProtocolTCP, ProtocolHTTP, or ProtocolHTTPS. - Protocol Protocol `json:"protocol" required:"true"` - - // The Loadbalancer on which the members of the pool will be associated with. - // Note: one of LoadbalancerID or ListenerID must be provided. - LoadbalancerID string `json:"loadbalancer_id,omitempty" xor:"ListenerID"` - - // The Listener on which the members of the pool will be associated with. - // Note: one of LoadbalancerID or ListenerID must be provided. - ListenerID string `json:"listener_id,omitempty" xor:"LoadbalancerID"` - - // TenantID is the UUID of the project who owns the Pool. - // Only administrative users can specify a project UUID other than their own. - TenantID string `json:"tenant_id,omitempty"` - - // ProjectID is the UUID of the project who owns the Pool. - // Only administrative users can specify a project UUID other than their own. - ProjectID string `json:"project_id,omitempty"` - - // Name of the pool. - Name string `json:"name,omitempty"` - - // Human-readable description for the pool. - Description string `json:"description,omitempty"` - - // Persistence is the session persistence of the pool. - // Omit this field to prevent session persistence. - Persistence *SessionPersistence `json:"session_persistence,omitempty"` - - // The administrative state of the Pool. A valid value is true (UP) - // or false (DOWN). - AdminStateUp *bool `json:"admin_state_up,omitempty"` -} - -// ToPoolCreateMap builds a request body from CreateOpts. -func (opts CreateOpts) ToPoolCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "pool") -} - -// Create accepts a CreateOpts struct and uses the values to create a new -// load balancer pool. -func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToPoolCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Post(rootURL(c), b, &r.Body, nil) - return -} - -// Get retrieves a particular pool based on its unique ID. -func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) - return -} - -// UpdateOptsBuilder allows extensions to add additional parameters to the -// Update request. -type UpdateOptsBuilder interface { - ToPoolUpdateMap() (map[string]interface{}, error) -} - -// UpdateOpts is the common options struct used in this package's Update -// operation. -type UpdateOpts struct { - // Name of the pool. - Name *string `json:"name,omitempty"` - - // Human-readable description for the pool. - Description *string `json:"description,omitempty"` - - // The algorithm used to distribute load between the members of the pool. The - // current specification supports LBMethodRoundRobin, LBMethodLeastConnections - // and LBMethodSourceIp as valid values for this attribute. - LBMethod LBMethod `json:"lb_algorithm,omitempty"` - - // The administrative state of the Pool. A valid value is true (UP) - // or false (DOWN). - AdminStateUp *bool `json:"admin_state_up,omitempty"` -} - -// ToPoolUpdateMap builds a request body from UpdateOpts. -func (opts UpdateOpts) ToPoolUpdateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "pool") -} - -// Update allows pools to be updated. -func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { - b, err := opts.ToPoolUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// Delete will permanently delete a particular pool based on its unique ID. -func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = c.Delete(resourceURL(c, id), nil) - return -} - -// ListMemberOptsBuilder allows extensions to add additional parameters to the -// ListMembers request. -type ListMembersOptsBuilder interface { - ToMembersListQuery() (string, error) -} - -// ListMembersOpts allows the filtering and sorting of paginated collections -// through the API. Filtering is achieved by passing in struct field values -// that map to the Member attributes you want to see returned. SortKey allows -// you to sort by a particular Member attribute. SortDir sets the direction, -// and is either `asc' or `desc'. Marker and Limit are used for pagination. -type ListMembersOpts struct { - Name string `q:"name"` - Weight int `q:"weight"` - AdminStateUp *bool `q:"admin_state_up"` - TenantID string `q:"tenant_id"` - Address string `q:"address"` - ProtocolPort int `q:"protocol_port"` - ID string `q:"id"` - Limit int `q:"limit"` - Marker string `q:"marker"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` -} - -// ToMemberListQuery formats a ListOpts into a query string. -func (opts ListMembersOpts) ToMembersListQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - return q.String(), err -} - -// ListMembers returns a Pager which allows you to iterate over a collection of -// members. It accepts a ListMembersOptsBuilder, which allows you to filter and -// sort the returned collection for greater efficiency. -// -// Default policy settings return only those members that are owned by the -// tenant who submits the request, unless an admin user submits the request. -func ListMembers(c *gophercloud.ServiceClient, poolID string, opts ListMembersOptsBuilder) pagination.Pager { - url := memberRootURL(c, poolID) - if opts != nil { - query, err := opts.ToMembersListQuery() - if err != nil { - return pagination.Pager{Err: err} - } - url += query - } - return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { - return MemberPage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -// CreateMemberOptsBuilder allows extensions to add additional parameters to the -// CreateMember request. -type CreateMemberOptsBuilder interface { - ToMemberCreateMap() (map[string]interface{}, error) -} - -// CreateMemberOpts is the common options struct used in this package's CreateMember -// operation. -type CreateMemberOpts struct { - // The IP address of the member to receive traffic from the load balancer. - Address string `json:"address" required:"true"` - - // The port on which to listen for client traffic. - ProtocolPort int `json:"protocol_port" required:"true"` - - // Name of the Member. - Name string `json:"name,omitempty"` - - // TenantID is the UUID of the project who owns the Member. - // Only administrative users can specify a project UUID other than their own. - TenantID string `json:"tenant_id,omitempty"` - - // ProjectID is the UUID of the project who owns the Member. - // Only administrative users can specify a project UUID other than their own. - ProjectID string `json:"project_id,omitempty"` - - // A positive integer value that indicates the relative portion of traffic - // that this member should receive from the pool. For example, a member with - // a weight of 10 receives five times as much traffic as a member with a - // weight of 2. - Weight *int `json:"weight,omitempty"` - - // If you omit this parameter, LBaaS uses the vip_subnet_id parameter value - // for the subnet UUID. - SubnetID string `json:"subnet_id,omitempty"` - - // The administrative state of the Pool. A valid value is true (UP) - // or false (DOWN). - AdminStateUp *bool `json:"admin_state_up,omitempty"` -} - -// ToMemberCreateMap builds a request body from CreateMemberOpts. -func (opts CreateMemberOpts) ToMemberCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "member") -} - -// CreateMember will create and associate a Member with a particular Pool. -func CreateMember(c *gophercloud.ServiceClient, poolID string, opts CreateMemberOpts) (r CreateMemberResult) { - b, err := opts.ToMemberCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Post(memberRootURL(c, poolID), b, &r.Body, nil) - return -} - -// GetMember retrieves a particular Pool Member based on its unique ID. -func GetMember(c *gophercloud.ServiceClient, poolID string, memberID string) (r GetMemberResult) { - _, r.Err = c.Get(memberResourceURL(c, poolID, memberID), &r.Body, nil) - return -} - -// UpdateMemberOptsBuilder allows extensions to add additional parameters to the -// List request. -type UpdateMemberOptsBuilder interface { - ToMemberUpdateMap() (map[string]interface{}, error) -} - -// UpdateMemberOpts is the common options struct used in this package's Update -// operation. -type UpdateMemberOpts struct { - // Name of the Member. - Name *string `json:"name,omitempty"` - - // A positive integer value that indicates the relative portion of traffic - // that this member should receive from the pool. For example, a member with - // a weight of 10 receives five times as much traffic as a member with a - // weight of 2. - Weight *int `json:"weight,omitempty"` - - // The administrative state of the Pool. A valid value is true (UP) - // or false (DOWN). - AdminStateUp *bool `json:"admin_state_up,omitempty"` -} - -// ToMemberUpdateMap builds a request body from UpdateMemberOpts. -func (opts UpdateMemberOpts) ToMemberUpdateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "member") -} - -// Update allows Member to be updated. -func UpdateMember(c *gophercloud.ServiceClient, poolID string, memberID string, opts UpdateMemberOptsBuilder) (r UpdateMemberResult) { - b, err := opts.ToMemberUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Put(memberResourceURL(c, poolID, memberID), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200, 201, 202}, - }) - return -} - -// DisassociateMember will remove and disassociate a Member from a particular -// Pool. -func DeleteMember(c *gophercloud.ServiceClient, poolID string, memberID string) (r DeleteMemberResult) { - _, r.Err = c.Delete(memberResourceURL(c, poolID, memberID), nil) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools/results.go deleted file mode 100644 index fba0d3a8782..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools/results.go +++ /dev/null @@ -1,291 +0,0 @@ -package pools - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors" - "github.com/gophercloud/gophercloud/pagination" -) - -// SessionPersistence represents the session persistence feature of the load -// balancing service. It attempts to force connections or requests in the same -// session to be processed by the same member as long as it is ative. Three -// types of persistence are supported: -// -// SOURCE_IP: With this mode, all connections originating from the same source -// IP address, will be handled by the same Member of the Pool. -// HTTP_COOKIE: With this persistence mode, the load balancing function will -// create a cookie on the first request from a client. Subsequent -// requests containing the same cookie value will be handled by -// the same Member of the Pool. -// APP_COOKIE: With this persistence mode, the load balancing function will -// rely on a cookie established by the backend application. All -// requests carrying the same cookie value will be handled by the -// same Member of the Pool. -type SessionPersistence struct { - // The type of persistence mode. - Type string `json:"type"` - - // Name of cookie if persistence mode is set appropriately. - CookieName string `json:"cookie_name,omitempty"` -} - -// LoadBalancerID represents a load balancer. -type LoadBalancerID struct { - ID string `json:"id"` -} - -// ListenerID represents a listener. -type ListenerID struct { - ID string `json:"id"` -} - -// Pool represents a logical set of devices, such as web servers, that you -// group together to receive and process traffic. The load balancing function -// chooses a Member of the Pool according to the configured load balancing -// method to handle the new requests or connections received on the VIP address. -type Pool struct { - // The load-balancer algorithm, which is round-robin, least-connections, and - // so on. This value, which must be supported, is dependent on the provider. - // Round-robin must be supported. - LBMethod string `json:"lb_algorithm"` - - // The protocol of the Pool, which is TCP, HTTP, or HTTPS. - Protocol string `json:"protocol"` - - // Description for the Pool. - Description string `json:"description"` - - // A list of listeners objects IDs. - Listeners []ListenerID `json:"listeners"` //[]map[string]interface{} - - // A list of member objects IDs. - Members []Member `json:"members"` - - // The ID of associated health monitor. - MonitorID string `json:"healthmonitor_id"` - - // The network on which the members of the Pool will be located. Only members - // that are on this network can be added to the Pool. - SubnetID string `json:"subnet_id"` - - // Owner of the Pool. - TenantID string `json:"tenant_id"` - - // The administrative state of the Pool, which is up (true) or down (false). - AdminStateUp bool `json:"admin_state_up"` - - // Pool name. Does not have to be unique. - Name string `json:"name"` - - // The unique ID for the Pool. - ID string `json:"id"` - - // A list of load balancer objects IDs. - Loadbalancers []LoadBalancerID `json:"loadbalancers"` - - // Indicates whether connections in the same session will be processed by the - // same Pool member or not. - Persistence SessionPersistence `json:"session_persistence"` - - // The load balancer provider. - Provider string `json:"provider"` - - // The Monitor associated with this Pool. - Monitor monitors.Monitor `json:"healthmonitor"` - - // The provisioning status of the pool. - // This value is ACTIVE, PENDING_* or ERROR. - ProvisioningStatus string `json:"provisioning_status"` - - // The operating status of the pool. - // This field seems to only be returned during a call to a load balancer's /status - // see: https://github.com/gophercloud/gophercloud/issues/1362 - OperatingStatus string `json:"operating_status"` -} - -// PoolPage is the page returned by a pager when traversing over a -// collection of pools. -type PoolPage struct { - pagination.LinkedPageBase -} - -// NextPageURL is invoked when a paginated collection of pools has reached -// the end of a page and the pager seeks to traverse over a new one. In order -// to do this, it needs to construct the next page's URL. -func (r PoolPage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"pools_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// IsEmpty checks whether a PoolPage struct is empty. -func (r PoolPage) IsEmpty() (bool, error) { - is, err := ExtractPools(r) - return len(is) == 0, err -} - -// ExtractPools accepts a Page struct, specifically a PoolPage struct, -// and extracts the elements into a slice of Pool structs. In other words, -// a generic collection is mapped into a relevant slice. -func ExtractPools(r pagination.Page) ([]Pool, error) { - var s struct { - Pools []Pool `json:"pools"` - } - err := (r.(PoolPage)).ExtractInto(&s) - return s.Pools, err -} - -type commonResult struct { - gophercloud.Result -} - -// Extract is a function that accepts a result and extracts a pool. -func (r commonResult) Extract() (*Pool, error) { - var s struct { - Pool *Pool `json:"pool"` - } - err := r.ExtractInto(&s) - return s.Pool, err -} - -// CreateResult represents the result of a Create operation. Call its Extract -// method to interpret the result as a Pool. -type CreateResult struct { - commonResult -} - -// GetResult represents the result of a Get operation. Call its Extract -// method to interpret the result as a Pool. -type GetResult struct { - commonResult -} - -// UpdateResult represents the result of an Update operation. Call its Extract -// method to interpret the result as a Pool. -type UpdateResult struct { - commonResult -} - -// DeleteResult represents the result of a Delete operation. Call its -// ExtractErr method to determine if the request succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} - -// Member represents the application running on a backend server. -type Member struct { - // Name of the Member. - Name string `json:"name"` - - // Weight of Member. - Weight int `json:"weight"` - - // The administrative state of the member, which is up (true) or down (false). - AdminStateUp bool `json:"admin_state_up"` - - // Owner of the Member. - TenantID string `json:"tenant_id"` - - // Parameter value for the subnet UUID. - SubnetID string `json:"subnet_id"` - - // The Pool to which the Member belongs. - PoolID string `json:"pool_id"` - - // The IP address of the Member. - Address string `json:"address"` - - // The port on which the application is hosted. - ProtocolPort int `json:"protocol_port"` - - // The unique ID for the Member. - ID string `json:"id"` - - // The provisioning status of the member. - // This value is ACTIVE, PENDING_* or ERROR. - ProvisioningStatus string `json:"provisioning_status"` - - // The operating status of the member. - // This field seems to only be returned during a call to a load balancer's /status - // see: https://github.com/gophercloud/gophercloud/issues/1362 - OperatingStatus string `json:"operating_status"` -} - -// MemberPage is the page returned by a pager when traversing over a -// collection of Members in a Pool. -type MemberPage struct { - pagination.LinkedPageBase -} - -// NextPageURL is invoked when a paginated collection of members has reached -// the end of a page and the pager seeks to traverse over a new one. In order -// to do this, it needs to construct the next page's URL. -func (r MemberPage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"members_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// IsEmpty checks whether a MemberPage struct is empty. -func (r MemberPage) IsEmpty() (bool, error) { - is, err := ExtractMembers(r) - return len(is) == 0, err -} - -// ExtractMembers accepts a Page struct, specifically a MemberPage struct, -// and extracts the elements into a slice of Members structs. In other words, -// a generic collection is mapped into a relevant slice. -func ExtractMembers(r pagination.Page) ([]Member, error) { - var s struct { - Members []Member `json:"members"` - } - err := (r.(MemberPage)).ExtractInto(&s) - return s.Members, err -} - -type commonMemberResult struct { - gophercloud.Result -} - -// ExtractMember is a function that accepts a result and extracts a member. -func (r commonMemberResult) Extract() (*Member, error) { - var s struct { - Member *Member `json:"member"` - } - err := r.ExtractInto(&s) - return s.Member, err -} - -// CreateMemberResult represents the result of a CreateMember operation. -// Call its Extract method to interpret it as a Member. -type CreateMemberResult struct { - commonMemberResult -} - -// GetMemberResult represents the result of a GetMember operation. -// Call its Extract method to interpret it as a Member. -type GetMemberResult struct { - commonMemberResult -} - -// UpdateMemberResult represents the result of an UpdateMember operation. -// Call its Extract method to interpret it as a Member. -type UpdateMemberResult struct { - commonMemberResult -} - -// DeleteMemberResult represents the result of a DeleteMember operation. -// Call its ExtractErr method to determine if the request succeeded or failed. -type DeleteMemberResult struct { - gophercloud.ErrResult -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools/urls.go deleted file mode 100644 index bceca67707f..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools/urls.go +++ /dev/null @@ -1,25 +0,0 @@ -package pools - -import "github.com/gophercloud/gophercloud" - -const ( - rootPath = "lbaas" - resourcePath = "pools" - memberPath = "members" -) - -func rootURL(c *gophercloud.ServiceClient) string { - return c.ServiceURL(rootPath, resourcePath) -} - -func resourceURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL(rootPath, resourcePath, id) -} - -func memberRootURL(c *gophercloud.ServiceClient, poolId string) string { - return c.ServiceURL(rootPath, resourcePath, poolId, memberPath) -} - -func memberResourceURL(c *gophercloud.ServiceClient, poolID string, memeberID string) string { - return c.ServiceURL(rootPath, resourcePath, poolID, memberPath, memeberID) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/doc.go deleted file mode 100644 index 7d8bbcaacba..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/doc.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Package groups provides information and interaction with Security Groups -for the OpenStack Networking service. - -Example to List Security Groups - - listOpts := groups.ListOpts{ - TenantID: "966b3c7d36a24facaf20b7e458bf2192", - } - - allPages, err := groups.List(networkClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - allGroups, err := groups.ExtractGroups(allPages) - if err != nil { - panic(err) - } - - for _, group := range allGroups { - fmt.Printf("%+v\n", group) - } - -Example to Create a Security Group - - createOpts := groups.CreateOpts{ - Name: "group_name", - Description: "A Security Group", - } - - group, err := groups.Create(networkClient, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to Update a Security Group - - groupID := "37d94f8a-d136-465c-ae46-144f0d8ef141" - - updateOpts := groups.UpdateOpts{ - Name: "new_name", - } - - group, err := groups.Update(networkClient, groupID, updateOpts).Extract() - if err != nil { - panic(err) - } - -Example to Delete a Security Group - - groupID := "37d94f8a-d136-465c-ae46-144f0d8ef141" - err := groups.Delete(networkClient, groupID).ExtractErr() - if err != nil { - panic(err) - } -*/ -package groups diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/requests.go deleted file mode 100644 index a22cd306e8a..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/requests.go +++ /dev/null @@ -1,166 +0,0 @@ -package groups - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// ListOpts allows the filtering and sorting of paginated collections through -// the API. Filtering is achieved by passing in struct field values that map to -// the group attributes you want to see returned. SortKey allows you to -// sort by a particular network attribute. SortDir sets the direction, and is -// either `asc' or `desc'. Marker and Limit are used for pagination. -type ListOpts struct { - ID string `q:"id"` - Name string `q:"name"` - Description string `q:"description"` - TenantID string `q:"tenant_id"` - ProjectID string `q:"project_id"` - Limit int `q:"limit"` - Marker string `q:"marker"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` - Tags string `q:"tags"` - TagsAny string `q:"tags-any"` - NotTags string `q:"not-tags"` - NotTagsAny string `q:"not-tags-any"` -} - -// List returns a Pager which allows you to iterate over a collection of -// security groups. It accepts a ListOpts struct, which allows you to filter -// and sort the returned collection for greater efficiency. -func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager { - q, err := gophercloud.BuildQueryString(&opts) - if err != nil { - return pagination.Pager{Err: err} - } - u := rootURL(c) + q.String() - return pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page { - return SecGroupPage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -// CreateOptsBuilder allows extensions to add additional parameters to the -// Create request. -type CreateOptsBuilder interface { - ToSecGroupCreateMap() (map[string]interface{}, error) -} - -// CreateOpts contains all the values needed to create a new security group. -type CreateOpts struct { - // Human-readable name for the Security Group. Does not have to be unique. - Name string `json:"name" required:"true"` - - // TenantID is the UUID of the project who owns the Group. - // Only administrative users can specify a tenant UUID other than their own. - TenantID string `json:"tenant_id,omitempty"` - - // ProjectID is the UUID of the project who owns the Group. - // Only administrative users can specify a tenant UUID other than their own. - ProjectID string `json:"project_id,omitempty"` - - // Describes the security group. - Description string `json:"description,omitempty"` -} - -// ToSecGroupCreateMap builds a request body from CreateOpts. -func (opts CreateOpts) ToSecGroupCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "security_group") -} - -// Create is an operation which provisions a new security group with default -// security group rules for the IPv4 and IPv6 ether types. -func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToSecGroupCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Post(rootURL(c), b, &r.Body, nil) - return -} - -// UpdateOptsBuilder allows extensions to add additional parameters to the -// Update request. -type UpdateOptsBuilder interface { - ToSecGroupUpdateMap() (map[string]interface{}, error) -} - -// UpdateOpts contains all the values needed to update an existing security -// group. -type UpdateOpts struct { - // Human-readable name for the Security Group. Does not have to be unique. - Name string `json:"name,omitempty"` - - // Describes the security group. - Description *string `json:"description,omitempty"` -} - -// ToSecGroupUpdateMap builds a request body from UpdateOpts. -func (opts UpdateOpts) ToSecGroupUpdateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "security_group") -} - -// Update is an operation which updates an existing security group. -func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { - b, err := opts.ToSecGroupUpdateMap() - if err != nil { - r.Err = err - return - } - - _, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// Get retrieves a particular security group based on its unique ID. -func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) - return -} - -// Delete will permanently delete a particular security group based on its -// unique ID. -func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = c.Delete(resourceURL(c, id), nil) - return -} - -// IDFromName is a convenience function that returns a security group's ID, -// given its name. -func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) { - count := 0 - id := "" - - listOpts := ListOpts{ - Name: name, - } - - pages, err := List(client, listOpts).AllPages() - if err != nil { - return "", err - } - - all, err := ExtractGroups(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: "security group"} - case 1: - return id, nil - default: - return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "security group"} - } -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/results.go deleted file mode 100644 index 468952b3e4e..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/results.go +++ /dev/null @@ -1,108 +0,0 @@ -package groups - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules" - "github.com/gophercloud/gophercloud/pagination" -) - -// SecGroup represents a container for security group rules. -type SecGroup struct { - // The UUID for the security group. - ID string - - // Human-readable name for the security group. Might not be unique. - // Cannot be named "default" as that is automatically created for a tenant. - Name string - - // The security group description. - Description string - - // A slice of security group rules that dictate the permitted behaviour for - // traffic entering and leaving the group. - Rules []rules.SecGroupRule `json:"security_group_rules"` - - // TenantID is the project owner of the security group. - TenantID string `json:"tenant_id"` - - // ProjectID is the project owner of the security group. - ProjectID string `json:"project_id"` - - // Tags optionally set via extensions/attributestags - Tags []string `json:"tags"` -} - -// SecGroupPage is the page returned by a pager when traversing over a -// collection of security groups. -type SecGroupPage struct { - pagination.LinkedPageBase -} - -// NextPageURL is invoked when a paginated collection of security groups has -// reached the end of a page and the pager seeks to traverse over a new one. In -// order to do this, it needs to construct the next page's URL. -func (r SecGroupPage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"security_groups_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - - return gophercloud.ExtractNextURL(s.Links) -} - -// IsEmpty checks whether a SecGroupPage struct is empty. -func (r SecGroupPage) IsEmpty() (bool, error) { - is, err := ExtractGroups(r) - return len(is) == 0, err -} - -// ExtractGroups accepts a Page struct, specifically a SecGroupPage struct, -// and extracts the elements into a slice of SecGroup structs. In other words, -// a generic collection is mapped into a relevant slice. -func ExtractGroups(r pagination.Page) ([]SecGroup, error) { - var s struct { - SecGroups []SecGroup `json:"security_groups"` - } - err := (r.(SecGroupPage)).ExtractInto(&s) - return s.SecGroups, err -} - -type commonResult struct { - gophercloud.Result -} - -// Extract is a function that accepts a result and extracts a security group. -func (r commonResult) Extract() (*SecGroup, error) { - var s struct { - SecGroup *SecGroup `json:"security_group"` - } - err := r.ExtractInto(&s) - return s.SecGroup, err -} - -// CreateResult represents the result of a create operation. Call its Extract -// method to interpret it as a SecGroup. -type CreateResult struct { - commonResult -} - -// UpdateResult represents the result of an update operation. Call its Extract -// method to interpret it as a SecGroup. -type UpdateResult struct { - commonResult -} - -// GetResult represents the result of a get operation. Call its Extract -// method to interpret it as a SecGroup. -type GetResult struct { - commonResult -} - -// DeleteResult represents the result of a delete operation. Call its -// ExtractErr method to determine if the request succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/urls.go deleted file mode 100644 index 104cbcc558d..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups/urls.go +++ /dev/null @@ -1,13 +0,0 @@ -package groups - -import "github.com/gophercloud/gophercloud" - -const rootPath = "security-groups" - -func rootURL(c *gophercloud.ServiceClient) string { - return c.ServiceURL(rootPath) -} - -func resourceURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL(rootPath, id) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules/doc.go deleted file mode 100644 index bf66dc8b40e..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules/doc.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Package rules provides information and interaction with Security Group Rules -for the OpenStack Networking service. - -Example to List Security Groups Rules - - listOpts := rules.ListOpts{ - Protocol: "tcp", - } - - allPages, err := rules.List(networkClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - allRules, err := rules.ExtractRules(allPages) - if err != nil { - panic(err) - } - - for _, rule := range allRules { - fmt.Printf("%+v\n", rule) - } - -Example to Create a Security Group Rule - - createOpts := rules.CreateOpts{ - Direction: "ingress", - PortRangeMin: 80, - EtherType: rules.EtherType4, - PortRangeMax: 80, - Protocol: "tcp", - RemoteGroupID: "85cc3048-abc3-43cc-89b3-377341426ac5", - SecGroupID: "a7734e61-b545-452d-a3cd-0189cbd9747a", - } - - rule, err := rules.Create(networkClient, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to Delete a Security Group Rule - - ruleID := "37d94f8a-d136-465c-ae46-144f0d8ef141" - err := rules.Delete(networkClient, ruleID).ExtractErr() - if err != nil { - panic(err) - } -*/ -package rules diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules/requests.go deleted file mode 100644 index c7741ffcd2c..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules/requests.go +++ /dev/null @@ -1,159 +0,0 @@ -package rules - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// ListOpts allows the filtering and sorting of paginated collections through -// the API. Filtering is achieved by passing in struct field values that map to -// the security group rule attributes you want to see returned. SortKey allows -// you to sort by a particular network attribute. SortDir sets the direction, -// and is either `asc' or `desc'. Marker and Limit are used for pagination. -type ListOpts struct { - Direction string `q:"direction"` - EtherType string `q:"ethertype"` - ID string `q:"id"` - Description string `q:"description"` - PortRangeMax int `q:"port_range_max"` - PortRangeMin int `q:"port_range_min"` - Protocol string `q:"protocol"` - RemoteGroupID string `q:"remote_group_id"` - RemoteIPPrefix string `q:"remote_ip_prefix"` - SecGroupID string `q:"security_group_id"` - TenantID string `q:"tenant_id"` - ProjectID string `q:"project_id"` - Limit int `q:"limit"` - Marker string `q:"marker"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` -} - -// List returns a Pager which allows you to iterate over a collection of -// security group rules. It accepts a ListOpts struct, which allows you to filter -// and sort the returned collection for greater efficiency. -func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager { - q, err := gophercloud.BuildQueryString(&opts) - if err != nil { - return pagination.Pager{Err: err} - } - u := rootURL(c) + q.String() - return pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page { - return SecGroupRulePage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -type RuleDirection string -type RuleProtocol string -type RuleEtherType string - -// Constants useful for CreateOpts -const ( - DirIngress RuleDirection = "ingress" - DirEgress RuleDirection = "egress" - EtherType4 RuleEtherType = "IPv4" - EtherType6 RuleEtherType = "IPv6" - ProtocolAH RuleProtocol = "ah" - ProtocolDCCP RuleProtocol = "dccp" - ProtocolEGP RuleProtocol = "egp" - ProtocolESP RuleProtocol = "esp" - ProtocolGRE RuleProtocol = "gre" - ProtocolICMP RuleProtocol = "icmp" - ProtocolIGMP RuleProtocol = "igmp" - ProtocolIPv6Encap RuleProtocol = "ipv6-encap" - ProtocolIPv6Frag RuleProtocol = "ipv6-frag" - ProtocolIPv6ICMP RuleProtocol = "ipv6-icmp" - ProtocolIPv6NoNxt RuleProtocol = "ipv6-nonxt" - ProtocolIPv6Opts RuleProtocol = "ipv6-opts" - ProtocolIPv6Route RuleProtocol = "ipv6-route" - ProtocolOSPF RuleProtocol = "ospf" - ProtocolPGM RuleProtocol = "pgm" - ProtocolRSVP RuleProtocol = "rsvp" - ProtocolSCTP RuleProtocol = "sctp" - ProtocolTCP RuleProtocol = "tcp" - ProtocolUDP RuleProtocol = "udp" - ProtocolUDPLite RuleProtocol = "udplite" - ProtocolVRRP RuleProtocol = "vrrp" -) - -// CreateOptsBuilder allows extensions to add additional parameters to the -// Create request. -type CreateOptsBuilder interface { - ToSecGroupRuleCreateMap() (map[string]interface{}, error) -} - -// CreateOpts contains all the values needed to create a new security group -// rule. -type CreateOpts struct { - // Must be either "ingress" or "egress": the direction in which the security - // group rule is applied. - Direction RuleDirection `json:"direction" required:"true"` - - // String description of each rule, optional - Description string `json:"description,omitempty"` - - // Must be "IPv4" or "IPv6", and addresses represented in CIDR must match the - // ingress or egress rules. - EtherType RuleEtherType `json:"ethertype" required:"true"` - - // The security group ID to associate with this security group rule. - SecGroupID string `json:"security_group_id" required:"true"` - - // The maximum port number in the range that is matched by the security group - // rule. The PortRangeMin attribute constrains the PortRangeMax attribute. If - // the protocol is ICMP, this value must be an ICMP type. - PortRangeMax int `json:"port_range_max,omitempty"` - - // The minimum port number in the range that is matched by the security group - // rule. If the protocol is TCP or UDP, this value must be less than or equal - // to the value of the PortRangeMax attribute. If the protocol is ICMP, this - // value must be an ICMP type. - PortRangeMin int `json:"port_range_min,omitempty"` - - // The protocol that is matched by the security group rule. Valid values are - // "tcp", "udp", "icmp" or an empty string. - Protocol RuleProtocol `json:"protocol,omitempty"` - - // The remote group ID to be associated with this security group rule. You can - // specify either RemoteGroupID or RemoteIPPrefix. - RemoteGroupID string `json:"remote_group_id,omitempty"` - - // The remote IP prefix to be associated with this security group rule. You can - // specify either RemoteGroupID or RemoteIPPrefix. This attribute matches the - // specified IP prefix as the source IP address of the IP packet. - RemoteIPPrefix string `json:"remote_ip_prefix,omitempty"` - - // TenantID is the UUID of the project who owns the Rule. - // Only administrative users can specify a project UUID other than their own. - ProjectID string `json:"project_id,omitempty"` -} - -// ToSecGroupRuleCreateMap builds a request body from CreateOpts. -func (opts CreateOpts) ToSecGroupRuleCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "security_group_rule") -} - -// Create is an operation which adds a new security group rule and associates it -// with an existing security group (whose ID is specified in CreateOpts). -func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToSecGroupRuleCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Post(rootURL(c), b, &r.Body, nil) - return -} - -// Get retrieves a particular security group rule based on its unique ID. -func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) - return -} - -// Delete will permanently delete a particular security group rule based on its -// unique ID. -func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = c.Delete(resourceURL(c, id), nil) - return -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules/results.go deleted file mode 100644 index 3bf5501d922..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules/results.go +++ /dev/null @@ -1,127 +0,0 @@ -package rules - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// SecGroupRule represents a rule to dictate the behaviour of incoming or -// outgoing traffic for a particular security group. -type SecGroupRule struct { - // The UUID for this security group rule. - ID string - - // The direction in which the security group rule is applied. The only values - // allowed are "ingress" or "egress". For a compute instance, an ingress - // security group rule is applied to incoming (ingress) traffic for that - // instance. An egress rule is applied to traffic leaving the instance. - Direction string - - // Descripton of the rule - Description string `json:"description"` - - // Must be IPv4 or IPv6, and addresses represented in CIDR must match the - // ingress or egress rules. - EtherType string `json:"ethertype"` - - // The security group ID to associate with this security group rule. - SecGroupID string `json:"security_group_id"` - - // The minimum port number in the range that is matched by the security group - // rule. If the protocol is TCP or UDP, this value must be less than or equal - // to the value of the PortRangeMax attribute. If the protocol is ICMP, this - // value must be an ICMP type. - PortRangeMin int `json:"port_range_min"` - - // The maximum port number in the range that is matched by the security group - // rule. The PortRangeMin attribute constrains the PortRangeMax attribute. If - // the protocol is ICMP, this value must be an ICMP type. - PortRangeMax int `json:"port_range_max"` - - // The protocol that is matched by the security group rule. Valid values are - // "tcp", "udp", "icmp" or an empty string. - Protocol string - - // The remote group ID to be associated with this security group rule. You - // can specify either RemoteGroupID or RemoteIPPrefix. - RemoteGroupID string `json:"remote_group_id"` - - // The remote IP prefix to be associated with this security group rule. You - // can specify either RemoteGroupID or RemoteIPPrefix . This attribute - // matches the specified IP prefix as the source IP address of the IP packet. - RemoteIPPrefix string `json:"remote_ip_prefix"` - - // TenantID is the project owner of this security group rule. - TenantID string `json:"tenant_id"` - - // ProjectID is the project owner of this security group rule. - ProjectID string `json:"project_id"` -} - -// SecGroupRulePage is the page returned by a pager when traversing over a -// collection of security group rules. -type SecGroupRulePage struct { - pagination.LinkedPageBase -} - -// NextPageURL is invoked when a paginated collection of security group rules has -// reached the end of a page and the pager seeks to traverse over a new one. In -// order to do this, it needs to construct the next page's URL. -func (r SecGroupRulePage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"security_group_rules_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// IsEmpty checks whether a SecGroupRulePage struct is empty. -func (r SecGroupRulePage) IsEmpty() (bool, error) { - is, err := ExtractRules(r) - return len(is) == 0, err -} - -// ExtractRules accepts a Page struct, specifically a SecGroupRulePage struct, -// and extracts the elements into a slice of SecGroupRule structs. In other words, -// a generic collection is mapped into a relevant slice. -func ExtractRules(r pagination.Page) ([]SecGroupRule, error) { - var s struct { - SecGroupRules []SecGroupRule `json:"security_group_rules"` - } - err := (r.(SecGroupRulePage)).ExtractInto(&s) - return s.SecGroupRules, err -} - -type commonResult struct { - gophercloud.Result -} - -// Extract is a function that accepts a result and extracts a security rule. -func (r commonResult) Extract() (*SecGroupRule, error) { - var s struct { - SecGroupRule *SecGroupRule `json:"security_group_rule"` - } - err := r.ExtractInto(&s) - return s.SecGroupRule, err -} - -// CreateResult represents the result of a create operation. Call its Extract -// method to interpret it as a SecGroupRule. -type CreateResult struct { - commonResult -} - -// GetResult represents the result of a get operation. Call its Extract -// method to interpret it as a SecGroupRule. -type GetResult struct { - commonResult -} - -// DeleteResult represents the result of a delete operation. Call its -// ExtractErr method to determine if the request succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules/urls.go deleted file mode 100644 index a5ede0e89b9..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules/urls.go +++ /dev/null @@ -1,13 +0,0 @@ -package rules - -import "github.com/gophercloud/gophercloud" - -const rootPath = "security-group-rules" - -func rootURL(c *gophercloud.ServiceClient) string { - return c.ServiceURL(rootPath) -} - -func resourceURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL(rootPath, id) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/doc.go deleted file mode 100644 index 9d1dd5a7ea4..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/doc.go +++ /dev/null @@ -1,66 +0,0 @@ -/* -Package networks contains functionality for working with Neutron network -resources. A network is an isolated virtual layer-2 broadcast domain that is -typically reserved for the tenant who created it (unless you configure the -network to be shared). Tenants can create multiple networks until the -thresholds per-tenant quota is reached. - -In the v2.0 Networking API, the network is the main entity. Ports and subnets -are always associated with a network. - -Example to List Networks - - listOpts := networks.ListOpts{ - TenantID: "a99e9b4e620e4db09a2dfb6e42a01e66", - } - - allPages, err := networks.List(networkClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - allNetworks, err := networks.ExtractNetworks(allPages) - if err != nil { - panic(err) - } - - for _, network := range allNetworks { - fmt.Printf("%+v", network) - } - -Example to Create a Network - - iTrue := true - createOpts := networks.CreateOpts{ - Name: "network_1", - AdminStateUp: &iTrue, - } - - network, err := networks.Create(networkClient, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to Update a Network - - networkID := "484cda0e-106f-4f4b-bb3f-d413710bbe78" - - name := "new_name" - updateOpts := networks.UpdateOpts{ - Name: &name, - } - - network, err := networks.Update(networkClient, networkID, updateOpts).Extract() - if err != nil { - panic(err) - } - -Example to Delete a Network - - networkID := "484cda0e-106f-4f4b-bb3f-d413710bbe78" - err := networks.Delete(networkClient, networkID).ExtractErr() - if err != nil { - panic(err) - } -*/ -package networks diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/requests.go deleted file mode 100644 index 8006c481679..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/requests.go +++ /dev/null @@ -1,180 +0,0 @@ -package networks - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// ListOptsBuilder allows extensions to add additional parameters to the -// List request. -type ListOptsBuilder interface { - ToNetworkListQuery() (string, error) -} - -// ListOpts allows the filtering and sorting of paginated collections through -// the API. Filtering is achieved by passing in struct field values that map to -// the network attributes you want to see returned. SortKey allows you to sort -// by a particular network attribute. SortDir sets the direction, and is either -// `asc' or `desc'. Marker and Limit are used for pagination. -type ListOpts struct { - Status string `q:"status"` - Name string `q:"name"` - Description string `q:"description"` - AdminStateUp *bool `q:"admin_state_up"` - TenantID string `q:"tenant_id"` - ProjectID string `q:"project_id"` - Shared *bool `q:"shared"` - ID string `q:"id"` - Marker string `q:"marker"` - Limit int `q:"limit"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` - Tags string `q:"tags"` - TagsAny string `q:"tags-any"` - NotTags string `q:"not-tags"` - NotTagsAny string `q:"not-tags-any"` -} - -// ToNetworkListQuery formats a ListOpts into a query string. -func (opts ListOpts) ToNetworkListQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - return q.String(), err -} - -// List returns a Pager which allows you to iterate over a collection of -// networks. It accepts a ListOpts struct, which allows you to filter and sort -// the returned collection for greater efficiency. -func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { - url := listURL(c) - if opts != nil { - query, err := opts.ToNetworkListQuery() - if err != nil { - return pagination.Pager{Err: err} - } - url += query - } - return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { - return NetworkPage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -// Get retrieves a specific network based on its unique ID. -func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = c.Get(getURL(c, id), &r.Body, nil) - return -} - -// CreateOptsBuilder allows extensions to add additional parameters to the -// Create request. -type CreateOptsBuilder interface { - ToNetworkCreateMap() (map[string]interface{}, error) -} - -// CreateOpts represents options used to create a network. -type CreateOpts struct { - AdminStateUp *bool `json:"admin_state_up,omitempty"` - Name string `json:"name,omitempty"` - Description string `json:"description,omitempty"` - Shared *bool `json:"shared,omitempty"` - TenantID string `json:"tenant_id,omitempty"` - ProjectID string `json:"project_id,omitempty"` - AvailabilityZoneHints []string `json:"availability_zone_hints,omitempty"` -} - -// ToNetworkCreateMap builds a request body from CreateOpts. -func (opts CreateOpts) ToNetworkCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "network") -} - -// Create accepts a CreateOpts struct and creates a new network using the values -// provided. This operation does not actually require a request body, i.e. the -// CreateOpts struct argument can be empty. -// -// The tenant ID that is contained in the URI is the tenant that creates the -// network. An admin user, however, has the option of specifying another tenant -// ID in the CreateOpts struct. -func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToNetworkCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Post(createURL(c), b, &r.Body, nil) - return -} - -// UpdateOptsBuilder allows extensions to add additional parameters to the -// Update request. -type UpdateOptsBuilder interface { - ToNetworkUpdateMap() (map[string]interface{}, error) -} - -// UpdateOpts represents options used to update a network. -type UpdateOpts struct { - AdminStateUp *bool `json:"admin_state_up,omitempty"` - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - Shared *bool `json:"shared,omitempty"` -} - -// ToNetworkUpdateMap builds a request body from UpdateOpts. -func (opts UpdateOpts) ToNetworkUpdateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "network") -} - -// Update accepts a UpdateOpts struct and updates an existing network using the -// values provided. For more information, see the Create function. -func Update(c *gophercloud.ServiceClient, networkID string, opts UpdateOptsBuilder) (r UpdateResult) { - b, err := opts.ToNetworkUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Put(updateURL(c, networkID), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200, 201}, - }) - return -} - -// Delete accepts a unique ID and deletes the network associated with it. -func Delete(c *gophercloud.ServiceClient, networkID string) (r DeleteResult) { - _, r.Err = c.Delete(deleteURL(c, networkID), nil) - return -} - -// IDFromName is a convenience function that returns a network's ID, given -// its name. -func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) { - count := 0 - id := "" - - listOpts := ListOpts{ - Name: name, - } - - pages, err := List(client, listOpts).AllPages() - if err != nil { - return "", err - } - - all, err := ExtractNetworks(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: "network"} - case 1: - return id, nil - default: - return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "network"} - } -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/results.go deleted file mode 100644 index f03067415fb..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/results.go +++ /dev/null @@ -1,124 +0,0 @@ -package networks - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -type commonResult struct { - gophercloud.Result -} - -// Extract is a function that accepts a result and extracts a network resource. -func (r commonResult) Extract() (*Network, error) { - var s Network - err := r.ExtractInto(&s) - return &s, err -} - -func (r commonResult) ExtractInto(v interface{}) error { - return r.Result.ExtractIntoStructPtr(v, "network") -} - -// CreateResult represents the result of a create operation. Call its Extract -// method to interpret it as a Network. -type CreateResult struct { - commonResult -} - -// GetResult represents the result of a get operation. Call its Extract -// method to interpret it as a Network. -type GetResult struct { - commonResult -} - -// UpdateResult represents the result of an update operation. Call its Extract -// method to interpret it as a Network. -type UpdateResult struct { - commonResult -} - -// DeleteResult represents the result of a delete operation. Call its -// ExtractErr method to determine if the request succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} - -// Network represents, well, a network. -type Network struct { - // UUID for the network - ID string `json:"id"` - - // Human-readable name for the network. Might not be unique. - Name string `json:"name"` - - // Description for the network - Description string `json:"description"` - - // The administrative state of network. If false (down), the network does not - // forward packets. - AdminStateUp bool `json:"admin_state_up"` - - // Indicates whether network is currently operational. Possible values include - // `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define additional - // values. - Status string `json:"status"` - - // Subnets associated with this network. - Subnets []string `json:"subnets"` - - // TenantID is the project owner of the network. - TenantID string `json:"tenant_id"` - - // ProjectID is the project owner of the network. - ProjectID string `json:"project_id"` - - // Specifies whether the network resource can be accessed by any tenant. - Shared bool `json:"shared"` - - // Availability zone hints groups network nodes that run services like DHCP, L3, FW, and others. - // Used to make network resources highly available. - AvailabilityZoneHints []string `json:"availability_zone_hints"` - - // Tags optionally set via extensions/attributestags - Tags []string `json:"tags"` -} - -// NetworkPage is the page returned by a pager when traversing over a -// collection of networks. -type NetworkPage struct { - pagination.LinkedPageBase -} - -// NextPageURL is invoked when a paginated collection of networks has reached -// the end of a page and the pager seeks to traverse over a new one. In order -// to do this, it needs to construct the next page's URL. -func (r NetworkPage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"networks_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// IsEmpty checks whether a NetworkPage struct is empty. -func (r NetworkPage) IsEmpty() (bool, error) { - is, err := ExtractNetworks(r) - return len(is) == 0, err -} - -// ExtractNetworks accepts a Page struct, specifically a NetworkPage struct, -// and extracts the elements into a slice of Network structs. In other words, -// a generic collection is mapped into a relevant slice. -func ExtractNetworks(r pagination.Page) ([]Network, error) { - var s []Network - err := ExtractNetworksInto(r, &s) - return s, err -} - -func ExtractNetworksInto(r pagination.Page, v interface{}) error { - return r.(NetworkPage).Result.ExtractIntoSlicePtr(v, "networks") -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/urls.go deleted file mode 100644 index 4a8fb1dc7d3..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/networks/urls.go +++ /dev/null @@ -1,31 +0,0 @@ -package networks - -import "github.com/gophercloud/gophercloud" - -func resourceURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL("networks", id) -} - -func rootURL(c *gophercloud.ServiceClient) string { - return c.ServiceURL("networks") -} - -func getURL(c *gophercloud.ServiceClient, id string) string { - return resourceURL(c, id) -} - -func listURL(c *gophercloud.ServiceClient) string { - return rootURL(c) -} - -func createURL(c *gophercloud.ServiceClient) string { - return rootURL(c) -} - -func updateURL(c *gophercloud.ServiceClient, id string) string { - return resourceURL(c, id) -} - -func deleteURL(c *gophercloud.ServiceClient, id string) string { - return resourceURL(c, id) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/doc.go deleted file mode 100644 index cfb1774fb4b..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/doc.go +++ /dev/null @@ -1,73 +0,0 @@ -/* -Package ports contains functionality for working with Neutron port resources. - -A port represents a virtual switch port on a logical network switch. Virtual -instances attach their interfaces into ports. The logical port also defines -the MAC address and the IP address(es) to be assigned to the interfaces -plugged into them. When IP addresses are associated to a port, this also -implies the port is associated with a subnet, as the IP address was taken -from the allocation pool for a specific subnet. - -Example to List Ports - - listOpts := ports.ListOpts{ - DeviceID: "b0b89efe-82f8-461d-958b-adbf80f50c7d", - } - - allPages, err := ports.List(networkClient, listOpts).AllPages() - if err != nil { - panic(err) - } - - allPorts, err := ports.ExtractPorts(allPages) - if err != nil { - panic(err) - } - - for _, port := range allPorts { - fmt.Printf("%+v\n", port) - } - -Example to Create a Port - - createOtps := ports.CreateOpts{ - Name: "private-port", - AdminStateUp: &asu, - NetworkID: "a87cc70a-3e15-4acf-8205-9b711a3531b7", - FixedIPs: []ports.IP{ - {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"}, - }, - SecurityGroups: &[]string{"foo"}, - AllowedAddressPairs: []ports.AddressPair{ - {IPAddress: "10.0.0.4", MACAddress: "fa:16:3e:c9:cb:f0"}, - }, - } - - port, err := ports.Create(networkClient, createOpts).Extract() - if err != nil { - panic(err) - } - -Example to Update a Port - - portID := "c34bae2b-7641-49b6-bf6d-d8e473620ed8" - - updateOpts := ports.UpdateOpts{ - Name: "new_name", - SecurityGroups: &[]string{}, - } - - port, err := ports.Update(networkClient, portID, updateOpts).Extract() - if err != nil { - panic(err) - } - -Example to Delete a Port - - portID := "c34bae2b-7641-49b6-bf6d-d8e473620ed8" - err := ports.Delete(networkClient, portID).ExtractErr() - if err != nil { - panic(err) - } -*/ -package ports diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/requests.go deleted file mode 100644 index f5f7d761ce8..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/requests.go +++ /dev/null @@ -1,191 +0,0 @@ -package ports - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -// ListOptsBuilder allows extensions to add additional parameters to the -// List request. -type ListOptsBuilder interface { - ToPortListQuery() (string, error) -} - -// ListOpts allows the filtering and sorting of paginated collections through -// the API. Filtering is achieved by passing in struct field values that map to -// the port attributes you want to see returned. SortKey allows you to sort -// by a particular port attribute. SortDir sets the direction, and is either -// `asc' or `desc'. Marker and Limit are used for pagination. -type ListOpts struct { - Status string `q:"status"` - Name string `q:"name"` - Description string `q:"description"` - AdminStateUp *bool `q:"admin_state_up"` - NetworkID string `q:"network_id"` - TenantID string `q:"tenant_id"` - ProjectID string `q:"project_id"` - DeviceOwner string `q:"device_owner"` - MACAddress string `q:"mac_address"` - ID string `q:"id"` - DeviceID string `q:"device_id"` - Limit int `q:"limit"` - Marker string `q:"marker"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` - Tags string `q:"tags"` - TagsAny string `q:"tags-any"` - NotTags string `q:"not-tags"` - NotTagsAny string `q:"not-tags-any"` -} - -// ToPortListQuery formats a ListOpts into a query string. -func (opts ListOpts) ToPortListQuery() (string, error) { - q, err := gophercloud.BuildQueryString(opts) - return q.String(), err -} - -// List returns a Pager which allows you to iterate over a collection of -// ports. It accepts a ListOpts struct, which allows you to filter and sort -// the returned collection for greater efficiency. -// -// Default policy settings return only those ports that are owned by the tenant -// who submits the request, unless the request is submitted by a user with -// administrative rights. -func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { - url := listURL(c) - if opts != nil { - query, err := opts.ToPortListQuery() - if err != nil { - return pagination.Pager{Err: err} - } - url += query - } - return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { - return PortPage{pagination.LinkedPageBase{PageResult: r}} - }) -} - -// Get retrieves a specific port based on its unique ID. -func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = c.Get(getURL(c, id), &r.Body, nil) - return -} - -// CreateOptsBuilder allows extensions to add additional parameters to the -// Create request. -type CreateOptsBuilder interface { - ToPortCreateMap() (map[string]interface{}, error) -} - -// CreateOpts represents the attributes used when creating a new port. -type CreateOpts struct { - NetworkID string `json:"network_id" required:"true"` - Name string `json:"name,omitempty"` - Description string `json:"description,omitempty"` - AdminStateUp *bool `json:"admin_state_up,omitempty"` - MACAddress string `json:"mac_address,omitempty"` - FixedIPs interface{} `json:"fixed_ips,omitempty"` - DeviceID string `json:"device_id,omitempty"` - DeviceOwner string `json:"device_owner,omitempty"` - TenantID string `json:"tenant_id,omitempty"` - ProjectID string `json:"project_id,omitempty"` - SecurityGroups *[]string `json:"security_groups,omitempty"` - AllowedAddressPairs []AddressPair `json:"allowed_address_pairs,omitempty"` -} - -// ToPortCreateMap builds a request body from CreateOpts. -func (opts CreateOpts) ToPortCreateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "port") -} - -// Create accepts a CreateOpts struct and creates a new network using the values -// provided. You must remember to provide a NetworkID value. -func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToPortCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Post(createURL(c), b, &r.Body, nil) - return -} - -// UpdateOptsBuilder allows extensions to add additional parameters to the -// Update request. -type UpdateOptsBuilder interface { - ToPortUpdateMap() (map[string]interface{}, error) -} - -// UpdateOpts represents the attributes used when updating an existing port. -type UpdateOpts struct { - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - AdminStateUp *bool `json:"admin_state_up,omitempty"` - FixedIPs interface{} `json:"fixed_ips,omitempty"` - DeviceID *string `json:"device_id,omitempty"` - DeviceOwner *string `json:"device_owner,omitempty"` - SecurityGroups *[]string `json:"security_groups,omitempty"` - AllowedAddressPairs *[]AddressPair `json:"allowed_address_pairs,omitempty"` -} - -// ToPortUpdateMap builds a request body from UpdateOpts. -func (opts UpdateOpts) ToPortUpdateMap() (map[string]interface{}, error) { - return gophercloud.BuildRequestBody(opts, "port") -} - -// Update accepts a UpdateOpts struct and updates an existing port using the -// values provided. -func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { - b, err := opts.ToPortUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Put(updateURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ - OkCodes: []int{200, 201}, - }) - return -} - -// Delete accepts a unique ID and deletes the port associated with it. -func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = c.Delete(deleteURL(c, id), nil) - return -} - -// IDFromName is a convenience function that returns a port's ID, -// given its name. -func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) { - count := 0 - id := "" - - listOpts := ListOpts{ - Name: name, - } - - pages, err := List(client, listOpts).AllPages() - if err != nil { - return "", err - } - - all, err := ExtractPorts(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: "port"} - case 1: - return id, nil - default: - return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "port"} - } -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/results.go deleted file mode 100644 index 3941b62300d..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/results.go +++ /dev/null @@ -1,149 +0,0 @@ -package ports - -import ( - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/pagination" -) - -type commonResult struct { - gophercloud.Result -} - -// Extract is a function that accepts a result and extracts a port resource. -func (r commonResult) Extract() (*Port, error) { - var s Port - err := r.ExtractInto(&s) - return &s, err -} - -func (r commonResult) ExtractInto(v interface{}) error { - return r.Result.ExtractIntoStructPtr(v, "port") -} - -// CreateResult represents the result of a create operation. Call its Extract -// method to interpret it as a Port. -type CreateResult struct { - commonResult -} - -// GetResult represents the result of a get operation. Call its Extract -// method to interpret it as a Port. -type GetResult struct { - commonResult -} - -// UpdateResult represents the result of an update operation. Call its Extract -// method to interpret it as a Port. -type UpdateResult struct { - commonResult -} - -// DeleteResult represents the result of a delete operation. Call its -// ExtractErr method to determine if the request succeeded or failed. -type DeleteResult struct { - gophercloud.ErrResult -} - -// IP is a sub-struct that represents an individual IP. -type IP struct { - SubnetID string `json:"subnet_id"` - IPAddress string `json:"ip_address,omitempty"` -} - -// AddressPair contains the IP Address and the MAC address. -type AddressPair struct { - IPAddress string `json:"ip_address,omitempty"` - MACAddress string `json:"mac_address,omitempty"` -} - -// Port represents a Neutron port. See package documentation for a top-level -// description of what this is. -type Port struct { - // UUID for the port. - ID string `json:"id"` - - // Network that this port is associated with. - NetworkID string `json:"network_id"` - - // Human-readable name for the port. Might not be unique. - Name string `json:"name"` - - // Describes the port. - Description string `json:"description"` - - // Administrative state of port. If false (down), port does not forward - // packets. - AdminStateUp bool `json:"admin_state_up"` - - // Indicates whether network is currently operational. Possible values include - // `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define additional - // values. - Status string `json:"status"` - - // Mac address to use on this port. - MACAddress string `json:"mac_address"` - - // Specifies IP addresses for the port thus associating the port itself with - // the subnets where the IP addresses are picked from - FixedIPs []IP `json:"fixed_ips"` - - // TenantID is the project owner of the port. - TenantID string `json:"tenant_id"` - - // ProjectID is the project owner of the port. - ProjectID string `json:"project_id"` - - // Identifies the entity (e.g.: dhcp agent) using this port. - DeviceOwner string `json:"device_owner"` - - // Specifies the IDs of any security groups associated with a port. - SecurityGroups []string `json:"security_groups"` - - // Identifies the device (e.g., virtual server) using this port. - DeviceID string `json:"device_id"` - - // Identifies the list of IP addresses the port will recognize/accept - AllowedAddressPairs []AddressPair `json:"allowed_address_pairs"` - - // Tags optionally set via extensions/attributestags - Tags []string `json:"tags"` -} - -// PortPage is the page returned by a pager when traversing over a collection -// of network ports. -type PortPage struct { - pagination.LinkedPageBase -} - -// NextPageURL is invoked when a paginated collection of ports has reached -// the end of a page and the pager seeks to traverse over a new one. In order -// to do this, it needs to construct the next page's URL. -func (r PortPage) NextPageURL() (string, error) { - var s struct { - Links []gophercloud.Link `json:"ports_links"` - } - err := r.ExtractInto(&s) - if err != nil { - return "", err - } - return gophercloud.ExtractNextURL(s.Links) -} - -// IsEmpty checks whether a PortPage struct is empty. -func (r PortPage) IsEmpty() (bool, error) { - is, err := ExtractPorts(r) - return len(is) == 0, err -} - -// ExtractPorts accepts a Page struct, specifically a PortPage struct, -// and extracts the elements into a slice of Port structs. In other words, -// a generic collection is mapped into a relevant slice. -func ExtractPorts(r pagination.Page) ([]Port, error) { - var s []Port - err := ExtractPortsInto(r, &s) - return s, err -} - -func ExtractPortsInto(r pagination.Page, v interface{}) error { - return r.(PortPage).Result.ExtractIntoSlicePtr(v, "ports") -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/urls.go deleted file mode 100644 index 600d6f2fd95..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports/urls.go +++ /dev/null @@ -1,31 +0,0 @@ -package ports - -import "github.com/gophercloud/gophercloud" - -func resourceURL(c *gophercloud.ServiceClient, id string) string { - return c.ServiceURL("ports", id) -} - -func rootURL(c *gophercloud.ServiceClient) string { - return c.ServiceURL("ports") -} - -func listURL(c *gophercloud.ServiceClient) string { - return rootURL(c) -} - -func getURL(c *gophercloud.ServiceClient, id string) string { - return resourceURL(c, id) -} - -func createURL(c *gophercloud.ServiceClient) string { - return rootURL(c) -} - -func updateURL(c *gophercloud.ServiceClient, id string) string { - return resourceURL(c, id) -} - -func deleteURL(c *gophercloud.ServiceClient, id string) string { - return resourceURL(c, id) -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/utils/base_endpoint.go b/vendor/github.com/gophercloud/gophercloud/openstack/utils/base_endpoint.go deleted file mode 100644 index 40080f7af20..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/utils/base_endpoint.go +++ /dev/null @@ -1,28 +0,0 @@ -package utils - -import ( - "net/url" - "regexp" - "strings" -) - -// BaseEndpoint will return a URL without the /vX.Y -// portion of the URL. -func BaseEndpoint(endpoint string) (string, error) { - u, err := url.Parse(endpoint) - if err != nil { - return "", err - } - - u.RawQuery, u.Fragment = "", "" - - path := u.Path - versionRe := regexp.MustCompile("v[0-9.]+/?") - - if version := versionRe.FindString(path); version != "" { - versionIndex := strings.Index(path, version) - u.Path = path[:versionIndex] - } - - return u.String(), nil -} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/utils/choose_version.go b/vendor/github.com/gophercloud/gophercloud/openstack/utils/choose_version.go deleted file mode 100644 index 27da19f91a8..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/openstack/utils/choose_version.go +++ /dev/null @@ -1,111 +0,0 @@ -package utils - -import ( - "fmt" - "strings" - - "github.com/gophercloud/gophercloud" -) - -// Version is a supported API version, corresponding to a vN package within the appropriate service. -type Version struct { - ID string - Suffix string - Priority int -} - -var goodStatus = map[string]bool{ - "current": true, - "supported": true, - "stable": true, -} - -// ChooseVersion queries the base endpoint of an API to choose the most recent non-experimental alternative from a service's -// published versions. -// It returns the highest-Priority Version among the alternatives that are provided, as well as its corresponding endpoint. -func ChooseVersion(client *gophercloud.ProviderClient, recognized []*Version) (*Version, string, error) { - type linkResp struct { - Href string `json:"href"` - Rel string `json:"rel"` - } - - type valueResp struct { - ID string `json:"id"` - Status string `json:"status"` - Links []linkResp `json:"links"` - } - - type versionsResp struct { - Values []valueResp `json:"values"` - } - - type response struct { - Versions versionsResp `json:"versions"` - } - - normalize := func(endpoint string) string { - if !strings.HasSuffix(endpoint, "/") { - return endpoint + "/" - } - return endpoint - } - identityEndpoint := normalize(client.IdentityEndpoint) - - // If a full endpoint is specified, check version suffixes for a match first. - for _, v := range recognized { - if strings.HasSuffix(identityEndpoint, v.Suffix) { - return v, identityEndpoint, nil - } - } - - var resp response - _, err := client.Request("GET", client.IdentityBase, &gophercloud.RequestOpts{ - JSONResponse: &resp, - OkCodes: []int{200, 300}, - }) - - if err != nil { - return nil, "", err - } - - var highest *Version - var endpoint string - - for _, value := range resp.Versions.Values { - href := "" - for _, link := range value.Links { - if link.Rel == "self" { - href = normalize(link.Href) - } - } - - for _, version := range recognized { - if strings.Contains(value.ID, version.ID) { - // Prefer a version that exactly matches the provided endpoint. - if href == identityEndpoint { - if href == "" { - return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", value.ID, client.IdentityBase) - } - return version, href, nil - } - - // Otherwise, find the highest-priority version with a whitelisted status. - if goodStatus[strings.ToLower(value.Status)] { - if highest == nil || version.Priority > highest.Priority { - highest = version - endpoint = href - } - } - } - } - } - - if highest == nil { - return nil, "", fmt.Errorf("No supported version available from endpoint %s", client.IdentityBase) - } - if endpoint == "" { - return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", highest.ID, client.IdentityBase) - } - - return highest, endpoint, nil -} diff --git a/vendor/github.com/gophercloud/gophercloud/pagination/http.go b/vendor/github.com/gophercloud/gophercloud/pagination/http.go deleted file mode 100644 index 757295c423a..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/pagination/http.go +++ /dev/null @@ -1,60 +0,0 @@ -package pagination - -import ( - "encoding/json" - "io/ioutil" - "net/http" - "net/url" - "strings" - - "github.com/gophercloud/gophercloud" -) - -// PageResult stores the HTTP response that returned the current page of results. -type PageResult struct { - gophercloud.Result - url.URL -} - -// PageResultFrom parses an HTTP response as JSON and returns a PageResult containing the -// results, interpreting it as JSON if the content type indicates. -func PageResultFrom(resp *http.Response) (PageResult, error) { - var parsedBody interface{} - - defer resp.Body.Close() - rawBody, err := ioutil.ReadAll(resp.Body) - if err != nil { - return PageResult{}, err - } - - if strings.HasPrefix(resp.Header.Get("Content-Type"), "application/json") { - err = json.Unmarshal(rawBody, &parsedBody) - if err != nil { - return PageResult{}, err - } - } else { - parsedBody = rawBody - } - - return PageResultFromParsed(resp, parsedBody), err -} - -// PageResultFromParsed constructs a PageResult from an HTTP response that has already had its -// body parsed as JSON (and closed). -func PageResultFromParsed(resp *http.Response, body interface{}) PageResult { - return PageResult{ - Result: gophercloud.Result{ - Body: body, - Header: resp.Header, - }, - URL: *resp.Request.URL, - } -} - -// Request performs an HTTP request and extracts the http.Response from the result. -func Request(client *gophercloud.ServiceClient, headers map[string]string, url string) (*http.Response, error) { - return client.Get(url, nil, &gophercloud.RequestOpts{ - MoreHeaders: headers, - OkCodes: []int{200, 204, 300}, - }) -} diff --git a/vendor/github.com/gophercloud/gophercloud/pagination/linked.go b/vendor/github.com/gophercloud/gophercloud/pagination/linked.go deleted file mode 100644 index 3656fb7f8f4..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/pagination/linked.go +++ /dev/null @@ -1,92 +0,0 @@ -package pagination - -import ( - "fmt" - "reflect" - - "github.com/gophercloud/gophercloud" -) - -// LinkedPageBase may be embedded to implement a page that provides navigational "Next" and "Previous" links within its result. -type LinkedPageBase struct { - PageResult - - // LinkPath lists the keys that should be traversed within a response to arrive at the "next" pointer. - // If any link along the path is missing, an empty URL will be returned. - // If any link results in an unexpected value type, an error will be returned. - // When left as "nil", []string{"links", "next"} will be used as a default. - LinkPath []string -} - -// NextPageURL extracts the pagination structure from a JSON response and returns the "next" link, if one is present. -// It assumes that the links are available in a "links" element of the top-level response object. -// If this is not the case, override NextPageURL on your result type. -func (current LinkedPageBase) NextPageURL() (string, error) { - var path []string - var key string - - if current.LinkPath == nil { - path = []string{"links", "next"} - } else { - path = current.LinkPath - } - - submap, ok := current.Body.(map[string]interface{}) - if !ok { - err := gophercloud.ErrUnexpectedType{} - err.Expected = "map[string]interface{}" - err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body)) - return "", err - } - - for { - key, path = path[0], path[1:len(path)] - - value, ok := submap[key] - if !ok { - return "", nil - } - - if len(path) > 0 { - submap, ok = value.(map[string]interface{}) - if !ok { - err := gophercloud.ErrUnexpectedType{} - err.Expected = "map[string]interface{}" - err.Actual = fmt.Sprintf("%v", reflect.TypeOf(value)) - return "", err - } - } else { - if value == nil { - // Actual null element. - return "", nil - } - - url, ok := value.(string) - if !ok { - err := gophercloud.ErrUnexpectedType{} - err.Expected = "string" - err.Actual = fmt.Sprintf("%v", reflect.TypeOf(value)) - return "", err - } - - return url, nil - } - } -} - -// IsEmpty satisifies the IsEmpty method of the Page interface -func (current LinkedPageBase) IsEmpty() (bool, error) { - if b, ok := current.Body.([]interface{}); ok { - return len(b) == 0, nil - } - err := gophercloud.ErrUnexpectedType{} - err.Expected = "[]interface{}" - err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body)) - return true, err -} - -// GetBody returns the linked page's body. This method is needed to satisfy the -// Page interface. -func (current LinkedPageBase) GetBody() interface{} { - return current.Body -} diff --git a/vendor/github.com/gophercloud/gophercloud/pagination/marker.go b/vendor/github.com/gophercloud/gophercloud/pagination/marker.go deleted file mode 100644 index 52e53bae850..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/pagination/marker.go +++ /dev/null @@ -1,58 +0,0 @@ -package pagination - -import ( - "fmt" - "reflect" - - "github.com/gophercloud/gophercloud" -) - -// MarkerPage is a stricter Page interface that describes additional functionality required for use with NewMarkerPager. -// For convenience, embed the MarkedPageBase struct. -type MarkerPage interface { - Page - - // LastMarker returns the last "marker" value on this page. - LastMarker() (string, error) -} - -// MarkerPageBase is a page in a collection that's paginated by "limit" and "marker" query parameters. -type MarkerPageBase struct { - PageResult - - // Owner is a reference to the embedding struct. - Owner MarkerPage -} - -// NextPageURL generates the URL for the page of results after this one. -func (current MarkerPageBase) NextPageURL() (string, error) { - currentURL := current.URL - - mark, err := current.Owner.LastMarker() - if err != nil { - return "", err - } - - q := currentURL.Query() - q.Set("marker", mark) - currentURL.RawQuery = q.Encode() - - return currentURL.String(), nil -} - -// IsEmpty satisifies the IsEmpty method of the Page interface -func (current MarkerPageBase) IsEmpty() (bool, error) { - if b, ok := current.Body.([]interface{}); ok { - return len(b) == 0, nil - } - err := gophercloud.ErrUnexpectedType{} - err.Expected = "[]interface{}" - err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body)) - return true, err -} - -// GetBody returns the linked page's body. This method is needed to satisfy the -// Page interface. -func (current MarkerPageBase) GetBody() interface{} { - return current.Body -} diff --git a/vendor/github.com/gophercloud/gophercloud/pagination/pager.go b/vendor/github.com/gophercloud/gophercloud/pagination/pager.go deleted file mode 100644 index 42c0b2dbe5b..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/pagination/pager.go +++ /dev/null @@ -1,251 +0,0 @@ -package pagination - -import ( - "errors" - "fmt" - "net/http" - "reflect" - "strings" - - "github.com/gophercloud/gophercloud" -) - -var ( - // ErrPageNotAvailable is returned from a Pager when a next or previous page is requested, but does not exist. - ErrPageNotAvailable = errors.New("The requested page does not exist.") -) - -// Page must be satisfied by the result type of any resource collection. -// It allows clients to interact with the resource uniformly, regardless of whether or not or how it's paginated. -// Generally, rather than implementing this interface directly, implementors should embed one of the concrete PageBase structs, -// instead. -// Depending on the pagination strategy of a particular resource, there may be an additional subinterface that the result type -// will need to implement. -type Page interface { - // NextPageURL generates the URL for the page of data that follows this collection. - // Return "" if no such page exists. - NextPageURL() (string, error) - - // IsEmpty returns true if this Page has no items in it. - IsEmpty() (bool, error) - - // GetBody returns the Page Body. This is used in the `AllPages` method. - GetBody() interface{} -} - -// Pager knows how to advance through a specific resource collection, one page at a time. -type Pager struct { - client *gophercloud.ServiceClient - - initialURL string - - createPage func(r PageResult) Page - - firstPage Page - - Err error - - // Headers supplies additional HTTP headers to populate on each paged request. - Headers map[string]string -} - -// NewPager constructs a manually-configured pager. -// Supply the URL for the first page, a function that requests a specific page given a URL, and a function that counts a page. -func NewPager(client *gophercloud.ServiceClient, initialURL string, createPage func(r PageResult) Page) Pager { - return Pager{ - client: client, - initialURL: initialURL, - createPage: createPage, - } -} - -// WithPageCreator returns a new Pager that substitutes a different page creation function. This is -// useful for overriding List functions in delegation. -func (p Pager) WithPageCreator(createPage func(r PageResult) Page) Pager { - return Pager{ - client: p.client, - initialURL: p.initialURL, - createPage: createPage, - } -} - -func (p Pager) fetchNextPage(url string) (Page, error) { - resp, err := Request(p.client, p.Headers, url) - if err != nil { - return nil, err - } - - remembered, err := PageResultFrom(resp) - if err != nil { - return nil, err - } - - return p.createPage(remembered), nil -} - -// EachPage iterates over each page returned by a Pager, yielding one at a time to a handler function. -// Return "false" from the handler to prematurely stop iterating. -func (p Pager) EachPage(handler func(Page) (bool, error)) error { - if p.Err != nil { - return p.Err - } - currentURL := p.initialURL - for { - var currentPage Page - - // if first page has already been fetched, no need to fetch it again - if p.firstPage != nil { - currentPage = p.firstPage - p.firstPage = nil - } else { - var err error - currentPage, err = p.fetchNextPage(currentURL) - if err != nil { - return err - } - } - - empty, err := currentPage.IsEmpty() - if err != nil { - return err - } - if empty { - return nil - } - - ok, err := handler(currentPage) - if err != nil { - return err - } - if !ok { - return nil - } - - currentURL, err = currentPage.NextPageURL() - if err != nil { - return err - } - if currentURL == "" { - return nil - } - } -} - -// AllPages returns all the pages from a `List` operation in a single page, -// allowing the user to retrieve all the pages at once. -func (p Pager) AllPages() (Page, error) { - // pagesSlice holds all the pages until they get converted into as Page Body. - var pagesSlice []interface{} - // body will contain the final concatenated Page body. - var body reflect.Value - - // Grab a first page to ascertain the page body type. - firstPage, err := p.fetchNextPage(p.initialURL) - if err != nil { - return nil, err - } - // Store the page type so we can use reflection to create a new mega-page of - // that type. - pageType := reflect.TypeOf(firstPage) - - // if it's a single page, just return the firstPage (first page) - if _, found := pageType.FieldByName("SinglePageBase"); found { - return firstPage, nil - } - - // store the first page to avoid getting it twice - p.firstPage = firstPage - - // Switch on the page body type. Recognized types are `map[string]interface{}`, - // `[]byte`, and `[]interface{}`. - switch pb := firstPage.GetBody().(type) { - case map[string]interface{}: - // key is the map key for the page body if the body type is `map[string]interface{}`. - var key string - // Iterate over the pages to concatenate the bodies. - err = p.EachPage(func(page Page) (bool, error) { - b := page.GetBody().(map[string]interface{}) - for k, v := range b { - // If it's a linked page, we don't want the `links`, we want the other one. - if !strings.HasSuffix(k, "links") { - // check the field's type. we only want []interface{} (which is really []map[string]interface{}) - switch vt := v.(type) { - case []interface{}: - key = k - pagesSlice = append(pagesSlice, vt...) - } - } - } - return true, nil - }) - if err != nil { - return nil, err - } - // Set body to value of type `map[string]interface{}` - body = reflect.MakeMap(reflect.MapOf(reflect.TypeOf(key), reflect.TypeOf(pagesSlice))) - body.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(pagesSlice)) - case []byte: - // Iterate over the pages to concatenate the bodies. - err = p.EachPage(func(page Page) (bool, error) { - b := page.GetBody().([]byte) - pagesSlice = append(pagesSlice, b) - // seperate pages with a comma - pagesSlice = append(pagesSlice, []byte{10}) - return true, nil - }) - if err != nil { - return nil, err - } - if len(pagesSlice) > 0 { - // Remove the trailing comma. - pagesSlice = pagesSlice[:len(pagesSlice)-1] - } - var b []byte - // Combine the slice of slices in to a single slice. - for _, slice := range pagesSlice { - b = append(b, slice.([]byte)...) - } - // Set body to value of type `bytes`. - body = reflect.New(reflect.TypeOf(b)).Elem() - body.SetBytes(b) - case []interface{}: - // Iterate over the pages to concatenate the bodies. - err = p.EachPage(func(page Page) (bool, error) { - b := page.GetBody().([]interface{}) - pagesSlice = append(pagesSlice, b...) - return true, nil - }) - if err != nil { - return nil, err - } - // Set body to value of type `[]interface{}` - body = reflect.MakeSlice(reflect.TypeOf(pagesSlice), len(pagesSlice), len(pagesSlice)) - for i, s := range pagesSlice { - body.Index(i).Set(reflect.ValueOf(s)) - } - default: - err := gophercloud.ErrUnexpectedType{} - err.Expected = "map[string]interface{}/[]byte/[]interface{}" - err.Actual = fmt.Sprintf("%T", pb) - return nil, err - } - - // Each `Extract*` function is expecting a specific type of page coming back, - // otherwise the type assertion in those functions will fail. pageType is needed - // to create a type in this method that has the same type that the `Extract*` - // function is expecting and set the Body of that object to the concatenated - // pages. - page := reflect.New(pageType) - // Set the page body to be the concatenated pages. - page.Elem().FieldByName("Body").Set(body) - // Set any additional headers that were pass along. The `objectstorage` pacakge, - // for example, passes a Content-Type header. - h := make(http.Header) - for k, v := range p.Headers { - h.Add(k, v) - } - page.Elem().FieldByName("Header").Set(reflect.ValueOf(h)) - // Type assert the page to a Page interface so that the type assertion in the - // `Extract*` methods will work. - return page.Elem().Interface().(Page), err -} diff --git a/vendor/github.com/gophercloud/gophercloud/pagination/pkg.go b/vendor/github.com/gophercloud/gophercloud/pagination/pkg.go deleted file mode 100644 index 912daea3642..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/pagination/pkg.go +++ /dev/null @@ -1,4 +0,0 @@ -/* -Package pagination contains utilities and convenience structs that implement common pagination idioms within OpenStack APIs. -*/ -package pagination diff --git a/vendor/github.com/gophercloud/gophercloud/pagination/single.go b/vendor/github.com/gophercloud/gophercloud/pagination/single.go deleted file mode 100644 index 4251d6491ef..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/pagination/single.go +++ /dev/null @@ -1,33 +0,0 @@ -package pagination - -import ( - "fmt" - "reflect" - - "github.com/gophercloud/gophercloud" -) - -// SinglePageBase may be embedded in a Page that contains all of the results from an operation at once. -type SinglePageBase PageResult - -// NextPageURL always returns "" to indicate that there are no more pages to return. -func (current SinglePageBase) NextPageURL() (string, error) { - return "", nil -} - -// IsEmpty satisifies the IsEmpty method of the Page interface -func (current SinglePageBase) IsEmpty() (bool, error) { - if b, ok := current.Body.([]interface{}); ok { - return len(b) == 0, nil - } - err := gophercloud.ErrUnexpectedType{} - err.Expected = "[]interface{}" - err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body)) - return true, err -} - -// GetBody returns the single page's body. This method is needed to satisfy the -// Page interface. -func (current SinglePageBase) GetBody() interface{} { - return current.Body -} diff --git a/vendor/github.com/gophercloud/gophercloud/params.go b/vendor/github.com/gophercloud/gophercloud/params.go deleted file mode 100644 index b9986660cbd..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/params.go +++ /dev/null @@ -1,491 +0,0 @@ -package gophercloud - -import ( - "encoding/json" - "fmt" - "net/url" - "reflect" - "strconv" - "strings" - "time" -) - -/* -BuildRequestBody builds a map[string]interface from the given `struct`. If -parent is not an empty string, the final map[string]interface returned will -encapsulate the built one. For example: - - disk := 1 - createOpts := flavors.CreateOpts{ - ID: "1", - Name: "m1.tiny", - Disk: &disk, - RAM: 512, - VCPUs: 1, - RxTxFactor: 1.0, - } - - body, err := gophercloud.BuildRequestBody(createOpts, "flavor") - -The above example can be run as-is, however it is recommended to look at how -BuildRequestBody is used within Gophercloud to more fully understand how it -fits within the request process as a whole rather than use it directly as shown -above. -*/ -func BuildRequestBody(opts interface{}, parent string) (map[string]interface{}, error) { - optsValue := reflect.ValueOf(opts) - if optsValue.Kind() == reflect.Ptr { - optsValue = optsValue.Elem() - } - - optsType := reflect.TypeOf(opts) - if optsType.Kind() == reflect.Ptr { - optsType = optsType.Elem() - } - - optsMap := make(map[string]interface{}) - if optsValue.Kind() == reflect.Struct { - //fmt.Printf("optsValue.Kind() is a reflect.Struct: %+v\n", optsValue.Kind()) - for i := 0; i < optsValue.NumField(); i++ { - v := optsValue.Field(i) - f := optsType.Field(i) - - if f.Name != strings.Title(f.Name) { - //fmt.Printf("Skipping field: %s...\n", f.Name) - continue - } - - //fmt.Printf("Starting on field: %s...\n", f.Name) - - zero := isZero(v) - //fmt.Printf("v is zero?: %v\n", zero) - - // if the field has a required tag that's set to "true" - if requiredTag := f.Tag.Get("required"); requiredTag == "true" { - //fmt.Printf("Checking required field [%s]:\n\tv: %+v\n\tisZero:%v\n", f.Name, v.Interface(), zero) - // if the field's value is zero, return a missing-argument error - if zero { - // if the field has a 'required' tag, it can't have a zero-value - err := ErrMissingInput{} - err.Argument = f.Name - return nil, err - } - } - - if xorTag := f.Tag.Get("xor"); xorTag != "" { - //fmt.Printf("Checking `xor` tag for field [%s] with value %+v:\n\txorTag: %s\n", f.Name, v, xorTag) - xorField := optsValue.FieldByName(xorTag) - var xorFieldIsZero bool - if reflect.ValueOf(xorField.Interface()) == reflect.Zero(xorField.Type()) { - xorFieldIsZero = true - } else { - if xorField.Kind() == reflect.Ptr { - xorField = xorField.Elem() - } - xorFieldIsZero = isZero(xorField) - } - if !(zero != xorFieldIsZero) { - err := ErrMissingInput{} - err.Argument = fmt.Sprintf("%s/%s", f.Name, xorTag) - err.Info = fmt.Sprintf("Exactly one of %s and %s must be provided", f.Name, xorTag) - return nil, err - } - } - - if orTag := f.Tag.Get("or"); orTag != "" { - //fmt.Printf("Checking `or` tag for field with:\n\tname: %+v\n\torTag:%s\n", f.Name, orTag) - //fmt.Printf("field is zero?: %v\n", zero) - if zero { - orField := optsValue.FieldByName(orTag) - var orFieldIsZero bool - if reflect.ValueOf(orField.Interface()) == reflect.Zero(orField.Type()) { - orFieldIsZero = true - } else { - if orField.Kind() == reflect.Ptr { - orField = orField.Elem() - } - orFieldIsZero = isZero(orField) - } - if orFieldIsZero { - err := ErrMissingInput{} - err.Argument = fmt.Sprintf("%s/%s", f.Name, orTag) - err.Info = fmt.Sprintf("At least one of %s and %s must be provided", f.Name, orTag) - return nil, err - } - } - } - - jsonTag := f.Tag.Get("json") - if jsonTag == "-" { - continue - } - - if v.Kind() == reflect.Slice || (v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Slice) { - sliceValue := v - if sliceValue.Kind() == reflect.Ptr { - sliceValue = sliceValue.Elem() - } - - for i := 0; i < sliceValue.Len(); i++ { - element := sliceValue.Index(i) - if element.Kind() == reflect.Struct || (element.Kind() == reflect.Ptr && element.Elem().Kind() == reflect.Struct) { - _, err := BuildRequestBody(element.Interface(), "") - if err != nil { - return nil, err - } - } - } - } - if v.Kind() == reflect.Struct || (v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct) { - if zero { - //fmt.Printf("value before change: %+v\n", optsValue.Field(i)) - if jsonTag != "" { - jsonTagPieces := strings.Split(jsonTag, ",") - if len(jsonTagPieces) > 1 && jsonTagPieces[1] == "omitempty" { - if v.CanSet() { - if !v.IsNil() { - if v.Kind() == reflect.Ptr { - v.Set(reflect.Zero(v.Type())) - } - } - //fmt.Printf("value after change: %+v\n", optsValue.Field(i)) - } - } - } - continue - } - - //fmt.Printf("Calling BuildRequestBody with:\n\tv: %+v\n\tf.Name:%s\n", v.Interface(), f.Name) - _, err := BuildRequestBody(v.Interface(), f.Name) - if err != nil { - return nil, err - } - } - } - - //fmt.Printf("opts: %+v \n", opts) - - b, err := json.Marshal(opts) - if err != nil { - return nil, err - } - - //fmt.Printf("string(b): %s\n", string(b)) - - err = json.Unmarshal(b, &optsMap) - if err != nil { - return nil, err - } - - //fmt.Printf("optsMap: %+v\n", optsMap) - - if parent != "" { - optsMap = map[string]interface{}{parent: optsMap} - } - //fmt.Printf("optsMap after parent added: %+v\n", optsMap) - return optsMap, nil - } - // Return an error if the underlying type of 'opts' isn't a struct. - return nil, fmt.Errorf("Options type is not a struct.") -} - -// EnabledState is a convenience type, mostly used in Create and Update -// operations. Because the zero value of a bool is FALSE, we need to use a -// pointer instead to indicate zero-ness. -type EnabledState *bool - -// Convenience vars for EnabledState values. -var ( - iTrue = true - iFalse = false - - Enabled EnabledState = &iTrue - Disabled EnabledState = &iFalse -) - -// IPVersion is a type for the possible IP address versions. Valid instances -// are IPv4 and IPv6 -type IPVersion int - -const ( - // IPv4 is used for IP version 4 addresses - IPv4 IPVersion = 4 - // IPv6 is used for IP version 6 addresses - IPv6 IPVersion = 6 -) - -// IntToPointer is a function for converting integers into integer pointers. -// This is useful when passing in options to operations. -func IntToPointer(i int) *int { - return &i -} - -/* -MaybeString is an internal function to be used by request methods in individual -resource packages. - -It takes a string that might be a zero value and returns either a pointer to its -address or nil. This is useful for allowing users to conveniently omit values -from an options struct by leaving them zeroed, but still pass nil to the JSON -serializer so they'll be omitted from the request body. -*/ -func MaybeString(original string) *string { - if original != "" { - return &original - } - return nil -} - -/* -MaybeInt is an internal function to be used by request methods in individual -resource packages. - -Like MaybeString, it accepts an int that may or may not be a zero value, and -returns either a pointer to its address or nil. It's intended to hint that the -JSON serializer should omit its field. -*/ -func MaybeInt(original int) *int { - if original != 0 { - return &original - } - return nil -} - -/* -func isUnderlyingStructZero(v reflect.Value) bool { - switch v.Kind() { - case reflect.Ptr: - return isUnderlyingStructZero(v.Elem()) - default: - return isZero(v) - } -} -*/ - -var t time.Time - -func isZero(v reflect.Value) bool { - //fmt.Printf("\n\nchecking isZero for value: %+v\n", v) - switch v.Kind() { - case reflect.Ptr: - if v.IsNil() { - return true - } - return false - case reflect.Func, reflect.Map, reflect.Slice: - return v.IsNil() - case reflect.Array: - z := true - for i := 0; i < v.Len(); i++ { - z = z && isZero(v.Index(i)) - } - return z - case reflect.Struct: - if v.Type() == reflect.TypeOf(t) { - if v.Interface().(time.Time).IsZero() { - return true - } - return false - } - z := true - for i := 0; i < v.NumField(); i++ { - z = z && isZero(v.Field(i)) - } - return z - } - // Compare other types directly: - z := reflect.Zero(v.Type()) - //fmt.Printf("zero type for value: %+v\n\n\n", z) - return v.Interface() == z.Interface() -} - -/* -BuildQueryString is an internal function to be used by request methods in -individual resource packages. - -It accepts a tagged structure and expands it into a URL struct. Field names are -converted into query parameters based on a "q" tag. For example: - - type struct Something { - Bar string `q:"x_bar"` - Baz int `q:"lorem_ipsum"` - } - - instance := Something{ - Bar: "AAA", - Baz: "BBB", - } - -will be converted into "?x_bar=AAA&lorem_ipsum=BBB". - -The struct's fields may be strings, integers, or boolean values. Fields left at -their type's zero value will be omitted from the query. -*/ -func BuildQueryString(opts interface{}) (*url.URL, error) { - optsValue := reflect.ValueOf(opts) - if optsValue.Kind() == reflect.Ptr { - optsValue = optsValue.Elem() - } - - optsType := reflect.TypeOf(opts) - if optsType.Kind() == reflect.Ptr { - optsType = optsType.Elem() - } - - params := url.Values{} - - if optsValue.Kind() == reflect.Struct { - for i := 0; i < optsValue.NumField(); i++ { - v := optsValue.Field(i) - f := optsType.Field(i) - qTag := f.Tag.Get("q") - - // if the field has a 'q' tag, it goes in the query string - if qTag != "" { - tags := strings.Split(qTag, ",") - - // if the field is set, add it to the slice of query pieces - if !isZero(v) { - loop: - switch v.Kind() { - case reflect.Ptr: - v = v.Elem() - goto loop - case reflect.String: - params.Add(tags[0], v.String()) - case reflect.Int: - params.Add(tags[0], strconv.FormatInt(v.Int(), 10)) - case reflect.Bool: - params.Add(tags[0], strconv.FormatBool(v.Bool())) - case reflect.Slice: - switch v.Type().Elem() { - case reflect.TypeOf(0): - for i := 0; i < v.Len(); i++ { - params.Add(tags[0], strconv.FormatInt(v.Index(i).Int(), 10)) - } - default: - for i := 0; i < v.Len(); i++ { - params.Add(tags[0], v.Index(i).String()) - } - } - case reflect.Map: - if v.Type().Key().Kind() == reflect.String && v.Type().Elem().Kind() == reflect.String { - var s []string - for _, k := range v.MapKeys() { - value := v.MapIndex(k).String() - s = append(s, fmt.Sprintf("'%s':'%s'", k.String(), value)) - } - params.Add(tags[0], fmt.Sprintf("{%s}", strings.Join(s, ", "))) - } - } - } else { - // if the field has a 'required' tag, it can't have a zero-value - if requiredTag := f.Tag.Get("required"); requiredTag == "true" { - return &url.URL{}, fmt.Errorf("Required query parameter [%s] not set.", f.Name) - } - } - } - } - - return &url.URL{RawQuery: params.Encode()}, nil - } - // Return an error if the underlying type of 'opts' isn't a struct. - return nil, fmt.Errorf("Options type is not a struct.") -} - -/* -BuildHeaders is an internal function to be used by request methods in -individual resource packages. - -It accepts an arbitrary tagged structure and produces a string map that's -suitable for use as the HTTP headers of an outgoing request. Field names are -mapped to header names based in "h" tags. - - type struct Something { - Bar string `h:"x_bar"` - Baz int `h:"lorem_ipsum"` - } - - instance := Something{ - Bar: "AAA", - Baz: "BBB", - } - -will be converted into: - - map[string]string{ - "x_bar": "AAA", - "lorem_ipsum": "BBB", - } - -Untagged fields and fields left at their zero values are skipped. Integers, -booleans and string values are supported. -*/ -func BuildHeaders(opts interface{}) (map[string]string, error) { - optsValue := reflect.ValueOf(opts) - if optsValue.Kind() == reflect.Ptr { - optsValue = optsValue.Elem() - } - - optsType := reflect.TypeOf(opts) - if optsType.Kind() == reflect.Ptr { - optsType = optsType.Elem() - } - - optsMap := make(map[string]string) - if optsValue.Kind() == reflect.Struct { - for i := 0; i < optsValue.NumField(); i++ { - v := optsValue.Field(i) - f := optsType.Field(i) - hTag := f.Tag.Get("h") - - // if the field has a 'h' tag, it goes in the header - if hTag != "" { - tags := strings.Split(hTag, ",") - - // if the field is set, add it to the slice of query pieces - if !isZero(v) { - switch v.Kind() { - case reflect.String: - optsMap[tags[0]] = v.String() - case reflect.Int: - optsMap[tags[0]] = strconv.FormatInt(v.Int(), 10) - case reflect.Bool: - optsMap[tags[0]] = strconv.FormatBool(v.Bool()) - } - } else { - // if the field has a 'required' tag, it can't have a zero-value - if requiredTag := f.Tag.Get("required"); requiredTag == "true" { - return optsMap, fmt.Errorf("Required header [%s] not set.", f.Name) - } - } - } - - } - return optsMap, nil - } - // Return an error if the underlying type of 'opts' isn't a struct. - return optsMap, fmt.Errorf("Options type is not a struct.") -} - -// IDSliceToQueryString takes a slice of elements and converts them into a query -// string. For example, if name=foo and slice=[]int{20, 40, 60}, then the -// result would be `?name=20&name=40&name=60' -func IDSliceToQueryString(name string, ids []int) string { - str := "" - for k, v := range ids { - if k == 0 { - str += "?" - } else { - str += "&" - } - str += fmt.Sprintf("%s=%s", name, strconv.Itoa(v)) - } - return str -} - -// IntWithinRange returns TRUE if an integer falls within a defined range, and -// FALSE if not. -func IntWithinRange(val, min, max int) bool { - return val > min && val < max -} diff --git a/vendor/github.com/gophercloud/gophercloud/provider_client.go b/vendor/github.com/gophercloud/gophercloud/provider_client.go deleted file mode 100644 index fce00462fd3..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/provider_client.go +++ /dev/null @@ -1,501 +0,0 @@ -package gophercloud - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "io" - "io/ioutil" - "net/http" - "strings" - "sync" -) - -// DefaultUserAgent is the default User-Agent string set in the request header. -const DefaultUserAgent = "gophercloud/2.0.0" - -// UserAgent represents a User-Agent header. -type UserAgent struct { - // prepend is the slice of User-Agent strings to prepend to DefaultUserAgent. - // All the strings to prepend are accumulated and prepended in the Join method. - prepend []string -} - -// Prepend prepends a user-defined string to the default User-Agent string. Users -// may pass in one or more strings to prepend. -func (ua *UserAgent) Prepend(s ...string) { - ua.prepend = append(s, ua.prepend...) -} - -// Join concatenates all the user-defined User-Agend strings with the default -// Gophercloud User-Agent string. -func (ua *UserAgent) Join() string { - uaSlice := append(ua.prepend, DefaultUserAgent) - return strings.Join(uaSlice, " ") -} - -// ProviderClient stores details that are required to interact with any -// services within a specific provider's API. -// -// Generally, you acquire a ProviderClient by calling the NewClient method in -// the appropriate provider's child package, providing whatever authentication -// credentials are required. -type ProviderClient struct { - // IdentityBase is the base URL used for a particular provider's identity - // service - it will be used when issuing authenticatation requests. It - // should point to the root resource of the identity service, not a specific - // identity version. - IdentityBase string - - // IdentityEndpoint is the identity endpoint. This may be a specific version - // of the identity service. If this is the case, this endpoint is used rather - // than querying versions first. - IdentityEndpoint string - - // TokenID is the ID of the most recently issued valid token. - // NOTE: Aside from within a custom ReauthFunc, this field shouldn't be set by an application. - // To safely read or write this value, call `Token` or `SetToken`, respectively - TokenID string - - // EndpointLocator describes how this provider discovers the endpoints for - // its constituent services. - EndpointLocator EndpointLocator - - // HTTPClient allows users to interject arbitrary http, https, or other transit behaviors. - HTTPClient http.Client - - // UserAgent represents the User-Agent header in the HTTP request. - UserAgent UserAgent - - // ReauthFunc is the function used to re-authenticate the user if the request - // fails with a 401 HTTP response code. This a needed because there may be multiple - // authentication functions for different Identity service versions. - ReauthFunc func() error - - // Throwaway determines whether if this client is a throw-away client. It's a copy of user's provider client - // with the token and reauth func zeroed. Such client can be used to perform reauthorization. - Throwaway bool - - // Context is the context passed to the HTTP request. - Context context.Context - - // mut is a mutex for the client. It protects read and write access to client attributes such as getting - // and setting the TokenID. - mut *sync.RWMutex - - // reauthmut is a mutex for reauthentication it attempts to ensure that only one reauthentication - // attempt happens at one time. - reauthmut *reauthlock - - authResult AuthResult -} - -// reauthlock represents a set of attributes used to help in the reauthentication process. -type reauthlock struct { - sync.RWMutex - reauthing bool - reauthingErr error - done *sync.Cond -} - -// AuthenticatedHeaders returns a map of HTTP headers that are common for all -// authenticated service requests. Blocks if Reauthenticate is in progress. -func (client *ProviderClient) AuthenticatedHeaders() (m map[string]string) { - if client.IsThrowaway() { - return - } - if client.reauthmut != nil { - client.reauthmut.Lock() - for client.reauthmut.reauthing { - client.reauthmut.done.Wait() - } - client.reauthmut.Unlock() - } - t := client.Token() - if t == "" { - return - } - return map[string]string{"X-Auth-Token": t} -} - -// UseTokenLock creates a mutex that is used to allow safe concurrent access to the auth token. -// If the application's ProviderClient is not used concurrently, this doesn't need to be called. -func (client *ProviderClient) UseTokenLock() { - client.mut = new(sync.RWMutex) - client.reauthmut = new(reauthlock) -} - -// GetAuthResult returns the result from the request that was used to obtain a -// provider client's Keystone token. -// -// The result is nil when authentication has not yet taken place, when the token -// was set manually with SetToken(), or when a ReauthFunc was used that does not -// record the AuthResult. -func (client *ProviderClient) GetAuthResult() AuthResult { - if client.mut != nil { - client.mut.RLock() - defer client.mut.RUnlock() - } - return client.authResult -} - -// Token safely reads the value of the auth token from the ProviderClient. Applications should -// call this method to access the token instead of the TokenID field -func (client *ProviderClient) Token() string { - if client.mut != nil { - client.mut.RLock() - defer client.mut.RUnlock() - } - return client.TokenID -} - -// SetToken safely sets the value of the auth token in the ProviderClient. Applications may -// use this method in a custom ReauthFunc. -// -// WARNING: This function is deprecated. Use SetTokenAndAuthResult() instead. -func (client *ProviderClient) SetToken(t string) { - if client.mut != nil { - client.mut.Lock() - defer client.mut.Unlock() - } - client.TokenID = t - client.authResult = nil -} - -// SetTokenAndAuthResult safely sets the value of the auth token in the -// ProviderClient and also records the AuthResult that was returned from the -// token creation request. Applications may call this in a custom ReauthFunc. -func (client *ProviderClient) SetTokenAndAuthResult(r AuthResult) error { - tokenID := "" - var err error - if r != nil { - tokenID, err = r.ExtractTokenID() - if err != nil { - return err - } - } - - if client.mut != nil { - client.mut.Lock() - defer client.mut.Unlock() - } - client.TokenID = tokenID - client.authResult = r - return nil -} - -// CopyTokenFrom safely copies the token from another ProviderClient into the -// this one. -func (client *ProviderClient) CopyTokenFrom(other *ProviderClient) { - if client.mut != nil { - client.mut.Lock() - defer client.mut.Unlock() - } - if other.mut != nil && other.mut != client.mut { - other.mut.RLock() - defer other.mut.RUnlock() - } - client.TokenID = other.TokenID - client.authResult = other.authResult -} - -// IsThrowaway safely reads the value of the client Throwaway field. -func (client *ProviderClient) IsThrowaway() bool { - if client.reauthmut != nil { - client.reauthmut.RLock() - defer client.reauthmut.RUnlock() - } - return client.Throwaway -} - -// SetThrowaway safely sets the value of the client Throwaway field. -func (client *ProviderClient) SetThrowaway(v bool) { - if client.reauthmut != nil { - client.reauthmut.Lock() - defer client.reauthmut.Unlock() - } - client.Throwaway = v -} - -// Reauthenticate calls client.ReauthFunc in a thread-safe way. If this is -// called because of a 401 response, the caller may pass the previous token. In -// this case, the reauthentication can be skipped if another thread has already -// reauthenticated in the meantime. If no previous token is known, an empty -// string should be passed instead to force unconditional reauthentication. -func (client *ProviderClient) Reauthenticate(previousToken string) (err error) { - if client.ReauthFunc == nil { - return nil - } - - if client.reauthmut == nil { - return client.ReauthFunc() - } - - client.reauthmut.Lock() - if client.reauthmut.reauthing { - for !client.reauthmut.reauthing { - client.reauthmut.done.Wait() - } - err = client.reauthmut.reauthingErr - client.reauthmut.Unlock() - return err - } - client.reauthmut.Unlock() - - client.reauthmut.Lock() - client.reauthmut.reauthing = true - client.reauthmut.done = sync.NewCond(client.reauthmut) - client.reauthmut.reauthingErr = nil - client.reauthmut.Unlock() - - if previousToken == "" || client.TokenID == previousToken { - err = client.ReauthFunc() - } - - client.reauthmut.Lock() - client.reauthmut.reauthing = false - client.reauthmut.reauthingErr = err - client.reauthmut.done.Broadcast() - client.reauthmut.Unlock() - return -} - -// RequestOpts customizes the behavior of the provider.Request() method. -type RequestOpts struct { - // JSONBody, if provided, will be encoded as JSON and used as the body of the HTTP request. The - // content type of the request will default to "application/json" unless overridden by MoreHeaders. - // It's an error to specify both a JSONBody and a RawBody. - JSONBody interface{} - // RawBody contains an io.Reader that will be consumed by the request directly. No content-type - // will be set unless one is provided explicitly by MoreHeaders. - RawBody io.Reader - // JSONResponse, if provided, will be populated with the contents of the response body parsed as - // JSON. - JSONResponse interface{} - // OkCodes contains a list of numeric HTTP status codes that should be interpreted as success. If - // the response has a different code, an error will be returned. - OkCodes []int - // MoreHeaders specifies additional HTTP headers to be provide on the request. If a header is - // provided with a blank value (""), that header will be *omitted* instead: use this to suppress - // the default Accept header or an inferred Content-Type, for example. - MoreHeaders map[string]string - // ErrorContext specifies the resource error type to return if an error is encountered. - // This lets resources override default error messages based on the response status code. - ErrorContext error -} - -var applicationJSON = "application/json" - -// Request performs an HTTP request using the ProviderClient's current HTTPClient. An authentication -// header will automatically be provided. -func (client *ProviderClient) Request(method, url string, options *RequestOpts) (*http.Response, error) { - var body io.Reader - var contentType *string - - // Derive the content body by either encoding an arbitrary object as JSON, or by taking a provided - // io.ReadSeeker as-is. Default the content-type to application/json. - if options.JSONBody != nil { - if options.RawBody != nil { - return nil, errors.New("please provide only one of JSONBody or RawBody to gophercloud.Request()") - } - - rendered, err := json.Marshal(options.JSONBody) - if err != nil { - return nil, err - } - - body = bytes.NewReader(rendered) - contentType = &applicationJSON - } - - if options.RawBody != nil { - body = options.RawBody - } - - // Construct the http.Request. - req, err := http.NewRequest(method, url, body) - if err != nil { - return nil, err - } - if client.Context != nil { - req = req.WithContext(client.Context) - } - - // Populate the request headers. Apply options.MoreHeaders last, to give the caller the chance to - // modify or omit any header. - if contentType != nil { - req.Header.Set("Content-Type", *contentType) - } - req.Header.Set("Accept", applicationJSON) - - // Set the User-Agent header - req.Header.Set("User-Agent", client.UserAgent.Join()) - - if options.MoreHeaders != nil { - for k, v := range options.MoreHeaders { - if v != "" { - req.Header.Set(k, v) - } else { - req.Header.Del(k) - } - } - } - - // get latest token from client - for k, v := range client.AuthenticatedHeaders() { - req.Header.Set(k, v) - } - - // Set connection parameter to close the connection immediately when we've got the response - req.Close = true - - prereqtok := req.Header.Get("X-Auth-Token") - - // Issue the request. - resp, err := client.HTTPClient.Do(req) - if err != nil { - return nil, err - } - - // Allow default OkCodes if none explicitly set - okc := options.OkCodes - if okc == nil { - okc = defaultOkCodes(method) - } - - // Validate the HTTP response status. - var ok bool - for _, code := range okc { - if resp.StatusCode == code { - ok = true - break - } - } - - if !ok { - body, _ := ioutil.ReadAll(resp.Body) - resp.Body.Close() - respErr := ErrUnexpectedResponseCode{ - URL: url, - Method: method, - Expected: options.OkCodes, - Actual: resp.StatusCode, - Body: body, - } - - errType := options.ErrorContext - switch resp.StatusCode { - case http.StatusBadRequest: - err = ErrDefault400{respErr} - if error400er, ok := errType.(Err400er); ok { - err = error400er.Error400(respErr) - } - case http.StatusUnauthorized: - if client.ReauthFunc != nil { - err = client.Reauthenticate(prereqtok) - if err != nil { - e := &ErrUnableToReauthenticate{} - e.ErrOriginal = respErr - return nil, e - } - if options.RawBody != nil { - if seeker, ok := options.RawBody.(io.Seeker); ok { - seeker.Seek(0, 0) - } - } - resp, err = client.Request(method, url, options) - if err != nil { - switch err.(type) { - case *ErrUnexpectedResponseCode: - e := &ErrErrorAfterReauthentication{} - e.ErrOriginal = err.(*ErrUnexpectedResponseCode) - return nil, e - default: - e := &ErrErrorAfterReauthentication{} - e.ErrOriginal = err - return nil, e - } - } - return resp, nil - } - err = ErrDefault401{respErr} - if error401er, ok := errType.(Err401er); ok { - err = error401er.Error401(respErr) - } - case http.StatusForbidden: - err = ErrDefault403{respErr} - if error403er, ok := errType.(Err403er); ok { - err = error403er.Error403(respErr) - } - case http.StatusNotFound: - err = ErrDefault404{respErr} - if error404er, ok := errType.(Err404er); ok { - err = error404er.Error404(respErr) - } - case http.StatusMethodNotAllowed: - err = ErrDefault405{respErr} - if error405er, ok := errType.(Err405er); ok { - err = error405er.Error405(respErr) - } - case http.StatusRequestTimeout: - err = ErrDefault408{respErr} - if error408er, ok := errType.(Err408er); ok { - err = error408er.Error408(respErr) - } - case http.StatusConflict: - err = ErrDefault409{respErr} - if error409er, ok := errType.(Err409er); ok { - err = error409er.Error409(respErr) - } - case 429: - err = ErrDefault429{respErr} - if error429er, ok := errType.(Err429er); ok { - err = error429er.Error429(respErr) - } - case http.StatusInternalServerError: - err = ErrDefault500{respErr} - if error500er, ok := errType.(Err500er); ok { - err = error500er.Error500(respErr) - } - case http.StatusServiceUnavailable: - err = ErrDefault503{respErr} - if error503er, ok := errType.(Err503er); ok { - err = error503er.Error503(respErr) - } - } - - if err == nil { - err = respErr - } - - return resp, err - } - - // Parse the response body as JSON, if requested to do so. - if options.JSONResponse != nil { - defer resp.Body.Close() - if err := json.NewDecoder(resp.Body).Decode(options.JSONResponse); err != nil { - return nil, err - } - } - - return resp, nil -} - -func defaultOkCodes(method string) []int { - switch { - case method == "GET": - return []int{200} - case method == "POST": - return []int{201, 202} - case method == "PUT": - return []int{201, 202} - case method == "PATCH": - return []int{200, 202, 204} - case method == "DELETE": - return []int{202, 204} - } - - return []int{} -} diff --git a/vendor/github.com/gophercloud/gophercloud/results.go b/vendor/github.com/gophercloud/gophercloud/results.go deleted file mode 100644 index 94a16bff0b4..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/results.go +++ /dev/null @@ -1,448 +0,0 @@ -package gophercloud - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "reflect" - "strconv" - "time" -) - -/* -Result is an internal type to be used by individual resource packages, but its -methods will be available on a wide variety of user-facing embedding types. - -It acts as a base struct that other Result types, returned from request -functions, can embed for convenience. All Results capture basic information -from the HTTP transaction that was performed, including the response body, -HTTP headers, and any errors that happened. - -Generally, each Result type will have an Extract method that can be used to -further interpret the result's payload in a specific context. Extensions or -providers can then provide additional extraction functions to pull out -provider- or extension-specific information as well. -*/ -type Result struct { - // Body is the payload of the HTTP response from the server. In most cases, - // this will be the deserialized JSON structure. - Body interface{} - - // Header contains the HTTP header structure from the original response. - Header http.Header - - // Err is an error that occurred during the operation. It's deferred until - // extraction to make it easier to chain the Extract call. - Err error -} - -// ExtractInto allows users to provide an object into which `Extract` will extract -// the `Result.Body`. This would be useful for OpenStack providers that have -// different fields in the response object than OpenStack proper. -func (r Result) ExtractInto(to interface{}) error { - if r.Err != nil { - return r.Err - } - - if reader, ok := r.Body.(io.Reader); ok { - if readCloser, ok := reader.(io.Closer); ok { - defer readCloser.Close() - } - return json.NewDecoder(reader).Decode(to) - } - - b, err := json.Marshal(r.Body) - if err != nil { - return err - } - err = json.Unmarshal(b, to) - - return err -} - -func (r Result) extractIntoPtr(to interface{}, label string) error { - if label == "" { - return r.ExtractInto(&to) - } - - var m map[string]interface{} - err := r.ExtractInto(&m) - if err != nil { - return err - } - - b, err := json.Marshal(m[label]) - if err != nil { - return err - } - - toValue := reflect.ValueOf(to) - if toValue.Kind() == reflect.Ptr { - toValue = toValue.Elem() - } - - switch toValue.Kind() { - case reflect.Slice: - typeOfV := toValue.Type().Elem() - if typeOfV.Kind() == reflect.Struct { - if typeOfV.NumField() > 0 && typeOfV.Field(0).Anonymous { - newSlice := reflect.MakeSlice(reflect.SliceOf(typeOfV), 0, 0) - - if mSlice, ok := m[label].([]interface{}); ok { - for _, v := range mSlice { - // For each iteration of the slice, we create a new struct. - // This is to work around a bug where elements of a slice - // are reused and not overwritten when the same copy of the - // struct is used: - // - // https://github.com/golang/go/issues/21092 - // https://github.com/golang/go/issues/24155 - // https://play.golang.org/p/NHo3ywlPZli - newType := reflect.New(typeOfV).Elem() - - b, err := json.Marshal(v) - if err != nil { - return err - } - - // This is needed for structs with an UnmarshalJSON method. - // Technically this is just unmarshalling the response into - // a struct that is never used, but it's good enough to - // trigger the UnmarshalJSON method. - for i := 0; i < newType.NumField(); i++ { - s := newType.Field(i).Addr().Interface() - - // Unmarshal is used rather than NewDecoder to also work - // around the above-mentioned bug. - err = json.Unmarshal(b, s) - if err != nil { - return err - } - } - - newSlice = reflect.Append(newSlice, newType) - } - } - - // "to" should now be properly modeled to receive the - // JSON response body and unmarshal into all the correct - // fields of the struct or composed extension struct - // at the end of this method. - toValue.Set(newSlice) - } - } - case reflect.Struct: - typeOfV := toValue.Type() - if typeOfV.NumField() > 0 && typeOfV.Field(0).Anonymous { - for i := 0; i < toValue.NumField(); i++ { - toField := toValue.Field(i) - if toField.Kind() == reflect.Struct { - s := toField.Addr().Interface() - err = json.NewDecoder(bytes.NewReader(b)).Decode(s) - if err != nil { - return err - } - } - } - } - } - - err = json.Unmarshal(b, &to) - return err -} - -// ExtractIntoStructPtr will unmarshal the Result (r) into the provided -// interface{} (to). -// -// NOTE: For internal use only -// -// `to` must be a pointer to an underlying struct type -// -// If provided, `label` will be filtered out of the response -// body prior to `r` being unmarshalled into `to`. -func (r Result) ExtractIntoStructPtr(to interface{}, label string) error { - if r.Err != nil { - return r.Err - } - - t := reflect.TypeOf(to) - if k := t.Kind(); k != reflect.Ptr { - return fmt.Errorf("Expected pointer, got %v", k) - } - switch t.Elem().Kind() { - case reflect.Struct: - return r.extractIntoPtr(to, label) - default: - return fmt.Errorf("Expected pointer to struct, got: %v", t) - } -} - -// ExtractIntoSlicePtr will unmarshal the Result (r) into the provided -// interface{} (to). -// -// NOTE: For internal use only -// -// `to` must be a pointer to an underlying slice type -// -// If provided, `label` will be filtered out of the response -// body prior to `r` being unmarshalled into `to`. -func (r Result) ExtractIntoSlicePtr(to interface{}, label string) error { - if r.Err != nil { - return r.Err - } - - t := reflect.TypeOf(to) - if k := t.Kind(); k != reflect.Ptr { - return fmt.Errorf("Expected pointer, got %v", k) - } - switch t.Elem().Kind() { - case reflect.Slice: - return r.extractIntoPtr(to, label) - default: - return fmt.Errorf("Expected pointer to slice, got: %v", t) - } -} - -// PrettyPrintJSON creates a string containing the full response body as -// pretty-printed JSON. It's useful for capturing test fixtures and for -// debugging extraction bugs. If you include its output in an issue related to -// a buggy extraction function, we will all love you forever. -func (r Result) PrettyPrintJSON() string { - pretty, err := json.MarshalIndent(r.Body, "", " ") - if err != nil { - panic(err.Error()) - } - return string(pretty) -} - -// ErrResult is an internal type to be used by individual resource packages, but -// its methods will be available on a wide variety of user-facing embedding -// types. -// -// It represents results that only contain a potential error and -// nothing else. Usually, if the operation executed successfully, the Err field -// will be nil; otherwise it will be stocked with a relevant error. Use the -// ExtractErr method -// to cleanly pull it out. -type ErrResult struct { - Result -} - -// ExtractErr is a function that extracts error information, or nil, from a result. -func (r ErrResult) ExtractErr() error { - return r.Err -} - -/* -HeaderResult is an internal type to be used by individual resource packages, but -its methods will be available on a wide variety of user-facing embedding types. - -It represents a result that only contains an error (possibly nil) and an -http.Header. This is used, for example, by the objectstorage packages in -openstack, because most of the operations don't return response bodies, but do -have relevant information in headers. -*/ -type HeaderResult struct { - Result -} - -// ExtractInto allows users to provide an object into which `Extract` will -// extract the http.Header headers of the result. -func (r HeaderResult) ExtractInto(to interface{}) error { - if r.Err != nil { - return r.Err - } - - tmpHeaderMap := map[string]string{} - for k, v := range r.Header { - if len(v) > 0 { - tmpHeaderMap[k] = v[0] - } - } - - b, err := json.Marshal(tmpHeaderMap) - if err != nil { - return err - } - err = json.Unmarshal(b, to) - - return err -} - -// RFC3339Milli describes a common time format used by some API responses. -const RFC3339Milli = "2006-01-02T15:04:05.999999Z" - -type JSONRFC3339Milli time.Time - -func (jt *JSONRFC3339Milli) UnmarshalJSON(data []byte) error { - b := bytes.NewBuffer(data) - dec := json.NewDecoder(b) - var s string - if err := dec.Decode(&s); err != nil { - return err - } - t, err := time.Parse(RFC3339Milli, s) - if err != nil { - return err - } - *jt = JSONRFC3339Milli(t) - return nil -} - -const RFC3339MilliNoZ = "2006-01-02T15:04:05.999999" - -type JSONRFC3339MilliNoZ time.Time - -func (jt *JSONRFC3339MilliNoZ) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - if s == "" { - return nil - } - t, err := time.Parse(RFC3339MilliNoZ, s) - if err != nil { - return err - } - *jt = JSONRFC3339MilliNoZ(t) - return nil -} - -type JSONRFC1123 time.Time - -func (jt *JSONRFC1123) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - if s == "" { - return nil - } - t, err := time.Parse(time.RFC1123, s) - if err != nil { - return err - } - *jt = JSONRFC1123(t) - return nil -} - -type JSONUnix time.Time - -func (jt *JSONUnix) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - if s == "" { - return nil - } - unix, err := strconv.ParseInt(s, 10, 64) - if err != nil { - return err - } - t = time.Unix(unix, 0) - *jt = JSONUnix(t) - return nil -} - -// RFC3339NoZ is the time format used in Heat (Orchestration). -const RFC3339NoZ = "2006-01-02T15:04:05" - -type JSONRFC3339NoZ time.Time - -func (jt *JSONRFC3339NoZ) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - if s == "" { - return nil - } - t, err := time.Parse(RFC3339NoZ, s) - if err != nil { - return err - } - *jt = JSONRFC3339NoZ(t) - return nil -} - -// RFC3339ZNoT is the time format used in Zun (Containers Service). -const RFC3339ZNoT = "2006-01-02 15:04:05-07:00" - -type JSONRFC3339ZNoT time.Time - -func (jt *JSONRFC3339ZNoT) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - if s == "" { - return nil - } - t, err := time.Parse(RFC3339ZNoT, s) - if err != nil { - return err - } - *jt = JSONRFC3339ZNoT(t) - return nil -} - -// RFC3339ZNoTNoZ is another time format used in Zun (Containers Service). -const RFC3339ZNoTNoZ = "2006-01-02 15:04:05" - -type JSONRFC3339ZNoTNoZ time.Time - -func (jt *JSONRFC3339ZNoTNoZ) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - if s == "" { - return nil - } - t, err := time.Parse(RFC3339ZNoTNoZ, s) - if err != nil { - return err - } - *jt = JSONRFC3339ZNoTNoZ(t) - return nil -} - -/* -Link is an internal type to be used in packages of collection resources that are -paginated in a certain way. - -It's a response substructure common to many paginated collection results that is -used to point to related pages. Usually, the one we care about is the one with -Rel field set to "next". -*/ -type Link struct { - Href string `json:"href"` - Rel string `json:"rel"` -} - -/* -ExtractNextURL is an internal function useful for packages of collection -resources that are paginated in a certain way. - -It attempts to extract the "next" URL from slice of Link structs, or -"" if no such URL is present. -*/ -func ExtractNextURL(links []Link) (string, error) { - var url string - - for _, l := range links { - if l.Rel == "next" { - url = l.Href - } - } - - if url == "" { - return "", nil - } - - return url, nil -} diff --git a/vendor/github.com/gophercloud/gophercloud/service_client.go b/vendor/github.com/gophercloud/gophercloud/service_client.go deleted file mode 100644 index f222f05a66d..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/service_client.go +++ /dev/null @@ -1,154 +0,0 @@ -package gophercloud - -import ( - "io" - "net/http" - "strings" -) - -// ServiceClient stores details required to interact with a specific service API implemented by a provider. -// Generally, you'll acquire these by calling the appropriate `New` method on a ProviderClient. -type ServiceClient struct { - // ProviderClient is a reference to the provider that implements this service. - *ProviderClient - - // Endpoint is the base URL of the service's API, acquired from a service catalog. - // It MUST end with a /. - Endpoint string - - // ResourceBase is the base URL shared by the resources within a service's API. It should include - // the API version and, like Endpoint, MUST end with a / if set. If not set, the Endpoint is used - // as-is, instead. - ResourceBase string - - // This is the service client type (e.g. compute, sharev2). - // NOTE: FOR INTERNAL USE ONLY. DO NOT SET. GOPHERCLOUD WILL SET THIS. - // It is only exported because it gets set in a different package. - Type string - - // The microversion of the service to use. Set this to use a particular microversion. - Microversion string - - // MoreHeaders allows users (or Gophercloud) to set service-wide headers on requests. Put another way, - // values set in this field will be set on all the HTTP requests the service client sends. - MoreHeaders map[string]string -} - -// ResourceBaseURL returns the base URL of any resources used by this service. It MUST end with a /. -func (client *ServiceClient) ResourceBaseURL() string { - if client.ResourceBase != "" { - return client.ResourceBase - } - return client.Endpoint -} - -// ServiceURL constructs a URL for a resource belonging to this provider. -func (client *ServiceClient) ServiceURL(parts ...string) string { - return client.ResourceBaseURL() + strings.Join(parts, "/") -} - -func (client *ServiceClient) initReqOpts(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) { - if v, ok := (JSONBody).(io.Reader); ok { - opts.RawBody = v - } else if JSONBody != nil { - opts.JSONBody = JSONBody - } - - if JSONResponse != nil { - opts.JSONResponse = JSONResponse - } - - if opts.MoreHeaders == nil { - opts.MoreHeaders = make(map[string]string) - } - - if client.Microversion != "" { - client.setMicroversionHeader(opts) - } -} - -// Get calls `Request` with the "GET" HTTP verb. -func (client *ServiceClient) Get(url string, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) { - if opts == nil { - opts = new(RequestOpts) - } - client.initReqOpts(url, nil, JSONResponse, opts) - return client.Request("GET", url, opts) -} - -// Post calls `Request` with the "POST" HTTP verb. -func (client *ServiceClient) Post(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) { - if opts == nil { - opts = new(RequestOpts) - } - client.initReqOpts(url, JSONBody, JSONResponse, opts) - return client.Request("POST", url, opts) -} - -// Put calls `Request` with the "PUT" HTTP verb. -func (client *ServiceClient) Put(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) { - if opts == nil { - opts = new(RequestOpts) - } - client.initReqOpts(url, JSONBody, JSONResponse, opts) - return client.Request("PUT", url, opts) -} - -// Patch calls `Request` with the "PATCH" HTTP verb. -func (client *ServiceClient) Patch(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) { - if opts == nil { - opts = new(RequestOpts) - } - client.initReqOpts(url, JSONBody, JSONResponse, opts) - return client.Request("PATCH", url, opts) -} - -// Delete calls `Request` with the "DELETE" HTTP verb. -func (client *ServiceClient) Delete(url string, opts *RequestOpts) (*http.Response, error) { - if opts == nil { - opts = new(RequestOpts) - } - client.initReqOpts(url, nil, nil, opts) - return client.Request("DELETE", url, opts) -} - -// Head calls `Request` with the "HEAD" HTTP verb. -func (client *ServiceClient) Head(url string, opts *RequestOpts) (*http.Response, error) { - if opts == nil { - opts = new(RequestOpts) - } - client.initReqOpts(url, nil, nil, opts) - return client.Request("HEAD", url, opts) -} - -func (client *ServiceClient) setMicroversionHeader(opts *RequestOpts) { - switch client.Type { - case "compute": - 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 - case "baremetal": - opts.MoreHeaders["X-OpenStack-Ironic-API-Version"] = client.Microversion - case "baremetal-introspection": - opts.MoreHeaders["X-OpenStack-Ironic-Inspector-API-Version"] = client.Microversion - } - - if client.Type != "" { - opts.MoreHeaders["OpenStack-API-Version"] = client.Type + " " + client.Microversion - } -} - -// Request carries out the HTTP operation for the service client -func (client *ServiceClient) Request(method, url string, options *RequestOpts) (*http.Response, error) { - if len(client.MoreHeaders) > 0 { - if options == nil { - options = new(RequestOpts) - } - for k, v := range client.MoreHeaders { - options.MoreHeaders[k] = v - } - } - return client.ProviderClient.Request(method, url, options) -} diff --git a/vendor/github.com/gophercloud/gophercloud/util.go b/vendor/github.com/gophercloud/gophercloud/util.go deleted file mode 100644 index 68f9a5d3eca..00000000000 --- a/vendor/github.com/gophercloud/gophercloud/util.go +++ /dev/null @@ -1,102 +0,0 @@ -package gophercloud - -import ( - "fmt" - "net/url" - "path/filepath" - "strings" - "time" -) - -// WaitFor polls a predicate function, once per second, up to a timeout limit. -// This is useful to wait for a resource to transition to a certain state. -// To handle situations when the predicate might hang indefinitely, the -// predicate will be prematurely cancelled after the timeout. -// Resource packages will wrap this in a more convenient function that's -// specific to a certain resource, but it can also be useful on its own. -func WaitFor(timeout int, predicate func() (bool, error)) error { - type WaitForResult struct { - Success bool - Error error - } - - start := time.Now().Unix() - - for { - // If a timeout is set, and that's been exceeded, shut it down. - if timeout >= 0 && time.Now().Unix()-start >= int64(timeout) { - return fmt.Errorf("A timeout occurred") - } - - time.Sleep(1 * time.Second) - - var result WaitForResult - ch := make(chan bool, 1) - go func() { - defer close(ch) - satisfied, err := predicate() - result.Success = satisfied - result.Error = err - }() - - select { - case <-ch: - if result.Error != nil { - return result.Error - } - if result.Success { - return nil - } - // If the predicate has not finished by the timeout, cancel it. - case <-time.After(time.Duration(timeout) * time.Second): - return fmt.Errorf("A timeout occurred") - } - } -} - -// NormalizeURL is an internal function to be used by provider clients. -// -// It ensures that each endpoint URL has a closing `/`, as expected by -// ServiceClient's methods. -func NormalizeURL(url string) string { - if !strings.HasSuffix(url, "/") { - return url + "/" - } - return url -} - -// NormalizePathURL is used to convert rawPath to a fqdn, using basePath as -// a reference in the filesystem, if necessary. basePath is assumed to contain -// either '.' when first used, or the file:// type fqdn of the parent resource. -// e.g. myFavScript.yaml => file://opt/lib/myFavScript.yaml -func NormalizePathURL(basePath, rawPath string) (string, error) { - u, err := url.Parse(rawPath) - if err != nil { - return "", err - } - // if a scheme is defined, it must be a fqdn already - if u.Scheme != "" { - return u.String(), nil - } - // if basePath is a url, then child resources are assumed to be relative to it - bu, err := url.Parse(basePath) - if err != nil { - return "", err - } - var basePathSys, absPathSys string - if bu.Scheme != "" { - basePathSys = filepath.FromSlash(bu.Path) - absPathSys = filepath.Join(basePathSys, rawPath) - bu.Path = filepath.ToSlash(absPathSys) - return bu.String(), nil - } - - absPathSys = filepath.Join(basePath, rawPath) - u.Path = filepath.ToSlash(absPathSys) - if err != nil { - return "", err - } - u.Scheme = "file" - return u.String(), nil - -} diff --git a/vendor/modules.txt b/vendor/modules.txt index f8f4d979023..37012e648e5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -463,39 +463,6 @@ github.com/google/uuid github.com/googleapis/gax-go/v2 github.com/googleapis/gax-go/v2/apierror github.com/googleapis/gax-go/v2/apierror/internal/proto -# github.com/gophercloud/gophercloud v0.1.0 => github.com/gophercloud/gophercloud v0.1.0 -## explicit -github.com/gophercloud/gophercloud -github.com/gophercloud/gophercloud/openstack -github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions -github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes -github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes -github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes -github.com/gophercloud/gophercloud/openstack/common/extensions -github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces -github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach -github.com/gophercloud/gophercloud/openstack/compute/v2/flavors -github.com/gophercloud/gophercloud/openstack/compute/v2/images -github.com/gophercloud/gophercloud/openstack/compute/v2/servers -github.com/gophercloud/gophercloud/openstack/identity/v2/tenants -github.com/gophercloud/gophercloud/openstack/identity/v2/tokens -github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts -github.com/gophercloud/gophercloud/openstack/identity/v3/tokens -github.com/gophercloud/gophercloud/openstack/networking/v2/extensions -github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external -github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips -github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers -github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies -github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners -github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers -github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors -github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools -github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups -github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules -github.com/gophercloud/gophercloud/openstack/networking/v2/networks -github.com/gophercloud/gophercloud/openstack/networking/v2/ports -github.com/gophercloud/gophercloud/openstack/utils -github.com/gophercloud/gophercloud/pagination # github.com/gorilla/mux v1.8.0 => github.com/gorilla/mux v1.8.0 ## explicit; go 1.12 # github.com/gorilla/websocket v1.4.2 => github.com/gorilla/websocket v1.4.2 @@ -1963,7 +1930,6 @@ k8s.io/client-go/plugin/pkg/client/auth/azure k8s.io/client-go/plugin/pkg/client/auth/exec k8s.io/client-go/plugin/pkg/client/auth/gcp k8s.io/client-go/plugin/pkg/client/auth/oidc -k8s.io/client-go/plugin/pkg/client/auth/openstack k8s.io/client-go/rest k8s.io/client-go/rest/fake k8s.io/client-go/rest/watch @@ -2360,7 +2326,6 @@ k8s.io/legacy-cloud-providers/azure/metrics k8s.io/legacy-cloud-providers/azure/retry k8s.io/legacy-cloud-providers/gce k8s.io/legacy-cloud-providers/gce/gcpcredential -k8s.io/legacy-cloud-providers/openstack k8s.io/legacy-cloud-providers/vsphere k8s.io/legacy-cloud-providers/vsphere/testing k8s.io/legacy-cloud-providers/vsphere/vclib @@ -2697,7 +2662,6 @@ sigs.k8s.io/yaml # github.com/google/shlex => github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 # github.com/google/uuid => github.com/google/uuid v1.1.2 # github.com/googleapis/gax-go/v2 => github.com/googleapis/gax-go/v2 v2.1.1 -# github.com/gophercloud/gophercloud => github.com/gophercloud/gophercloud v0.1.0 # github.com/gopherjs/gopherjs => github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 # github.com/gorilla/mux => github.com/gorilla/mux v1.8.0 # github.com/gorilla/websocket => github.com/gorilla/websocket v1.4.2