ruby_vcloud_sdk 0.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. data/README +1 -0
  2. data/Rakefile +50 -0
  3. data/lib/ruby_vcloud_sdk.rb +19 -0
  4. data/lib/ruby_vcloud_sdk/client.rb +899 -0
  5. data/lib/ruby_vcloud_sdk/config.rb +17 -0
  6. data/lib/ruby_vcloud_sdk/connection/connection.rb +163 -0
  7. data/lib/ruby_vcloud_sdk/connection/file_uploader.rb +43 -0
  8. data/lib/ruby_vcloud_sdk/errors.rb +21 -0
  9. data/lib/ruby_vcloud_sdk/ovf_directory.rb +45 -0
  10. data/lib/ruby_vcloud_sdk/util.rb +21 -0
  11. data/lib/ruby_vcloud_sdk/version.rb +3 -0
  12. data/lib/ruby_vcloud_sdk/xml/constants.rb +427 -0
  13. data/lib/ruby_vcloud_sdk/xml/wrapper.rb +242 -0
  14. data/lib/ruby_vcloud_sdk/xml/wrapper_classes.rb +3 -0
  15. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/admin_catalog.rb +20 -0
  16. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/admin_org.rb +15 -0
  17. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/catalog_item.rb +27 -0
  18. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/disk.rb +40 -0
  19. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/disk_attach_or_detach_params.rb +12 -0
  20. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/disk_create_params.rb +47 -0
  21. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/entity.rb +11 -0
  22. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/file.rb +11 -0
  23. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/hard_disk_item_wrapper.rb +50 -0
  24. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/instantiate_vapp_template_params.rb +71 -0
  25. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/ip_scope.rb +55 -0
  26. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/item.rb +32 -0
  27. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/media.rb +53 -0
  28. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/media_insert_or_eject_params.rb +17 -0
  29. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/metadata_value.rb +15 -0
  30. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/network.rb +15 -0
  31. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/network_config.rb +27 -0
  32. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/network_config_section.rb +25 -0
  33. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/network_connection.rb +71 -0
  34. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/network_connection_section.rb +67 -0
  35. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/nic_item_wrapper.rb +91 -0
  36. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/org_network.rb +19 -0
  37. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/org_vdc_network.rb +11 -0
  38. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/session.rb +17 -0
  39. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/task.rb +32 -0
  40. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/upload_vapp_template_params.rb +11 -0
  41. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vapp.rb +55 -0
  42. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vapp_template.rb +19 -0
  43. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vcloud.rb +15 -0
  44. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vdc.rb +54 -0
  45. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vdc_storage_profile.rb +15 -0
  46. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/virtual_hardware_section.rb +68 -0
  47. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vm.rb +179 -0
  48. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminAllocatedExtIpRecord.xml +1 -0
  49. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminCatalog.xml +1 -0
  50. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminCatalogItemRecord.xml +1 -0
  51. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminCatalogRecord.xml +1 -0
  52. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminGroupRecord.xml +1 -0
  53. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminMediaRecord.xml +1 -0
  54. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminOrg.xml +1 -0
  55. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminOrgNetworkRecord.xml +1 -0
  56. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminShadowVmRecord.xml +1 -0
  57. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminTaskRecord.xml +1 -0
  58. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminUserRecord.xml +1 -0
  59. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVAppNetworkRecord.xml +1 -0
  60. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVAppRecord.xml +1 -0
  61. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVAppReference.xml +1 -0
  62. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVAppReferences.xml +1 -0
  63. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVAppTemplateRecord.xml +1 -0
  64. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVdc.xml +1 -0
  65. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVdcRecord.xml +1 -0
  66. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVdcReference.xml +1 -0
  67. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVdcReferences.xml +1 -0
  68. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVmRecord.xml +1 -0
  69. data/lib/ruby_vcloud_sdk/xml/xml_templates/AllEULAsAccepted.xml +1 -0
  70. data/lib/ruby_vcloud_sdk/xml/xml_templates/AllocatedExtIpRecord.xml +1 -0
  71. data/lib/ruby_vcloud_sdk/xml/xml_templates/BlockingTaskRecord.xml +1 -0
  72. data/lib/ruby_vcloud_sdk/xml/xml_templates/BlockingTaskReference.xml +1 -0
  73. data/lib/ruby_vcloud_sdk/xml/xml_templates/BlockingTaskReferences.xml +1 -0
  74. data/lib/ruby_vcloud_sdk/xml/xml_templates/CaptureVAppParams.xml +1 -0
  75. data/lib/ruby_vcloud_sdk/xml/xml_templates/Catalog.xml +1 -0
  76. data/lib/ruby_vcloud_sdk/xml/xml_templates/CatalogItem.xml +1 -0
  77. data/lib/ruby_vcloud_sdk/xml/xml_templates/CatalogItemRecord.xml +1 -0
  78. data/lib/ruby_vcloud_sdk/xml/xml_templates/CatalogItemReference.xml +1 -0
  79. data/lib/ruby_vcloud_sdk/xml/xml_templates/CatalogItemReferences.xml +1 -0
  80. data/lib/ruby_vcloud_sdk/xml/xml_templates/CatalogRecord.xml +1 -0
  81. data/lib/ruby_vcloud_sdk/xml/xml_templates/CatalogReference.xml +1 -0
  82. data/lib/ruby_vcloud_sdk/xml/xml_templates/CatalogReferences.xml +1 -0
  83. data/lib/ruby_vcloud_sdk/xml/xml_templates/CellRecord.xml +1 -0
  84. data/lib/ruby_vcloud_sdk/xml/xml_templates/CloneMediaParams.xml +1 -0
  85. data/lib/ruby_vcloud_sdk/xml/xml_templates/CloneVAppParams.xml +1 -0
  86. data/lib/ruby_vcloud_sdk/xml/xml_templates/CloneVAppTemplateParams.xml +1 -0
  87. data/lib/ruby_vcloud_sdk/xml/xml_templates/ComposeVAppParams.xml +1 -0
  88. data/lib/ruby_vcloud_sdk/xml/xml_templates/ControlAccessParams.xml +1 -0
  89. data/lib/ruby_vcloud_sdk/xml/xml_templates/CustomizationSection.xml +1 -0
  90. data/lib/ruby_vcloud_sdk/xml/xml_templates/DatastoreProviderVdcRelationRecord.xml +1 -0
  91. data/lib/ruby_vcloud_sdk/xml/xml_templates/DatastoreRecord.xml +1 -0
  92. data/lib/ruby_vcloud_sdk/xml/xml_templates/DatastoreReference.xml +1 -0
  93. data/lib/ruby_vcloud_sdk/xml/xml_templates/DatastoreReferences.xml +1 -0
  94. data/lib/ruby_vcloud_sdk/xml/xml_templates/DeployVAppParams.xml +1 -0
  95. data/lib/ruby_vcloud_sdk/xml/xml_templates/DhcpService.xml +1 -0
  96. data/lib/ruby_vcloud_sdk/xml/xml_templates/DiskAttachOrDetachParams.xml +5 -0
  97. data/lib/ruby_vcloud_sdk/xml/xml_templates/DiskCreateParams.xml +9 -0
  98. data/lib/ruby_vcloud_sdk/xml/xml_templates/DvSwitchRecord.xml +1 -0
  99. data/lib/ruby_vcloud_sdk/xml/xml_templates/Entity.xml +1 -0
  100. data/lib/ruby_vcloud_sdk/xml/xml_templates/Error.xml +1 -0
  101. data/lib/ruby_vcloud_sdk/xml/xml_templates/EventRecord.xml +1 -0
  102. data/lib/ruby_vcloud_sdk/xml/xml_templates/ExternalNetwork.xml +1 -0
  103. data/lib/ruby_vcloud_sdk/xml/xml_templates/File.xml +1 -0
  104. data/lib/ruby_vcloud_sdk/xml/xml_templates/FirewallService.xml +1 -0
  105. data/lib/ruby_vcloud_sdk/xml/xml_templates/GeneralOrgSettings.xml +1 -0
  106. data/lib/ruby_vcloud_sdk/xml/xml_templates/Group.xml +1 -0
  107. data/lib/ruby_vcloud_sdk/xml/xml_templates/GroupRecord.xml +1 -0
  108. data/lib/ruby_vcloud_sdk/xml/xml_templates/GroupReference.xml +1 -0
  109. data/lib/ruby_vcloud_sdk/xml/xml_templates/GroupReferences.xml +1 -0
  110. data/lib/ruby_vcloud_sdk/xml/xml_templates/GuestCustomizationSection.xml +1 -0
  111. data/lib/ruby_vcloud_sdk/xml/xml_templates/HostRecord.xml +1 -0
  112. data/lib/ruby_vcloud_sdk/xml/xml_templates/HostReference.xml +1 -0
  113. data/lib/ruby_vcloud_sdk/xml/xml_templates/HostReferences.xml +1 -0
  114. data/lib/ruby_vcloud_sdk/xml/xml_templates/InstantiateOvfParams.xml +1 -0
  115. data/lib/ruby_vcloud_sdk/xml/xml_templates/InstantiateVAppTemplateParams.xml +1 -0
  116. data/lib/ruby_vcloud_sdk/xml/xml_templates/IpScope.xml +12 -0
  117. data/lib/ruby_vcloud_sdk/xml/xml_templates/IpsecVpnLocalPeer.xml +1 -0
  118. data/lib/ruby_vcloud_sdk/xml/xml_templates/IpsecVpnPeer.xml +1 -0
  119. data/lib/ruby_vcloud_sdk/xml/xml_templates/IpsecVpnRemotePeer.xml +1 -0
  120. data/lib/ruby_vcloud_sdk/xml/xml_templates/IpsecVpnService.xml +1 -0
  121. data/lib/ruby_vcloud_sdk/xml/xml_templates/IpsecVpnThirdPartyPeer.xml +1 -0
  122. data/lib/ruby_vcloud_sdk/xml/xml_templates/Item.xml +3 -0
  123. data/lib/ruby_vcloud_sdk/xml/xml_templates/ItemVcd.xml +5 -0
  124. data/lib/ruby_vcloud_sdk/xml/xml_templates/LeaseSettingsSection.xml +1 -0
  125. data/lib/ruby_vcloud_sdk/xml/xml_templates/Link.xml +1 -0
  126. data/lib/ruby_vcloud_sdk/xml/xml_templates/Media.xml +6 -0
  127. data/lib/ruby_vcloud_sdk/xml/xml_templates/MediaInsertOrEjectParams.xml +4 -0
  128. data/lib/ruby_vcloud_sdk/xml/xml_templates/MediaRecord.xml +1 -0
  129. data/lib/ruby_vcloud_sdk/xml/xml_templates/MediaReference.xml +1 -0
  130. data/lib/ruby_vcloud_sdk/xml/xml_templates/MediaReferences.xml +1 -0
  131. data/lib/ruby_vcloud_sdk/xml/xml_templates/Metadata.xml +5 -0
  132. data/lib/ruby_vcloud_sdk/xml/xml_templates/MetadataEntry.xml +7 -0
  133. data/lib/ruby_vcloud_sdk/xml/xml_templates/MetadataValue.xml +8 -0
  134. data/lib/ruby_vcloud_sdk/xml/xml_templates/NatService.xml +1 -0
  135. data/lib/ruby_vcloud_sdk/xml/xml_templates/Network.xml +4 -0
  136. data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkAssignment.xml +1 -0
  137. data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkConfig.xml +21 -0
  138. data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkConfigSection.xml +1 -0
  139. data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkConnection.xml +11 -0
  140. data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkConnectionSection.xml +1 -0
  141. data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkPoolRecord.xml +1 -0
  142. data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkPoolReference.xml +1 -0
  143. data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkPoolReferences.xml +1 -0
  144. data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkRecord.xml +1 -0
  145. data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkReference.xml +1 -0
  146. data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkReferences.xml +1 -0
  147. data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkService.xml +1 -0
  148. data/lib/ruby_vcloud_sdk/xml/xml_templates/Org.xml +1 -0
  149. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgEmailSettings.xml +1 -0
  150. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgList.xml +1 -0
  151. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgNetwork.xml +1 -0
  152. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgNetworkRecord.xml +1 -0
  153. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgNetworkReference.xml +1 -0
  154. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgNetworkReferences.xml +1 -0
  155. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgPasswordPolicySettings.xml +1 -0
  156. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgRecord.xml +1 -0
  157. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgReference.xml +1 -0
  158. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgReferences.xml +1 -0
  159. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgSettings.xml +1 -0
  160. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgVAppTemplateLeaseSettings.xml +1 -0
  161. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgVdcNetwork.xml +1 -0
  162. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgVdcRecord.xml +1 -0
  163. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgVdcReference.xml +1 -0
  164. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgVdcReferences.xml +1 -0
  165. data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgVdcResourcePoolRelationRecord.xml +1 -0
  166. data/lib/ruby_vcloud_sdk/xml/xml_templates/Owner.xml +1 -0
  167. data/lib/ruby_vcloud_sdk/xml/xml_templates/PortgroupRecord.xml +1 -0
  168. data/lib/ruby_vcloud_sdk/xml/xml_templates/ProductSectionList.xml +1 -0
  169. data/lib/ruby_vcloud_sdk/xml/xml_templates/ProviderVdc.xml +1 -0
  170. data/lib/ruby_vcloud_sdk/xml/xml_templates/ProviderVdcResourcePoolRelationRecord.xml +1 -0
  171. data/lib/ruby_vcloud_sdk/xml/xml_templates/PublishCatalogParams.xml +1 -0
  172. data/lib/ruby_vcloud_sdk/xml/xml_templates/QueryList.xml +1 -0
  173. data/lib/ruby_vcloud_sdk/xml/xml_templates/QueryResultRecords.xml +1 -0
  174. data/lib/ruby_vcloud_sdk/xml/xml_templates/RasdItemsList.xml +1 -0
  175. data/lib/ruby_vcloud_sdk/xml/xml_templates/RecomposeVAppParams.xml +1 -0
  176. data/lib/ruby_vcloud_sdk/xml/xml_templates/Record.xml +1 -0
  177. data/lib/ruby_vcloud_sdk/xml/xml_templates/Reference.xml +1 -0
  178. data/lib/ruby_vcloud_sdk/xml/xml_templates/References.xml +1 -0
  179. data/lib/ruby_vcloud_sdk/xml/xml_templates/RelocateParams.xml +1 -0
  180. data/lib/ruby_vcloud_sdk/xml/xml_templates/ResourceEntity.xml +1 -0
  181. data/lib/ruby_vcloud_sdk/xml/xml_templates/ResourcePoolRecord.xml +1 -0
  182. data/lib/ruby_vcloud_sdk/xml/xml_templates/Right.xml +1 -0
  183. data/lib/ruby_vcloud_sdk/xml/xml_templates/RightRecord.xml +1 -0
  184. data/lib/ruby_vcloud_sdk/xml/xml_templates/RightReference.xml +1 -0
  185. data/lib/ruby_vcloud_sdk/xml/xml_templates/RightReferences.xml +1 -0
  186. data/lib/ruby_vcloud_sdk/xml/xml_templates/Role.xml +1 -0
  187. data/lib/ruby_vcloud_sdk/xml/xml_templates/RoleRecord.xml +1 -0
  188. data/lib/ruby_vcloud_sdk/xml/xml_templates/RoleReference.xml +1 -0
  189. data/lib/ruby_vcloud_sdk/xml/xml_templates/RoleReferences.xml +1 -0
  190. data/lib/ruby_vcloud_sdk/xml/xml_templates/RuntimeInfoSection.xml +1 -0
  191. data/lib/ruby_vcloud_sdk/xml/xml_templates/ScreenTicket.xml +1 -0
  192. data/lib/ruby_vcloud_sdk/xml/xml_templates/Session.xml +1 -0
  193. data/lib/ruby_vcloud_sdk/xml/xml_templates/ShadowVMReferences.xml +1 -0
  194. data/lib/ruby_vcloud_sdk/xml/xml_templates/StaticRoutingService.xml +1 -0
  195. data/lib/ruby_vcloud_sdk/xml/xml_templates/StrandedUserRecord.xml +1 -0
  196. data/lib/ruby_vcloud_sdk/xml/xml_templates/Task.xml +0 -0
  197. data/lib/ruby_vcloud_sdk/xml/xml_templates/TaskRecord.xml +1 -0
  198. data/lib/ruby_vcloud_sdk/xml/xml_templates/TaskReference.xml +1 -0
  199. data/lib/ruby_vcloud_sdk/xml/xml_templates/TaskReferences.xml +1 -0
  200. data/lib/ruby_vcloud_sdk/xml/xml_templates/TasksList.xml +1 -0
  201. data/lib/ruby_vcloud_sdk/xml/xml_templates/UndeployVAppParams.xml +1 -0
  202. data/lib/ruby_vcloud_sdk/xml/xml_templates/UploadVAppTemplateParams.xml +1 -0
  203. data/lib/ruby_vcloud_sdk/xml/xml_templates/User.xml +1 -0
  204. data/lib/ruby_vcloud_sdk/xml/xml_templates/UserRecord.xml +1 -0
  205. data/lib/ruby_vcloud_sdk/xml/xml_templates/UserReference.xml +1 -0
  206. data/lib/ruby_vcloud_sdk/xml/xml_templates/UserReferences.xml +1 -0
  207. data/lib/ruby_vcloud_sdk/xml/xml_templates/VApp.xml +1 -0
  208. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppLeaseSettings.xml +1 -0
  209. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppNetwork.xml +1 -0
  210. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppNetworkRecord.xml +1 -0
  211. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppNetworkReference.xml +1 -0
  212. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppNetworkReferences.xml +1 -0
  213. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppOrgNetworkRelationRecord.xml +1 -0
  214. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppOrgNetworkRelationReference.xml +1 -0
  215. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppOrgNetworkRelationReferences.xml +1 -0
  216. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppRecord.xml +1 -0
  217. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppReference.xml +1 -0
  218. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppReferences.xml +1 -0
  219. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppTemplate.xml +1 -0
  220. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppTemplateRecord.xml +1 -0
  221. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppTemplateReference.xml +1 -0
  222. data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppTemplateReferences.xml +1 -0
  223. data/lib/ruby_vcloud_sdk/xml/xml_templates/VCloud.xml +1 -0
  224. data/lib/ruby_vcloud_sdk/xml/xml_templates/VMRecord.xml +1 -0
  225. data/lib/ruby_vcloud_sdk/xml/xml_templates/VMReference.xml +1 -0
  226. data/lib/ruby_vcloud_sdk/xml/xml_templates/VMReferences.xml +1 -0
  227. data/lib/ruby_vcloud_sdk/xml/xml_templates/VMWProviderVdcRecord.xml +1 -0
  228. data/lib/ruby_vcloud_sdk/xml/xml_templates/VMWProviderVdcReference.xml +1 -0
  229. data/lib/ruby_vcloud_sdk/xml/xml_templates/VMWProviderVdcReferences.xml +1 -0
  230. data/lib/ruby_vcloud_sdk/xml/xml_templates/Vdc.xml +1 -0
  231. data/lib/ruby_vcloud_sdk/xml/xml_templates/VdcReferences.xml +1 -0
  232. data/lib/ruby_vcloud_sdk/xml/xml_templates/VdcStorageProfile.xml +1 -0
  233. data/lib/ruby_vcloud_sdk/xml/xml_templates/VirtualCenterRecord.xml +1 -0
  234. data/lib/ruby_vcloud_sdk/xml/xml_templates/VirtualCenterReference.xml +1 -0
  235. data/lib/ruby_vcloud_sdk/xml/xml_templates/VirtualCenterReferences.xml +1 -0
  236. data/lib/ruby_vcloud_sdk/xml/xml_templates/Vm.xml +1 -0
  237. data/lib/ruby_vcloud_sdk/xml/xml_templates/VmPendingQuestion.xml +1 -0
  238. data/lib/ruby_vcloud_sdk/xml/xml_templates/VmQuestionAnswer.xml +1 -0
  239. data/lib/ruby_vcloud_sdk/xml/xml_templates/generate_dictionary.rb +8 -0
  240. data/spec/assets/admin_org_response.xml +75 -0
  241. data/spec/assets/catalog_add_item_response.xml +8 -0
  242. data/spec/assets/catalog_add_vapp_request.xml +5 -0
  243. data/spec/assets/catalog_item_added_response.xml +19 -0
  244. data/spec/assets/catalog_response.xml +19 -0
  245. data/spec/assets/existing_media_busy_response.xml +19 -0
  246. data/spec/assets/existing_media_catalog_item.xml +8 -0
  247. data/spec/assets/existing_media_delete_task_done.xml +6 -0
  248. data/spec/assets/existing_media_done_response.xml +11 -0
  249. data/spec/assets/existing_vapp_resolver_response.xml +3 -0
  250. data/spec/assets/existing_vapp_template_catalog_resolver_response.xml +3 -0
  251. data/spec/assets/existing_vapp_template_instantiate_response.xml +20 -0
  252. data/spec/assets/existing_vapp_template_instantiate_task_error_response.xml +7 -0
  253. data/spec/assets/existing_vapp_template_instantiate_task_start_response.xml +7 -0
  254. data/spec/assets/existing_vapp_template_instantiate_task_success_response.xml +7 -0
  255. data/spec/assets/existing_vapp_template_item_response.xml +8 -0
  256. data/spec/assets/existing_vapp_template_ready_response.xml +79 -0
  257. data/spec/assets/finalize_upload_task_done_response.xml +7 -0
  258. data/spec/assets/finalize_upload_task_response.xml +7 -0
  259. data/spec/assets/indy_disk_attach_request.xml +3 -0
  260. data/spec/assets/indy_disk_attach_task.xml +6 -0
  261. data/spec/assets/indy_disk_attach_task_error.xml +6 -0
  262. data/spec/assets/indy_disk_create_error.xml +1 -0
  263. data/spec/assets/indy_disk_create_request.xml +4 -0
  264. data/spec/assets/indy_disk_create_response.xml +19 -0
  265. data/spec/assets/indy_disk_delete_task.xml +6 -0
  266. data/spec/assets/indy_disk_detach_request.xml +3 -0
  267. data/spec/assets/indy_disk_detach_task.xml +6 -0
  268. data/spec/assets/indy_disk_response.xml +11 -0
  269. data/spec/assets/instantiated_suspended_vapp_response.xml +209 -0
  270. data/spec/assets/instantiated_vapp_delelete_done_task.xml +5 -0
  271. data/spec/assets/instantiated_vapp_delelete_running_task.xml +6 -0
  272. data/spec/assets/instantiated_vapp_network_config_add_network_request.xml +36 -0
  273. data/spec/assets/instantiated_vapp_network_config_modify_network_task_success.xml +6 -0
  274. data/spec/assets/instantiated_vapp_network_config_remove_network_request.xml +6 -0
  275. data/spec/assets/instantiated_vapp_network_config_section_response.xml +17 -0
  276. data/spec/assets/instantiated_vapp_off_response.xml +206 -0
  277. data/spec/assets/instantiated_vapp_on_response.xml +205 -0
  278. data/spec/assets/instantiated_vapp_power_task_running.xml +6 -0
  279. data/spec/assets/instantiated_vapp_power_task_success.xml +6 -0
  280. data/spec/assets/instantiated_vapp_response.xml +205 -0
  281. data/spec/assets/instantiated_vm_change_task_running.xml +6 -0
  282. data/spec/assets/instantiated_vm_change_task_success.xml +6 -0
  283. data/spec/assets/instantiated_vm_cpu_response.xml +11 -0
  284. data/spec/assets/instantiated_vm_insert_media_task_done.xml +6 -0
  285. data/spec/assets/instantiated_vm_memory_response.xml +11 -0
  286. data/spec/assets/instantiated_vm_modify_task_running.xml +6 -0
  287. data/spec/assets/instantiated_vm_modify_task_success.xml +5 -0
  288. data/spec/assets/instantiated_vm_network_section_response.xml +11 -0
  289. data/spec/assets/instantiated_vm_response.xml +149 -0
  290. data/spec/assets/media_add_to_catalog_request.xml +5 -0
  291. data/spec/assets/media_add_to_catalog_response.xml +8 -0
  292. data/spec/assets/media_delete_task_done.xml +6 -0
  293. data/spec/assets/media_upload_pending_response.xml +13 -0
  294. data/spec/assets/media_upload_request.xml +2 -0
  295. data/spec/assets/metadata_set_request.xml +3 -0
  296. data/spec/assets/metadata_set_task_done.xml +6 -0
  297. data/spec/assets/org_network_response.xml +22 -0
  298. data/spec/assets/reconfigure_vm_request.xml +133 -0
  299. data/spec/assets/reconfigure_vm_task.xml +8 -0
  300. data/spec/assets/session.xml +7 -0
  301. data/spec/assets/test-config.yml +38 -0
  302. data/spec/assets/undeploy_params.xml +1 -0
  303. data/spec/assets/vapp_template_catalog_resolver_response.xml +3 -0
  304. data/spec/assets/vapp_template_delelete_done_task.xml +5 -0
  305. data/spec/assets/vapp_template_delelete_running_task.xml +6 -0
  306. data/spec/assets/vapp_template_instantiate_request.xml +8 -0
  307. data/spec/assets/vapp_template_instantiate_with_locality_request.xml +14 -0
  308. data/spec/assets/vapp_template_no_disk_response.xml +27 -0
  309. data/spec/assets/vapp_template_ready_response.xml +79 -0
  310. data/spec/assets/vapp_template_upload_complete.xml +28 -0
  311. data/spec/assets/vapp_template_upload_failed.xml +28 -0
  312. data/spec/assets/vapp_template_upload_request.xml +4 -0
  313. data/spec/assets/vapp_template_upload_response.xml +25 -0
  314. data/spec/assets/vcloud_response.xml +56 -0
  315. data/spec/assets/vdc_response.xml +57 -0
  316. data/spec/spec_helper.rb +107 -0
  317. data/spec/unit/client_response.rb +700 -0
  318. data/spec/unit/client_spec.rb +1152 -0
  319. metadata +498 -0
data/README ADDED
@@ -0,0 +1 @@
1
+ Ruby VCloud SDK is a gem to simplify making vCloud Director API calls.
data/Rakefile ADDED
@@ -0,0 +1,50 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ $:.unshift(File.expand_path("../../rake", __FILE__))
4
+
5
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __FILE__)
6
+
7
+ require "rubygems"
8
+ require "bundler"
9
+ Bundler.setup(:default, :test)
10
+
11
+ require "rake"
12
+ begin
13
+ require "rspec/core/rake_task"
14
+ rescue LoadError
15
+ end
16
+
17
+ require "bundler_task"
18
+ require "ci_task"
19
+
20
+ gem_helper = Bundler::GemHelper.new(Dir.pwd)
21
+
22
+ desc "Build Ruby VCloud Client gem into the pkg directory"
23
+ task "build" do
24
+ gem_helper.build_gem
25
+ end
26
+
27
+ desc "Build and install Ruby VCloud Client into system gems"
28
+ task "install" do
29
+ Rake::Task["bundler:install"].invoke
30
+ gem_helper.install_gem
31
+ end
32
+
33
+ BundlerTask.new
34
+
35
+ if defined?(RSpec)
36
+ namespace :spec do
37
+ desc "Run Unit Tests"
38
+ rspec_task = RSpec::Core::RakeTask.new(:unit) do |t|
39
+ t.pattern = "spec/unit/**/*_spec.rb"
40
+ t.rspec_opts = %w(--format progress --colour)
41
+ end
42
+
43
+ CiTask.new do |task|
44
+ task.rspec_task = rspec_task
45
+ end
46
+ end
47
+
48
+ desc "Install dependencies and run tests"
49
+ task :spec => %w(bundler:install:test spec:unit)
50
+ end
@@ -0,0 +1,19 @@
1
+ $:.unshift(File.expand_path("..", __FILE__))
2
+
3
+ require "rubygems" # Needed for Ruby 1.8
4
+ require "logger"
5
+
6
+ module VCloudSdk; end
7
+
8
+ require "ruby_vcloud_sdk/xml/constants"
9
+ require "ruby_vcloud_sdk/xml/wrapper"
10
+ require "ruby_vcloud_sdk/xml/wrapper_classes"
11
+
12
+ require "ruby_vcloud_sdk/config"
13
+ require "ruby_vcloud_sdk/errors"
14
+ require "ruby_vcloud_sdk/util"
15
+ require "ruby_vcloud_sdk/client"
16
+ require "ruby_vcloud_sdk/ovf_directory"
17
+
18
+ require "ruby_vcloud_sdk/connection/connection"
19
+ require "ruby_vcloud_sdk/connection/file_uploader"
@@ -0,0 +1,899 @@
1
+ require "rest_client" # Need this for the exception classes
2
+ require "set"
3
+
4
+ module VCloudSdk
5
+
6
+ class Client
7
+ attr_reader :ovdc
8
+
9
+ def initialize(url, username, password, entities, control,
10
+ connection = nil)
11
+ @logger = Config.logger
12
+ @url = url
13
+ @organization = entities["organization"]
14
+ @ovdc_name = entities["virtual_datacenter"]
15
+ @vapp_catalog_name = entities["vapp_catalog"]
16
+ @media_catalog_name = entities["media_catalog"]
17
+ @control = control
18
+ @retries = @control["retries"]
19
+ @time_limit = @control["time_limit_sec"]
20
+ construct_rest_logger
21
+ Config.configure({ "rest_logger" => @rest_logger,
22
+ "rest_throttle" => control["rest_throttle"] })
23
+
24
+ if connection
25
+ @connection = connection
26
+ else
27
+ @connection = Connection::Connection.new(@url, @organization,
28
+ @time_limit["http_request"])
29
+ end
30
+ @root = @connection.connect(username, password)
31
+ @admin_root = @connection.get(@root.admin_root)
32
+ @entity_resolver_link = @root.entity_resolver.href
33
+ # We assume the organization does not change often so we can get it at
34
+ # login and cache it
35
+ @admin_org = @connection.get(@admin_root.organization(@organization))
36
+ @logger.info("Successfully connected.")
37
+ end
38
+
39
+ def get_catalog_vapp(id)
40
+ resolve_entity(id)
41
+ end
42
+
43
+ def get_vapp(obj)
44
+ if obj.is_a?(Xml::VApp)
45
+ obj
46
+ elsif obj.is_a?(String)
47
+ resolve_entity(obj)
48
+ else
49
+ raise CloudError, "Expecting Xml::VApp or String, got #{obj.inspect}."
50
+ end
51
+ end
52
+
53
+ def upload_vapp_template(vapp_name, directory)
54
+ ovdc = get_ovdc
55
+ @logger.info("Uploading VM #{vapp_name} to #{ovdc["name"]} in " +
56
+ "organization #{@organization}")
57
+ # if directory behaves like an OVFDirectory, then use it
58
+ is_ovf_directory = [:ovf_file, :ovf_file_path, :vmdk_file,
59
+ :vmdk_file_path].reduce(true) do |present, name|
60
+ present && directory.respond_to?(name)
61
+ end
62
+ ovf_directory = is_ovf_directory ? directory :
63
+ OVFDirectory.new(directory)
64
+ upload_params = Xml::WrapperFactory.create_instance(
65
+ "UploadVAppTemplateParams")
66
+ upload_params.name = vapp_name
67
+ vapp_template = @connection.post(ovdc.upload_link, upload_params)
68
+ catalog_name = @vapp_catalog_name
69
+ vapp_template = upload_vapp_files(vapp_template, ovf_directory)
70
+ raise ObjectNotFoundError, "Error uploading vApp template" unless
71
+ vapp_template
72
+ @logger.info("#{vapp_template.name} has tasks in progress. " +
73
+ "Waiting until done.")
74
+ vapp_template.running_tasks.each do |task|
75
+ monitor_task(task, @time_limit["process_descriptor_vapp_template"])
76
+ end
77
+ err_tasks = @connection.get(vapp_template).tasks.find_all {
78
+ |t| t.status != Xml::TASK_STATUS[:SUCCESS] }
79
+ unless err_tasks.empty?
80
+ @logger.error("Error uploading vApp template. " +
81
+ "Non-successful tasks:#{err_tasks}.")
82
+ raise CloudError, "Error uploading vApp template"
83
+ end
84
+ @logger.info("vApp #{vapp_name} uploaded, adding to " +
85
+ "catalog #{catalog_name}")
86
+ catalog_item = add_catalog_item(vapp_template, catalog_name)
87
+ @logger.info("vApp #{vapp_name} added to catalog " +
88
+ "#{catalog_name} #{catalog_item.to_s}")
89
+ catalog_item
90
+ rescue ApiError => e
91
+ log_exception(e, "Error in uploading vApp template #{vapp_name}")
92
+ rollback_upload_vapp(vapp_template)
93
+ raise e
94
+ end
95
+
96
+ def insert_catalog_media(vm, catalog_media_name)
97
+ catalog_media = get_catalog_media(catalog_media_name)
98
+ media = @connection.get(catalog_media.entity)
99
+ current_vm = @connection.get(vm)
100
+ insert_media(current_vm, media)
101
+ end
102
+
103
+ def eject_catalog_media(vm, catalog_media_name)
104
+ catalog_media = get_catalog_media(catalog_media_name)
105
+ unless catalog_media
106
+ raise CatalogMediaNotFoundError,
107
+ "Catalog media #{catalog_media_name} not found."
108
+ end
109
+ media = @connection.get(catalog_media.entity)
110
+ current_vm = @connection.get(vm)
111
+ eject_media(current_vm, media)
112
+ end
113
+
114
+ def upload_catalog_media(media_name, file, storage_profile = nil,
115
+ image_type = "iso")
116
+ ovdc = get_ovdc
117
+ @logger.info("Uploading media #{media_name} to #{storage_profile}/" +
118
+ "#{ovdc["name"]} in organization #{@organization}")
119
+ catalog_name = @media_catalog_name
120
+ upload_params = Xml::WrapperFactory.create_instance("Media")
121
+ upload_params.name = media_name
122
+ media_file = file.is_a?(String) ? File.new(file, "rb") : file
123
+ upload_params.size = media_file.stat.size
124
+ upload_params.image_type = image_type
125
+ upload_params.storage_profile = storage_profile
126
+ media = @connection.post(ovdc.upload_media_link, upload_params)
127
+ incomplete_file = media.incomplete_files.pop
128
+ @connection.put_file(incomplete_file.upload_link, media_file)
129
+ media = @connection.get(media)
130
+ add_catalog_item(media, catalog_name)
131
+ rescue ArgumentError, ApiError => e
132
+ log_exception(e, "Error uploading media #{media_name}" +
133
+ "to catalog #{catalog_name}. #{e.message}")
134
+ delete_media(media) if media
135
+ raise e
136
+ end
137
+
138
+ def delete_catalog_media(name)
139
+ raise ArgumentError, "Media name cannot be nil." unless name
140
+ catalog_media = get_catalog_media(name)
141
+ if catalog_media
142
+ media = @connection.get(catalog_media.entity)
143
+ delete_media(media)
144
+ @connection.delete(catalog_media)
145
+ end
146
+ rescue RestClient::ResourceNotFound => e
147
+ # Media might be deleted already
148
+ @logger.debug("Catalog media #{name} no longer exists.")
149
+ end
150
+
151
+ def delete_catalog_vapp(id)
152
+ raise ArgumentError, "Catalog ID cannot be nil." unless id
153
+ catalog_vapp = get_catalog_vapp(id)
154
+ if catalog_vapp
155
+ vapp = @connection.get(catalog_vapp.entity)
156
+ delete_vapp_template(vapp)
157
+ @connection.delete(catalog_vapp)
158
+ end
159
+ rescue => e
160
+ # vApp template might be deleted already
161
+ @logger.debug("Catalog vApp #{id} no longer exists.")
162
+ end
163
+
164
+ def delete_vapp(vapp)
165
+ @logger.info("Deleting vApp #{vapp.name}.")
166
+ current_vapp = @connection.get(vapp)
167
+ if is_vapp_status(current_vapp, :POWERED_ON)
168
+ raise CloudError,
169
+ "vApp #{vapp.name} is powered on, power-off before deleting."
170
+ end
171
+ delete_vapp_or_template(current_vapp, @retries["default"],
172
+ @time_limit["delete_vapp"], "vApp")
173
+ end
174
+
175
+ def instantiate_vapp_template(source_template_id, vapp_name,
176
+ description = nil, disk_locality = nil)
177
+ catalog_item = get_catalog_vapp(source_template_id)
178
+ unless catalog_item
179
+ @logger.error("Catalog item with ID #{source_template_id} not " +
180
+ "found in catalog #{@vapp_catalog_name}.")
181
+ raise ObjectNotFoundError, "Item with ID #{source_template_id} " +
182
+ "not found in catalog #{@vapp_catalog_name}."
183
+ end
184
+ src_vapp_template = @connection.get(catalog_item.entity)
185
+ instantiate_vapp_params = Xml::WrapperFactory.create_instance(
186
+ "InstantiateVAppTemplateParams")
187
+ instantiate_vapp_params.name = vapp_name
188
+ instantiate_vapp_params.description = description
189
+ instantiate_vapp_params.source = src_vapp_template
190
+ instantiate_vapp_params.all_eulas_accepted = true
191
+ instantiate_vapp_params.linked_clone = false
192
+ instantiate_vapp_params.set_locality = locality_spec(src_vapp_template,
193
+ disk_locality)
194
+ vdc = get_ovdc
195
+ vapp = @connection.post(vdc.instantiate_vapp_template_link,
196
+ instantiate_vapp_params)
197
+ vapp.running_tasks.each do |task|
198
+ begin
199
+ monitor_task(task, @time_limit["instantiate_vapp_template"])
200
+ rescue ApiError => e
201
+ log_exception(e, "Instantiate vApp template #{vapp_name} failed." +
202
+ " Task #{task.operation} did not complete successfully.")
203
+ delete_vapp(vapp)
204
+ raise e
205
+ end
206
+ end
207
+ @connection.get(vapp)
208
+ end
209
+
210
+ def reconfigure_vm(vm, &b)
211
+ b.call(vm)
212
+ monitor_task(@connection.post("#{vm.reconfigure_link.href}", vm,
213
+ Xml::MEDIA_TYPE[:VM]))
214
+ end
215
+
216
+ def get_metadata(entity, key)
217
+ metadata = @connection.get(generate_metadata_href(entity, key))
218
+ metadata.value
219
+ end
220
+
221
+ def set_metadata(entity, key, value)
222
+ metadata = Xml::WrapperFactory.create_instance("MetadataValue")
223
+ metadata.value = value
224
+ task = @connection.put(generate_metadata_href(entity, key), metadata,
225
+ Xml::MEDIA_TYPE[:METADATA_ITEM_VALUE])
226
+ monitor_task(task)
227
+ end
228
+
229
+ def delete_networks(vapp, exclude_nets = [])
230
+ current_vapp = get_vapp(vapp)
231
+ raise ObjectNotFoundError, "Cannot delete nets, vApp #{vapp.name} no " +
232
+ "longer exists" unless current_vapp
233
+ current = current_vapp.network_config_section.network_configs.map {
234
+ |n| n.network_name }
235
+ nets = current - exclude_nets
236
+ @logger.debug("nets:: current:#{current}, exclude:#{exclude_nets}, " +
237
+ "to delete:#{nets}")
238
+ return if nets.nil? || nets.length == 0
239
+ delete_network(current_vapp, *nets)
240
+ end
241
+
242
+ def add_network(vapp, network, vapp_net_name = nil,
243
+ fence_mode = Xml::FENCE_MODES[:BRIDGED])
244
+ current_network = @connection.get(network)
245
+ raise ObjectNotFoundError, "Cannot add network to vApp #{vapp.name}. " +
246
+ "The network #{network.name} no longer exists." unless current_network
247
+ current_vapp = get_vapp(vapp)
248
+ raise ObjectNotFoundError, "Cannot add network to vApp #{vapp.name}. " +
249
+ "The vApp #{vapp.name} no longer exists." unless current_vapp
250
+ network_config = Xml::WrapperFactory.create_instance("NetworkConfig")
251
+ new_vapp_net_name = vapp_net_name.nil? ?
252
+ current_network["name"] : vapp_net_name
253
+ copy_network_settings(current_network, network_config,
254
+ new_vapp_net_name, fence_mode)
255
+ current_vapp.network_config_section.add_network_config(network_config)
256
+ task = @connection.put(current_vapp.network_config_section,
257
+ current_vapp.network_config_section,
258
+ Xml::MEDIA_TYPE[:NETWORK_CONFIG_SECTION])
259
+ monitor_task(task)
260
+ end
261
+
262
+ # There must be no NICs on the network when it is deleted. Otherwise the
263
+ # task will fail. Use set_nic_network to move NICs onto other network or
264
+ # the NONE network prior to deleting the network from the vApp.
265
+ def delete_network(vapp, *network_names)
266
+ raise ArgumentError, "Must specify a network name to delete." if
267
+ network_names.nil? || network_names.length == 0
268
+ unique_network_names = network_names.uniq
269
+ @logger.info("Delete networks(s) #{unique_network_names.join(" ")} " +
270
+ "from vApp #{vapp.name}")
271
+ current_vapp = get_vapp(vapp)
272
+ unique_network_names.each do |n|
273
+ current_vapp.network_config_section.delete_network_config(n)
274
+ end
275
+ task = @connection.put(current_vapp.network_config_section,
276
+ current_vapp.network_config_section,
277
+ Xml::MEDIA_TYPE[:NETWORK_CONFIG_SECTION])
278
+ monitor_task(task)
279
+ end
280
+
281
+ # Size at creation is in bytes
282
+ # We currently assumes the disk is SCSI and bus sub type LSILOGIC
283
+ def create_disk(name, size_mb, vm = nil, retries = @retries["default"])
284
+ new_disk = Xml::WrapperFactory.create_instance("DiskCreateParams")
285
+ new_disk.name = name
286
+ new_disk.size_bytes = size_mb * 1024 * 1024 # VCD expects bytes
287
+ new_disk.bus_type = Xml::HARDWARE_TYPE[:SCSI_CONTROLLER]
288
+ new_disk.bus_sub_type = Xml::BUS_SUB_TYPE[:LSILOGIC]
289
+ new_disk.add_locality(vm) if vm
290
+ vdc = get_ovdc
291
+ @logger.info("Creating independent disk #{name} of #{size_mb}MB.")
292
+ @logger.info("Disk locality ist set to #{vm.name} #{vm.urn}.") if vm
293
+ disk = @connection.post(vdc.add_disk_link, new_disk,
294
+ Xml::MEDIA_TYPE[:DISK_CREATE_PARAMS])
295
+ raise ApiRequestError unless disk.respond_to?(:running_tasks)
296
+ # Creating a disk returns a disk with tasks inside
297
+ retries.times do |try|
298
+ return disk if disk.running_tasks.nil? || disk.running_tasks.empty?
299
+ @logger.info("Disk #{disk.urn} has running tasks. Waiting for " +
300
+ "tasks to finish. Try: #{try}/#{retries} ." )
301
+ disk.running_tasks.each do |t|
302
+ monitor_task(t)
303
+ end
304
+ disk = @connection.get(disk)
305
+ end
306
+ end
307
+
308
+ def delete_disk(disk)
309
+ current_disk = @connection.get(disk)
310
+ unless current_disk
311
+ @logger.warn("Disk #{disk.name} #{disk.urn} no longer exists.")
312
+ return
313
+ end
314
+ task = @connection.delete(current_disk.delete_link)
315
+ monitor_task(task) do |t|
316
+ @logger.info("Deleted disk #{current_disk.name} #{current_disk.urn}")
317
+ t
318
+ end
319
+ end
320
+
321
+ def attach_disk(disk, vm)
322
+ current_vm = @connection.get(vm)
323
+ raise ObjectNotFoundError, "VM #{vm.name} not found." unless current_vm
324
+
325
+ current_disk = @connection.get(disk)
326
+ unless current_disk
327
+ raise ObjectNotFoundError, "Disk #{disk.name} not found."
328
+ end
329
+
330
+ params = Xml::WrapperFactory.create_instance("DiskAttachOrDetachParams")
331
+ params.disk_href = current_disk.href
332
+ task = @connection.post(current_vm.attach_disk_link, params,
333
+ Xml::MEDIA_TYPE[:DISK_ATTACH_DETACH_PARAMS])
334
+ monitor_task(task) do |t|
335
+ @logger.info("Attached disk #{current_disk.name} to VM " +
336
+ "#{current_vm.name}.")
337
+ t
338
+ end
339
+ end
340
+
341
+ def detach_disk(disk, vm)
342
+ current_vm = @connection.get(vm)
343
+ raise ObjectNotFoundError, "VM #{vm.name} not found." unless current_vm
344
+
345
+ current_disk = @connection.get(disk)
346
+ unless current_disk
347
+ raise ObjectNotFoundError, "Disk #{disk.name} not found."
348
+ end
349
+
350
+ disk_href = current_disk.href
351
+
352
+ if is_vapp_status(current_vm, :SUSPENDED)
353
+ @logger.debug("vApp #{current_vm.name} suspended, discard state " +
354
+ "before detaching disk.")
355
+ raise VmSuspendedError, "discard state first"
356
+ end
357
+
358
+ begin
359
+ get_disk_id(current_vm, disk_href)
360
+ rescue DiskNotFoundError
361
+ @logger.warn("Disk #{current_disk.name} not found on VM " +
362
+ "#{current_vm.name}. No need to detach.")
363
+ return
364
+ end
365
+ params = Xml::WrapperFactory.create_instance("DiskAttachOrDetachParams")
366
+ params.disk_href = disk_href
367
+ task = @connection.post(current_vm.detach_disk_link, params,
368
+ Xml::MEDIA_TYPE[:DISK_ATTACH_DETACH_PARAMS])
369
+ monitor_task(task) do |t|
370
+ @logger.info("Detached disk #{current_disk.name} from VM " +
371
+ "#{current_vm.name}.")
372
+ t
373
+ end
374
+ end
375
+
376
+ def get_disk(disk_id)
377
+ resolve_entity(disk_id)
378
+ end
379
+
380
+ def power_on_vapp(vapp)
381
+ @logger.info("Powering on vApp #{vapp.name} .")
382
+ current_vapp = @connection.get(vapp)
383
+ unless current_vapp
384
+ raise ObjectNotFoundError, "vApp #{vapp.name} not found."
385
+ end
386
+ @logger.debug("vApp status: #{current_vapp["status"]}")
387
+ if is_vapp_status(current_vapp, :POWERED_ON)
388
+ @logger.info("vApp #{vapp.name} already powered-on.")
389
+ return
390
+ end
391
+ unless current_vapp.power_on_link
392
+ raise CloudError, "vApp #{vapp.name} not in a state to be " +
393
+ "powered on."
394
+ end
395
+ task = @connection.post(current_vapp.power_on_link, nil)
396
+ monitor_task(task, @time_limit["power_on"])
397
+ @logger.info("vApp #{current_vapp.name} powered on.")
398
+ task
399
+ end
400
+
401
+ def power_off_vapp(vapp, undeploy = true)
402
+ @logger.info("Powering off vApp #{vapp.name} .")
403
+ @logger.info("Undeploying vApp #{vapp.name} .") if undeploy
404
+ current_vapp = @connection.get(vapp)
405
+ unless current_vapp
406
+ raise ObjectNotFoundError, "vApp #{vapp.name} no longer exists."
407
+ end
408
+ @logger.debug("vApp status: #{current_vapp["status"]}")
409
+
410
+ if is_vapp_status(current_vapp, :SUSPENDED)
411
+ @logger.debug("vApp #{current_vapp.name} suspended, discard state " +
412
+ "before powering off.")
413
+ raise VappSuspendedError, "discard state first"
414
+ end
415
+
416
+ if undeploy
417
+ # Since we do not apparently differentiate between powered-off and
418
+ # undeployed in our status, we should check if the undeploy link is
419
+ # available first. If undeploy is not available and status is
420
+ # powered_off then it is undeployed.
421
+ unless current_vapp.undeploy_link
422
+ if is_vapp_status(current_vapp, :POWERED_OFF)
423
+ @logger.info("vApp #{vapp.name} already powered-off, undeployed.")
424
+ return
425
+ end
426
+ raise CloudError, "vApp #{vapp.name} not in a state be " +
427
+ "powered-off, undeployed."
428
+ end
429
+ params = Xml::WrapperFactory.create_instance("UndeployVAppParams")
430
+ task = @connection.post(current_vapp.undeploy_link, params)
431
+ monitor_task(task, @time_limit["undeploy"])
432
+ @logger.info("vApp #{current_vapp.name} powered-off, undeployed.")
433
+ task
434
+ else
435
+ unless current_vapp.power_off_link
436
+ if is_vapp_status(current_vapp, :POWERED_OFF)
437
+ @logger.info("vApp #{vapp.name} already powered off.")
438
+ return
439
+ end
440
+ raise CloudError, "vApp #{vapp.name} not in a state be powered off."
441
+ end
442
+ task = @connection.post(current_vapp.power_off_link, nil)
443
+ monitor_task(task, @time_limit["power_off"])
444
+ @logger.info("vApp #{current_vapp.name} powered off.")
445
+ task
446
+ end
447
+ end
448
+
449
+ def discard_suspended_state_vapp(vapp)
450
+ @logger.info("Discarding suspended state of vApp #{vapp.name}.")
451
+ current_vapp = @connection.get(vapp)
452
+ unless current_vapp
453
+ raise ObjectNotFoundError, "vApp #{vapp.name} no longer exists."
454
+ end
455
+ @logger.debug("vApp status: #{current_vapp["status"]}")
456
+
457
+ return unless is_vapp_status(current_vapp, :SUSPENDED)
458
+
459
+ @logger.info("Discarding suspended state of vApp #{current_vapp.name}.")
460
+ task = @connection.post(current_vapp.discard_state, nil)
461
+ monitor_task(task, @time_limit["undeploy"])
462
+ current_vapp = @connection.get(current_vapp)
463
+ @logger.info("vApp #{current_vapp.name} suspended state discarded.")
464
+ task
465
+ end
466
+
467
+ def reboot_vapp(vapp)
468
+ @logger.info("Rebooting vApp #{vapp.name}.")
469
+ current_vapp = @connection.get(vapp)
470
+ unless current_vapp
471
+ raise ObjectNotFoundError, "vApp #{vapp.name} no longer exists."
472
+ end
473
+ @logger.debug("vApp status: #{current_vapp["status"]}")
474
+
475
+ if is_vapp_status(current_vapp, :SUSPENDED)
476
+ @logger.debug("vApp #{current_vapp.name} suspended.")
477
+ raise VappSuspendedError, "vapp suspended"
478
+ end
479
+ if is_vapp_status(current_vapp, :POWERED_OFF)
480
+ @logger.debug("vApp #{current_vapp.name} powered off.")
481
+ raise VappPoweredOffError, "vapp powered off"
482
+ end
483
+
484
+ @logger.info("Rebooting vApp #{current_vapp.name}.")
485
+ task = @connection.post(current_vapp.reboot_link, nil)
486
+ monitor_task(task)
487
+ current_vapp = @connection.get(current_vapp)
488
+ @logger.info("vApp #{current_vapp.name} rebooted.")
489
+ task
490
+ end
491
+
492
+ def get_ovdc
493
+ vdc = @admin_org.vdc(@ovdc_name)
494
+ raise ObjectNotFoundError, "VDC #{@ovdc_name} not found." unless vdc
495
+ @connection.get(vdc)
496
+ end
497
+
498
+ def get_catalog(name)
499
+ catalog = @connection.get(@admin_org.catalog(name))
500
+ end
501
+
502
+ private
503
+
504
+ ERROR_STATUSES = [Xml::TASK_STATUS[:ABORTED], Xml::TASK_STATUS[:ERROR],
505
+ Xml::TASK_STATUS[:CANCELED]]
506
+ SUCCESS_STATUS = [Xml::TASK_STATUS[:SUCCESS]]
507
+
508
+ def resolve_entity(id)
509
+ url = "#{@entity_resolver_link}#{id}"
510
+ entity = @connection.get(url)
511
+ raise ObjectNotFoundError, "Unable to get entity" unless entity
512
+ @connection.get(entity.link)
513
+ end
514
+
515
+ def get_disk_id(vm, disk_href)
516
+ hardware_section = vm.hardware_section
517
+ disk = hardware_section.hard_disks.find do |d|
518
+ d.host_resource["disk"] == disk_href
519
+ end
520
+ unless disk
521
+ raise DiskNotFoundError, "Disk with href #{disk_href} not attached " +
522
+ "to VM #{vm.name}."
523
+ end
524
+ disk.disk_id
525
+ end
526
+
527
+ def log_exception(e, message = nil)
528
+ @logger.error(message) if message
529
+ @logger.error(e.message)
530
+ @logger.error(e.backtrace.join("\n\r"))
531
+ end
532
+
533
+ def copy_network_settings(network, network_config, vapp_net_name,
534
+ fence_mode)
535
+ config_ip_scope = network_config.ip_scope
536
+ net_ip_scope = network.ip_scope
537
+ config_ip_scope.is_inherited = net_ip_scope.is_inherited?
538
+ config_ip_scope.gateway= net_ip_scope.gateway
539
+ config_ip_scope.netmask = net_ip_scope.netmask
540
+ if net_ip_scope.start_address
541
+ config_ip_scope.start_address = net_ip_scope.start_address
542
+ end
543
+ if net_ip_scope.end_address
544
+ config_ip_scope.end_address = net_ip_scope.end_address
545
+ end
546
+ network_config.fence_mode = fence_mode
547
+ network_config.parent_network["name"] = network["name"]
548
+ network_config.parent_network["href"] = network["href"]
549
+ network_config["networkName"] = vapp_net_name
550
+ end
551
+
552
+ def delete_vapp_template(vapp_template)
553
+ delete_vapp_or_template(vapp_template, @retries["default"],
554
+ @time_limit["delete_vapp_template"], "vApp Template")
555
+ end
556
+
557
+ def check_vapp_for_remove_link(vapp)
558
+ current_vapp = @connection.get(vapp)
559
+ unless current_vapp.remove_link
560
+ raise ObjectNotFoundError, "No link available to delete vApp."
561
+ end
562
+ return current_vapp
563
+ end
564
+
565
+ def delete_vapp_or_template(vapp, retries, time_limit, type_name)
566
+ retries.times do |try|
567
+ @logger.info("Deleting #{type_name} #{vapp.name}")
568
+ current_vapp = @connection.get(vapp)
569
+ if (current_vapp.running_tasks.empty?)
570
+ Util.retry_operation(current_vapp, @retries["default"],
571
+ @control["backoff"]) do
572
+ current_vapp = check_vapp_for_remove_link(current_vapp)
573
+ end
574
+ Util.retry_operation(current_vapp.remove_link, @retries["default"],
575
+ @control["backoff"]) do
576
+ monitor_task(@connection.delete(current_vapp.remove_link),
577
+ time_limit) do |task|
578
+ @logger.info("#{type_name} #{current_vapp.name} deleted.")
579
+ return task
580
+ end
581
+ end
582
+ else
583
+ @logger.info("#{vapp.name} has tasks in progress, wait until done.")
584
+ current_vapp.running_tasks.each do |task|
585
+ monitor_task(task)
586
+ end
587
+ sleep (@control["backoff"] ** try)
588
+ end
589
+ end
590
+ raise ApiRequestError,
591
+ "Unable to delete #{type_name} after #{retries} attempts"
592
+ end
593
+
594
+ def insert_media(vm, media, retries = @retries["default"])
595
+ params = Xml::WrapperFactory.create_instance("MediaInsertOrEjectParams")
596
+ params.media_href = media.href
597
+
598
+ # Wait for media to be ready
599
+ retries.times do |try|
600
+ @logger.info("Inserting media #{media.name} into VM #{vm.name}.")
601
+ current_media = @connection.get(media)
602
+ if (current_media.running_tasks.empty?)
603
+ Util.retry_operation(vm.insert_media_link, @retries["default"],
604
+ @control["backoff"]) do
605
+ task = @connection.post(vm.insert_media_link, params,
606
+ Xml::MEDIA_TYPE[:MEDIA_INSERT_EJECT_PARAMS])
607
+ monitor_task(task) do |t|
608
+ raise CloudError, "Error inserting media #{media.name} " +
609
+ "into VM #{vm.name}." if t.status != "success"
610
+ @logger.info("Inserted media #{media.name} into VM #{vm.name}.")
611
+ return t
612
+ end
613
+ end
614
+ else
615
+ @logger.info("#{current_media.name} has tasks in progress, " +
616
+ "waiting until done.")
617
+ current_media.running_tasks.each do |task|
618
+ monitor_task(task)
619
+ end
620
+ sleep (@control["backoff"] ** try)
621
+ end
622
+ end
623
+ raise ApiRequestError, "Unable to insert media #{media.name} into " +
624
+ "VM #{vm.name} after #{retries} attempts"
625
+ end
626
+
627
+ def eject_media(vm, media, retries = @retries["default"])
628
+ params = Xml::WrapperFactory.create_instance("MediaInsertOrEjectParams")
629
+ params.media_href = media.href
630
+
631
+ #Wait for media to be ready
632
+ retries.times do |try|
633
+ @logger.info("Ejecting media #{media.name} from VM #{vm.name}.")
634
+ current_media = @connection.get(media)
635
+ if (current_media.running_tasks.empty?)
636
+ return eject_media_task(vm, params, media)
637
+ else
638
+ @logger.info("#{current_media.name} has tasks in progress, " +
639
+ "waiting until done.")
640
+ current_media.running_tasks.each do |task|
641
+ monitor_task(task)
642
+ end
643
+ sleep (@control["backoff"] ** try)
644
+ end
645
+ end
646
+ raise ApiRequestError, "Unable to eject media #{media.name} from " +
647
+ "VM #{vm.name} after #{retries} attempts"
648
+ end
649
+
650
+ def delete_media(media, retries = @retries["default"],
651
+ time_limit = @time_limit["delete_media"])
652
+ retries.times do |try|
653
+ @logger.info("Deleting media #{media.name}")
654
+ current_media = @connection.get(media)
655
+ if (current_media.running_tasks.empty?)
656
+ Util.retry_operation(current_media.delete_link, @retries["default"],
657
+ @control["backoff"]) do
658
+ monitor_task(@connection.delete(current_media.delete_link),
659
+ time_limit) do |task|
660
+ @logger.info("Media #{current_media.name} deleted.")
661
+ return task
662
+ end
663
+ end
664
+ else
665
+ @logger.info("#{current_media.name} has tasks in progress, " +
666
+ "waiting until done.")
667
+ current_media.running_tasks.each do |task|
668
+ monitor_task(task)
669
+ end
670
+ sleep (@control["backoff"] ** try)
671
+ end
672
+ end
673
+ raise ApiRequestError, "Unable to delete #{type_name} after "
674
+ "#{retries} attempts"
675
+ end
676
+
677
+ def get_catalog_media(name)
678
+ get_catalog_item(name, Xml::MEDIA_TYPE[:MEDIA], @media_catalog_name)
679
+ end
680
+
681
+ # Get catalog item from catalog by name and type.
682
+ # Raises an exception if catalog is not found.
683
+ # Returns nil if an item matching the name and type is not found.
684
+ # Otherwise, returns the catalog item.
685
+ # The catalog item is not the uderlying object itself, i.e. vApp template.
686
+ def get_catalog_item(name, item_type, catalog_name)
687
+ raise ObjectNotFoundError, "Catalog item name cannot be nil" unless name
688
+ unless @admin_org.catalog(catalog_name)
689
+ raise ObjectNotFoundError, "Catalog #{catalog_name} not found."
690
+ end
691
+ # For some reason, if the catalog no longer exists,
692
+ # VCD throws a Forbidden exception when getting
693
+ catalog = @connection.get(@admin_org.catalog(catalog_name))
694
+ items = catalog.catalog_items(name)
695
+ if items.nil? || items.empty?
696
+ @logger.debug("Item #{name} does not exist in catalog #{catalog_name}")
697
+ return nil
698
+ end
699
+ items.each do |i|
700
+ entity = @connection.get(i)
701
+ # Return the entity node. Another get on that node is necessary to
702
+ # get the actual object itself
703
+ return entity if entity.entity["type"] == item_type
704
+ end
705
+ nil
706
+ end
707
+
708
+ def get_vm_network_connections(vm)
709
+ current_vm = @connection.get(vm)
710
+ unless current_vm
711
+ raise ObjectNotFoundError, "VM #{vm.name} no longer exists."
712
+ end
713
+ @connection.get(current_vm.network_connection_section)
714
+ end
715
+
716
+ def task_progressed?(current_task, prev_progress, prev_status)
717
+ (current_task.progress && (current_task.progress != prev_progress)) ||
718
+ (current_task.status && (current_task.status != prev_status))
719
+ end
720
+
721
+ def task_is_success(current_task, success = SUCCESS_STATUS)
722
+ success.map { |s| s.downcase }.find {
723
+ |s| s == current_task.status.downcase }
724
+ end
725
+
726
+ def task_has_error(current_task, error_statuses = ERROR_STATUSES)
727
+ error_statuses.map { |s| s.downcase }.find {
728
+ |s| s == current_task.status.downcase }
729
+ end
730
+
731
+ def monitor_task(task, time_limit = @time_limit["default"],
732
+ error_statuses = ERROR_STATUSES, success = SUCCESS_STATUS,
733
+ delay = @control["delay"], &b)
734
+ iterations = time_limit / delay
735
+ i = 0
736
+ prev_progress = task.progress
737
+ prev_status = task.status
738
+ current_task = task
739
+ while (i < iterations)
740
+ @logger.debug("#{current_task.urn} #{current_task.operation} is " +
741
+ "#{current_task.status}")
742
+ if task_is_success(current_task, success)
743
+ if b
744
+ return b.call(current_task)
745
+ else
746
+ return current_task
747
+ end
748
+ elsif task_has_error(current_task, error_statuses)
749
+ raise ApiRequestError, "Task #{task.urn} #{task.operation} did " +
750
+ "not complete successfully."
751
+ elsif task_progressed?(current_task, prev_progress, prev_status)
752
+ @logger.debug("task status #{prev_status} => " +
753
+ "#{current_task.status}, progress #{prev_progress}%" +
754
+ " => #{current_task.progress}%, timer #{i} reset.")
755
+ prev_progress = current_task.progress
756
+ prev_status = current_task.status
757
+ i = 0 #reset clock if status changes or running task makes progress
758
+ sleep(delay)
759
+ else
760
+ @logger.debug("Approximately #{i * delay}s elapsed waiting for " +
761
+ "#{current_task.operation} to reach " +
762
+ "#{success.join("/")}/#{error_statuses.join("/")}." +
763
+ " Checking again in #{delay} seconds.")
764
+ @logger.debug("Task #{task.urn} progress: " +
765
+ "#{current_task.progress} %.") if current_task.progress
766
+ sleep(delay)
767
+ end
768
+ current_task = @connection.get(task)
769
+ i += 1
770
+ end
771
+ raise ApiTimeoutError, "Task #{task.operation} did not complete " +
772
+ "within limit of #{time_limit} seconds."
773
+ end
774
+
775
+
776
+ # TODO use times.upload_vapp_files
777
+ def upload_vapp_files(vapp, ovf_directory,
778
+ tries = @retries["upload_vapp_files"], try = 0)
779
+ current_vapp = @connection.get(vapp)
780
+ return current_vapp if !current_vapp.files || current_vapp.files.empty?
781
+
782
+ @logger.debug("vapp files left to upload #{current_vapp.files}.")
783
+ @logger.debug("vapp incomplete files left to upload " +
784
+ "#{current_vapp.incomplete_files}.")
785
+ raise ApiTimeoutError, "Unable to finish uploading vApp after " +
786
+ "#{tries} tries #{current_vapp.files}." if tries == try
787
+
788
+ current_vapp.incomplete_files.each do |f|
789
+ # switch on extension
790
+ case f.name.split(".").pop.downcase
791
+ when "ovf"
792
+ @logger.info("Uploading OVF file: " +
793
+ "#{ovf_directory.ovf_file_path} for #{vapp.name}")
794
+ @connection.put(f.upload_link, ovf_directory.ovf_file.read,
795
+ Xml::MEDIA_TYPE[:OVF])
796
+ when "vmdk"
797
+ @logger.info("Uploading VMDK file " +
798
+ "#{ovf_directory.vmdk_file_path(f.name)} for #{vapp.name}")
799
+ @connection.put_file(f.upload_link,
800
+ ovf_directory.vmdk_file(f.name))
801
+ end
802
+ end
803
+ #repeat
804
+ sleep (2 ** try)
805
+ upload_vapp_files(current_vapp, ovf_directory, tries, try + 1)
806
+ end
807
+
808
+ def add_catalog_item(item, catalog_name)
809
+ unless @admin_org.catalog(catalog_name)
810
+ raise ArgumentError,
811
+ "Error adding #{item.name}, catalog #{catalog_name} not found."
812
+ end
813
+ catalog = @connection.get(@admin_org.catalog(catalog_name))
814
+ raise ObjectNotFoundError, "Error adding #{item.name}, catalog " +
815
+ "#{catalog_name} not available." unless catalog
816
+ catalog_item = Xml::WrapperFactory.create_instance("CatalogItem")
817
+ catalog_item.name = item.name
818
+ catalog_item.entity = item
819
+ @logger.info("Adding #{catalog_item.name} to catalog #{catalog_name}")
820
+ @connection.post(catalog.add_item_link, catalog_item,
821
+ Xml::ADMIN_MEDIA_TYPE[:CATALOG_ITEM])
822
+ end
823
+
824
+ def generate_metadata_href(entity, key)
825
+ raise ObjectNotFoundError, "Entity #{entity.name} does not expose a " +
826
+ "metadata link method." if !entity.respond_to?(:metadata_link)
827
+ "#{entity.metadata_link.href}/#{key}"
828
+ end
829
+
830
+ def get_vapp_by_name(name)
831
+ @logger.debug("Getting vApp #{name}")
832
+ vdc = get_ovdc
833
+ node = vdc.get_vapp(name)
834
+ raise ObjectNotFoundError, "vApp #{name} does not exist." unless node
835
+ vapp = @connection.get(node)
836
+ raise ObjectNotFoundError, "vApp #{name} does not exist." unless vapp
837
+ vapp
838
+ end
839
+
840
+ def locality_spec(src_vapp_template, disk_locality)
841
+ disk_locality ||= []
842
+ locality = {}
843
+ disk_locality.each do |disk|
844
+ current_disk = @connection.get(disk)
845
+ unless current_disk
846
+ @logger.warn("Disk #{disk.name} no longer exists.")
847
+ next
848
+ end
849
+ src_vapp_template.vms.each do |vm|
850
+ locality[vm] = current_disk
851
+ end
852
+ end
853
+ locality
854
+ end
855
+
856
+ def is_vapp_status(current_vapp, status)
857
+ current_vapp["status"] == Xml::RESOURCE_ENTITY_STATUS[status].to_s
858
+ end
859
+
860
+ def rollback_upload_vapp(vapp_template)
861
+ @logger.error("Rolling back changes.")
862
+ begin
863
+ delete_vapp_template(vapp_template) if vapp_template
864
+ rescue => rollbackex
865
+ log_exception(rollbackex, "Error in rolling back failed vApp " +
866
+ "template #{vapp_name}.")
867
+ end
868
+ end
869
+
870
+ def eject_media_task(vm, params, media)
871
+ Util.retry_operation(vm.eject_media_link, @retries["default"],
872
+ @control["backoff"]) do
873
+ task = @connection.post(vm.eject_media_link, params,
874
+ Xml::MEDIA_TYPE[:MEDIA_INSERT_EJECT_PARAMS])
875
+ monitor_task(task) do |t|
876
+ if t.status != "success"
877
+ raise CloudError, "Error ejecting media #{media.name} from " +
878
+ "VM #{vm.name}."
879
+ end
880
+ @logger.info("Ejected media #{media.name} from VM #{vm.name}.")
881
+ return t
882
+ end
883
+ end
884
+ end
885
+
886
+ def construct_rest_logger
887
+ @logger.debug("constructing rest_logger")
888
+ rest_log_filename = File.join(File.dirname(@logger.instance_eval {
889
+ @logdev }.dev.path), "rest")
890
+ log_file = File.open(rest_log_filename, "w")
891
+ log_file.sync = true
892
+
893
+ @rest_logger = Logger.new(log_file || STDOUT)
894
+ @rest_logger.level = @logger.level
895
+ @rest_logger.formatter = @logger.formatter
896
+ end
897
+ end
898
+
899
+ end