import vimconn
import os
+import shutil
+import subprocess
+import tempfile
import traceback
import itertools
import requests
INTERVAL_TIME = 5
MAX_WAIT_TIME = 1800
-API_VERSION = '5.9'
+API_VERSION = '27.0'
__author__ = "Mustafa Bayramov, Arpita Kate, Sachin Bhangare, Prakash Kasar"
__date__ = "$09-Mar-2018 11:09:29$"
Returns:
The return client object that latter can be used to connect to vcloud director as admin for provider vdc
"""
-
self.logger.debug("Logging into vCD {} as admin.".format(self.org_name))
try:
host = self.url
org = 'System'
client_as_admin = Client(host, verify_ssl_certs=False)
+ client_as_admin.set_highest_supported_version()
client_as_admin.set_credentials(BasicLoginCredentials(self.admin_user, org, self.admin_password))
except Exception as e:
raise vimconn.vimconnException(
Returns:
The return client object that latter can be used to connect to vCloud director as admin for VDC
"""
-
try:
self.logger.debug("Logging into vCD {} as {} to datacenter {}.".format(self.org_name,
self.user,
self.org_name))
host = self.url
client = Client(host, verify_ssl_certs=False)
+ client.set_highest_supported_version()
client.set_credentials(BasicLoginCredentials(self.user, self.org_name, self.passwd))
except:
raise vimconn.vimconnConnectionException("Can't connect to a vCloud director org: "
return vdclist
- def new_network(self, net_name, net_type, ip_profile=None, shared=False):
+ def new_network(self, net_name, net_type, ip_profile=None, shared=False, vlan=None):
"""Adds a tenant network to VIM
- net_name is the name
- net_type can be 'bridge','data'.'ptp'.
- ip_profile is a dict containing the IP parameters of the network
- shared is a boolean
- Returns the network identifier"""
+ Params:
+ 'net_name': name of the network
+ 'net_type': one of:
+ 'bridge': overlay isolated network
+ 'data': underlay E-LAN network for Passthrough and SRIOV interfaces
+ 'ptp': underlay E-LINE network for Passthrough and SRIOV interfaces.
+ 'ip_profile': is a dict containing the IP parameters of the network
+ 'ip_version': can be "IPv4" or "IPv6" (Currently only IPv4 is implemented)
+ 'subnet_address': ip_prefix_schema, that is X.X.X.X/Y
+ 'gateway_address': (Optional) ip_schema, that is X.X.X.X
+ 'dns_address': (Optional) comma separated list of ip_schema, e.g. X.X.X.X[,X,X,X,X]
+ 'dhcp_enabled': True or False
+ 'dhcp_start_address': ip_schema, first IP to grant
+ 'dhcp_count': number of IPs to grant.
+ 'shared': if this network can be seen/use by other tenants/organization
+ 'vlan': in case of a data or ptp net_type, the intended vlan tag to be used for the network
+ Returns a tuple with the network identifier and created_items, or raises an exception on error
+ created_items can be None or a dictionary where this method can include key-values that will be passed to
+ the method delete_network. Can be used to store created segments, created l2gw connections, etc.
+ Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
+ as not present.
+ """
self.logger.debug("new_network tenant {} net_type {} ip_profile {} shared {}"
.format(net_name, net_type, ip_profile, shared))
+ created_items = {}
isshared = 'false'
if shared:
isshared = 'true'
network_uuid = self.create_network(network_name=net_name, net_type=net_type,
ip_profile=ip_profile, isshared=isshared)
if network_uuid is not None:
- return network_uuid
+ return network_uuid, created_items
else:
raise vimconn.vimconnUnexpectedResponse("Failed create a new network {}".format(net_name))
return filter_dict
- def delete_network(self, net_id):
+ def delete_network(self, net_id, created_items=None):
"""
- Method Deletes a tenant network from VIM, provide the network id.
-
- Returns the network identifier or raise an exception
+ Removes a tenant network from VIM and its associated elements
+ :param net_id: VIM identifier of the network, provided by method new_network
+ :param created_items: dictionary with extra items to be deleted. provided by method new_network
+ Returns the network identifier or raises an exception upon error or when network is not found
"""
# ############# Stub code for SRIOV #################
"""
for catalog in catalogs:
if catalog['name'] == catalog_name:
- return True
- return False
+ return catalog['id']
def create_vimcatalog(self, vca=None, catalog_name=None):
""" Create new catalog entry in vCloud director.
catalog_name catalog that client wish to create. Note no validation done for a name.
Client must make sure that provide valid string representation.
- Return (bool) True if catalog created.
+ Returns catalog id if catalog created else None.
"""
try:
- result = vca.create_catalog(catalog_name, catalog_name)
- if result is not None:
- return True
+ lxml_catalog_element = vca.create_catalog(catalog_name, catalog_name)
+ if lxml_catalog_element:
+ id_attr_value = lxml_catalog_element.get('id') # 'urn:vcloud:catalog:7490d561-d384-4dac-8229-3575fd1fc7b4'
+ return id_attr_value.split(':')[-1]
catalogs = vca.list_catalogs()
- except:
- return False
+ except Exception as ex:
+ self.logger.error(
+ 'create_vimcatalog(): Creation of catalog "{}" failed with error: {}'.format(catalog_name, ex))
+ raise
return self.catalog_exists(catalog_name, catalogs)
# noinspection PyIncorrectDocstring
if len(catalogs) == 0:
self.logger.info("Creating a new catalog entry {} in vcloud director".format(catalog_name))
- result = self.create_vimcatalog(org, catalog_md5_name)
- if not result:
+ if self.create_vimcatalog(org, catalog_md5_name) is None:
raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
result = self.upload_vimimage(vca=org, catalog_name=catalog_md5_name,
# if we didn't find existing catalog we create a new one and upload image.
self.logger.debug("Creating new catalog entry {} - {}".format(catalog_name, catalog_md5_name))
- result = self.create_vimcatalog(org, catalog_md5_name)
- if not result:
+ if self.create_vimcatalog(org, catalog_md5_name) is None:
raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
result = self.upload_vimimage(vca=org, catalog_name=catalog_md5_name,
vmname_andid = ''.join(new_vm_name)
for net in net_list:
- if net['type'] == "SR-IOV" or net['type'] == "PCI-PASSTHROUGH":
+ if net['type'] == "PCI-PASSTHROUGH":
raise vimconn.vimconnNotSupportedException(
"Current vCD version does not support type : {}".format(net['type']))
raise vimconn.vimconnNotFoundException("new_vminstance(): Failed create vApp {}: "
"(Failed retrieve catalog information {})".format(name, image_id))
-
# Set vCPU and Memory based on flavor.
vm_cpus = None
vm_memory = None
else:
result = (response.content).replace("\n"," ")
- src = re.search('<Vm goldMaster="false"\sstatus="\d+"\sname="(.*?)"\s'
- 'id="(\w+:\w+:vm:.*?)"\shref="(.*?)"\s'
- 'type="application/vnd\.vmware\.vcloud\.vm\+xml',result)
- if src:
- vm_name = src.group(1)
- vm_id = src.group(2)
- vm_href = src.group(3)
+ vapp_template_tree = XmlElementTree.fromstring(response.content)
+ children_element = [child for child in vapp_template_tree if 'Children' in child.tag][0]
+ vm_element = [child for child in children_element if 'Vm' in child.tag][0]
+ vm_name = vm_element.get('name')
+ vm_id = vm_element.get('id')
+ vm_href = vm_element.get('href')
cpus = re.search('<rasd:Description>Number of Virtual CPUs</.*?>(\d+)</rasd:VirtualQuantity>',result).group(1)
memory_mb = re.search('<rasd:Description>Memory Size</.*?>(\d+)</rasd:VirtualQuantity>',result).group(1)
#Add PCI passthrough/SRIOV configrations
vm_obj = None
pci_devices_info = []
- sriov_net_info = []
reserve_memory = False
for net in net_list:
if net["type"] == "PF" or net["type"] == "PCI-PASSTHROUGH":
pci_devices_info.append(net)
elif (net["type"] == "VF" or net["type"] == "SR-IOV" or net["type"] == "VFnotShared") and 'net_id'in net:
- sriov_net_info.append(net)
+ reserve_memory = True
#Add PCI
if len(pci_devices_info) > 0:
self.logger.info("new_vminstance(): Attaching net {} to vapp".format(interface_net_name))
self.connect_vapp_to_org_vdc_network(vapp_id, nets[0].get('name'))
- type_list = ('PF', 'PCI-PASSTHROUGH', 'VF', 'SR-IOV', 'VFnotShared')
+ type_list = ('PF', 'PCI-PASSTHROUGH', 'VFnotShared')
+ nic_type = 'VMXNET3'
if 'type' in net and net['type'] not in type_list:
# fetching nic type from vnf
if 'model' in net:
else:
self.logger.info("new_vminstance(): adding network adapter "\
"to a network {}".format(nets[0].get('name')))
- nic_type = 'VMXNET3'
if net['type'] in ['SR-IOV', 'VF']:
nic_type = net['type']
self.add_network_adapter_to_vms(vapp, nets[0].get('name'),
# cloud-init for ssh-key injection
if cloud_config:
- self.cloud_init(vapp,cloud_config)
-
- # ############# Stub code for SRIOV #################
- #Add SRIOV
-# if len(sriov_net_info) > 0:
-# self.logger.info("Need to add SRIOV adapters {} into VM {}".format(sriov_net_info,
-# vmname_andid ))
-# sriov_status, vm_obj, vcenter_conect = self.add_sriov(vapp_uuid,
-# sriov_net_info,
-# vmname_andid)
-# if sriov_status:
-# self.logger.info("Added SRIOV {} to VM {}".format(
-# sriov_net_info,
-# vmname_andid)
-# )
-# reserve_memory = True
-# else:
-# self.logger.info("Fail to add SRIOV {} to VM {}".format(
-# sriov_net_info,
-# vmname_andid)
-# )
+ # Create a catalog which will be carrying the config drive ISO
+ # This catalog is deleted during vApp deletion. The catalog name carries
+ # vApp UUID and thats how it gets identified during its deletion.
+ config_drive_catalog_name = 'cfg_drv-' + vapp_uuid
+ self.logger.info('new_vminstance(): Creating catalog "{}" to carry config drive ISO'.format(
+ config_drive_catalog_name))
+ config_drive_catalog_id = self.create_vimcatalog(org, config_drive_catalog_name)
+ if config_drive_catalog_id is None:
+ error_msg = "new_vminstance(): Failed to create new catalog '{}' to carry the config drive " \
+ "ISO".format(config_drive_catalog_name)
+ raise Exception(error_msg)
+
+ # Create config-drive ISO
+ _, userdata = self._create_user_data(cloud_config)
+ # self.logger.debug('new_vminstance(): The userdata for cloud-init: {}'.format(userdata))
+ iso_path = self.create_config_drive_iso(userdata)
+ self.logger.debug('new_vminstance(): The ISO is successfully created. Path: {}'.format(iso_path))
+
+ self.logger.info('new_vminstance(): uploading iso to catalog {}'.format(config_drive_catalog_name))
+ self.upload_iso_to_catalog(config_drive_catalog_id, iso_path)
+ # Attach the config-drive ISO to the VM
+ self.logger.info('new_vminstance(): Attaching the config-drive ISO to the VM')
+ # The ISO remains in INVALID_STATE right after the PUT request (its a blocking call though)
+ time.sleep(5)
+ self.insert_media_to_vm(vapp, config_drive_catalog_id)
+ shutil.rmtree(os.path.dirname(iso_path), ignore_errors=True)
# If VM has PCI devices or SRIOV reserve memory for VM
if reserve_memory:
- memReserve = vm_obj.config.hardware.memoryMB
- spec = vim.vm.ConfigSpec()
- spec.memoryAllocation = vim.ResourceAllocationInfo(reservation=memReserve)
- task = vm_obj.ReconfigVM_Task(spec=spec)
- if task:
- result = self.wait_for_vcenter_task(task, vcenter_conect)
- self.logger.info("Reserved memory {} MB for "
- "VM VM status: {}".format(str(memReserve), result))
- else:
- self.logger.info("Fail to reserved memory {} to VM {}".format(
- str(memReserve), str(vm_obj)))
+ self.reserve_memory_for_all_vms(vapp, memory_mb)
self.logger.debug("new_vminstance(): starting power on vApp {} ".format(vmname_andid))
self.logger.error("new_vminstance(): failed to power on vApp "\
"{}".format(vmname_andid))
- except Exception as exp :
+ except Exception as exp:
+ try:
+ self.delete_vminstance(vapp_uuid)
+ except Exception as exp2:
+ self.logger.error("new_vminstance rollback fail {}".format(exp2))
# it might be a case if specific mandatory entry in dict is empty or some other pyVcloud exception
self.logger.error("new_vminstance(): Failed create new vm instance {} with exception {}"
.format(name, exp))
else:
raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name))
+ def create_config_drive_iso(self, user_data):
+ tmpdir = tempfile.mkdtemp()
+ iso_path = os.path.join(tmpdir, 'ConfigDrive.iso')
+ latest_dir = os.path.join(tmpdir, 'openstack', 'latest')
+ os.makedirs(latest_dir)
+ with open(os.path.join(latest_dir, 'meta_data.json'), 'w') as meta_file_obj, \
+ open(os.path.join(latest_dir, 'user_data'), 'w') as userdata_file_obj:
+ userdata_file_obj.write(user_data)
+ meta_file_obj.write(json.dumps({"availability_zone": "nova",
+ "launch_index": 0,
+ "name": "ConfigDrive",
+ "uuid": str(uuid.uuid4())}
+ )
+ )
+ genisoimage_cmd = 'genisoimage -J -r -V config-2 -o {iso_path} {source_dir_path}'.format(
+ iso_path=iso_path, source_dir_path=tmpdir)
+ self.logger.info('create_config_drive_iso(): Creating ISO by running command "{}"'.format(genisoimage_cmd))
+ try:
+ FNULL = open(os.devnull, 'w')
+ subprocess.check_call(genisoimage_cmd, shell=True, stdout=FNULL)
+ except subprocess.CalledProcessError as e:
+ shutil.rmtree(tmpdir, ignore_errors=True)
+ error_msg = 'create_config_drive_iso(): Exception while running genisoimage command: {}'.format(e)
+ self.logger.error(error_msg)
+ raise Exception(error_msg)
+ return iso_path
+
+ def upload_iso_to_catalog(self, catalog_id, iso_file_path):
+ if not os.path.isfile(iso_file_path):
+ error_msg = "upload_iso_to_catalog(): Given iso file is not present. Given path: {}".format(iso_file_path)
+ self.logger.error(error_msg)
+ raise Exception(error_msg)
+ iso_file_stat = os.stat(iso_file_path)
+ xml_media_elem = '''<?xml version="1.0" encoding="UTF-8"?>
+ <Media
+ xmlns="http://www.vmware.com/vcloud/v1.5"
+ name="{iso_name}"
+ size="{iso_size}"
+ imageType="iso">
+ <Description>ISO image for config-drive</Description>
+ </Media>'''.format(iso_name=os.path.basename(iso_file_path), iso_size=iso_file_stat.st_size)
+ headers = {'Accept':'application/*+xml;version=' + API_VERSION,
+ 'x-vcloud-authorization': self.client._session.headers['x-vcloud-authorization']}
+ headers['Content-Type'] = 'application/vnd.vmware.vcloud.media+xml'
+ catalog_href = self.url + '/api/catalog/' + catalog_id + '/action/upload'
+ response = self.perform_request(req_type='POST', url=catalog_href, headers=headers, data=xml_media_elem)
+
+ if response.status_code != 201:
+ error_msg = "upload_iso_to_catalog(): Failed to POST an action/upload request to {}".format(catalog_href)
+ self.logger.error(error_msg)
+ raise Exception(error_msg)
+
+ catalogItem = XmlElementTree.fromstring(response.content)
+ entity = [child for child in catalogItem if child.get("type") == "application/vnd.vmware.vcloud.media+xml"][0]
+ entity_href = entity.get('href')
+
+ response = self.perform_request(req_type='GET', url=entity_href, headers=headers)
+ if response.status_code != 200:
+ raise Exception("upload_iso_to_catalog(): Failed to GET entity href {}".format(entity_href))
+
+ match = re.search(r'<Files>\s+?<File.+?href="(.+?)"/>\s+?</File>\s+?</Files>', response.text, re.DOTALL)
+ if match:
+ media_upload_href = match.group(1)
+ else:
+ raise Exception('Could not parse the upload URL for the media file from the last response')
+
+ headers['Content-Type'] = 'application/octet-stream'
+ response = self.perform_request(req_type='PUT',
+ url=media_upload_href,
+ headers=headers,
+ data=open(iso_file_path, 'rb'))
+
+ if response.status_code != 200:
+ raise Exception('PUT request to "{}" failed'.format(media_upload_href))
def get_vcd_availibility_zones(self,respool_href, headers):
""" Method to find presence of av zone is VIM resource pool
try:
vapp_name = self.get_namebyvappid(vm__vim_uuid)
- vapp_resource = vdc_obj.get_vapp(vapp_name)
- vapp = VApp(self.client, resource=vapp_resource)
if vapp_name is None:
self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
- else:
- self.logger.info("Deleting vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
+ self.logger.info("Deleting vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
+ vapp_resource = vdc_obj.get_vapp(vapp_name)
+ vapp = VApp(self.client, resource=vapp_resource)
# Delete vApp and wait for status change if task executed and vApp is None.
self.logger.debug("delete_vminstance(): Failed delete uuid {} ".format(vm__vim_uuid))
else:
self.logger.info("Deleted vm instance {} sccessfully".format(vm__vim_uuid))
+ config_drive_catalog_name, config_drive_catalog_id = 'cfg_drv-' + vm__vim_uuid, None
+ catalog_list = self.get_image_list()
+ try:
+ config_drive_catalog_id = [catalog_['id'] for catalog_ in catalog_list
+ if catalog_['name'] == config_drive_catalog_name][0]
+ except IndexError:
+ pass
+ if config_drive_catalog_id:
+ self.logger.debug('delete_vminstance(): Found a config drive catalog {} matching '
+ 'vapp_name"{}". Deleting it.'.format(config_drive_catalog_id, vapp_name))
+ self.delete_image(config_drive_catalog_id)
return vm__vim_uuid
except:
self.logger.debug(traceback.format_exc())
else:
self.logger.error("action_vminstance: Failed to {} vApp: {}".format(action, vapp_name))
- def get_vminstance_console(self, vm_id, console_type="vnc"):
+ def get_vminstance_console(self, vm_id, console_type="novnc"):
"""
Get a console for the virtual machine
Params:
port: the http, ssh, ... port
suffix: extra text, e.g. the http path and query string
"""
- raise vimconn.vimconnNotImplemented("Should have implemented this")
+ console_dict = {}
+
+ if console_type==None or console_type=='novnc':
+
+ url_rest_call = "{}/api/vApp/vm-{}/screen/action/acquireMksTicket".format(self.url, vm_id)
+
+ headers = {'Accept':'application/*+xml;version=' + API_VERSION,
+ 'x-vcloud-authorization': self.client._session.headers['x-vcloud-authorization']}
+ response = self.perform_request(req_type='POST',
+ url=url_rest_call,
+ headers=headers)
+
+ if response.status_code == 403:
+ response = self.retry_rest('GET', url_rest_call)
+
+ if response.status_code != 200:
+ self.logger.error("REST call {} failed reason : {}"\
+ "status code : {}".format(url_rest_call,
+ response.content,
+ response.status_code))
+ raise vimconn.vimconnException("get_vminstance_console : Failed to get "\
+ "VM Mks ticket details")
+ s = re.search("<Host>(.*?)</Host>",response.content)
+ console_dict['server'] = s.group(1) if s else None
+ s1 = re.search("<Port>(\d+)</Port>",response.content)
+ console_dict['port'] = s1.group(1) if s1 else None
+
+
+ url_rest_call = "{}/api/vApp/vm-{}/screen/action/acquireTicket".format(self.url, vm_id)
+
+ headers = {'Accept':'application/*+xml;version=' + API_VERSION,
+ 'x-vcloud-authorization': self.client._session.headers['x-vcloud-authorization']}
+ response = self.perform_request(req_type='POST',
+ url=url_rest_call,
+ headers=headers)
+
+ if response.status_code == 403:
+ response = self.retry_rest('GET', url_rest_call)
+
+ if response.status_code != 200:
+ self.logger.error("REST call {} failed reason : {}"\
+ "status code : {}".format(url_rest_call,
+ response.content,
+ response.status_code))
+ raise vimconn.vimconnException("get_vminstance_console : Failed to get "\
+ "VM console details")
+ s = re.search(">.*?/(vm-\d+.*)</",response.content)
+ console_dict['suffix'] = s.group(1) if s else None
+ console_dict['protocol'] = "https"
+
+ return console_dict
# NOT USED METHODS in current version
#Creating all networks as Direct Org VDC type networks.
#Unused in case of Underlay (data/ptp) network interface.
- fence_mode="bridged"
+ fence_mode="isolated"
is_inherited='false'
dns_list = dns_address.split(";")
dns1 = dns_list[0]
</IpRanges>
</IpScope>
</IpScopes>
- <ParentNetwork href="{9:s}"/>
- <FenceMode>{10:s}</FenceMode>
+ <FenceMode>{9:s}</FenceMode>
</Configuration>
- <IsShared>{11:s}</IsShared>
+ <IsShared>{10:s}</IsShared>
</OrgVdcNetwork> """.format(escape(network_name), is_inherited, gateway_address,
subnet_address, dns1, dns2_text, dhcp_enabled,
- dhcp_start_address, dhcp_end_address, available_networks,
+ dhcp_start_address, dhcp_end_address,
fence_mode, isshared)
headers['Content-Type'] = 'application/vnd.vmware.vcloud.orgVdcNetwork+xml'
namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
nwcfglist = newelem.findall(".//xmlns:NetworkConfig", namespaces)
+ # VCD 9.7 returns an incorrect parentnetwork element. Fix it before PUT operation
+ parentnetworklist = newelem.findall(".//xmlns:ParentNetwork", namespaces)
+ if parentnetworklist:
+ for pn in parentnetworklist:
+ if "href" not in pn.keys():
+ id_val = pn.get("id")
+ href_val = "{}/api/network/{}".format(self.url, id_val)
+ pn.set("href", href_val)
+
newstr = """<NetworkConfig networkName="{}">
<Configuration>
<ParentNetwork href="{}/api/network/{}"/>
"network connection section")
data = response.content
data = data.split('<Link rel="edit"')[0]
+ vcd_netadapter_type = nic_type
+ if nic_type in ['SR-IOV', 'VF']:
+ vcd_netadapter_type = "SRIOVETHERNETCARD"
+
if '<PrimaryNetworkConnectionIndex>' not in data:
self.logger.debug("add_network_adapter PrimaryNIC not in data nic_type {}".format(nic_type))
item = """<PrimaryNetworkConnectionIndex>{}</PrimaryNetworkConnectionIndex>
<IpAddressAllocationMode>{}</IpAddressAllocationMode>
<NetworkAdapterType>{}</NetworkAdapterType>
</NetworkConnection>""".format(primary_nic_index, network_name, nicIndex,
- allocation_mode, nic_type)
+ allocation_mode, vcd_netadapter_type)
# Stub for ip_address feature
if ip_address:
ip_tag = '<IpAddress>{}</IpAddress>'.format(ip_address)
<IpAddressAllocationMode>{}</IpAddressAllocationMode>
<NetworkAdapterType>{}</NetworkAdapterType>
</NetworkConnection>""".format(network_name, nicIndex,
- allocation_mode, nic_type)
+ allocation_mode, vcd_netadapter_type)
# Stub for ip_address feature
if ip_address:
ip_tag = '<IpAddress>{}</IpAddress>'.format(ip_address)
if iso_name and media_id:
data ="""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns6:MediaInsertOrEjectParams
- xmlns="http://www.vmware.com/vcloud/versions" xmlns:ns2="http://schemas.dmtf.org/ovf/envelope/1" xmlns:ns3="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:ns4="http://schemas.dmtf.org/wbem/wscim/1/common" xmlns:ns5="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:ns6="http://www.vmware.com/vcloud/v1.5" xmlns:ns7="http://www.vmware.com/schema/ovf" xmlns:ns8="http://schemas.dmtf.org/ovf/environment/1" xmlns:ns9="http://www.vmware.com/vcloud/extension/v1.5">
+ xmlns="http://www.vmware.com/vcloud/versions" xmlns:ns2="http://schemas.dmtf.org/ovf/envelope/1"
+ xmlns:ns3="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
+ xmlns:ns4="http://schemas.dmtf.org/wbem/wscim/1/common"
+ xmlns:ns5="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
+ xmlns:ns6="http://www.vmware.com/vcloud/v1.5"
+ xmlns:ns7="http://www.vmware.com/schema/ovf"
+ xmlns:ns8="http://schemas.dmtf.org/ovf/environment/1"
+ xmlns:ns9="http://www.vmware.com/vcloud/extension/v1.5">
<ns6:Media
type="application/vnd.vmware.vcloud.media+xml"
- name="{}.iso"
+ name="{}"
id="urn:vcloud:media:{}"
href="https://{}/api/media/{}"/>
</ns6:MediaInsertOrEjectParams>""".format(iso_name, media_id,
headers=headers)
if response.status_code != 202:
- self.logger.error("Failed to insert CD-ROM to vm")
- raise vimconn.vimconnException("insert_media_to_vm() : Failed to insert"\
- "ISO image to vm")
+ error_msg = "insert_media_to_vm() : Failed to insert CD-ROM to vm. Reason {}. " \
+ "Status code {}".format(response.text, response.status_code)
+ self.logger.error(error_msg)
+ raise vimconn.vimconnException(error_msg)
else:
task = self.get_task_from_response(response.content)
result = self.client.get_task_monitor().wait_for_success(task=task)
Returns org and vdc object
"""
- org = Org(self.client, resource=self.client.get_org())
- vdc = org.get_vdc(self.tenant_name)
+ vdc = None
+ try:
+ org = Org(self.client, resource=self.client.get_org())
+ vdc = org.get_vdc(self.tenant_name)
+ except Exception as e:
+ # pyvcloud not giving a specific exception, Refresh nevertheless
+ self.logger.debug("Received exception {}, refreshing token ".format(str(e)))
#Retry once, if failed by refreshing token
if vdc is None:
self.get_token()
+ org = Org(self.client, resource=self.client.get_org())
vdc = org.get_vdc(self.tenant_name)
return org, vdc