mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 18:28:13 +00:00 
			
		
		
		
	Merge pull request #40423 from mkutsevol/feature/openstack_cinder_v1_2_auto
Automatic merge from submit-queue (batch tested with PRs 43681, 40423, 43562, 43008, 43381) Openstack cinder v1/v2/auto API support **What this PR does / why we need it**: It adds support for v2 cinder API + autodetection of available cinder API level (as in LBs). **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #39572 **Special notes for your reviewer**: Based on work by @anguslees. The first two commits are just rebased from https://github.com/kubernetes/kubernetes/pull/36344 which already had a lgtm by @jbeda **Release note**: ``` Add support for v2 cinder API for openstack cloud provider. By default it autodetects the available version. ```
This commit is contained in:
		
							
								
								
									
										10
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							| @@ -1,7 +1,7 @@ | ||||
| { | ||||
| 	"ImportPath": "k8s.io/kubernetes", | ||||
| 	"GoVersion": "go1.7", | ||||
| 	"GodepVersion": "v79", | ||||
| 	"GodepVersion": "v74", | ||||
| 	"Packages": [ | ||||
| 		"github.com/ugorji/go/codec/codecgen", | ||||
| 		"github.com/onsi/ginkgo/ginkgo", | ||||
| @@ -1416,10 +1416,18 @@ | ||||
| 			"ImportPath": "github.com/gophercloud/gophercloud/openstack", | ||||
| 			"Rev": "12f19e5e04d617182cffa5c11f189ef0013b9791" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions", | ||||
| 			"Rev": "12f19e5e04d617182cffa5c11f189ef0013b9791" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes", | ||||
| 			"Rev": "12f19e5e04d617182cffa5c11f189ef0013b9791" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes", | ||||
| 			"Rev": "12f19e5e04d617182cffa5c11f189ef0013b9791" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "github.com/gophercloud/gophercloud/openstack/common/extensions", | ||||
| 			"Rev": "12f19e5e04d617182cffa5c11f189ef0013b9791" | ||||
|   | ||||
							
								
								
									
										398
									
								
								Godeps/LICENSES
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										398
									
								
								Godeps/LICENSES
									
									
									
										generated
									
									
									
								
							| @@ -47689,6 +47689,205 @@ specific language governing permissions and limitations under the License. | ||||
| ================================================================================ | ||||
| 
 | ||||
| 
 | ||||
| ================================================================================ | ||||
| = vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions licensed under: = | ||||
| 
 | ||||
| Copyright 2012-2013 Rackspace, Inc. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||||
| this file except in compliance with the License.  You may obtain a copy of the | ||||
| License at | ||||
| 
 | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software distributed | ||||
| under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR | ||||
| CONDITIONS OF ANY KIND, either express or implied.  See the License for the | ||||
| specific language governing permissions and limitations under the License.                                 | ||||
| 
 | ||||
| ------ | ||||
|   | ||||
| 				Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
| 
 | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
| 
 | ||||
|    1. Definitions. | ||||
| 
 | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
| 
 | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
| 
 | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
| 
 | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
| 
 | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
| 
 | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
| 
 | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
| 
 | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
| 
 | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
| 
 | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
| 
 | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
| 
 | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
| 
 | ||||
|    4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
| 
 | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
| 
 | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
| 
 | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
| 
 | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
| 
 | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
| 
 | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
| 
 | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
| 
 | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
| 
 | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
| 
 | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
| 
 | ||||
|    END OF TERMS AND CONDITIONS | ||||
| 
 | ||||
| = vendor/github.com/gophercloud/gophercloud/LICENSE dd19699707373c2ca31531a659130416  - | ||||
| ================================================================================ | ||||
| 
 | ||||
| 
 | ||||
| ================================================================================ | ||||
| = vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes licensed under: = | ||||
| 
 | ||||
| @@ -47888,6 +48087,205 @@ specific language governing permissions and limitations under the License. | ||||
| ================================================================================ | ||||
| 
 | ||||
| 
 | ||||
| ================================================================================ | ||||
| = vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes licensed under: = | ||||
| 
 | ||||
| Copyright 2012-2013 Rackspace, Inc. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||||
| this file except in compliance with the License.  You may obtain a copy of the | ||||
| License at | ||||
| 
 | ||||
|   http://www.apache.org/licenses/LICENSE-2.0 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software distributed | ||||
| under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR | ||||
| CONDITIONS OF ANY KIND, either express or implied.  See the License for the | ||||
| specific language governing permissions and limitations under the License.                                 | ||||
| 
 | ||||
| ------ | ||||
|   | ||||
| 				Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
| 
 | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
| 
 | ||||
|    1. Definitions. | ||||
| 
 | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
| 
 | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
| 
 | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
| 
 | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
| 
 | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
| 
 | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
| 
 | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
| 
 | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
| 
 | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
| 
 | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
| 
 | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
| 
 | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
| 
 | ||||
|    4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
| 
 | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
| 
 | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
| 
 | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
| 
 | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
| 
 | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
| 
 | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
| 
 | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
| 
 | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
| 
 | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
| 
 | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
| 
 | ||||
|    END OF TERMS AND CONDITIONS | ||||
| 
 | ||||
| = vendor/github.com/gophercloud/gophercloud/LICENSE dd19699707373c2ca31531a659130416  - | ||||
| ================================================================================ | ||||
| 
 | ||||
| 
 | ||||
| ================================================================================ | ||||
| = vendor/github.com/gophercloud/gophercloud/openstack/common/extensions licensed under: = | ||||
| 
 | ||||
|   | ||||
| @@ -29,7 +29,9 @@ go_library( | ||||
|         "//vendor:github.com/golang/glog", | ||||
|         "//vendor:github.com/gophercloud/gophercloud", | ||||
|         "//vendor:github.com/gophercloud/gophercloud/openstack", | ||||
|         "//vendor:github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions", | ||||
|         "//vendor:github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes", | ||||
|         "//vendor:github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes", | ||||
|         "//vendor:github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach", | ||||
|         "//vendor:github.com/gophercloud/gophercloud/openstack/compute/v2/flavors", | ||||
|         "//vendor:github.com/gophercloud/gophercloud/openstack/compute/v2/servers", | ||||
| @@ -72,6 +74,7 @@ go_test( | ||||
|         "//pkg/api/v1:go_default_library", | ||||
|         "//pkg/cloudprovider:go_default_library", | ||||
|         "//vendor:github.com/gophercloud/gophercloud", | ||||
|         "//vendor:github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions", | ||||
|         "//vendor:github.com/gophercloud/gophercloud/openstack/compute/v2/servers", | ||||
|         "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", | ||||
|         "//vendor:k8s.io/apimachinery/pkg/types", | ||||
|   | ||||
| @@ -24,11 +24,13 @@ import ( | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"regexp" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/gophercloud/gophercloud" | ||||
| 	"github.com/gophercloud/gophercloud/openstack" | ||||
| 	apiversions_v1 "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions" | ||||
| 	"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" | ||||
| @@ -89,7 +91,8 @@ type LoadBalancerOpts struct { | ||||
| } | ||||
|  | ||||
| type BlockStorageOpts struct { | ||||
| 	TrustDevicePath bool `gcfg:"trust-device-path"` // See Issue #33128 | ||||
| 	BSVersion       string `gcfg:"bs-version"`        // overrides autodetection. v1 or v2. Defaults to auto | ||||
| 	TrustDevicePath bool   `gcfg:"trust-device-path"` // See Issue #33128 | ||||
| } | ||||
|  | ||||
| type RouterOpts struct { | ||||
| @@ -173,6 +176,7 @@ func readConfig(config io.Reader) (Config, error) { | ||||
| 	var cfg Config | ||||
|  | ||||
| 	// Set default values for config params | ||||
| 	cfg.BlockStorage.BSVersion = "auto" | ||||
| 	cfg.BlockStorage.TrustDevicePath = false | ||||
|  | ||||
| 	err := gcfg.ReadInto(&cfg, config) | ||||
| @@ -535,3 +539,111 @@ func (os *OpenStack) Routes() (cloudprovider.Routes, bool) { | ||||
|  | ||||
| 	return r, true | ||||
| } | ||||
|  | ||||
| // Implementation of sort interface for blockstorage version probing | ||||
| type APIVersionsByID []apiversions_v1.APIVersion | ||||
|  | ||||
| func (apiVersions APIVersionsByID) Len() int { | ||||
| 	return len(apiVersions) | ||||
| } | ||||
|  | ||||
| func (apiVersions APIVersionsByID) Swap(i, j int) { | ||||
| 	apiVersions[i], apiVersions[j] = apiVersions[j], apiVersions[i] | ||||
| } | ||||
|  | ||||
| func (apiVersions APIVersionsByID) Less(i, j int) bool { | ||||
| 	return apiVersions[i].ID > apiVersions[j].ID | ||||
| } | ||||
|  | ||||
| func autoVersionSelector(apiVersion *apiversions_v1.APIVersion) string { | ||||
| 	switch strings.ToLower(apiVersion.ID) { | ||||
| 	case "v2.0": | ||||
| 		return "v2" | ||||
| 	case "v1.0": | ||||
| 		return "v1" | ||||
| 	default: | ||||
| 		return "" | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func doBsApiVersionAutodetect(availableApiVersions []apiversions_v1.APIVersion) string { | ||||
| 	sort.Sort(APIVersionsByID(availableApiVersions)) | ||||
| 	for _, status := range []string{"CURRENT", "SUPPORTED"} { | ||||
| 		for _, version := range availableApiVersions { | ||||
| 			if strings.ToUpper(version.Status) == status { | ||||
| 				if detectedApiVersion := autoVersionSelector(&version); detectedApiVersion != "" { | ||||
| 					glog.V(3).Infof("Blockstorage API version probing has found a suitable %s api version: %s", status, detectedApiVersion) | ||||
| 					return detectedApiVersion | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return "" | ||||
|  | ||||
| } | ||||
|  | ||||
| func (os *OpenStack) volumeService(forceVersion string) (volumeService, error) { | ||||
| 	bsVersion := "" | ||||
| 	if forceVersion == "" { | ||||
| 		bsVersion = os.bsOpts.BSVersion | ||||
| 	} else { | ||||
| 		bsVersion = forceVersion | ||||
| 	} | ||||
|  | ||||
| 	switch bsVersion { | ||||
| 	case "v1": | ||||
| 		sClient, err := openstack.NewBlockStorageV1(os.provider, gophercloud.EndpointOpts{ | ||||
| 			Region: os.region, | ||||
| 		}) | ||||
| 		if err != nil || sClient == nil { | ||||
| 			glog.Errorf("Unable to initialize cinder client for region: %s", os.region) | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return &VolumesV1{sClient, os.bsOpts}, nil | ||||
| 	case "v2": | ||||
| 		sClient, err := openstack.NewBlockStorageV2(os.provider, gophercloud.EndpointOpts{ | ||||
| 			Region: os.region, | ||||
| 		}) | ||||
| 		if err != nil || sClient == nil { | ||||
| 			glog.Errorf("Unable to initialize cinder v2 client for region: %s", os.region) | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return &VolumesV2{sClient, os.bsOpts}, nil | ||||
| 	case "auto": | ||||
| 		sClient, err := openstack.NewBlockStorageV1(os.provider, gophercloud.EndpointOpts{ | ||||
| 			Region: os.region, | ||||
| 		}) | ||||
| 		if err != nil || sClient == nil { | ||||
| 			glog.Errorf("Unable to initialize cinder client for region: %s", os.region) | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		availableApiVersions := []apiversions_v1.APIVersion{} | ||||
| 		err = apiversions_v1.List(sClient).EachPage(func(page pagination.Page) (bool, error) { | ||||
| 			// returning false from this handler stops page iteration, error is propagated to the upper function | ||||
| 			apiversions, err := apiversions_v1.ExtractAPIVersions(page) | ||||
| 			if err != nil { | ||||
| 				glog.Errorf("Unable to extract api versions from page: %v", err) | ||||
| 				return false, err | ||||
| 			} | ||||
| 			availableApiVersions = append(availableApiVersions, apiversions...) | ||||
| 			return true, nil | ||||
| 		}) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			glog.Errorf("Error when retrieving list of supported blockstorage api versions: %v", err) | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if autodetectedVersion := doBsApiVersionAutodetect(availableApiVersions); autodetectedVersion != "" { | ||||
| 			return os.volumeService(autodetectedVersion) | ||||
| 		} else { | ||||
| 			// Nothing suitable found, failed autodetection | ||||
| 			return nil, errors.New("BS API version autodetection failed.") | ||||
| 		} | ||||
|  | ||||
| 	default: | ||||
| 		err_txt := fmt.Sprintf("Config error: unrecognised bs-version \"%v\"", os.bsOpts.BSVersion) | ||||
| 		glog.Warningf(err_txt) | ||||
| 		return nil, errors.New(err_txt) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -17,6 +17,10 @@ limitations under the License. | ||||
| package openstack | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/gophercloud/gophercloud" | ||||
| 	"github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions" | ||||
| 	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
| @@ -24,9 +28,6 @@ import ( | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/gophercloud/gophercloud" | ||||
| 	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers" | ||||
|  | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/apimachinery/pkg/util/rand" | ||||
| 	"k8s.io/kubernetes/pkg/api/v1" | ||||
| @@ -81,7 +82,9 @@ func TestReadConfig(t *testing.T) { | ||||
|  monitor-timeout = 30s | ||||
|  monitor-max-retries = 3 | ||||
|  [BlockStorage] | ||||
|  bs-version = auto | ||||
|  trust-device-path = yes | ||||
|  | ||||
|  `)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Should succeed when a valid config is provided: %s", err) | ||||
| @@ -105,6 +108,9 @@ func TestReadConfig(t *testing.T) { | ||||
| 	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) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestToAuthOptions(t *testing.T) { | ||||
| @@ -385,3 +391,45 @@ func TestVolumes(t *testing.T) { | ||||
| 	t.Logf("Volume (%s) deleted\n", vol) | ||||
|  | ||||
| } | ||||
|  | ||||
| func TestCinderAutoDetectApiVersion(t *testing.T) { | ||||
| 	updated := "" // not relevant to this test, can be set to any value | ||||
| 	status_current := "CURRENT" | ||||
| 	status_supported := "SUPpORTED" // lowercase to test regression resitance if api returns different case | ||||
| 	status_deprecated := "DEPRECATED" | ||||
|  | ||||
| 	var result_version, api_version [4]string | ||||
|  | ||||
| 	for ver := 0; ver <= 3; ver++ { | ||||
| 		api_version[ver] = fmt.Sprintf("v%d.0", ver) | ||||
| 		result_version[ver] = fmt.Sprintf("v%d", ver) | ||||
| 	} | ||||
| 	result_version[0] = "" | ||||
| 	api_current_v1 := apiversions.APIVersion{ID: api_version[1], Status: status_current, Updated: updated} | ||||
| 	api_current_v2 := apiversions.APIVersion{ID: api_version[2], Status: status_current, Updated: updated} | ||||
| 	api_current_v3 := apiversions.APIVersion{ID: api_version[3], Status: status_current, Updated: updated} | ||||
|  | ||||
| 	api_supported_v1 := apiversions.APIVersion{ID: api_version[1], Status: status_supported, Updated: updated} | ||||
| 	api_supported_v2 := apiversions.APIVersion{ID: api_version[2], Status: status_supported, Updated: updated} | ||||
|  | ||||
| 	api_deprecated_v1 := apiversions.APIVersion{ID: api_version[1], Status: status_deprecated, Updated: updated} | ||||
| 	api_deprecated_v2 := apiversions.APIVersion{ID: api_version[2], Status: status_deprecated, Updated: updated} | ||||
|  | ||||
| 	var testCases = []struct { | ||||
| 		test_case     []apiversions.APIVersion | ||||
| 		wanted_result string | ||||
| 	}{ | ||||
| 		{[]apiversions.APIVersion{api_current_v1}, result_version[1]}, | ||||
| 		{[]apiversions.APIVersion{api_current_v2}, result_version[2]}, | ||||
| 		{[]apiversions.APIVersion{api_supported_v1, api_current_v2}, result_version[2]},                     // current always selected | ||||
| 		{[]apiversions.APIVersion{api_current_v1, api_supported_v2}, result_version[1]},                     // current always selected | ||||
| 		{[]apiversions.APIVersion{api_current_v3, api_supported_v2, api_deprecated_v1}, result_version[2]},  // with current v3, but should fall back to v2 | ||||
| 		{[]apiversions.APIVersion{api_current_v3, api_deprecated_v2, api_deprecated_v1}, result_version[0]}, // v3 is not supported | ||||
| 	} | ||||
|  | ||||
| 	for _, suite := range testCases { | ||||
| 		if autodetectedVersion := doBsApiVersionAutodetect(suite.test_case); autodetectedVersion != suite.wanted_result { | ||||
| 			t.Fatalf("Autodetect for suite: %s, failed with result: '%s', wanted '%s'", suite.test_case, autodetectedVersion, suite.wanted_result) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -23,100 +23,96 @@ import ( | ||||
| 	"path" | ||||
| 	"strings" | ||||
|  | ||||
| 	"k8s.io/kubernetes/pkg/volume" | ||||
| 	k8s_volume "k8s.io/kubernetes/pkg/volume" | ||||
|  | ||||
| 	"github.com/gophercloud/gophercloud" | ||||
| 	"github.com/gophercloud/gophercloud/openstack" | ||||
| 	"github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes" | ||||
| 	volumes_v1 "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes" | ||||
| 	volumes_v2 "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes" | ||||
| 	"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach" | ||||
| 	"github.com/gophercloud/gophercloud/pagination" | ||||
|  | ||||
| 	"github.com/golang/glog" | ||||
| ) | ||||
|  | ||||
| // Attaches given cinder volume to the compute running kubelet | ||||
| func (os *OpenStack) AttachDisk(instanceID string, diskName string) (string, error) { | ||||
| 	disk, err := os.getVolume(diskName) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	cClient, err := openstack.NewComputeV2(os.provider, gophercloud.EndpointOpts{ | ||||
| 		Region: os.region, | ||||
| 	}) | ||||
| 	if err != nil || cClient == nil { | ||||
| 		glog.Errorf("Unable to initialize nova client for region: %s", os.region) | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil { | ||||
| 		if instanceID == disk.Attachments[0]["server_id"] { | ||||
| 			glog.V(4).Infof("Disk: %q is already attached to compute: %q", diskName, instanceID) | ||||
| 			return disk.ID, nil | ||||
| 		} | ||||
|  | ||||
| 		glog.V(2).Infof("Disk %q is attached to a different compute (%q), detaching", diskName, disk.Attachments[0]["server_id"]) | ||||
| 		err = os.DetachDisk(fmt.Sprintf("%s", disk.Attachments[0]["server_id"]), diskName) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// add read only flag here if possible spothanis | ||||
| 	_, err = volumeattach.Create(cClient, instanceID, &volumeattach.CreateOpts{ | ||||
| 		VolumeID: disk.ID, | ||||
| 	}).Extract() | ||||
| 	if err != nil { | ||||
| 		glog.Errorf("Failed to attach %s volume to %s compute: %v", diskName, instanceID, err) | ||||
| 		return "", err | ||||
| 	} | ||||
| 	glog.V(2).Infof("Successfully attached %s volume to %s compute", diskName, instanceID) | ||||
| 	return disk.ID, nil | ||||
| type volumeService interface { | ||||
| 	createVolume(opts VolumeCreateOpts) (string, error) | ||||
| 	getVolume(diskName string) (Volume, error) | ||||
| 	deleteVolume(volumeName string) error | ||||
| } | ||||
|  | ||||
| // Detaches given cinder volume from the compute running kubelet | ||||
| func (os *OpenStack) DetachDisk(instanceID string, partialDiskId string) error { | ||||
| 	disk, err := os.getVolume(partialDiskId) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	cClient, err := openstack.NewComputeV2(os.provider, gophercloud.EndpointOpts{ | ||||
| 		Region: os.region, | ||||
| 	}) | ||||
| 	if err != nil || cClient == nil { | ||||
| 		glog.Errorf("Unable to initialize nova client for region: %s", os.region) | ||||
| 		return err | ||||
| 	} | ||||
| 	if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil && instanceID == disk.Attachments[0]["server_id"] { | ||||
| 		// 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, disk.ID).ExtractErr() | ||||
| 		if err != nil { | ||||
| 			glog.Errorf("Failed to delete volume %s from compute %s attached %v", disk.ID, instanceID, err) | ||||
| 			return err | ||||
| 		} | ||||
| 		glog.V(2).Infof("Successfully detached volume: %s from compute: %s", disk.ID, instanceID) | ||||
| 	} else { | ||||
| 		errMsg := fmt.Sprintf("Disk: %s has no attachments or is not attached to compute: %s", disk.Name, instanceID) | ||||
| 		glog.Errorf(errMsg) | ||||
| 		return errors.New(errMsg) | ||||
| 	} | ||||
| 	return nil | ||||
| // Volumes implementation for v1 | ||||
| type VolumesV1 struct { | ||||
| 	blockstorage *gophercloud.ServiceClient | ||||
| 	opts         BlockStorageOpts | ||||
| } | ||||
|  | ||||
| // Takes a partial/full disk id or diskname | ||||
| func (os *OpenStack) getVolume(diskName string) (volumes.Volume, error) { | ||||
| 	sClient, err := openstack.NewBlockStorageV1(os.provider, gophercloud.EndpointOpts{ | ||||
| 		Region: os.region, | ||||
| 	}) | ||||
| // Volumes implementation for v2 | ||||
| type VolumesV2 struct { | ||||
| 	blockstorage *gophercloud.ServiceClient | ||||
| 	opts         BlockStorageOpts | ||||
| } | ||||
|  | ||||
| 	var volume volumes.Volume | ||||
| 	if err != nil || sClient == nil { | ||||
| 		glog.Errorf("Unable to initialize cinder client for region: %s", os.region) | ||||
| 		return volume, err | ||||
| type Volume struct { | ||||
| 	// ID of the instance, to which this volume is attached. "" if not attached | ||||
| 	AttachedServerId string | ||||
| 	// Device file path | ||||
| 	AttachedDevice string | ||||
| 	// Unique identifier for the volume. | ||||
| 	ID string | ||||
| 	// Human-readable display name for the volume. | ||||
| 	Name string | ||||
| 	// Current status of the volume. | ||||
| 	Status string | ||||
| } | ||||
|  | ||||
| type VolumeCreateOpts struct { | ||||
| 	Size         int | ||||
| 	Availability string | ||||
| 	Name         string | ||||
| 	VolumeType   string | ||||
| 	Metadata     map[string]string | ||||
| } | ||||
|  | ||||
| func (volumes *VolumesV1) createVolume(opts VolumeCreateOpts) (string, error) { | ||||
|  | ||||
| 	create_opts := volumes_v1.CreateOpts{ | ||||
| 		Name:         opts.Name, | ||||
| 		Size:         opts.Size, | ||||
| 		VolumeType:   opts.VolumeType, | ||||
| 		Availability: opts.Availability, | ||||
| 		Metadata:     opts.Metadata, | ||||
| 	} | ||||
|  | ||||
| 	err = volumes.List(sClient, nil).EachPage(func(page pagination.Page) (bool, error) { | ||||
| 		vols, err := volumes.ExtractVolumes(page) | ||||
| 	vol, err := volumes_v1.Create(volumes.blockstorage, create_opts).Extract() | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return vol.ID, nil | ||||
| } | ||||
|  | ||||
| func (volumes *VolumesV2) createVolume(opts VolumeCreateOpts) (string, error) { | ||||
|  | ||||
| 	create_opts := 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, create_opts).Extract() | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return vol.ID, nil | ||||
| } | ||||
|  | ||||
| func (volumes *VolumesV1) getVolume(diskName string) (Volume, error) { | ||||
| 	var volume_v1 volumes_v1.Volume | ||||
| 	var volume Volume | ||||
| 	err := volumes_v1.List(volumes.blockstorage, nil).EachPage(func(page pagination.Page) (bool, error) { | ||||
| 		vols, err := volumes_v1.ExtractVolumes(page) | ||||
| 		if err != nil { | ||||
| 			glog.Errorf("Failed to extract volumes: %v", err) | ||||
| 			return false, err | ||||
| @@ -124,35 +120,177 @@ func (os *OpenStack) getVolume(diskName string) (volumes.Volume, error) { | ||||
| 			for _, v := range vols { | ||||
| 				glog.V(4).Infof("%s %s %v", v.ID, v.Name, v.Attachments) | ||||
| 				if v.Name == diskName || strings.Contains(v.ID, diskName) { | ||||
| 					volume = v | ||||
| 					volume_v1 = v | ||||
| 					return true, nil | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		// if it reached here then no disk with the given name was found. | ||||
| 		errmsg := fmt.Sprintf("Unable to find disk: %s in region %s", diskName, os.region) | ||||
| 		errmsg := fmt.Sprintf("Unable to find disk: %s", diskName) | ||||
| 		return false, errors.New(errmsg) | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		glog.Errorf("Error occurred getting volume: %s", diskName) | ||||
| 		return volume, err | ||||
| 	} | ||||
| 	return volume, err | ||||
|  | ||||
| 	volume.ID = volume_v1.ID | ||||
| 	volume.Name = volume_v1.Name | ||||
| 	volume.Status = volume_v1.Status | ||||
|  | ||||
| 	if len(volume_v1.Attachments) > 0 && volume_v1.Attachments[0]["server_id"] != nil { | ||||
| 		volume.AttachedServerId = volume_v1.Attachments[0]["server_id"].(string) | ||||
| 		volume.AttachedDevice = volume_v1.Attachments[0]["device"].(string) | ||||
| 	} | ||||
|  | ||||
| 	return volume, nil | ||||
| } | ||||
|  | ||||
| func (volumes *VolumesV2) getVolume(diskName string) (Volume, error) { | ||||
| 	var volume_v2 volumes_v2.Volume | ||||
| 	var volume Volume | ||||
| 	err := volumes_v2.List(volumes.blockstorage, nil).EachPage(func(page pagination.Page) (bool, error) { | ||||
| 		vols, err := volumes_v2.ExtractVolumes(page) | ||||
| 		if err != nil { | ||||
| 			glog.Errorf("Failed to extract volumes: %v", err) | ||||
| 			return false, err | ||||
| 		} else { | ||||
| 			for _, v := range vols { | ||||
| 				glog.V(4).Infof("%s %s %v", v.ID, v.Name, v.Attachments) | ||||
| 				if v.Name == diskName || strings.Contains(v.ID, diskName) { | ||||
| 					volume_v2 = v | ||||
| 					return true, nil | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		// if it reached here then no disk with the given name was found. | ||||
| 		errmsg := fmt.Sprintf("Unable to find disk: %s", diskName) | ||||
| 		return false, errors.New(errmsg) | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		glog.Errorf("Error occurred getting volume: %s", diskName) | ||||
| 		return volume, err | ||||
| 	} | ||||
|  | ||||
| 	volume.ID = volume_v2.ID | ||||
| 	volume.Name = volume_v2.Name | ||||
| 	volume.Status = volume_v2.Status | ||||
|  | ||||
| 	if len(volume_v2.Attachments) > 0 { | ||||
| 		volume.AttachedServerId = volume_v2.Attachments[0].ServerID | ||||
| 		volume.AttachedDevice = volume_v2.Attachments[0].Device | ||||
| 	} | ||||
|  | ||||
| 	return volume, nil | ||||
| } | ||||
|  | ||||
| func (volumes *VolumesV1) deleteVolume(volumeName string) error { | ||||
|  | ||||
| 	err := volumes_v1.Delete(volumes.blockstorage, volumeName).ExtractErr() | ||||
| 	if err != nil { | ||||
| 		glog.Errorf("Cannot delete volume %s: %v", volumeName, err) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (volumes *VolumesV2) deleteVolume(volumeName string) error { | ||||
| 	err := volumes_v2.Delete(volumes.blockstorage, volumeName).ExtractErr() | ||||
| 	if err != nil { | ||||
| 		glog.Errorf("Cannot delete volume %s: %v", volumeName, err) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // Attaches given cinder volume to the compute running kubelet | ||||
| func (os *OpenStack) AttachDisk(instanceID string, diskName string) (string, error) { | ||||
| 	volume, err := os.getVolume(diskName) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	cClient, err := openstack.NewComputeV2(os.provider, gophercloud.EndpointOpts{ | ||||
| 		Region: os.region, | ||||
| 	}) | ||||
| 	if err != nil || cClient == nil { | ||||
| 		glog.Errorf("Unable to initialize nova client for region: %s", os.region) | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	if volume.AttachedServerId != "" { | ||||
| 		if instanceID == volume.AttachedServerId { | ||||
| 			glog.V(4).Infof("Disk: %q is already attached to compute: %q", diskName, instanceID) | ||||
| 			return volume.ID, nil | ||||
| 		} | ||||
| 		glog.V(2).Infof("Disk %q is attached to a different compute (%q), detaching", diskName, volume.AttachedServerId) | ||||
| 		err = os.DetachDisk(volume.AttachedServerId, diskName) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// add read only flag here if possible spothanis | ||||
| 	_, err = volumeattach.Create(cClient, instanceID, &volumeattach.CreateOpts{ | ||||
| 		VolumeID: volume.ID, | ||||
| 	}).Extract() | ||||
| 	if err != nil { | ||||
| 		glog.Errorf("Failed to attach %s volume to %s compute: %v", diskName, instanceID, err) | ||||
| 		return "", err | ||||
| 	} | ||||
| 	glog.V(2).Infof("Successfully attached %s volume to %s compute", diskName, instanceID) | ||||
| 	return volume.ID, nil | ||||
| } | ||||
|  | ||||
| // Detaches given cinder volume from the compute running kubelet | ||||
| func (os *OpenStack) DetachDisk(instanceID string, partialDiskId string) error { | ||||
| 	volume, err := os.getVolume(partialDiskId) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	cClient, err := openstack.NewComputeV2(os.provider, gophercloud.EndpointOpts{ | ||||
| 		Region: os.region, | ||||
| 	}) | ||||
| 	if err != nil || cClient == nil { | ||||
| 		glog.Errorf("Unable to initialize nova client for region: %s", os.region) | ||||
| 		return err | ||||
| 	} | ||||
| 	if volume.AttachedServerId != instanceID { | ||||
| 		errMsg := fmt.Sprintf("Disk: %s has no attachments or is not attached to compute: %s", volume.Name, instanceID) | ||||
| 		glog.Errorf(errMsg) | ||||
| 		return errors.New(errMsg) | ||||
| 	} else { | ||||
| 		// 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() | ||||
| 		if err != nil { | ||||
| 			glog.Errorf("Failed to delete volume %s from compute %s attached %v", volume.ID, instanceID, err) | ||||
| 			return err | ||||
| 		} | ||||
| 		glog.V(2).Infof("Successfully detached volume: %s from compute: %s", volume.ID, instanceID) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Takes a partial/full disk id or diskname | ||||
| func (os *OpenStack) getVolume(diskName string) (Volume, error) { | ||||
|  | ||||
| 	volumes, err := os.volumeService("") | ||||
| 	if err != nil || volumes == nil { | ||||
| 		glog.Errorf("Unable to initialize cinder client for region: %s", os.region) | ||||
| 		return Volume{}, err | ||||
| 	} | ||||
|  | ||||
| 	return volumes.getVolume(diskName) | ||||
| } | ||||
|  | ||||
| // Create a volume of given size (in GiB) | ||||
| func (os *OpenStack) CreateVolume(name string, size int, vtype, availability string, tags *map[string]string) (volumeName string, err error) { | ||||
|  | ||||
| 	sClient, err := openstack.NewBlockStorageV1(os.provider, gophercloud.EndpointOpts{ | ||||
| 		Region: os.region, | ||||
| 	}) | ||||
|  | ||||
| 	if err != nil || sClient == nil { | ||||
| 	volumes, err := os.volumeService("") | ||||
| 	if err != nil || volumes == nil { | ||||
| 		glog.Errorf("Unable to initialize cinder client for region: %s", os.region) | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	opts := volumes.CreateOpts{ | ||||
| 	opts := VolumeCreateOpts{ | ||||
| 		Name:         name, | ||||
| 		Size:         size, | ||||
| 		VolumeType:   vtype, | ||||
| @@ -161,13 +299,15 @@ func (os *OpenStack) CreateVolume(name string, size int, vtype, availability str | ||||
| 	if tags != nil { | ||||
| 		opts.Metadata = *tags | ||||
| 	} | ||||
| 	vol, err := volumes.Create(sClient, opts).Extract() | ||||
| 	volume_id, err := volumes.createVolume(opts) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		glog.Errorf("Failed to create a %d GB volume: %v", size, err) | ||||
| 		return "", err | ||||
| 	} | ||||
| 	glog.Infof("Created volume %v", vol.ID) | ||||
| 	return vol.ID, err | ||||
|  | ||||
| 	glog.Infof("Created volume %v", volume_id) | ||||
| 	return volume_id, nil | ||||
| } | ||||
|  | ||||
| // GetDevicePath returns the path of an attached block storage volume, specified by its id. | ||||
| @@ -202,39 +342,38 @@ func (os *OpenStack) DeleteVolume(volumeName string) error { | ||||
| 	} | ||||
| 	if used { | ||||
| 		msg := fmt.Sprintf("Cannot delete the volume %q, it's still attached to a node", volumeName) | ||||
| 		return volume.NewDeletedVolumeInUseError(msg) | ||||
| 		return k8s_volume.NewDeletedVolumeInUseError(msg) | ||||
| 	} | ||||
|  | ||||
| 	sClient, err := openstack.NewBlockStorageV1(os.provider, gophercloud.EndpointOpts{ | ||||
| 		Region: os.region, | ||||
| 	}) | ||||
|  | ||||
| 	if err != nil || sClient == nil { | ||||
| 	volumes, err := os.volumeService("") | ||||
| 	if err != nil || volumes == nil { | ||||
| 		glog.Errorf("Unable to initialize cinder client for region: %s", os.region) | ||||
| 		return err | ||||
| 	} | ||||
| 	err = volumes.Delete(sClient, volumeName).ExtractErr() | ||||
|  | ||||
| 	err = volumes.deleteVolume(volumeName) | ||||
| 	if err != nil { | ||||
| 		glog.Errorf("Cannot delete volume %s: %v", volumeName, err) | ||||
| 	} | ||||
| 	return err | ||||
| 	return nil | ||||
|  | ||||
| } | ||||
|  | ||||
| // Get device path of attached volume to the compute running kubelet, as known by cinder | ||||
| func (os *OpenStack) GetAttachmentDiskPath(instanceID string, diskName 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. | ||||
| 	disk, err := os.getVolume(diskName) | ||||
| 	volume, err := os.getVolume(diskName) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil { | ||||
| 		if instanceID == disk.Attachments[0]["server_id"] { | ||||
| 	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 disk.Attachments[0]["device"].(string), nil | ||||
| 			return volume.AttachedDevice, nil | ||||
| 		} else { | ||||
| 			errMsg := fmt.Sprintf("Disk %q is attached to a different compute: %q, should be detached before proceeding", diskName, disk.Attachments[0]["server_id"]) | ||||
| 			errMsg := fmt.Sprintf("Disk %q is attached to a different compute: %q, should be detached before proceeding", diskName, volume.AttachedServerId) | ||||
| 			glog.Errorf(errMsg) | ||||
| 			return "", errors.New(errMsg) | ||||
| 		} | ||||
| @@ -244,11 +383,12 @@ func (os *OpenStack) GetAttachmentDiskPath(instanceID string, diskName string) ( | ||||
|  | ||||
| // query if a volume is attached to a compute instance | ||||
| func (os *OpenStack) DiskIsAttached(diskName, instanceID string) (bool, error) { | ||||
| 	disk, err := os.getVolume(diskName) | ||||
| 	volume, err := os.getVolume(diskName) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil && instanceID == disk.Attachments[0]["server_id"] { | ||||
|  | ||||
| 	if instanceID == volume.AttachedServerId { | ||||
| 		return true, nil | ||||
| 	} | ||||
| 	return false, nil | ||||
| @@ -258,27 +398,19 @@ func (os *OpenStack) DiskIsAttached(diskName, instanceID string) (bool, error) { | ||||
| func (os *OpenStack) DisksAreAttached(diskNames []string, instanceID string) (map[string]bool, error) { | ||||
| 	attached := make(map[string]bool) | ||||
| 	for _, diskName := range diskNames { | ||||
| 		attached[diskName] = false | ||||
| 	} | ||||
| 	for _, diskName := range diskNames { | ||||
| 		disk, err := os.getVolume(diskName) | ||||
| 		if err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil && instanceID == disk.Attachments[0]["server_id"] { | ||||
| 			attached[diskName] = true | ||||
| 		} | ||||
| 		is_attached, _ := os.DiskIsAttached(diskName, instanceID) | ||||
| 		attached[diskName] = is_attached | ||||
| 	} | ||||
| 	return attached, nil | ||||
| } | ||||
|  | ||||
| // diskIsUsed returns true a disk is attached to any node. | ||||
| func (os *OpenStack) diskIsUsed(diskName string) (bool, error) { | ||||
| 	disk, err := os.getVolume(diskName) | ||||
| 	volume, err := os.getVolume(diskName) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	if len(disk.Attachments) > 0 { | ||||
| 	if volume.AttachedServerId != "" { | ||||
| 		return true, nil | ||||
| 	} | ||||
| 	return false, nil | ||||
|   | ||||
							
								
								
									
										31
									
								
								vendor/BUILD
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								vendor/BUILD
									
									
									
									
										vendored
									
									
								
							| @@ -4160,6 +4160,21 @@ go_library( | ||||
|     ], | ||||
| ) | ||||
|  | ||||
| go_library( | ||||
|     name = "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions", | ||||
|     srcs = [ | ||||
|         "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions/doc.go", | ||||
|         "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions/requests.go", | ||||
|         "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions/results.go", | ||||
|         "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions/urls.go", | ||||
|     ], | ||||
|     tags = ["automanaged"], | ||||
|     deps = [ | ||||
|         "//vendor:github.com/gophercloud/gophercloud", | ||||
|         "//vendor:github.com/gophercloud/gophercloud/pagination", | ||||
|     ], | ||||
| ) | ||||
|  | ||||
| go_library( | ||||
|     name = "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes", | ||||
|     srcs = [ | ||||
| @@ -4176,6 +4191,22 @@ go_library( | ||||
|     ], | ||||
| ) | ||||
|  | ||||
| go_library( | ||||
|     name = "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes", | ||||
|     srcs = [ | ||||
|         "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/doc.go", | ||||
|         "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/requests.go", | ||||
|         "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/results.go", | ||||
|         "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/urls.go", | ||||
|         "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/util.go", | ||||
|     ], | ||||
|     tags = ["automanaged"], | ||||
|     deps = [ | ||||
|         "//vendor:github.com/gophercloud/gophercloud", | ||||
|         "//vendor:github.com/gophercloud/gophercloud/pagination", | ||||
|     ], | ||||
| ) | ||||
|  | ||||
| go_library( | ||||
|     name = "github.com/gophercloud/gophercloud/openstack/common/extensions", | ||||
|     srcs = [ | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| // Package apiversions provides information and interaction with the different | ||||
| // API versions for the OpenStack Block Storage service, code-named Cinder. | ||||
| package apiversions | ||||
							
								
								
									
										20
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions/requests.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions/requests.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| package apiversions | ||||
|  | ||||
| import ( | ||||
| 	"github.com/gophercloud/gophercloud" | ||||
| 	"github.com/gophercloud/gophercloud/pagination" | ||||
| ) | ||||
|  | ||||
| // List lists all the Cinder API versions available to end-users. | ||||
| func List(c *gophercloud.ServiceClient) pagination.Pager { | ||||
| 	return pagination.NewPager(c, listURL(c), func(r pagination.PageResult) pagination.Page { | ||||
| 		return APIVersionPage{pagination.SinglePageBase(r)} | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // Get will retrieve the volume type with the provided ID. To extract the volume | ||||
| // type from the result, call the Extract method on the GetResult. | ||||
| func Get(client *gophercloud.ServiceClient, v string) (r GetResult) { | ||||
| 	_, r.Err = client.Get(getURL(client, v), &r.Body, nil) | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										49
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions/results.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions/results.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| package apiversions | ||||
|  | ||||
| import ( | ||||
| 	"github.com/gophercloud/gophercloud" | ||||
| 	"github.com/gophercloud/gophercloud/pagination" | ||||
| ) | ||||
|  | ||||
| // APIVersion represents an API version for Cinder. | ||||
| type APIVersion struct { | ||||
| 	ID      string `json:"id"`      // unique identifier | ||||
| 	Status  string `json:"status"`  // current status | ||||
| 	Updated string `json:"updated"` // date last updated | ||||
| } | ||||
|  | ||||
| // APIVersionPage is the page returned by a pager when traversing over a | ||||
| // collection of API versions. | ||||
| type APIVersionPage struct { | ||||
| 	pagination.SinglePageBase | ||||
| } | ||||
|  | ||||
| // IsEmpty checks whether an APIVersionPage struct is empty. | ||||
| func (r APIVersionPage) IsEmpty() (bool, error) { | ||||
| 	is, err := ExtractAPIVersions(r) | ||||
| 	return len(is) == 0, err | ||||
| } | ||||
|  | ||||
| // ExtractAPIVersions takes a collection page, extracts all of the elements, | ||||
| // and returns them a slice of APIVersion structs. It is effectively a cast. | ||||
| func ExtractAPIVersions(r pagination.Page) ([]APIVersion, error) { | ||||
| 	var s struct { | ||||
| 		Versions []APIVersion `json:"versions"` | ||||
| 	} | ||||
| 	err := (r.(APIVersionPage)).ExtractInto(&s) | ||||
| 	return s.Versions, err | ||||
| } | ||||
|  | ||||
| // GetResult represents the result of a get operation. | ||||
| type GetResult struct { | ||||
| 	gophercloud.Result | ||||
| } | ||||
|  | ||||
| // Extract is a function that accepts a result and extracts an API version resource. | ||||
| func (r GetResult) Extract() (*APIVersion, error) { | ||||
| 	var s struct { | ||||
| 		Version *APIVersion `json:"version"` | ||||
| 	} | ||||
| 	err := r.ExtractInto(&s) | ||||
| 	return s.Version, err | ||||
| } | ||||
							
								
								
									
										18
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions/urls.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions/urls.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| package apiversions | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
| 	"net/url" | ||||
|  | ||||
| 	"github.com/gophercloud/gophercloud" | ||||
| ) | ||||
|  | ||||
| func getURL(c *gophercloud.ServiceClient, version string) string { | ||||
| 	return c.ServiceURL(strings.TrimRight(version, "/") + "/") | ||||
| } | ||||
|  | ||||
| func listURL(c *gophercloud.ServiceClient) string { | ||||
| 	u, _ := url.Parse(c.ServiceURL("")) | ||||
| 	u.Path = "/" | ||||
| 	return u.String() | ||||
| } | ||||
							
								
								
									
										5
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| // Package volumes provides information and interaction with volumes in the | ||||
| // OpenStack Block Storage service. A volume is a detachable block storage | ||||
| // device, akin to a USB hard drive. It can only be attached to one instance at | ||||
| // a time. | ||||
| package volumes | ||||
							
								
								
									
										182
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/requests.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/requests.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,182 @@ | ||||
| package volumes | ||||
|  | ||||
| import ( | ||||
| 	"github.com/gophercloud/gophercloud" | ||||
| 	"github.com/gophercloud/gophercloud/pagination" | ||||
| ) | ||||
|  | ||||
| // CreateOptsBuilder allows extensions to add additional parameters to the | ||||
| // Create request. | ||||
| type CreateOptsBuilder interface { | ||||
| 	ToVolumeCreateMap() (map[string]interface{}, error) | ||||
| } | ||||
|  | ||||
| // CreateOpts contains options for creating a Volume. This object is passed to | ||||
| // the volumes.Create function. For more information about these parameters, | ||||
| // see the Volume object. | ||||
| type CreateOpts struct { | ||||
| 	// The size of the volume, in GB | ||||
| 	Size int `json:"size" required:"true"` | ||||
| 	// The availability zone | ||||
| 	AvailabilityZone string `json:"availability_zone,omitempty"` | ||||
| 	// ConsistencyGroupID is the ID of a consistency group | ||||
| 	ConsistencyGroupID string `json:"consistencygroup_id,omitempty"` | ||||
| 	// The volume description | ||||
| 	Description string `json:"description,omitempty"` | ||||
| 	// One or more metadata key and value pairs to associate with the volume | ||||
| 	Metadata map[string]string `json:"metadata,omitempty"` | ||||
| 	// The volume name | ||||
| 	Name string `json:"name,omitempty"` | ||||
| 	// the ID of the existing volume snapshot | ||||
| 	SnapshotID string `json:"snapshot_id,omitempty"` | ||||
| 	// SourceReplica is a UUID of an existing volume to replicate with | ||||
| 	SourceReplica string `json:"source_replica,omitempty"` | ||||
| 	// the ID of the existing volume | ||||
| 	SourceVolID string `json:"source_volid,omitempty"` | ||||
| 	// The ID of the image from which you want to create the volume. | ||||
| 	// Required to create a bootable volume. | ||||
| 	ImageID string `json:"imageRef,omitempty"` | ||||
| 	// The associated volume type | ||||
| 	VolumeType string `json:"volume_type,omitempty"` | ||||
| } | ||||
|  | ||||
| // ToVolumeCreateMap assembles a request body based on the contents of a | ||||
| // CreateOpts. | ||||
| func (opts CreateOpts) ToVolumeCreateMap() (map[string]interface{}, error) { | ||||
| 	return gophercloud.BuildRequestBody(opts, "volume") | ||||
| } | ||||
|  | ||||
| // Create will create a new Volume based on the values in CreateOpts. To extract | ||||
| // the Volume object from the response, call the Extract method on the | ||||
| // CreateResult. | ||||
| func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { | ||||
| 	b, err := opts.ToVolumeCreateMap() | ||||
| 	if err != nil { | ||||
| 		r.Err = err | ||||
| 		return | ||||
| 	} | ||||
| 	_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{ | ||||
| 		OkCodes: []int{202}, | ||||
| 	}) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Delete will delete the existing Volume with the provided ID. | ||||
| func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) { | ||||
| 	_, r.Err = client.Delete(deleteURL(client, id), nil) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Get retrieves the Volume with the provided ID. To extract the Volume object | ||||
| // from the response, call the Extract method on the GetResult. | ||||
| func Get(client *gophercloud.ServiceClient, id string) (r GetResult) { | ||||
| 	_, r.Err = client.Get(getURL(client, id), &r.Body, nil) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // ListOptsBuilder allows extensions to add additional parameters to the List | ||||
| // request. | ||||
| type ListOptsBuilder interface { | ||||
| 	ToVolumeListQuery() (string, error) | ||||
| } | ||||
|  | ||||
| // ListOpts holds options for listing Volumes. It is passed to the volumes.List | ||||
| // function. | ||||
| type ListOpts struct { | ||||
| 	// admin-only option. Set it to true to see all tenant volumes. | ||||
| 	AllTenants bool `q:"all_tenants"` | ||||
| 	// List only volumes that contain Metadata. | ||||
| 	Metadata map[string]string `q:"metadata"` | ||||
| 	// List only volumes that have Name as the display name. | ||||
| 	Name string `q:"name"` | ||||
| 	// List only volumes that have a status of Status. | ||||
| 	Status string `q:"status"` | ||||
| } | ||||
|  | ||||
| // ToVolumeListQuery formats a ListOpts into a query string. | ||||
| func (opts ListOpts) ToVolumeListQuery() (string, error) { | ||||
| 	q, err := gophercloud.BuildQueryString(opts) | ||||
| 	return q.String(), err | ||||
| } | ||||
|  | ||||
| // List returns Volumes optionally limited by the conditions provided in ListOpts. | ||||
| func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { | ||||
| 	url := listURL(client) | ||||
| 	if opts != nil { | ||||
| 		query, err := opts.ToVolumeListQuery() | ||||
| 		if err != nil { | ||||
| 			return pagination.Pager{Err: err} | ||||
| 		} | ||||
| 		url += query | ||||
| 	} | ||||
|  | ||||
| 	return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { | ||||
| 		return VolumePage{pagination.SinglePageBase(r)} | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // UpdateOptsBuilder allows extensions to add additional parameters to the | ||||
| // Update request. | ||||
| type UpdateOptsBuilder interface { | ||||
| 	ToVolumeUpdateMap() (map[string]interface{}, error) | ||||
| } | ||||
|  | ||||
| // UpdateOpts contain options for updating an existing Volume. This object is passed | ||||
| // to the volumes.Update function. For more information about the parameters, see | ||||
| // the Volume object. | ||||
| type UpdateOpts struct { | ||||
| 	Name        string            `json:"name,omitempty"` | ||||
| 	Description string            `json:"description,omitempty"` | ||||
| 	Metadata    map[string]string `json:"metadata,omitempty"` | ||||
| } | ||||
|  | ||||
| // ToVolumeUpdateMap assembles a request body based on the contents of an | ||||
| // UpdateOpts. | ||||
| func (opts UpdateOpts) ToVolumeUpdateMap() (map[string]interface{}, error) { | ||||
| 	return gophercloud.BuildRequestBody(opts, "volume") | ||||
| } | ||||
|  | ||||
| // Update will update the Volume with provided information. To extract the updated | ||||
| // Volume from the response, call the Extract method on the UpdateResult. | ||||
| func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { | ||||
| 	b, err := opts.ToVolumeUpdateMap() | ||||
| 	if err != nil { | ||||
| 		r.Err = err | ||||
| 		return | ||||
| 	} | ||||
| 	_, r.Err = client.Put(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ | ||||
| 		OkCodes: []int{200}, | ||||
| 	}) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // IDFromName is a convienience function that returns a server's ID given its name. | ||||
| func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) { | ||||
| 	count := 0 | ||||
| 	id := "" | ||||
| 	pages, err := List(client, nil).AllPages() | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	all, err := ExtractVolumes(pages) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	for _, s := range all { | ||||
| 		if s.Name == name { | ||||
| 			count++ | ||||
| 			id = s.ID | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	switch count { | ||||
| 	case 0: | ||||
| 		return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "volume"} | ||||
| 	case 1: | ||||
| 		return id, nil | ||||
| 	default: | ||||
| 		return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "volume"} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										121
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/results.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/results.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| package volumes | ||||
|  | ||||
| import ( | ||||
| 	"github.com/gophercloud/gophercloud" | ||||
| 	"github.com/gophercloud/gophercloud/pagination" | ||||
| ) | ||||
|  | ||||
| type Attachment struct { | ||||
| 	AttachedAt   gophercloud.JSONRFC3339MilliNoZ `json:"attached_at"` | ||||
| 	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"` | ||||
| } | ||||
|  | ||||
| // 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 gophercloud.JSONRFC3339MilliNoZ `json:"created_at"` | ||||
| 	// The date when this volume was last updated | ||||
| 	UpdatedAt gophercloud.JSONRFC3339MilliNoZ `json:"updated_at"` | ||||
| 	// 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"` | ||||
| } | ||||
|  | ||||
| /* | ||||
| THESE BELONG IN EXTENSIONS: | ||||
| // ReplicationDriverData contains data about the replication driver. | ||||
| ReplicationDriverData string `json:"os-volume-replication:driver_data"` | ||||
| // ReplicationExtendedStatus contains extended status about replication. | ||||
| ReplicationExtendedStatus string `json:"os-volume-replication:extended_status"` | ||||
| // TenantID is the id of the project that owns the volume. | ||||
| TenantID string `json:"os-vol-tenant-attr:tenant_id"` | ||||
| */ | ||||
|  | ||||
| // VolumePage is a pagination.pager that is returned from a call to the List function. | ||||
| type VolumePage struct { | ||||
| 	pagination.SinglePageBase | ||||
| } | ||||
|  | ||||
| // IsEmpty returns true if a ListResult contains no Volumes. | ||||
| func (r VolumePage) IsEmpty() (bool, error) { | ||||
| 	volumes, err := ExtractVolumes(r) | ||||
| 	return len(volumes) == 0, err | ||||
| } | ||||
|  | ||||
| // ExtractVolumes extracts and returns Volumes. It is used while iterating over a volumes.List call. | ||||
| func ExtractVolumes(r pagination.Page) ([]Volume, error) { | ||||
| 	var s struct { | ||||
| 		Volumes []Volume `json:"volumes"` | ||||
| 	} | ||||
| 	err := (r.(VolumePage)).ExtractInto(&s) | ||||
| 	return s.Volumes, 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 struct { | ||||
| 		Volume *Volume `json:"volume"` | ||||
| 	} | ||||
| 	err := r.ExtractInto(&s) | ||||
| 	return s.Volume, 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 | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| } | ||||
							
								
								
									
										23
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/urls.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/urls.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| package volumes | ||||
|  | ||||
| import "github.com/gophercloud/gophercloud" | ||||
|  | ||||
| func createURL(c *gophercloud.ServiceClient) string { | ||||
| 	return c.ServiceURL("volumes") | ||||
| } | ||||
|  | ||||
| func listURL(c *gophercloud.ServiceClient) string { | ||||
| 	return c.ServiceURL("volumes", "detail") | ||||
| } | ||||
|  | ||||
| func deleteURL(c *gophercloud.ServiceClient, id string) string { | ||||
| 	return c.ServiceURL("volumes", id) | ||||
| } | ||||
|  | ||||
| func getURL(c *gophercloud.ServiceClient, id string) string { | ||||
| 	return deleteURL(c, id) | ||||
| } | ||||
|  | ||||
| func updateURL(c *gophercloud.ServiceClient, id string) string { | ||||
| 	return deleteURL(c, id) | ||||
| } | ||||
							
								
								
									
										22
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| package volumes | ||||
|  | ||||
| import ( | ||||
| 	"github.com/gophercloud/gophercloud" | ||||
| ) | ||||
|  | ||||
| // WaitForStatus will continually poll the resource, checking for a particular | ||||
| // status. It will do this for the amount of seconds defined. | ||||
| func WaitForStatus(c *gophercloud.ServiceClient, id, status string, secs int) error { | ||||
| 	return gophercloud.WaitFor(secs, func() (bool, error) { | ||||
| 		current, err := Get(c, id).Extract() | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
|  | ||||
| 		if current.Status == status { | ||||
| 			return true, nil | ||||
| 		} | ||||
|  | ||||
| 		return false, nil | ||||
| 	}) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Kubernetes Submit Queue
					Kubernetes Submit Queue