bug 425 fix SR-IOV PCI-PASSTHROUGH interfaces
[osm/RO.git] / osm_ro / vimconn_vmware.py
index 5b04458..d1c3977 100644 (file)
@@ -1,8 +1,8 @@
 # -*- coding: utf-8 -*-
 
 ##
-# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
-# This file is part of openmano
+# Copyright 2016-2017 VMware Inc.
+# This file is part of ETSI OSM
 # All Rights Reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -18,7 +18,7 @@
 # under the License.
 #
 # For those usages not covered by the Apache License, Version 2.0 please
-# contact with: nfvlabs@tid.es
+# contact:  osslegalrouting@vmware.com
 ##
 
 """
@@ -357,6 +357,11 @@ class vimconnector(vimconn.vimconnector):
             Returns:
                 The return vca object that letter can be used to connect to vcloud direct as admin
         """
+        vca = self.connect()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
+        self.vca = vca
         try:
             if self.org_uuid is None:
                 org_dict = self.get_org_list()
@@ -422,9 +427,61 @@ class vimconnector(vimconn.vimconnector):
             raise vimconn.vimconnException("Failed create tenant {}".format(tenant_name))
 
     def delete_tenant(self, tenant_id=None):
-        """Delete a tenant from VIM"""
-        'Returns the tenant identifier'
-        raise vimconn.vimconnNotImplemented("Should have implemented this")
+        """ Delete a tenant from VIM
+             Args:
+                tenant_id is tenant_id to be deleted.
+
+            Return:
+                returns the tenant identifier in UUID format.
+                If action is failed method will throw exception
+        """
+        vca = self.connect_as_admin()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+
+        if tenant_id is not None:
+            if vca.vcloud_session and vca.vcloud_session.organization:
+                #Get OrgVDC
+                url_list = [self.vca.host, '/api/vdc/', tenant_id]
+                orgvdc_herf = ''.join(url_list)
+                response = Http.get(url=orgvdc_herf,
+                                headers=vca.vcloud_session.get_vcloud_headers(),
+                                verify=vca.verify,
+                                logger=vca.logger)
+
+                if response.status_code != requests.codes.ok:
+                    self.logger.debug("delete_tenant():GET REST API call {} failed. "\
+                                      "Return status code {}".format(orgvdc_herf,
+                                                                     response.status_code))
+                    raise vimconn.vimconnNotFoundException("Fail to get tenant {}".format(tenant_id))
+
+                lxmlroot_respond = lxmlElementTree.fromstring(response.content)
+                namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.iteritems() if prefix}
+                namespaces["xmlns"]= "http://www.vmware.com/vcloud/v1.5"
+                vdc_remove_href = lxmlroot_respond.find("xmlns:Link[@rel='remove']",namespaces).attrib['href']
+                vdc_remove_href = vdc_remove_href + '?recursive=true&force=true'
+
+                #Delete OrgVDC
+                response = Http.delete(url=vdc_remove_href,
+                                    headers=vca.vcloud_session.get_vcloud_headers(),
+                                    verify=vca.verify,
+                                    logger=vca.logger)
+
+                if response.status_code == 202:
+                        delete_vdc_task = taskType.parseString(response.content, True)
+                        if type(delete_vdc_task) is GenericTask:
+                            self.vca.block_until_completed(delete_vdc_task)
+                            self.logger.info("Deleted tenant with ID {}".format(tenant_id))
+                            return tenant_id
+                else:
+                    self.logger.debug("delete_tenant(): DELETE REST API call {} failed. "\
+                                      "Return status code {}".format(vdc_remove_href,
+                                                                     response.status_code))
+                    raise vimconn.vimconnException("Fail to delete tenant with ID {}".format(tenant_id))
+        else:
+            self.logger.debug("delete_tenant():Incorrect tenant ID  {}".format(tenant_id))
+            raise vimconn.vimconnNotFoundException("Fail to get tenant {}".format(tenant_id))
+
 
     def get_tenant_list(self, filter_dict={}):
         """Obtain tenants of VIM
@@ -495,19 +552,16 @@ class vimconnector(vimconn.vimconnector):
         """
 
         self.logger.debug("get_vcd_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
 
         if not self.tenant_name:
             raise vimconn.vimconnConnectionException("Tenant name is empty.")
 
-        vdc = vca.get_vdc(self.tenant_name)
+        vdc = self.get_vdc_details()
         if vdc is None:
             raise vimconn.vimconnConnectionException("Can't retrieve information for a VDC {}".format(self.tenant_name))
 
         vdc_uuid = vdc.get_id().split(":")[3]
-        networks = vca.get_networks(vdc.get_name())
+        networks = self.vca.get_networks(vdc.get_name())
         network_list = []
         try:
             for network in networks:
@@ -553,21 +607,18 @@ class vimconnector(vimconn.vimconnector):
             List can be empty
         """
 
-        self.logger.debug("get_vcd_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+        self.logger.debug("get_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
 
         if not self.tenant_name:
             raise vimconn.vimconnConnectionException("Tenant name is empty.")
 
-        vdc = vca.get_vdc(self.tenant_name)
+        vdc = self.get_vdc_details()
         if vdc is None:
             raise vimconn.vimconnConnectionException("Can't retrieve information for a VDC {}.".format(self.tenant_name))
 
         try:
             vdcid = vdc.get_id().split(":")[3]
-            networks = vca.get_networks(vdc.get_name())
+            networks = self.vca.get_networks(vdc.get_name())
             network_list = []
 
             for network in networks:
@@ -613,15 +664,11 @@ class vimconnector(vimconn.vimconnector):
         """Method obtains network details of net_id VIM network
            Return a dict with  the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]"""
 
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-
         try:
-            vdc = vca.get_vdc(self.tenant_name)
+            vdc = self.get_vdc_details()
             vdc_id = vdc.get_id().split(":")[3]
 
-            networks = vca.get_networks(vdc.get_name())
+            networks = self.vca.get_networks(vdc.get_name())
             filter_dict = {}
 
             for network in networks:
@@ -652,10 +699,6 @@ class vimconnector(vimconn.vimconnector):
             Returns the network identifier or raise an exception
         """
 
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() for tenant {} is failed.".format(self.tenant_name))
-
         # ############# Stub code for SRIOV #################
 #         dvport_group = self.get_dvport_group(net_id)
 #         if dvport_group:
@@ -693,10 +736,6 @@ class vimconnector(vimconn.vimconnector):
 
         """
 
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-
         dict_entry = {}
         try:
             for net in net_list:
@@ -754,6 +793,13 @@ class vimconnector(vimconn.vimconnector):
         cpu = flavor_data.get(FLAVOR_VCPUS_KEY, 1)
         disk = flavor_data.get(FLAVOR_DISK_KEY, 1)
 
+        if not isinstance(ram, int):
+            raise vimconn.vimconnException("Non-integer value for ram")
+        elif not isinstance(cpu, int):
+            raise vimconn.vimconnException("Non-integer value for cpu")
+        elif not isinstance(disk, int):
+            raise vimconn.vimconnException("Non-integer value for disk")
+
         extended_flv = flavor_data.get("extended")
         if extended_flv:
             numas=extended_flv.get("numas")
@@ -801,12 +847,81 @@ class vimconnector(vimconn.vimconnector):
 
     def delete_image(self, image_id):
         """
-
-        :param image_id:
-        :return:
+            Deletes a tenant image from VIM
+            Args:
+                image_id is ID of Image to be deleted
+            Return:
+                returns the image identifier in UUID format or raises an exception on error
         """
+        vca = self.connect_as_admin()
+        if not vca:
+            raise vimconn.vimconnConnectionException("self.connect() is failed")
+        # Get Catalog details
+        url_list = [self.vca.host, '/api/catalog/', image_id]
+        catalog_herf = ''.join(url_list)
+        response = Http.get(url=catalog_herf,
+                            headers=vca.vcloud_session.get_vcloud_headers(),
+                            verify=vca.verify,
+                            logger=vca.logger)
+
+        if response.status_code != requests.codes.ok:
+            self.logger.debug("delete_image():GET REST API call {} failed. "\
+                              "Return status code {}".format(catalog_herf,
+                                                             response.status_code))
+            raise vimconn.vimconnNotFoundException("Fail to get image {}".format(image_id))
+
+        lxmlroot_respond = lxmlElementTree.fromstring(response.content)
+        namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.iteritems() if prefix}
+        namespaces["xmlns"]= "http://www.vmware.com/vcloud/v1.5"
+
+        catalogItems_section = lxmlroot_respond.find("xmlns:CatalogItems",namespaces)
+        catalogItems = catalogItems_section.iterfind("xmlns:CatalogItem",namespaces)
+        for catalogItem in catalogItems:
+            catalogItem_href = catalogItem.attrib['href']
+
+            #GET details of catalogItem
+            response = Http.get(url=catalogItem_href,
+                            headers=vca.vcloud_session.get_vcloud_headers(),
+                            verify=vca.verify,
+                            logger=vca.logger)
+
+            if response.status_code != requests.codes.ok:
+                self.logger.debug("delete_image():GET REST API call {} failed. "\
+                                  "Return status code {}".format(catalog_herf,
+                                                                 response.status_code))
+                raise vimconn.vimconnNotFoundException("Fail to get catalogItem {} for catalog {}".format(
+                                                                                    catalogItem,
+                                                                                    image_id))
+
+            lxmlroot_respond = lxmlElementTree.fromstring(response.content)
+            namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.iteritems() if prefix}
+            namespaces["xmlns"]= "http://www.vmware.com/vcloud/v1.5"
+            catalogitem_remove_href = lxmlroot_respond.find("xmlns:Link[@rel='remove']",namespaces).attrib['href']
+
+            #Remove catalogItem
+            response = Http.delete(url= catalogitem_remove_href,
+                                    headers=vca.vcloud_session.get_vcloud_headers(),
+                                    verify=vca.verify,
+                                    logger=vca.logger)
+            if response.status_code == requests.codes.no_content:
+                self.logger.debug("Deleted Catalog item {}".format(catalogItem))
+            else:
+                raise vimconn.vimconnException("Fail to delete Catalog Item {}".format(catalogItem))
+
+        #Remove catalog
+        url_list = [self.vca.host, '/api/admin/catalog/', image_id]
+        catalog_remove_herf = ''.join(url_list)
+        response = Http.delete(url= catalog_remove_herf,
+                                    headers=vca.vcloud_session.get_vcloud_headers(),
+                                    verify=vca.verify,
+                                    logger=vca.logger)
+
+        if response.status_code == requests.codes.no_content:
+            self.logger.debug("Deleted Catalog {}".format(image_id))
+            return image_id
+        else:
+            raise vimconn.vimconnException("Fail to delete Catalog {}".format(image_id))
 
-        raise vimconn.vimconnNotImplemented("Should have implemented this")
 
     def catalog_exists(self, catalog_name, catalogs):
         """
@@ -1077,9 +1192,6 @@ class vimconnector(vimconn.vimconnector):
 
         Return: if image uploaded correct method will provide image catalog UUID.
         """
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
 
         if not path:
             raise vimconn.vimconnException("Image path can't be None.")
@@ -1104,21 +1216,21 @@ class vimconnector(vimconn.vimconnector):
                           "vdc catalog name {}".format(filename, catalog_name, path, catalog_md5_name))
 
         try:
-            catalogs = vca.get_catalogs()
+            catalogs = self.vca.get_catalogs()
         except Exception as exp:
             self.logger.debug("Failed get catalogs() with Exception {} ".format(exp))
             raise vimconn.vimconnException("Failed get catalogs() with Exception {} ".format(exp))
 
         if len(catalogs) == 0:
             self.logger.info("Creating a new catalog entry {} in vcloud director".format(catalog_name))
-            result = self.create_vimcatalog(vca, catalog_md5_name)
+            result = self.create_vimcatalog(self.vca, catalog_md5_name)
             if not result:
                 raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
-            result = self.upload_vimimage(vca=vca, catalog_name=catalog_md5_name,
+            result = self.upload_vimimage(vca=self.vca, catalog_name=catalog_md5_name,
                                           media_name=filename, medial_file_name=path, progress=progress)
             if not result:
                 raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_name))
-            return self.get_catalogid(catalog_name, vca.get_catalogs())
+            return self.get_catalogid(catalog_name, self.vca.get_catalogs())
         else:
             for catalog in catalogs:
                 # search for existing catalog if we find same name we return ID
@@ -1127,20 +1239,20 @@ class vimconnector(vimconn.vimconnector):
                     self.logger.debug("Found existing catalog entry for {} "
                                       "catalog id {}".format(catalog_name,
                                                              self.get_catalogid(catalog_md5_name, catalogs)))
-                    return self.get_catalogid(catalog_md5_name, vca.get_catalogs())
+                    return self.get_catalogid(catalog_md5_name, self.vca.get_catalogs())
 
         # 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(vca, catalog_md5_name)
+        result = self.create_vimcatalog(self.vca, catalog_md5_name)
         if not result:
             raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
 
-        result = self.upload_vimimage(vca=vca, catalog_name=catalog_md5_name,
+        result = self.upload_vimimage(vca=self.vca, catalog_name=catalog_md5_name,
                                       media_name=filename, medial_file_name=path, progress=progress)
         if not result:
             raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_md5_name))
 
-        return self.get_catalogid(catalog_md5_name, vca.get_catalogs())
+        return self.get_catalogid(catalog_md5_name, self.vca.get_catalogs())
 
     def get_image_list(self, filter_dict={}):
         '''Obtain tenant images from VIM
@@ -1153,12 +1265,10 @@ class vimconnector(vimconn.vimconnector):
             [{<the fields at Filter_dict plus some VIM specific>}, ...]
             List can be empty
         '''
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
+
         try:
             image_list = []
-            catalogs = vca.get_catalogs()
+            catalogs = self.vca.get_catalogs()
             if len(catalogs) == 0:
                 return image_list
             else:
@@ -1229,7 +1339,7 @@ class vimconnector(vimconn.vimconnector):
             return False
         return False
 
-    def get_namebyvappid(self, vca=None, vdc=None, vapp_uuid=None):
+    def get_namebyvappid(self, vdc=None, vapp_uuid=None):
         """Method returns vApp name from vCD and lookup done by vapp_id.
 
         Args:
@@ -1248,8 +1358,13 @@ class vimconnector(vimconn.vimconnector):
                 # we care only about UUID the rest doesn't matter
                 vappid = ref.href.split("vapp")[1][1:]
                 if vappid == vapp_uuid:
-                    response = Http.get(ref.href, headers=vca.vcloud_session.get_vcloud_headers(), verify=vca.verify,
+                    response = Http.get(ref.href, headers=self.vca.vcloud_session.get_vcloud_headers(), verify=self.vca.verify,
                                         logger=self.logger)
+
+                    #Retry login if session expired & retry sending request
+                    if response.status_code == 403:
+                        response = self.retry_rest('GET', ref.href)
+
                     tree = XmlElementTree.fromstring(response.content)
                     return tree.attrib['name']
         except Exception as e:
@@ -1257,36 +1372,63 @@ class vimconnector(vimconn.vimconnector):
             return None
         return None
 
-    def new_vminstance(self, name=None, description="", start=False, image_id=None, flavor_id=None, net_list={},
-                       cloud_config=None, disk_list=None):
+    def new_vminstance(self, name=None, description="", start=False, image_id=None, flavor_id=None, net_list=[],
+                       cloud_config=None, disk_list=None, availability_zone_index=None, availability_zone_list=None):
         """Adds a VM instance to VIM
         Params:
-            start: indicates if VM must start or boot in pause mode. Ignored
-            image_id,flavor_id: image and flavor uuid
-            net_list: list of interfaces, each one is a dictionary with:
-                name:
-                net_id: network uuid to connect
-                vpci: virtual vcpi to assign
-                model: interface model, virtio, e2000, ...
-                mac_address:
-                use: 'data', 'bridge',  'mgmt'
-                type: 'virtual', 'PF', 'VF', 'VFnotShared'
-                vim_id: filled/added by this function
-                cloud_config: can be a text script to be passed directly to cloud-init,
-                    or an object to inject users and ssh keys with format:
-                        key-pairs: [] list of keys to install to the default user
-                        users: [{ name, key-pairs: []}] list of users to add with their key-pair
-                #TODO ip, security groups
-        Returns >=0, the instance identifier
-                <0, error_text
+            'start': (boolean) indicates if VM must start or created in pause mode.
+            'image_id','flavor_id': image and flavor VIM id to use for the VM
+            'net_list': list of interfaces, each one is a dictionary with:
+                'name': (optional) name for the interface.
+                'net_id': VIM network id where this interface must be connect to. Mandatory for type==virtual
+                'vpci': (optional) virtual vPCI address to assign at the VM. Can be ignored depending on VIM capabilities
+                'model': (optional and only have sense for type==virtual) interface model: virtio, e2000, ...
+                'mac_address': (optional) mac address to assign to this interface
+                #TODO: CHECK if an optional 'vlan' parameter is needed for VIMs when type if VF and net_id is not provided,
+                    the VLAN tag to be used. In case net_id is provided, the internal network vlan is used for tagging VF
+                'type': (mandatory) can be one of:
+                    'virtual', in this case always connected to a network of type 'net_type=bridge'
+                     'PCI-PASSTHROUGH' or 'PF' (passthrough): depending on VIM capabilities it can be connected to a data/ptp network ot it
+                           can created unconnected
+                     'SR-IOV' or 'VF' (SRIOV with VLAN tag): same as PF for network connectivity.
+                     'VFnotShared'(SRIOV without VLAN tag) same as PF for network connectivity. VF where no other VFs
+                            are allocated on the same physical NIC
+                'bw': (optional) only for PF/VF/VFnotShared. Minimal Bandwidth required for the interface in GBPS
+                'port_security': (optional) If False it must avoid any traffic filtering at this interface. If missing
+                                or True, it must apply the default VIM behaviour
+                After execution the method will add the key:
+                'vim_id': must be filled/added by this method with the VIM identifier generated by the VIM for this
+                        interface. 'net_list' is modified
+            'cloud_config': (optional) dictionary with:
+                'key-pairs': (optional) list of strings with the public key to be inserted to the default user
+                'users': (optional) list of users to be inserted, each item is a dict with:
+                    'name': (mandatory) user name,
+                    'key-pairs': (optional) list of strings with the public key to be inserted to the user
+                'user-data': (optional) can be a string with the text script to be passed directly to cloud-init,
+                    or a list of strings, each one contains a script to be passed, usually with a MIMEmultipart file
+                'config-files': (optional). List of files to be transferred. Each item is a dict with:
+                    'dest': (mandatory) string with the destination absolute path
+                    'encoding': (optional, by default text). Can be one of:
+                        'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
+                    'content' (mandatory): string with the content of the file
+                    'permissions': (optional) string with file permissions, typically octal notation '0644'
+                    'owner': (optional) file owner, string with the format 'owner:group'
+                'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk)
+            'disk_list': (optional) list with additional disks to the VM. Each item is a dict with:
+                'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted
+                'size': (mandatory) string with the size of the disk in GB
+            availability_zone_index: Index of availability_zone_list to use for this this VM. None if not AV required
+            availability_zone_list: list of availability zones given by user in the VNFD descriptor.  Ignore if
+                availability_zone_index is None
+        Returns a tuple with the instance 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_vminstance and action_vminstance. Can be used to store created ports, volumes, 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.info("Creating new instance for entry {}".format(name))
         self.logger.debug("desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {} disk_list {}".format(
                                     description, start, image_id, flavor_id, net_list, cloud_config, disk_list))
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
 
         #new vm name = vmname + tenant_id + uuid
         new_vm_name = [name, '-', str(uuid.uuid4())]
@@ -1298,11 +1440,15 @@ class vimconnector(vimconn.vimconnector):
         #     return vapp_uuid
 
         # we check for presence of VDC, Catalog entry and Flavor.
-        vdc = vca.get_vdc(self.tenant_name)
+        vdc = self.get_vdc_details()
         if vdc is None:
             raise vimconn.vimconnNotFoundException(
                 "new_vminstance(): Failed create vApp {}: (Failed retrieve VDC information)".format(name))
-        catalogs = vca.get_catalogs()
+        catalogs = self.vca.get_catalogs()
+        if catalogs is None:
+            #Retry once, if failed by refreshing token
+            self.get_token()
+            catalogs = self.vca.get_catalogs()
         if catalogs is None:
             raise vimconn.vimconnNotFoundException(
                 "new_vminstance(): Failed create vApp {}: (Failed retrieve catalogs list)".format(name))
@@ -1319,6 +1465,7 @@ class vimconnector(vimconn.vimconnector):
         vm_cpus = None
         vm_memory = None
         vm_disk = None
+        numas = None
 
         if flavor_id is not None:
             if flavor_id not in vimconnector.flavorlist:
@@ -1352,7 +1499,7 @@ class vimconnector(vimconn.vimconnector):
         network_mode = 'bridged'
         if net_list is not None and len(net_list) > 0:
             for net in net_list:
-                if 'use' in net and net['use'] == 'mgmt':
+                if 'use' in net and net['use'] == 'mgmt' and not primary_net:
                     primary_net = net
             if primary_net is None:
                 primary_net = net_list[0]
@@ -1371,19 +1518,26 @@ class vimconnector(vimconn.vimconnector):
         # use: 'data', 'bridge', 'mgmt'
         # create vApp.  Set vcpu and ram based on flavor id.
         try:
-            vapptask = vca.create_vapp(self.tenant_name, vmname_andid, templateName,
-                                       self.get_catalogbyid(image_id, catalogs),
-                                       network_name=None,  # None while creating vapp
-                                       network_mode=network_mode,
-                                       vm_name=vmname_andid,
-                                       vm_cpus=vm_cpus,  # can be None if flavor is None
-                                       vm_memory=vm_memory)  # can be None if flavor is None
+            for retry in (1,2):
+                vapptask = self.vca.create_vapp(self.tenant_name, vmname_andid, templateName,
+                                           self.get_catalogbyid(image_id, catalogs),
+                                           network_name=None,  # None while creating vapp
+                                           network_mode=network_mode,
+                                           vm_name=vmname_andid,
+                                           vm_cpus=vm_cpus,  # can be None if flavor is None
+                                           vm_memory=vm_memory)  # can be None if flavor is None
+
+                if not vapptask and retry==1:
+                    self.get_token() # Retry getting token
+                    continue
+                else:
+                    break
 
             if vapptask is None or vapptask is False:
                 raise vimconn.vimconnUnexpectedResponse(
                     "new_vminstance(): failed to create vApp {}".format(vmname_andid))
             if type(vapptask) is VappTask:
-                vca.block_until_completed(vapptask)
+                self.vca.block_until_completed(vapptask)
 
         except Exception as exp:
             raise vimconn.vimconnUnexpectedResponse(
@@ -1391,14 +1545,14 @@ class vimconnector(vimconn.vimconnector):
 
         # we should have now vapp in undeployed state.
         try:
-            vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vmname_andid)
-            vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), vmname_andid)
+            vapp_uuid = self.get_vappid(self.get_vdc_details(), vmname_andid)
+
         except Exception as exp:
             raise vimconn.vimconnUnexpectedResponse(
                     "new_vminstance(): Failed to retrieve vApp {} after creation: Exception:{}"
                     .format(vmname_andid, exp))
 
-        if vapp is None:
+        if vapp_uuid is None:
             raise vimconn.vimconnUnexpectedResponse(
                 "new_vminstance(): Failed to retrieve vApp {} after creation".format(
                                                                             vmname_andid))
@@ -1410,9 +1564,9 @@ class vimconnector(vimconn.vimconnector):
         reserve_memory = False
 
         for net in net_list:
-            if net["type"]=="PF":
+            if net["type"] == "PF" or net["type"] == "PCI-PASSTHROUGH":
                 pci_devices_info.append(net)
-            elif  (net["type"]=="VF" or  net["type"]=="VFnotShared") and 'net_id'in net:
+            elif (net["type"] == "VF" or net["type"] == "SR-IOV" or net["type"] == "VFnotShared") and 'net_id'in net:
                 sriov_net_info.append(net)
 
         #Add PCI
@@ -1433,6 +1587,8 @@ class vimconnector(vimconn.vimconnector):
                                                             pci_devices_info,
                                                             vmname_andid)
                                  )
+
+        vapp = self.vca.get_vapp(self.get_vdc_details(), vmname_andid)
         # Modify vm disk
         if vm_disk:
             #Assuming there is only one disk in ovf and fast provisioning in organization vDC is disabled
@@ -1444,7 +1600,12 @@ class vimconnector(vimconn.vimconnector):
         if disk_list:
             added_existing_disk = False
             for disk in disk_list:
-                if "image_id" in disk and disk["image_id"] is not None:
+                if 'device_type' in disk and disk['device_type'] == 'cdrom':
+                    image_id = disk['image_id']
+                    # Adding CD-ROM to VM
+                    # will revisit code once specification ready to support this feature
+                    self.insert_media_to_vm(vapp, image_id)
+                elif "image_id" in disk and disk["image_id"] is not None:
                     self.logger.debug("Adding existing disk from image {} to vm {} ".format(
                                                                     disk["image_id"] , vapp_uuid))
                     self.add_existing_disk(catalogs=catalogs,
@@ -1459,7 +1620,7 @@ class vimconnector(vimconn.vimconnector):
                     if added_existing_disk:
                         time.sleep(5)
                         added_existing_disk = False
-                    self.add_new_disk(vca, vapp_uuid, disk['size'])
+                    self.add_new_disk(vapp_uuid, disk['size'])
 
         if numas:
             # Assigning numa affinity setting
@@ -1482,6 +1643,10 @@ class vimconnector(vimconn.vimconnector):
                 if 'net_id' not in net:
                     continue
 
+                #Using net_id as a vim_id i.e. vim interface id, as do not have saperate vim interface id
+                #Same will be returned in refresh_vms_status() as vim_interface_id
+                net['vim_id'] = net['net_id']  # Provide the same VIM identifier as the VIM network
+
                 interface_net_id = net['net_id']
                 interface_net_name = self.get_network_name_by_id(network_uuid=interface_net_id)
                 interface_network_mode = net['use']
@@ -1495,15 +1660,17 @@ class vimconnector(vimconn.vimconnector):
                                   - NONE (No IP addressing mode specified.)"""
 
                 if primary_netname is not None:
-                    nets = filter(lambda n: n.name == interface_net_name, vca.get_networks(self.tenant_name))
+                    nets = filter(lambda n: n.name == interface_net_name, self.vca.get_networks(self.tenant_name))
                     if len(nets) == 1:
                         self.logger.info("new_vminstance(): Found requested network: {}".format(nets[0].name))
+
+                        vapp = self.vca.get_vapp(self.get_vdc_details(), vmname_andid)
                         task = vapp.connect_to_network(nets[0].name, nets[0].href)
                         if type(task) is GenericTask:
-                            vca.block_until_completed(task)
+                            self.vca.block_until_completed(task)
                         # connect network to VM - with all DHCP by default
 
-                        type_list = ['PF','VF','VFnotShared']
+                        type_list = ('PF', 'PCI-PASSTHROUGH', 'VF', 'SR-IOV', 'VFnotShared')
                         if 'type' in net and net['type'] not in type_list:
                             # fetching nic type from vnf
                             if 'model' in net:
@@ -1524,6 +1691,7 @@ class vimconnector(vimconn.vimconnector):
                                                                 net)
                 nicIndex += 1
 
+            vapp = self.vca.get_vapp(self.get_vdc_details(), vmname_andid)
             # cloud-init for ssh-key injection
             if cloud_config:
                 self.cloud_init(vapp,cloud_config)
@@ -1532,7 +1700,7 @@ class vimconnector(vimconn.vimconnector):
             self.logger.debug("new_vminstance(): Deploying vApp {} ".format(name))
             deploytask = vapp.deploy(powerOn=False)
             if type(deploytask) is GenericTask:
-                vca.block_until_completed(deploytask)
+                self.vca.block_until_completed(deploytask)
 
         # ############# Stub code for SRIOV #################
         #Add SRIOV
@@ -1562,35 +1730,39 @@ class vimconnector(vimconn.vimconnector):
                 task = vm_obj.ReconfigVM_Task(spec=spec)
                 if task:
                     result = self.wait_for_vcenter_task(task, vcenter_conect)
-                    self.logger.info("Reserved memmoery {} MB for "\
-                                     "VM VM status: {}".format(str(memReserve),result))
+                    self.logger.info("Reserved memory {} MB for "
+                                     "VM VM status: {}".format(str(memReserve), result))
                 else:
-                    self.logger.info("Fail to reserved memmoery {} to VM {}".format(
-                                                                str(memReserve),str(vm_obj)))
+                    self.logger.info("Fail to reserved memory {} to VM {}".format(
+                                                                str(memReserve), str(vm_obj)))
 
             self.logger.debug("new_vminstance(): power on vApp {} ".format(name))
+
+            vapp = self.vca.get_vapp(self.get_vdc_details(), vmname_andid)
             poweron_task = vapp.poweron()
             if type(poweron_task) is GenericTask:
-                vca.block_until_completed(poweron_task)
+                self.vca.block_until_completed(poweron_task)
 
         except Exception as exp :
             # it might be a case if specific mandatory entry in dict is empty or some other pyVcloud exception
-            self.logger.debug("new_vminstance(): Failed create new vm instance {}".format(name, exp))
-            raise vimconn.vimconnException("new_vminstance(): Failed create new vm instance {}".format(name, exp))
+            self.logger.debug("new_vminstance(): Failed create new vm instance {} with exception {}"
+                              .format(name, exp))
+            raise vimconn.vimconnException("new_vminstance(): Failed create new vm instance {} with exception {}"
+                                           .format(name, exp))
 
         # check if vApp deployed and if that the case return vApp UUID otherwise -1
         wait_time = 0
         vapp_uuid = None
         while wait_time <= MAX_WAIT_TIME:
             try:
-                vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vmname_andid)
+                vapp = self.vca.get_vapp(self.get_vdc_details(), vmname_andid)
             except Exception as exp:
                 raise vimconn.vimconnUnexpectedResponse(
                         "new_vminstance(): Failed to retrieve vApp {} after creation: Exception:{}"
                         .format(vmname_andid, exp))
 
             if vapp and vapp.me.deployed:
-                vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), vmname_andid)
+                vapp_uuid = self.get_vappid(self.get_vdc_details(), vmname_andid)
                 break
             else:
                 self.logger.debug("new_vminstance(): Wait for vApp {} to deploy".format(name))
@@ -1599,7 +1771,7 @@ class vimconnector(vimconn.vimconnector):
             wait_time +=INTERVAL_TIME
 
         if vapp_uuid is not None:
-            return vapp_uuid
+            return vapp_uuid, None
         else:
             raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name))
 
@@ -1622,11 +1794,8 @@ class vimconnector(vimconn.vimconnector):
         """Returns the VM instance information from VIM"""
 
         self.logger.debug("Client requesting vm instance {} ".format(vim_vm_uuid))
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
 
-        vdc = vca.get_vdc(self.tenant_name)
+        vdc = self.get_vdc_details()
         if vdc is None:
             raise vimconn.vimconnConnectionException(
                 "Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
@@ -1660,7 +1829,7 @@ class vimconnector(vimconn.vimconnector):
 
         return vm_dict
 
-    def delete_vminstance(self, vm__vim_uuid):
+    def delete_vminstance(self, vm__vim_uuid, created_items=None):
         """Method poweroff and remove VM instance from vcloud director network.
 
         Args:
@@ -1671,11 +1840,8 @@ class vimconnector(vimconn.vimconnector):
         """
 
         self.logger.debug("Client requesting delete vm instance {} ".format(vm__vim_uuid))
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
 
-        vdc = vca.get_vdc(self.tenant_name)
+        vdc = self.get_vdc_details()
         if vdc is None:
             self.logger.debug("delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(
                 self.tenant_name))
@@ -1683,7 +1849,7 @@ class vimconnector(vimconn.vimconnector):
                 "delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
 
         try:
-            vapp_name = self.get_namebyvappid(vca, vdc, vm__vim_uuid)
+            vapp_name = self.get_namebyvappid(vdc, vm__vim_uuid)
             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)
@@ -1691,7 +1857,7 @@ class vimconnector(vimconn.vimconnector):
                 self.logger.info("Deleting vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
 
             # Delete vApp and wait for status change if task executed and vApp is None.
-            vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
+            vapp = self.vca.get_vapp(self.get_vdc_details(), vapp_name)
 
             if vapp:
                 if vapp.me.deployed:
@@ -1700,14 +1866,14 @@ class vimconnector(vimconn.vimconnector):
                     powered_off = False
                     wait_time = 0
                     while wait_time <= MAX_WAIT_TIME:
-                        vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
+                        vapp = self.vca.get_vapp(self.get_vdc_details(), vapp_name)
                         if not vapp:
                             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)
 
                         power_off_task = vapp.poweroff()
                         if type(power_off_task) is GenericTask:
-                            result = vca.block_until_completed(power_off_task)
+                            result = self.vca.block_until_completed(power_off_task)
                             if result:
                                 powered_off = True
                                 break
@@ -1726,14 +1892,14 @@ class vimconnector(vimconn.vimconnector):
                     wait_time = 0
                     undeployed = False
                     while wait_time <= MAX_WAIT_TIME:
-                        vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
+                        vapp = self.vca.get_vapp(self.get_vdc_details(), vapp_name)
                         if not vapp:
                             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)
                         undeploy_task = vapp.undeploy(action='powerOff')
 
                         if type(undeploy_task) is GenericTask:
-                            result = vca.block_until_completed(undeploy_task)
+                            result = self.vca.block_until_completed(undeploy_task)
                             if result:
                                 undeployed = True
                                 break
@@ -1748,14 +1914,14 @@ class vimconnector(vimconn.vimconnector):
 
                 # delete vapp
                 self.logger.info("Start deletion of vApp {} ".format(vapp_name))
-                vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
+                vapp = self.vca.get_vapp(self.get_vdc_details(), vapp_name)
 
                 if vapp is not None:
                     wait_time = 0
                     result = False
 
                     while wait_time <= MAX_WAIT_TIME:
-                        vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
+                        vapp = self.vca.get_vapp(self.get_vdc_details(), vapp_name)
                         if not vapp:
                             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)
@@ -1763,8 +1929,8 @@ class vimconnector(vimconn.vimconnector):
                         delete_task = vapp.delete()
 
                         if type(delete_task) is GenericTask:
-                            vca.block_until_completed(delete_task)
-                            result = vca.block_until_completed(delete_task)
+                            self.vca.block_until_completed(delete_task)
+                            result = self.vca.block_until_completed(delete_task)
                             if result:
                                 break
                         else:
@@ -1780,7 +1946,7 @@ class vimconnector(vimconn.vimconnector):
             self.logger.debug(traceback.format_exc())
             raise vimconn.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid))
 
-        if vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name) is None:
+        if self.vca.get_vapp(self.get_vdc_details(), vapp_name) is None:
             self.logger.info("Deleted vm instance {} sccessfully".format(vm__vim_uuid))
             return vm__vim_uuid
         else:
@@ -1812,25 +1978,21 @@ class vimconnector(vimconn.vimconnector):
 
         self.logger.debug("Client requesting refresh vm status for {} ".format(vm_list))
 
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-
-        vdc = vca.get_vdc(self.tenant_name)
+        vdc = self.get_vdc_details()
         if vdc is None:
             raise vimconn.vimconnException("Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
 
         vms_dict = {}
         nsx_edge_list = []
         for vmuuid in vm_list:
-            vmname = self.get_namebyvappid(vca, vdc, vmuuid)
+            vmname = self.get_namebyvappid(self.get_vdc_details(), vmuuid)
             if vmname is not None:
 
                 try:
-                    the_vapp = vca.get_vapp(vdc, vmname)
+                    vm_pci_details = self.get_vm_pci_details(vmuuid)
+                    the_vapp = self.vca.get_vapp(self.get_vdc_details(), vmname)
                     vm_info = the_vapp.get_vms_details()
                     vm_status = vm_info[0]['status']
-                    vm_pci_details = self.get_vm_pci_details(vmuuid)
                     vm_info[0].update(vm_pci_details)
 
                     vm_dict = {'status': vcdStatusCode2manoFormat[the_vapp.me.get_status()],
@@ -1971,7 +2133,7 @@ class vimconnector(vimconn.vimconnector):
             self.logger.debug("ParseError in response from NSX Manager {}".format(Err.message), exc_info=True)
 
 
-    def action_vminstance(self, vm__vim_uuid=None, action_dict=None):
+    def action_vminstance(self, vm__vim_uuid=None, action_dict=None, created_items={}):
         """Send and action over a VM instance from VIM
         Returns the vm_id if the action was successfully sent to the VIM"""
 
@@ -1979,15 +2141,11 @@ class vimconnector(vimconn.vimconnector):
         if vm__vim_uuid is None or action_dict is None:
             raise vimconn.vimconnException("Invalid request. VM id or action is None.")
 
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-
-        vdc = vca.get_vdc(self.tenant_name)
+        vdc = self.get_vdc_details()
         if vdc is None:
-            return -1, "Failed to get a reference of VDC for a tenant {}".format(self.tenant_name)
+            raise  vimconn.vimconnException("Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
 
-        vapp_name = self.get_namebyvappid(vca, vdc, vm__vim_uuid)
+        vapp_name = self.get_namebyvappid(vdc, vm__vim_uuid)
         if vapp_name is None:
             self.logger.debug("action_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
             raise vimconn.vimconnException("Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
@@ -1995,7 +2153,7 @@ class vimconnector(vimconn.vimconnector):
             self.logger.info("Action_vminstance vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
 
         try:
-            the_vapp = vca.get_vapp(vdc, vapp_name)
+            the_vapp = self.vca.get_vapp(vdc, vapp_name)
             # TODO fix all status
             if "start" in action_dict:
                 vm_info = the_vapp.get_vms_details()
@@ -2003,28 +2161,28 @@ class vimconnector(vimconn.vimconnector):
                 self.logger.info("action_vminstance: Power on vApp: {}".format(vapp_name))
                 if vm_status == "Suspended" or vm_status == "Powered off":
                     power_on_task = the_vapp.poweron()
-                    result = vca.block_until_completed(power_on_task)
+                    result = self.vca.block_until_completed(power_on_task)
                     self.instance_actions_result("start", result, vapp_name)
             elif "rebuild" in action_dict:
                 self.logger.info("action_vminstance: Rebuild vApp: {}".format(vapp_name))
                 rebuild_task = the_vapp.deploy(powerOn=True)
-                result = vca.block_until_completed(rebuild_task)
+                result = self.vca.block_until_completed(rebuild_task)
                 self.instance_actions_result("rebuild", result, vapp_name)
             elif "pause" in action_dict:
                 self.logger.info("action_vminstance: pause vApp: {}".format(vapp_name))
                 pause_task = the_vapp.undeploy(action='suspend')
-                result = vca.block_until_completed(pause_task)
+                result = self.vca.block_until_completed(pause_task)
                 self.instance_actions_result("pause", result, vapp_name)
             elif "resume" in action_dict:
                 self.logger.info("action_vminstance: resume vApp: {}".format(vapp_name))
                 power_task = the_vapp.poweron()
-                result = vca.block_until_completed(power_task)
+                result = self.vca.block_until_completed(power_task)
                 self.instance_actions_result("resume", result, vapp_name)
             elif "shutoff" in action_dict or "shutdown" in action_dict:
                 action_name , value = action_dict.items()[0]
                 self.logger.info("action_vminstance: {} vApp: {}".format(action_name, vapp_name))
                 power_off_task = the_vapp.undeploy(action='powerOff')
-                result = vca.block_until_completed(power_off_task)
+                result = self.vca.block_until_completed(power_off_task)
                 if action_name == "shutdown":
                     self.instance_actions_result("shutdown", result, vapp_name)
                 else:
@@ -2037,7 +2195,7 @@ class vimconnector(vimconn.vimconnector):
                 reboot_task = the_vapp.reboot()
             else:
                 raise vimconn.vimconnException("action_vminstance: Invalid action {} or action is None.".format(action_dict))
-            return vm__vim_uuid
+            return None
         except Exception as exp :
             self.logger.debug("action_vminstance: Failed with Exception {}".format(exp))
             raise vimconn.vimconnException("action_vminstance: Failed with Exception {}".format(exp))
@@ -2121,10 +2279,6 @@ class vimconnector(vimconn.vimconnector):
             The return network name.
         """
 
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-
         if not network_uuid:
             return None
 
@@ -2151,10 +2305,6 @@ class vimconnector(vimconn.vimconnector):
             network_uuid: network_id
         """
 
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed.")
-
         if not network_name:
             self.logger.debug("get_network_id_by_name() : Network name is empty")
             return None
@@ -2184,18 +2334,18 @@ class vimconnector(vimconn.vimconnector):
                 The return XML respond
         """
 
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-
-        url_list = [vca.host, '/api/org']
+        url_list = [self.vca.host, '/api/org']
         vm_list_rest_call = ''.join(url_list)
 
-        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
+        if not (not self.vca.vcloud_session or not self.vca.vcloud_session.organization):
             response = Http.get(url=vm_list_rest_call,
-                                headers=vca.vcloud_session.get_vcloud_headers(),
-                                verify=vca.verify,
-                                logger=vca.logger)
+                                headers=self.vca.vcloud_session.get_vcloud_headers(),
+                                verify=self.vca.verify,
+                                logger=self.vca.logger)
+
+            if response.status_code == 403:
+                response = self.retry_rest('GET', vm_list_rest_call)
+
             if response.status_code == requests.codes.ok:
                 return response.content
 
@@ -2213,21 +2363,22 @@ class vimconnector(vimconn.vimconnector):
                 The return XML respond
         """
 
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-
         if org_uuid is None:
             return None
 
-        url_list = [vca.host, '/api/org/', org_uuid]
+        url_list = [self.vca.host, '/api/org/', org_uuid]
         vm_list_rest_call = ''.join(url_list)
 
-        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
+        if not (not self.vca.vcloud_session or not self.vca.vcloud_session.organization):
             response = Http.get(url=vm_list_rest_call,
-                                headers=vca.vcloud_session.get_vcloud_headers(),
-                                verify=vca.verify,
-                                logger=vca.logger)
+                                headers=self.vca.vcloud_session.get_vcloud_headers(),
+                                verify=self.vca.verify,
+                                logger=self.vca.logger)
+
+            #Retry login if session expired & retry sending request
+            if response.status_code == 403:
+                response = self.retry_rest('GET', vm_list_rest_call)
+
             if response.status_code == requests.codes.ok:
                 return response.content
 
@@ -2248,9 +2399,6 @@ class vimconnector(vimconn.vimconnector):
         """
 
         org_dict = {}
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
 
         if org_uuid is None:
             return org_dict
@@ -2288,9 +2436,6 @@ class vimconnector(vimconn.vimconnector):
         """
 
         org_dict = {}
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
 
         content = self.list_org_action()
         try:
@@ -2462,21 +2607,22 @@ class vimconnector(vimconn.vimconnector):
                 The return XML respond
         """
 
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
-
         if network_uuid is None:
             return None
 
-        url_list = [vca.host, '/api/network/', network_uuid]
+        url_list = [self.vca.host, '/api/network/', network_uuid]
         vm_list_rest_call = ''.join(url_list)
 
-        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
+        if not (not self.vca.vcloud_session or not self.vca.vcloud_session.organization):
             response = Http.get(url=vm_list_rest_call,
-                                headers=vca.vcloud_session.get_vcloud_headers(),
-                                verify=vca.verify,
-                                logger=vca.logger)
+                                headers=self.vca.vcloud_session.get_vcloud_headers(),
+                                verify=self.vca.verify,
+                                logger=self.vca.logger)
+
+            #Retry login if session expired & retry sending request
+            if response.status_code == 403:
+                response = self.retry_rest('GET', vm_list_rest_call)
+
             if response.status_code == requests.codes.ok:
                 return response.content
 
@@ -2746,6 +2892,11 @@ class vimconnector(vimconn.vimconnector):
             #Unused in case of Underlay (data/ptp) network interface.
             fence_mode="bridged"
             is_inherited='false'
+            dns_list = dns_address.split(";")
+            dns1 = dns_list[0]
+            dns2_text = ""
+            if len(dns_list) >= 2:
+                dns2_text = "\n                                                <Dns2>{}</Dns2>\n".format(dns_list[1])
             data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
                             <Description>Openmano created</Description>
                                     <Configuration>
@@ -2754,22 +2905,22 @@ class vimconnector(vimconn.vimconnector):
                                                 <IsInherited>{1:s}</IsInherited>
                                                 <Gateway>{2:s}</Gateway>
                                                 <Netmask>{3:s}</Netmask>
-                                                <Dns1>{4:s}</Dns1>
-                                                <IsEnabled>{5:s}</IsEnabled>
+                                                <Dns1>{4:s}</Dns1>{5:s}
+                                                <IsEnabled>{6:s}</IsEnabled>
                                                 <IpRanges>
                                                     <IpRange>
-                                                        <StartAddress>{6:s}</StartAddress>
-                                                        <EndAddress>{7:s}</EndAddress>
+                                                        <StartAddress>{7:s}</StartAddress>
+                                                        <EndAddress>{8:s}</EndAddress>
                                                     </IpRange>
                                                 </IpRanges>
                                             </IpScope>
                                         </IpScopes>
-                                        <ParentNetwork href="{8:s}"/>
-                                        <FenceMode>{9:s}</FenceMode>
+                                        <ParentNetwork href="{9:s}"/>
+                                        <FenceMode>{10:s}</FenceMode>
                                     </Configuration>
-                                    <IsShared>{10:s}</IsShared>
+                                    <IsShared>{11:s}</IsShared>
                         </OrgVdcNetwork> """.format(escape(network_name), is_inherited, gateway_address,
-                                                    subnet_address, dns_address, dhcp_enabled,
+                                                    subnet_address, dns1, dns2_text, dhcp_enabled,
                                                     dhcp_start_address, dhcp_end_address, available_networks,
                                                     fence_mode, isshared)
 
@@ -2896,8 +3047,7 @@ class vimconnector(vimconn.vimconnector):
                 # application/vnd.vmware.admin.providervdc+xml
                 # we need find a template from witch we instantiate VDC
                 if child.tag.split("}")[1] == 'VdcTemplate':
-                    if child.attrib.get('type') == 'application/vnd.vmware.admin.vdcTemplate+xml' and child.attrib.get(
-                            'name') == 'openmano':
+                    if child.attrib.get('type') == 'application/vnd.vmware.admin.vdcTemplate+xml':
                         vdc_template_ref = child.attrib.get('href')
         except:
             self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
@@ -2920,6 +3070,11 @@ class vimconnector(vimconn.vimconnector):
             headers['Content-Type'] = 'application/vnd.vmware.vcloud.instantiateVdcTemplateParams+xml'
             response = Http.post(url=vm_list_rest_call, headers=headers, data=data, verify=vca.verify,
                                  logger=vca.logger)
+
+            vdc_task = taskType.parseString(response.content, True)
+            if type(vdc_task) is GenericTask:
+                self.vca.block_until_completed(vdc_task)
+
             # if we all ok we respond with content otherwise by default None
             if response.status_code >= 200 and response.status_code < 300:
                 return response.content
@@ -3034,7 +3189,7 @@ class vimconnector(vimconn.vimconnector):
         if need_admin_access:
             vca = self.connect_as_admin()
         else:
-            vca = self.connect()
+            vca = self.vca
 
         if not vca:
             raise vimconn.vimconnConnectionException("self.connect() is failed")
@@ -3050,6 +3205,10 @@ class vimconnector(vimconn.vimconnector):
                                 verify=vca.verify,
                                 logger=vca.logger)
 
+            if response.status_code == 403:
+                if need_admin_access == False:
+                    response = self.retry_rest('GET', get_vapp_restcall)
+
             if response.status_code != requests.codes.ok:
                 self.logger.debug("REST API call {} failed. Return status code {}".format(get_vapp_restcall,
                                                                                           response.status_code))
@@ -3156,21 +3315,20 @@ class vimconnector(vimconn.vimconnector):
 
     def acuire_console(self, vm_uuid=None):
 
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
         if vm_uuid is None:
             return None
 
-        if not (not vca.vcloud_session or not vca.vcloud_session.organization):
+        if not (not self.vca.vcloud_session or not self.vca.vcloud_session.organization):
             vm_dict = self.get_vapp_details_rest(self, vapp_uuid=vm_uuid)
             console_dict = vm_dict['acquireTicket']
             console_rest_call = console_dict['href']
 
             response = Http.post(url=console_rest_call,
-                                 headers=vca.vcloud_session.get_vcloud_headers(),
-                                 verify=vca.verify,
-                                 logger=vca.logger)
+                                 headers=self.vca.vcloud_session.get_vcloud_headers(),
+                                 verify=self.vca.verify,
+                                 logger=self.vca.logger)
+            if response.status_code == 403:
+                response = self.retry_rest('POST', console_rest_call)
 
             if response.status_code == requests.codes.ok:
                 return response.content
@@ -3227,17 +3385,17 @@ class vimconnector(vimconn.vimconnector):
             Returns:
                 The return network uuid or return None
         """
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("self.connect() is failed")
         if disk_href is None or disk_size is None:
             return None
 
-        if vca.vcloud_session and vca.vcloud_session.organization:
+        if self.vca.vcloud_session and self.vca.vcloud_session.organization:
             response = Http.get(url=disk_href,
-                                headers=vca.vcloud_session.get_vcloud_headers(),
-                                verify=vca.verify,
-                                logger=vca.logger)
+                                headers=self.vca.vcloud_session.get_vcloud_headers(),
+                                verify=self.vca.verify,
+                                logger=self.vca.logger)
+
+        if response.status_code == 403:
+            response = self.retry_rest('GET', disk_href)
 
         if response.status_code != requests.codes.ok:
             self.logger.debug("GET REST API call {} failed. Return status code {}".format(disk_href,
@@ -3259,13 +3417,17 @@ class vimconnector(vimconn.vimconnector):
                                              xml_declaration=True)
 
             #Send PUT request to modify disk size
-            headers = vca.vcloud_session.get_vcloud_headers()
+            headers = self.vca.vcloud_session.get_vcloud_headers()
             headers['Content-Type'] = 'application/vnd.vmware.vcloud.rasdItemsList+xml; charset=ISO-8859-1'
 
             response = Http.put(url=disk_href,
                                 data=data,
                                 headers=headers,
-                                verify=vca.verify, logger=self.logger)
+                                verify=self.vca.verify, logger=self.logger)
+
+            if response.status_code == 403:
+                add_headers = {'Content-Type': headers['Content-Type']}
+                response = self.retry_rest('PUT', disk_href, add_headers, data)
 
             if response.status_code != 202:
                 self.logger.debug("PUT REST API call {} failed. Return status code {}".format(disk_href,
@@ -3273,7 +3435,7 @@ class vimconnector(vimconn.vimconnector):
             else:
                 modify_disk_task = taskType.parseString(response.content, True)
                 if type(modify_disk_task) is GenericTask:
-                    status = vca.block_until_completed(modify_disk_task)
+                    status = self.vca.block_until_completed(modify_disk_task)
                     return status
 
             return None
@@ -3658,9 +3820,6 @@ class vimconnector(vimconn.vimconnector):
             Returns:
                 None
         """
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("Failed to connect vCloud director")
 
         try:
             ip_address = None
@@ -3681,12 +3840,16 @@ class vimconnector(vimconn.vimconnector):
                 for vms in vapp._get_vms():
                     vm_id = (vms.id).split(':')[-1]
 
-                    url_rest_call = "{}/api/vApp/vm-{}/networkConnectionSection/".format(vca.host, vm_id)
+                    url_rest_call = "{}/api/vApp/vm-{}/networkConnectionSection/".format(self.vca.host, vm_id)
 
                     response = Http.get(url=url_rest_call,
-                                        headers=vca.vcloud_session.get_vcloud_headers(),
-                                        verify=vca.verify,
-                                        logger=vca.logger)
+                                        headers=self.vca.vcloud_session.get_vcloud_headers(),
+                                        verify=self.vca.verify,
+                                        logger=self.vca.logger)
+
+                    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,
@@ -3724,11 +3887,16 @@ class vimconnector(vimconn.vimconnector):
 
                         data = data.replace('</NetworkConnection>\n','</NetworkConnection>\n{}\n'.format(new_item))
 
-                    headers = vca.vcloud_session.get_vcloud_headers()
+                    headers = self.vca.vcloud_session.get_vcloud_headers()
                     headers['Content-Type'] = 'application/vnd.vmware.vcloud.networkConnectionSection+xml'
                     response = Http.put(url=url_rest_call, headers=headers, data=data,
-                                                                   verify=vca.verify,
-                                                                   logger=vca.logger)
+                                                                   verify=self.vca.verify,
+                                                                   logger=self.vca.logger)
+
+                    if response.status_code == 403:
+                        add_headers = {'Content-Type': headers['Content-Type']}
+                        response = self.retry_rest('PUT', url_rest_call, add_headers, data)
+
                     if response.status_code != 202:
                         self.logger.error("REST call {} failed reason : {}"\
                                             "status code : {} ".format(url_rest_call,
@@ -3739,7 +3907,7 @@ class vimconnector(vimconn.vimconnector):
                     else:
                         nic_task = taskType.parseString(response.content, True)
                         if isinstance(nic_task, GenericTask):
-                            vca.block_until_completed(nic_task)
+                            self.vca.block_until_completed(nic_task)
                             self.logger.info("add_network_adapter_to_vms(): VM {} conneced to "\
                                                                "default NIC type".format(vm_id))
                         else:
@@ -3749,12 +3917,16 @@ class vimconnector(vimconn.vimconnector):
                 for vms in vapp._get_vms():
                     vm_id = (vms.id).split(':')[-1]
 
-                    url_rest_call = "{}/api/vApp/vm-{}/networkConnectionSection/".format(vca.host, vm_id)
+                    url_rest_call = "{}/api/vApp/vm-{}/networkConnectionSection/".format(self.vca.host, vm_id)
 
                     response = Http.get(url=url_rest_call,
-                                        headers=vca.vcloud_session.get_vcloud_headers(),
-                                        verify=vca.verify,
-                                        logger=vca.logger)
+                                        headers=self.vca.vcloud_session.get_vcloud_headers(),
+                                        verify=self.vca.verify,
+                                        logger=self.vca.logger)
+
+                    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,
@@ -3793,11 +3965,15 @@ class vimconnector(vimconn.vimconnector):
 
                         data = data.replace('</NetworkConnection>\n','</NetworkConnection>\n{}\n'.format(new_item))
 
-                    headers = vca.vcloud_session.get_vcloud_headers()
+                    headers = self.vca.vcloud_session.get_vcloud_headers()
                     headers['Content-Type'] = 'application/vnd.vmware.vcloud.networkConnectionSection+xml'
                     response = Http.put(url=url_rest_call, headers=headers, data=data,
-                                                                   verify=vca.verify,
-                                                                   logger=vca.logger)
+                                                                   verify=self.vca.verify,
+                                                                   logger=self.vca.logger)
+
+                    if response.status_code == 403:
+                        add_headers = {'Content-Type': headers['Content-Type']}
+                        response = self.retry_rest('PUT', url_rest_call, add_headers, data)
 
                     if response.status_code != 202:
                         self.logger.error("REST call {} failed reason : {}"\
@@ -3809,7 +3985,7 @@ class vimconnector(vimconn.vimconnector):
                     else:
                         nic_task = taskType.parseString(response.content, True)
                         if isinstance(nic_task, GenericTask):
-                            vca.block_until_completed(nic_task)
+                            self.vca.block_until_completed(nic_task)
                             self.logger.info("add_network_adapter_to_vms(): VM {} "\
                                                "conneced to NIC type {}".format(vm_id, nic_type))
                         else:
@@ -3872,7 +4048,6 @@ class vimconnector(vimconn.vimconnector):
                                                                            "affinity".format(exp))
 
 
-
     def cloud_init(self, vapp, cloud_config):
         """
         Method to inject ssh-key
@@ -3882,7 +4057,8 @@ class vimconnector(vimconn.vimconnector):
                 'users': (optional) list of users to be inserted, each item is a dict with:
                     'name': (mandatory) user name,
                     'key-pairs': (optional) list of strings with the public key to be inserted to the user
-                'user-data': (optional) string is a text script to be passed directly to cloud-init
+                'user-data': (optional) can be a string with the text script to be passed directly to cloud-init,
+                    or a list of strings, each one contains a script to be passed, usually with a MIMEmultipart file
                 'config-files': (optional). List of files to be transferred. Each item is a dict with:
                     'dest': (mandatory) string with the destination absolute path
                     'encoding': (optional, by default text). Can be one of:
@@ -3892,12 +4068,10 @@ class vimconnector(vimconn.vimconnector):
                     'owner': (optional) file owner, string with the format 'owner:group'
                 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk
         """
-        vca = self.connect()
-        if not vca:
-            raise vimconn.vimconnConnectionException("Failed to connect vCloud director")
-
         try:
-            if isinstance(cloud_config, dict):
+            if not isinstance(cloud_config, dict):
+                raise Exception("cloud_init : parameter cloud_config is not a dictionary")
+            else:
                 key_pairs = []
                 userdata = []
                 if "key-pairs" in cloud_config:
@@ -3906,70 +4080,96 @@ class vimconnector(vimconn.vimconnector):
                 if "users" in cloud_config:
                     userdata = cloud_config["users"]
 
-            for key in key_pairs:
-                for user in userdata:
-                    if 'name' in user: user_name = user['name']
-                    if 'key-pairs' in user and len(user['key-pairs']) > 0:
-                        for user_key in user['key-pairs']:
-                            customize_script = """
-                        #!/bin/bash
-                        echo performing customization tasks with param $1 at `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"` >> /root/customization.log
-                        if [ "$1" = "precustomization" ];then
-                            echo performing precustomization tasks   on `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"` >> /root/customization.log
-                            if [ ! -d /root/.ssh ];then
-                                mkdir /root/.ssh
-                                chown root:root /root/.ssh
-                                chmod 700 /root/.ssh
-                                touch /root/.ssh/authorized_keys
-                                chown root:root /root/.ssh/authorized_keys
-                                chmod 600 /root/.ssh/authorized_keys
-                                # make centos with selinux happy
-                                which restorecon && restorecon -Rv /root/.ssh
-                                echo '{key}' >> /root/.ssh/authorized_keys
-                            else
-                                touch /root/.ssh/authorized_keys
-                                chown root:root /root/.ssh/authorized_keys
-                                chmod 600 /root/.ssh/authorized_keys
-                                echo '{key}' >> /root/.ssh/authorized_keys
-                            fi
-                            if [ -d /home/{user_name} ];then
-                                if [ ! -d /home/{user_name}/.ssh ];then
-                                    mkdir /home/{user_name}/.ssh
-                                    chown {user_name}:{user_name} /home/{user_name}/.ssh
-                                    chmod 700 /home/{user_name}/.ssh
-                                    touch /home/{user_name}/.ssh/authorized_keys
-                                    chown {user_name}:{user_name} /home/{user_name}/.ssh/authorized_keys
-                                    chmod 600 /home/{user_name}/.ssh/authorized_keys
-                                    # make centos with selinux happy
-                                    which restorecon && restorecon -Rv /home/{user_name}/.ssh
-                                    echo '{user_key}' >> /home/{user_name}/.ssh/authorized_keys
-                                else
-                                    touch /home/{user_name}/.ssh/authorized_keys
-                                    chown {user_name}:{user_name} /home/{user_name}/.ssh/authorized_keys
-                                    chmod 600 /home/{user_name}/.ssh/authorized_keys
-                                    echo '{user_key}' >> /home/{user_name}/.ssh/authorized_keys
-                                fi
-                            fi
-                        fi""".format(key=key, user_name=user_name, user_key=user_key)
-
-                            for vm in vapp._get_vms():
-                                vm_name = vm.name
-                                task = vapp.customize_guest_os(vm_name, customization_script=customize_script)
-                                if isinstance(task, GenericTask):
-                                    vca.block_until_completed(task)
-                                    self.logger.info("cloud_init : customized guest os task "\
-                                                        "completed for VM {}".format(vm_name))
-                                else:
-                                    self.logger.error("cloud_init : task for customized guest os"\
-                                                               "failed for VM {}".format(vm_name))
+                self.logger.debug("cloud_init : Guest os customization started..")
+                customize_script = self.format_script(key_pairs=key_pairs, users_list=userdata)
+                self.guest_customization(vapp, customize_script)
+
         except Exception as exp:
             self.logger.error("cloud_init : exception occurred while injecting "\
                                                                        "ssh-key")
             raise vimconn.vimconnException("cloud_init : Error {} failed to inject "\
                                                                "ssh-key".format(exp))
 
+    def format_script(self, key_pairs=[], users_list=[]):
+        bash_script = """
+        #!/bin/bash
+        echo performing customization tasks with param $1 at `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"` >> /root/customization.log
+        if [ "$1" = "precustomization" ];then
+            echo performing precustomization tasks   on `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"` >> /root/customization.log
+        """
+
+        keys = "\n".join(key_pairs)
+        if keys:
+            keys_data = """
+            if [ ! -d /root/.ssh ];then
+                mkdir /root/.ssh
+                chown root:root /root/.ssh
+                chmod 700 /root/.ssh
+                touch /root/.ssh/authorized_keys
+                chown root:root /root/.ssh/authorized_keys
+                chmod 600 /root/.ssh/authorized_keys
+                # make centos with selinux happy
+                which restorecon && restorecon -Rv /root/.ssh
+            else
+                touch /root/.ssh/authorized_keys
+                chown root:root /root/.ssh/authorized_keys
+                chmod 600 /root/.ssh/authorized_keys
+            fi
+            echo '{key}' >> /root/.ssh/authorized_keys
+            """.format(key=keys)
+
+            bash_script+= keys_data
+
+        for user in users_list:
+            if 'name' in user: user_name = user['name']
+            if 'key-pairs' in user:
+                user_keys = "\n".join(user['key-pairs'])
+            else:
+                user_keys = None
+
+            add_user_name = """
+                useradd -d /home/{user_name} -m -g users -s /bin/bash {user_name}
+                """.format(user_name=user_name)
+
+            bash_script+= add_user_name
+
+            if user_keys:
+                user_keys_data = """
+                mkdir /home/{user_name}/.ssh
+                chown {user_name}:{user_name} /home/{user_name}/.ssh
+                chmod 700 /home/{user_name}/.ssh
+                touch /home/{user_name}/.ssh/authorized_keys
+                chown {user_name}:{user_name} /home/{user_name}/.ssh/authorized_keys
+                chmod 600 /home/{user_name}/.ssh/authorized_keys
+                # make centos with selinux happy
+                which restorecon && restorecon -Rv /home/{user_name}/.ssh
+                echo '{user_key}' >> /home/{user_name}/.ssh/authorized_keys
+                """.format(user_name=user_name,user_key=user_keys)
+
+                bash_script+= user_keys_data
+
+        return bash_script+"\n\tfi"
+
+    def guest_customization(self, vapp, customize_script):
+        """
+        Method to customize guest os
+        vapp - Vapp object
+        customize_script - Customize script to be run at first boot of VM.
+        """
+        for vm in vapp._get_vms():
+            vm_name = vm.name
+            task = vapp.customize_guest_os(vm_name, customization_script=customize_script)
+            if isinstance(task, GenericTask):
+                self.vca.block_until_completed(task)
+                self.logger.info("guest_customization : customized guest os task "\
+                                             "completed for VM {}".format(vm_name))
+            else:
+                self.logger.error("guest_customization : task for customized guest os"\
+                                                    "failed for VM {}".format(vm_name))
+                raise vimconn.vimconnException("guest_customization : failed to perform"\
+                                       "guest os customization on VM {}".format(vm_name))
 
-    def add_new_disk(self, vca, vapp_uuid, disk_size):
+    def add_new_disk(self, vapp_uuid, disk_size):
         """
             Method to create an empty vm disk
 
@@ -3991,7 +4191,7 @@ class vimconnector(vimconn.vimconnector):
             if vm_details and "vm_virtual_hardware" in vm_details:
                 self.logger.info("Adding disk to VM: {} disk size:{}GB".format(vm_details["name"], disk_size))
                 disk_href = vm_details["vm_virtual_hardware"]["disk_edit_href"]
-                status = self.add_new_disk_rest(vca, disk_href, disk_size_mb)
+                status = self.add_new_disk_rest(disk_href, disk_size_mb)
 
         except Exception as exp:
             msg = "Error occurred while creating new disk {}.".format(exp)
@@ -4005,7 +4205,7 @@ class vimconnector(vimconn.vimconnector):
             self.rollback_newvm(vapp_uuid, msg)
 
 
-    def add_new_disk_rest(self, vca, disk_href, disk_size_mb):
+    def add_new_disk_rest(self, disk_href, disk_size_mb):
         """
         Retrives vApp Disks section & add new empty disk
 
@@ -4016,11 +4216,14 @@ class vimconnector(vimconn.vimconnector):
             Returns: Status of add new disk task
         """
         status = False
-        if vca.vcloud_session and vca.vcloud_session.organization:
+        if self.vca.vcloud_session and self.vca.vcloud_session.organization:
             response = Http.get(url=disk_href,
-                                headers=vca.vcloud_session.get_vcloud_headers(),
-                                verify=vca.verify,
-                                logger=vca.logger)
+                                headers=self.vca.vcloud_session.get_vcloud_headers(),
+                                verify=self.vca.verify,
+                                logger=self.vca.logger)
+
+        if response.status_code == 403:
+            response = self.retry_rest('GET', disk_href)
 
         if response.status_code != requests.codes.ok:
             self.logger.error("add_new_disk_rest: GET REST API call {} failed. Return status code {}"
@@ -4059,13 +4262,17 @@ class vimconnector(vimconn.vimconnector):
             new_data = new_data.replace('</Item>\n</RasdItemsList>', '</Item>\n{}\n</RasdItemsList>'.format(new_item))
 
             # Send PUT request to modify virtual hardware section with new disk
-            headers = vca.vcloud_session.get_vcloud_headers()
+            headers = self.vca.vcloud_session.get_vcloud_headers()
             headers['Content-Type'] = 'application/vnd.vmware.vcloud.rasdItemsList+xml; charset=ISO-8859-1'
 
             response = Http.put(url=disk_href,
                                 data=new_data,
                                 headers=headers,
-                                verify=vca.verify, logger=self.logger)
+                                verify=self.vca.verify, logger=self.logger)
+
+            if response.status_code == 403:
+                add_headers = {'Content-Type': headers['Content-Type']}
+                response = self.retry_rest('PUT', disk_href, add_headers, new_data)
 
             if response.status_code != 202:
                 self.logger.error("PUT REST API call {} failed. Return status code {}. Response Content:{}"
@@ -4073,7 +4280,7 @@ class vimconnector(vimconn.vimconnector):
             else:
                 add_disk_task = taskType.parseString(response.content, True)
                 if type(add_disk_task) is GenericTask:
-                    status = vca.block_until_completed(add_disk_task)
+                    status = self.vca.block_until_completed(add_disk_task)
                     if not status:
                         self.logger.error("Add new disk REST task failed to add {} MB disk".format(disk_size_mb))
 
@@ -4430,7 +4637,7 @@ class vimconnector(vimconn.vimconnector):
                             for sriov_net in sriov_nets:
                                 network_name = sriov_net.get('net_id')
                                 dvs_portgr_name = self.create_dvPort_group(network_name)
-                                if sriov_net.get('type') == "VF":
+                                if sriov_net.get('type') == "VF" or sriov_net.get('type') == "SR-IOV":
                                     #add vlan ID ,Modify portgroup for vlan ID
                                     self.configure_vlanID(content, vcenter_conect, network_name)
 
@@ -4788,3 +4995,212 @@ class vimconnector(vimconn.vimconnector):
                 break
         return obj
 
+
+    def insert_media_to_vm(self, vapp, image_id):
+        """
+        Method to insert media CD-ROM (ISO image) from catalog to vm.
+        vapp - vapp object to get vm id
+        Image_id - image id for cdrom to be inerted to vm
+        """
+        # create connection object
+        vca = self.connect()
+        try:
+            # fetching catalog details
+            rest_url = "{}/api/catalog/{}".format(vca.host,image_id)
+            response = Http.get(url=rest_url,
+                                headers=vca.vcloud_session.get_vcloud_headers(),
+                                verify=vca.verify,
+                                logger=vca.logger)
+
+            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("insert_media_to_vm(): Failed to get "\
+                                                                    "catalog details")
+            # searching iso name and id
+            iso_name,media_id = self.get_media_details(vca, response.content)
+
+            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">
+                     <ns6:Media
+                        type="application/vnd.vmware.vcloud.media+xml"
+                        name="{}.iso"
+                        id="urn:vcloud:media:{}"
+                        href="https://{}/api/media/{}"/>
+                     </ns6:MediaInsertOrEjectParams>""".format(iso_name, media_id,
+                                                                vca.host,media_id)
+
+                for vms in vapp._get_vms():
+                    vm_id = (vms.id).split(':')[-1]
+
+                    headers = vca.vcloud_session.get_vcloud_headers()
+                    headers['Content-Type'] = 'application/vnd.vmware.vcloud.mediaInsertOrEjectParams+xml'
+                    rest_url = "{}/api/vApp/vm-{}/media/action/insertMedia".format(vca.host,vm_id)
+
+                    response = Http.post(url=rest_url,
+                                      headers=headers,
+                                            data=data,
+                                    verify=vca.verify,
+                                    logger=vca.logger)
+
+                    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")
+                    else:
+                        task = taskType.parseString(response.content, True)
+                        if isinstance(task, GenericTask):
+                            vca.block_until_completed(task)
+                            self.logger.info("insert_media_to_vm(): Sucessfully inserted media ISO"\
+                                                                    " image to vm {}".format(vm_id))
+        except Exception as exp:
+            self.logger.error("insert_media_to_vm() : exception occurred "\
+                                            "while inserting media CD-ROM")
+            raise vimconn.vimconnException(message=exp)
+
+
+    def get_media_details(self, vca, content):
+        """
+        Method to get catalog item details
+        vca - connection object
+        content - Catalog details
+        Return - Media name, media id
+        """
+        cataloghref_list = []
+        try:
+            if content:
+                vm_list_xmlroot = XmlElementTree.fromstring(content)
+                for child in vm_list_xmlroot.iter():
+                    if 'CatalogItem' in child.tag:
+                        cataloghref_list.append(child.attrib.get('href'))
+                if cataloghref_list is not None:
+                    for href in cataloghref_list:
+                        if href:
+                            response = Http.get(url=href,
+                                        headers=vca.vcloud_session.get_vcloud_headers(),
+                                        verify=vca.verify,
+                                        logger=vca.logger)
+                            if response.status_code != 200:
+                                self.logger.error("REST call {} failed reason : {}"\
+                                             "status code : {}".format(href,
+                                                           response.content,
+                                                      response.status_code))
+                                raise vimconn.vimconnException("get_media_details : Failed to get "\
+                                                                         "catalogitem details")
+                            list_xmlroot = XmlElementTree.fromstring(response.content)
+                            for child in list_xmlroot.iter():
+                                if 'Entity' in child.tag:
+                                    if 'media' in child.attrib.get('href'):
+                                        name = child.attrib.get('name')
+                                        media_id = child.attrib.get('href').split('/').pop()
+                                        return name,media_id
+                            else:
+                                self.logger.debug("Media name and id not found")
+                                return False,False
+        except Exception as exp:
+            self.logger.error("get_media_details : exception occurred "\
+                                               "getting media details")
+            raise vimconn.vimconnException(message=exp)
+
+
+    def retry_rest(self, method, url, add_headers=None, data=None):
+        """ Method to get Token & retry respective REST request
+            Args:
+                api - REST API - Can be one of 'GET' or 'PUT' or 'POST'
+                url - request url to be used
+                add_headers - Additional headers (optional)
+                data - Request payload data to be passed in request
+            Returns:
+                response - Response of request
+        """
+        response = None
+
+        #Get token
+        self.get_token()
+
+        headers=self.vca.vcloud_session.get_vcloud_headers()
+
+        if add_headers:
+            headers.update(add_headers)
+
+        if method == 'GET':
+            response = Http.get(url=url,
+                                headers=headers,
+                                verify=self.vca.verify,
+                                logger=self.vca.logger)
+        elif method == 'PUT':
+            response = Http.put(url=url,
+                                data=data,
+                                headers=headers,
+                                verify=self.vca.verify,
+                                logger=self.logger)
+        elif method == 'POST':
+            response = Http.post(url=url,
+                                 headers=headers,
+                                 data=data,
+                                 verify=self.vca.verify,
+                                 logger=self.vca.logger)
+        elif method == 'DELETE':
+            response = Http.delete(url=url,
+                                 headers=headers,
+                                 verify=self.vca.verify,
+                                 logger=self.vca.logger)
+        return response
+
+
+    def get_token(self):
+        """ Generate a new token if expired
+
+            Returns:
+                The return vca object that letter can be used to connect to vCloud director as admin for VDC
+        """
+        vca = None
+
+        try:
+            self.logger.debug("Generate token for vca {} as {} to datacenter {}.".format(self.org_name,
+                                                                                      self.user,
+                                                                                      self.org_name))
+            vca = VCA(host=self.url,
+                      username=self.user,
+                      service_type=STANDALONE,
+                      version=VCAVERSION,
+                      verify=False,
+                      log=False)
+
+            result = vca.login(password=self.passwd, org=self.org_name)
+            if result is True:
+                result = vca.login(token=vca.token, org=self.org_name, org_url=vca.vcloud_session.org_url)
+                if result is True:
+                    self.logger.info(
+                        "Successfully generated token for vcloud direct org: {} as user: {}".format(self.org_name, self.user))
+                    #Update vca
+                    self.vca = vca
+                    return
+
+        except:
+            raise vimconn.vimconnConnectionException("Can't connect to a vCloud director org: "
+                                                     "{} as user: {}".format(self.org_name, self.user))
+
+        if not vca or not result:
+            raise vimconn.vimconnConnectionException("self.connect() is failed while reconnecting")
+
+
+    def get_vdc_details(self):
+        """ Get VDC details using pyVcloud Lib
+
+            Returns vdc object
+        """
+        vdc = self.vca.get_vdc(self.tenant_name)
+
+        #Retry once, if failed by refreshing token
+        if vdc is None:
+            self.get_token()
+            vdc = self.vca.get_vdc(self.tenant_name)
+
+        return vdc
+
+