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.
- data/README +1 -0
- data/Rakefile +50 -0
- data/lib/ruby_vcloud_sdk.rb +19 -0
- data/lib/ruby_vcloud_sdk/client.rb +899 -0
- data/lib/ruby_vcloud_sdk/config.rb +17 -0
- data/lib/ruby_vcloud_sdk/connection/connection.rb +163 -0
- data/lib/ruby_vcloud_sdk/connection/file_uploader.rb +43 -0
- data/lib/ruby_vcloud_sdk/errors.rb +21 -0
- data/lib/ruby_vcloud_sdk/ovf_directory.rb +45 -0
- data/lib/ruby_vcloud_sdk/util.rb +21 -0
- data/lib/ruby_vcloud_sdk/version.rb +3 -0
- data/lib/ruby_vcloud_sdk/xml/constants.rb +427 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper.rb +242 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes.rb +3 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/admin_catalog.rb +20 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/admin_org.rb +15 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/catalog_item.rb +27 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/disk.rb +40 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/disk_attach_or_detach_params.rb +12 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/disk_create_params.rb +47 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/entity.rb +11 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/file.rb +11 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/hard_disk_item_wrapper.rb +50 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/instantiate_vapp_template_params.rb +71 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/ip_scope.rb +55 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/item.rb +32 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/media.rb +53 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/media_insert_or_eject_params.rb +17 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/metadata_value.rb +15 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/network.rb +15 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/network_config.rb +27 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/network_config_section.rb +25 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/network_connection.rb +71 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/network_connection_section.rb +67 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/nic_item_wrapper.rb +91 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/org_network.rb +19 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/org_vdc_network.rb +11 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/session.rb +17 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/task.rb +32 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/upload_vapp_template_params.rb +11 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vapp.rb +55 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vapp_template.rb +19 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vcloud.rb +15 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vdc.rb +54 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vdc_storage_profile.rb +15 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/virtual_hardware_section.rb +68 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vm.rb +179 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminAllocatedExtIpRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminCatalog.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminCatalogItemRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminCatalogRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminGroupRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminMediaRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminOrg.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminOrgNetworkRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminShadowVmRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminTaskRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminUserRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVAppNetworkRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVAppRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVAppReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVAppReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVAppTemplateRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVdc.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVdcRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVdcReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVdcReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminVmRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AllEULAsAccepted.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AllocatedExtIpRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/BlockingTaskRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/BlockingTaskReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/BlockingTaskReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/CaptureVAppParams.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Catalog.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/CatalogItem.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/CatalogItemRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/CatalogItemReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/CatalogItemReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/CatalogRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/CatalogReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/CatalogReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/CellRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/CloneMediaParams.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/CloneVAppParams.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/CloneVAppTemplateParams.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/ComposeVAppParams.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/ControlAccessParams.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/CustomizationSection.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/DatastoreProviderVdcRelationRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/DatastoreRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/DatastoreReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/DatastoreReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/DeployVAppParams.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/DhcpService.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/DiskAttachOrDetachParams.xml +5 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/DiskCreateParams.xml +9 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/DvSwitchRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Entity.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Error.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/EventRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/ExternalNetwork.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/File.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/FirewallService.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/GeneralOrgSettings.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Group.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/GroupRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/GroupReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/GroupReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/GuestCustomizationSection.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/HostRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/HostReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/HostReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/InstantiateOvfParams.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/InstantiateVAppTemplateParams.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/IpScope.xml +12 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/IpsecVpnLocalPeer.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/IpsecVpnPeer.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/IpsecVpnRemotePeer.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/IpsecVpnService.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/IpsecVpnThirdPartyPeer.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Item.xml +3 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/ItemVcd.xml +5 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/LeaseSettingsSection.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Link.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Media.xml +6 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/MediaInsertOrEjectParams.xml +4 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/MediaRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/MediaReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/MediaReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Metadata.xml +5 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/MetadataEntry.xml +7 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/MetadataValue.xml +8 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/NatService.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Network.xml +4 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkAssignment.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkConfig.xml +21 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkConfigSection.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkConnection.xml +11 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkConnectionSection.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkPoolRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkPoolReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkPoolReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkService.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Org.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgEmailSettings.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgList.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgNetwork.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgNetworkRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgNetworkReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgNetworkReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgPasswordPolicySettings.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgSettings.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgVAppTemplateLeaseSettings.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgVdcNetwork.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgVdcRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgVdcReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgVdcReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/OrgVdcResourcePoolRelationRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Owner.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/PortgroupRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/ProductSectionList.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/ProviderVdc.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/ProviderVdcResourcePoolRelationRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/PublishCatalogParams.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/QueryList.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/QueryResultRecords.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/RasdItemsList.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/RecomposeVAppParams.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Record.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Reference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/References.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/RelocateParams.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/ResourceEntity.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/ResourcePoolRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Right.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/RightRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/RightReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/RightReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Role.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/RoleRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/RoleReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/RoleReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/RuntimeInfoSection.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/ScreenTicket.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Session.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/ShadowVMReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/StaticRoutingService.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/StrandedUserRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Task.xml +0 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/TaskRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/TaskReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/TaskReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/TasksList.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/UndeployVAppParams.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/UploadVAppTemplateParams.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/User.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/UserRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/UserReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/UserReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VApp.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppLeaseSettings.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppNetwork.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppNetworkRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppNetworkReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppNetworkReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppOrgNetworkRelationRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppOrgNetworkRelationReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppOrgNetworkRelationReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppTemplate.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppTemplateRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppTemplateReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VAppTemplateReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VCloud.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VMRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VMReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VMReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VMWProviderVdcRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VMWProviderVdcReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VMWProviderVdcReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Vdc.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VdcReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VdcStorageProfile.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VirtualCenterRecord.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VirtualCenterReference.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VirtualCenterReferences.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/Vm.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VmPendingQuestion.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/VmQuestionAnswer.xml +1 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/generate_dictionary.rb +8 -0
- data/spec/assets/admin_org_response.xml +75 -0
- data/spec/assets/catalog_add_item_response.xml +8 -0
- data/spec/assets/catalog_add_vapp_request.xml +5 -0
- data/spec/assets/catalog_item_added_response.xml +19 -0
- data/spec/assets/catalog_response.xml +19 -0
- data/spec/assets/existing_media_busy_response.xml +19 -0
- data/spec/assets/existing_media_catalog_item.xml +8 -0
- data/spec/assets/existing_media_delete_task_done.xml +6 -0
- data/spec/assets/existing_media_done_response.xml +11 -0
- data/spec/assets/existing_vapp_resolver_response.xml +3 -0
- data/spec/assets/existing_vapp_template_catalog_resolver_response.xml +3 -0
- data/spec/assets/existing_vapp_template_instantiate_response.xml +20 -0
- data/spec/assets/existing_vapp_template_instantiate_task_error_response.xml +7 -0
- data/spec/assets/existing_vapp_template_instantiate_task_start_response.xml +7 -0
- data/spec/assets/existing_vapp_template_instantiate_task_success_response.xml +7 -0
- data/spec/assets/existing_vapp_template_item_response.xml +8 -0
- data/spec/assets/existing_vapp_template_ready_response.xml +79 -0
- data/spec/assets/finalize_upload_task_done_response.xml +7 -0
- data/spec/assets/finalize_upload_task_response.xml +7 -0
- data/spec/assets/indy_disk_attach_request.xml +3 -0
- data/spec/assets/indy_disk_attach_task.xml +6 -0
- data/spec/assets/indy_disk_attach_task_error.xml +6 -0
- data/spec/assets/indy_disk_create_error.xml +1 -0
- data/spec/assets/indy_disk_create_request.xml +4 -0
- data/spec/assets/indy_disk_create_response.xml +19 -0
- data/spec/assets/indy_disk_delete_task.xml +6 -0
- data/spec/assets/indy_disk_detach_request.xml +3 -0
- data/spec/assets/indy_disk_detach_task.xml +6 -0
- data/spec/assets/indy_disk_response.xml +11 -0
- data/spec/assets/instantiated_suspended_vapp_response.xml +209 -0
- data/spec/assets/instantiated_vapp_delelete_done_task.xml +5 -0
- data/spec/assets/instantiated_vapp_delelete_running_task.xml +6 -0
- data/spec/assets/instantiated_vapp_network_config_add_network_request.xml +36 -0
- data/spec/assets/instantiated_vapp_network_config_modify_network_task_success.xml +6 -0
- data/spec/assets/instantiated_vapp_network_config_remove_network_request.xml +6 -0
- data/spec/assets/instantiated_vapp_network_config_section_response.xml +17 -0
- data/spec/assets/instantiated_vapp_off_response.xml +206 -0
- data/spec/assets/instantiated_vapp_on_response.xml +205 -0
- data/spec/assets/instantiated_vapp_power_task_running.xml +6 -0
- data/spec/assets/instantiated_vapp_power_task_success.xml +6 -0
- data/spec/assets/instantiated_vapp_response.xml +205 -0
- data/spec/assets/instantiated_vm_change_task_running.xml +6 -0
- data/spec/assets/instantiated_vm_change_task_success.xml +6 -0
- data/spec/assets/instantiated_vm_cpu_response.xml +11 -0
- data/spec/assets/instantiated_vm_insert_media_task_done.xml +6 -0
- data/spec/assets/instantiated_vm_memory_response.xml +11 -0
- data/spec/assets/instantiated_vm_modify_task_running.xml +6 -0
- data/spec/assets/instantiated_vm_modify_task_success.xml +5 -0
- data/spec/assets/instantiated_vm_network_section_response.xml +11 -0
- data/spec/assets/instantiated_vm_response.xml +149 -0
- data/spec/assets/media_add_to_catalog_request.xml +5 -0
- data/spec/assets/media_add_to_catalog_response.xml +8 -0
- data/spec/assets/media_delete_task_done.xml +6 -0
- data/spec/assets/media_upload_pending_response.xml +13 -0
- data/spec/assets/media_upload_request.xml +2 -0
- data/spec/assets/metadata_set_request.xml +3 -0
- data/spec/assets/metadata_set_task_done.xml +6 -0
- data/spec/assets/org_network_response.xml +22 -0
- data/spec/assets/reconfigure_vm_request.xml +133 -0
- data/spec/assets/reconfigure_vm_task.xml +8 -0
- data/spec/assets/session.xml +7 -0
- data/spec/assets/test-config.yml +38 -0
- data/spec/assets/undeploy_params.xml +1 -0
- data/spec/assets/vapp_template_catalog_resolver_response.xml +3 -0
- data/spec/assets/vapp_template_delelete_done_task.xml +5 -0
- data/spec/assets/vapp_template_delelete_running_task.xml +6 -0
- data/spec/assets/vapp_template_instantiate_request.xml +8 -0
- data/spec/assets/vapp_template_instantiate_with_locality_request.xml +14 -0
- data/spec/assets/vapp_template_no_disk_response.xml +27 -0
- data/spec/assets/vapp_template_ready_response.xml +79 -0
- data/spec/assets/vapp_template_upload_complete.xml +28 -0
- data/spec/assets/vapp_template_upload_failed.xml +28 -0
- data/spec/assets/vapp_template_upload_request.xml +4 -0
- data/spec/assets/vapp_template_upload_response.xml +25 -0
- data/spec/assets/vcloud_response.xml +56 -0
- data/spec/assets/vdc_response.xml +57 -0
- data/spec/spec_helper.rb +107 -0
- data/spec/unit/client_response.rb +700 -0
- data/spec/unit/client_spec.rb +1152 -0
- 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
|