]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
VMware: Optional create backing parameters
authorVipin Balachandran <vbala@vmware.com>
Thu, 5 Jun 2014 06:55:53 +0000 (12:25 +0530)
committerVipin Balachandran <vbala@vmware.com>
Mon, 23 Jun 2014 06:02:35 +0000 (11:32 +0530)
The current create backing methods do not support specifying an adapter
type for the backing VM. These methods always create a backing VM with
a single disk and LSI logic adapter. This change adds optional parameters
to create backing methods so that a backing VM can be created without a
disk or with a specific adapter type.

Partial-Bug: #1284284
Partial-Bug: #1287185
Partial-Bug: #1287176
Change-Id: Ifff64eb2be4af1c4218e810366e25dbecdc5847f

cinder/tests/test_vmware_vmdk.py
cinder/tests/test_vmware_volumeops.py
cinder/volume/drivers/vmware/error_util.py
cinder/volume/drivers/vmware/vmdk.py
cinder/volume/drivers/vmware/volumeops.py

index 200ebbf1fc071be07968e565a7416ae4abdd9402..51c2f53b4af20957c189f92d087898056ad38d69 100644 (file)
@@ -353,9 +353,9 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
         volume = FakeObject()
         volume['name'] = 'vol_name'
         backing = FakeMor('VirtualMachine', 'my_back')
-        mux = self._driver._create_backing(volume, host1.obj)
+        mux = self._driver._create_backing(volume, host1.obj, {})
         mux.AndRaise(error_util.VimException('Maintenance mode'))
-        mux = self._driver._create_backing(volume, host2.obj)
+        mux = self._driver._create_backing(volume, host2.obj, {})
         mux.AndReturn(backing)
         m.StubOutWithMock(self._volumeops, 'cancel_retrieval')
         self._volumeops.cancel_retrieval(retrieve_result)
@@ -537,6 +537,7 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
                                        mox.IgnoreArg(), folder,
                                        resource_pool, host,
                                        mox.IgnoreArg(),
+                                       mox.IgnoreArg(),
                                        mox.IgnoreArg()).AndReturn(backing)
 
         m.ReplayAll()
@@ -1074,17 +1075,17 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
         timeout = self._config.vmware_image_transfer_timeout_secs
 
         image_service.show.return_value = fake_image_meta
-        volumeops._get_create_spec.return_value = fake_vm_create_spec
+        volumeops.get_create_spec.return_value = fake_vm_create_spec
         volumeops.get_backing.return_value = fake_backing
 
-        # If _select_ds_for_volume raises an exception, _get_create_spec
+        # If _select_ds_for_volume raises an exception, get_create_spec
         # will not be called.
         _select_ds_for_volume.side_effect = error_util.VimException('Error')
         self.assertRaises(exception.VolumeBackendAPIException,
                           self._driver.copy_image_to_volume,
                           fake_context, fake_volume,
                           image_service, fake_image_id)
-        self.assertFalse(volumeops._get_create_spec.called)
+        self.assertFalse(volumeops.get_create_spec.called)
 
         # If the volume size is greater then than the image size,
         # _extend_vmdk_virtual_disk will be called.
@@ -1095,10 +1096,10 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
                                           image_service, fake_image_id)
         image_service.show.assert_called_with(fake_context, fake_image_id)
         _select_ds_for_volume.assert_called_with(fake_volume)
-        volumeops._get_create_spec.assert_called_with(fake_volume['name'],
-                                                      0,
-                                                      fake_disk_type,
-                                                      fake_summary.name)
+        volumeops.get_create_spec.assert_called_with(fake_volume['name'],
+                                                     0,
+                                                     fake_disk_type,
+                                                     fake_summary.name)
         self.assertTrue(fetch_optimized_image.called)
         fetch_optimized_image.assert_called_with(fake_context, timeout,
                                                  image_service,
@@ -1906,3 +1907,37 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
         """Test extend_volume."""
         self._test_extend_volume(volume_ops, _extend_virtual_disk,
                                  _select_ds_for_volume)
+
+    @mock.patch.object(VMDK_DRIVER, '_get_folder_ds_summary')
+    @mock.patch.object(VMDK_DRIVER, 'volumeops')
+    def test_create_backing_with_params(self, vops, get_folder_ds_summary):
+        resource_pool = mock.sentinel.resource_pool
+        vops.get_dss_rp.return_value = (mock.Mock(), resource_pool)
+        folder = mock.sentinel.folder
+        summary = mock.sentinel.summary
+        get_folder_ds_summary.return_value = (folder, summary)
+
+        volume = {'name': 'vol-1', 'volume_type_id': None, 'size': 1}
+        host = mock.Mock()
+        create_params = {vmdk.CREATE_PARAM_DISK_LESS: True}
+        self._driver._create_backing(volume, host, create_params)
+
+        vops.create_backing_disk_less.assert_called_once_with('vol-1',
+                                                              folder,
+                                                              resource_pool,
+                                                              host,
+                                                              summary.name,
+                                                              None)
+
+        create_params = {vmdk.CREATE_PARAM_ADAPTER_TYPE: 'ide'}
+        self._driver._create_backing(volume, host, create_params)
+
+        vops.create_backing.assert_called_once_with('vol-1',
+                                                    units.Mi,
+                                                    vmdk.THIN_VMDK_TYPE,
+                                                    folder,
+                                                    resource_pool,
+                                                    host,
+                                                    summary.name,
+                                                    None,
+                                                    'ide')
index d3dade714c29df6a9c7c580db3c384a335a3360f..e1952eed617dd3eba8a23fddf5bb0936bf266100 100644 (file)
@@ -402,29 +402,60 @@ class VolumeOpsTestCase(test.TestCase):
         self.assertEqual(expected_invoke_api,
                          self.session.invoke_api.mock_calls)
 
-    def test_get_create_spec(self):
+    def test_create_specs_for_ide_disk_add(self):
         factory = self.session.vim.client.factory
         factory.create.return_value = mock.Mock(spec=object)
-        name = mock.sentinel.name
+
         size_kb = 0.5
         disk_type = 'thin'
-        ds_name = mock.sentinel.ds_name
-        ret = self.vops._get_create_spec(name, size_kb, disk_type, ds_name)
-        self.assertEqual(name, ret.name)
-        self.assertEqual('[%s]' % ds_name, ret.files.vmPathName)
-        self.assertEqual(1, ret.deviceChange[1].device.capacityInKB)
-        self.assertEqual("vmx-08", ret.version)
-        expected = [mock.call.create('ns0:VirtualLsiLogicController'),
+        adapter_type = 'ide'
+        ret = self.vops._create_specs_for_disk_add(size_kb, disk_type,
+                                                   adapter_type)
+        self.assertFalse(hasattr(ret[0].device, 'sharedBus'))
+        self.assertEqual(1, ret[1].device.capacityInKB)
+        expected = [mock.call.create('ns0:VirtualIDEController'),
                     mock.call.create('ns0:VirtualDeviceConfigSpec'),
                     mock.call.create('ns0:VirtualDisk'),
                     mock.call.create('ns0:VirtualDiskFlatVer2BackingInfo'),
+                    mock.call.create('ns0:VirtualDeviceConfigSpec')]
+        factory.create.assert_has_calls(expected, any_order=True)
+
+    def test_create_specs_for_scsi_disk_add(self):
+        factory = self.session.vim.client.factory
+        factory.create.return_value = mock.Mock(spec=object)
+
+        size_kb = 2
+        disk_type = 'thin'
+        adapter_type = 'lsiLogicsas'
+        ret = self.vops._create_specs_for_disk_add(size_kb, disk_type,
+                                                   adapter_type)
+        self.assertEqual('noSharing', ret[0].device.sharedBus)
+        self.assertEqual(size_kb, ret[1].device.capacityInKB)
+        expected = [mock.call.create('ns0:VirtualLsiLogicSASController'),
                     mock.call.create('ns0:VirtualDeviceConfigSpec'),
-                    mock.call.create('ns0:VirtualMachineFileInfo'),
-                    mock.call.create('ns0:VirtualMachineConfigSpec')]
+                    mock.call.create('ns0:VirtualDisk'),
+                    mock.call.create('ns0:VirtualDiskFlatVer2BackingInfo'),
+                    mock.call.create('ns0:VirtualDeviceConfigSpec')]
+        factory.create.assert_has_calls(expected, any_order=True)
+
+    def test_get_create_spec_disk_less(self):
+        factory = self.session.vim.client.factory
+        factory.create.return_value = mock.Mock(spec=object)
+        name = mock.sentinel.name
+        ds_name = mock.sentinel.ds_name
+        profile_id = mock.sentinel.profile_id
+        ret = self.vops._get_create_spec_disk_less(name, ds_name, profile_id)
+        self.assertEqual(name, ret.name)
+        self.assertEqual('[%s]' % ds_name, ret.files.vmPathName)
+        self.assertEqual("vmx-08", ret.version)
+        self.assertEqual(profile_id, ret.vmProfile[0].profileId)
+        expected = [mock.call.create('ns0:VirtualMachineFileInfo'),
+                    mock.call.create('ns0:VirtualMachineConfigSpec'),
+                    mock.call.create('ns0:VirtualMachineDefinedProfileSpec')]
         factory.create.assert_has_calls(expected, any_order=True)
 
     @mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
-                '_get_create_spec')
+                'get_create_spec')
     def test_create_backing(self, get_create_spec):
         create_spec = mock.sentinel.create_spec
         get_create_spec.return_value = create_spec
@@ -436,15 +467,49 @@ class VolumeOpsTestCase(test.TestCase):
         name = 'backing_name'
         size_kb = mock.sentinel.size_kb
         disk_type = mock.sentinel.disk_type
+        adapter_type = mock.sentinel.adapter_type
         folder = mock.sentinel.folder
         resource_pool = mock.sentinel.resource_pool
         host = mock.sentinel.host
         ds_name = mock.sentinel.ds_name
+        profile_id = mock.sentinel.profile_id
         ret = self.vops.create_backing(name, size_kb, disk_type, folder,
-                                       resource_pool, host, ds_name)
+                                       resource_pool, host, ds_name,
+                                       profile_id, adapter_type)
         self.assertEqual(mock.sentinel.result, ret)
         get_create_spec.assert_called_once_with(name, size_kb, disk_type,
-                                                ds_name, None)
+                                                ds_name, profile_id,
+                                                adapter_type)
+        self.session.invoke_api.assert_called_once_with(self.session.vim,
+                                                        'CreateVM_Task',
+                                                        folder,
+                                                        config=create_spec,
+                                                        pool=resource_pool,
+                                                        host=host)
+        self.session.wait_for_task.assert_called_once_with(task)
+
+    @mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
+                '_get_create_spec_disk_less')
+    def test_create_backing_disk_less(self, get_create_spec_disk_less):
+        create_spec = mock.sentinel.create_spec
+        get_create_spec_disk_less.return_value = create_spec
+        task = mock.sentinel.task
+        self.session.invoke_api.return_value = task
+        task_info = mock.Mock(spec=object)
+        task_info.result = mock.sentinel.result
+        self.session.wait_for_task.return_value = task_info
+        name = 'backing_name'
+        folder = mock.sentinel.folder
+        resource_pool = mock.sentinel.resource_pool
+        host = mock.sentinel.host
+        ds_name = mock.sentinel.ds_name
+        profile_id = mock.sentinel.profile_id
+        ret = self.vops.create_backing_disk_less(name, folder, resource_pool,
+                                                 host, ds_name, profile_id)
+
+        self.assertEqual(mock.sentinel.result, ret)
+        get_create_spec_disk_less.assert_called_once_with(name, ds_name,
+                                                          profile_id)
         self.session.invoke_api.assert_called_once_with(self.session.vim,
                                                         'CreateVM_Task',
                                                         folder,
@@ -814,3 +879,34 @@ class VolumeOpsTestCase(test.TestCase):
                                            newCapacityKb=fake_size_in_kb,
                                            eagerZero=False)
         self.session.wait_for_task.assert_called_once_with(task)
+
+
+class ControllerTypeTest(test.TestCase):
+    """Unit tests for ControllerType."""
+
+    def test_get_controller_type(self):
+        self.assertEqual(volumeops.ControllerType.LSI_LOGIC,
+                         volumeops.ControllerType.get_controller_type(
+                             'lsiLogic'))
+        self.assertEqual(volumeops.ControllerType.BUS_LOGIC,
+                         volumeops.ControllerType.get_controller_type(
+                             'busLogic'))
+        self.assertEqual(volumeops.ControllerType.LSI_LOGIC_SAS,
+                         volumeops.ControllerType.get_controller_type(
+                             'lsiLogicsas'))
+        self.assertEqual(volumeops.ControllerType.IDE,
+                         volumeops.ControllerType.get_controller_type(
+                             'ide'))
+        self.assertRaises(error_util.InvalidAdapterTypeException,
+                          volumeops.ControllerType.get_controller_type,
+                          'invalid_type')
+
+    def test_is_scsi_controller(self):
+        self.assertTrue(volumeops.ControllerType.is_scsi_controller(
+            volumeops.ControllerType.LSI_LOGIC))
+        self.assertTrue(volumeops.ControllerType.is_scsi_controller(
+            volumeops.ControllerType.BUS_LOGIC))
+        self.assertTrue(volumeops.ControllerType.is_scsi_controller(
+            volumeops.ControllerType.LSI_LOGIC_SAS))
+        self.assertFalse(volumeops.ControllerType.is_scsi_controller(
+            volumeops.ControllerType.IDE))
index fc69d432668fca085d794985925cac61050fcd24..ca93d8c0d350cdea466ed3a35ef685aa57ddaaec 100644 (file)
@@ -67,3 +67,8 @@ class VMwaredriverConfigurationException(VMwareDriverException):
     """Base class for all configuration exceptions.
     """
     message = _("VMware VMDK driver configuration error.")
+
+
+class InvalidAdapterTypeException(VMwareDriverException):
+    """Thrown when the disk adapter type is invalid."""
+    message = _("Invalid disk adapter type: %(invalid_type)s.")
index cc1cc315124cbe60b93eebecfd47798784f10412..a7d90860328cb14996fbe9205693c9dd5a475e3c 100644 (file)
@@ -46,6 +46,9 @@ THIN_VMDK_TYPE = 'thin'
 THICK_VMDK_TYPE = 'thick'
 EAGER_ZEROED_THICK_VMDK_TYPE = 'eagerZeroedThick'
 
+CREATE_PARAM_ADAPTER_TYPE = 'adapter_type'
+CREATE_PARAM_DISK_LESS = 'disk_less'
+
 vmdk_opts = [
     cfg.StrOpt('vmware_host_ip',
                default=None,
@@ -426,11 +429,13 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
                                             EAGER_ZEROED_THICK_VMDK_TYPE),
                                            THIN_VMDK_TYPE)
 
-    def _create_backing(self, volume, host):
+    def _create_backing(self, volume, host, create_params={}):
         """Create volume backing under the given host.
 
         :param volume: Volume object
         :param host: Reference of the host
+        :param create_params: Dictionary specifying optional parameters for
+                              backing VM creation
         :return: Reference to the created backing
         """
         # Get datastores and resource pool of the host
@@ -439,21 +444,41 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
         (folder, summary) = self._get_folder_ds_summary(volume,
                                                         resource_pool,
                                                         datastores)
-        disk_type = VMwareEsxVmdkDriver._get_disk_type(volume)
-        size_kb = volume['size'] * units.Mi
+
+        # check if a storage profile needs to be associated with the backing VM
         storage_profile = self._get_storage_profile(volume)
         profileId = None
         if self._storage_policy_enabled and storage_profile:
             profile = self.volumeops.retrieve_profile_id(storage_profile)
             if profile:
                 profileId = profile.uniqueId
+
+        # default is a backing with single disk
+        disk_less = create_params.get(CREATE_PARAM_DISK_LESS, False)
+        if disk_less:
+            # create a disk-less backing-- disk can be added later; for e.g.,
+            # by copying an image
+            return self.volumeops.create_backing_disk_less(volume['name'],
+                                                           folder,
+                                                           resource_pool,
+                                                           host,
+                                                           summary.name,
+                                                           profileId)
+
+        # create a backing with single disk
+        disk_type = VMwareEsxVmdkDriver._get_disk_type(volume)
+        size_kb = volume['size'] * units.Mi
+        adapter_type = create_params.get(CREATE_PARAM_ADAPTER_TYPE,
+                                         'lsiLogic')
         return self.volumeops.create_backing(volume['name'],
                                              size_kb,
-                                             disk_type, folder,
+                                             disk_type,
+                                             folder,
                                              resource_pool,
                                              host,
                                              summary.name,
-                                             profileId)
+                                             profileId,
+                                             adapter_type)
 
     def _relocate_backing(self, volume, backing, host):
         pass
@@ -495,13 +520,15 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
         LOG.error(msg)
         raise error_util.VimException(msg)
 
-    def _create_backing_in_inventory(self, volume):
+    def _create_backing_in_inventory(self, volume, create_params={}):
         """Creates backing under any suitable host.
 
         The method tries to pick datastore that can fit the volume under
         any host in the inventory.
 
         :param volume: Volume object
+        :param create_params: Dictionary specifying optional parameters for
+                              backing VM creation
         :return: Reference to the created backing
         """
 
@@ -513,7 +540,9 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
             backing = None
             for host in hosts:
                 try:
-                    backing = self._create_backing(volume, host.obj)
+                    backing = self._create_backing(volume,
+                                                   host.obj,
+                                                   create_params)
                     if backing:
                         break
                 except error_util.VimException as excep:
@@ -879,10 +908,10 @@ class VMwareEsxVmdkDriver(driver.VolumeDriver):
         # The size of stream optimized glance image is often suspect,
         # so better let VC figure out the disk capacity during import.
         dummy_disk_size = 0
-        vm_create_spec = self.volumeops._get_create_spec(volume['name'],
-                                                         dummy_disk_size,
-                                                         disk_type,
-                                                         summary.name)
+        vm_create_spec = self.volumeops.get_create_spec(volume['name'],
+                                                        dummy_disk_size,
+                                                        disk_type,
+                                                        summary.name)
         # convert vm_create_spec to vm_import_spec
         cf = self.session.vim.client.factory
         vm_import_spec = cf.create('ns0:VirtualMachineImportSpec')
index 94d34b39b9e806290f3329f1aafafbf5b7f9a95d..8bbdd0b765afa9c0c1d901409c2efb379a4a5412 100644 (file)
@@ -57,6 +57,43 @@ def split_datastore_path(datastore_path):
     return (datastore_name.strip(), folder_path.strip(), file_name.strip())
 
 
+class ControllerType:
+    """Encapsulate various controller types."""
+
+    LSI_LOGIC = 'VirtualLsiLogicController'
+    BUS_LOGIC = 'VirtualBusLogicController'
+    LSI_LOGIC_SAS = 'VirtualLsiLogicSASController'
+    IDE = 'VirtualIDEController'
+
+    CONTROLLER_TYPE_DICT = {'lsiLogic': LSI_LOGIC,
+                            'busLogic': BUS_LOGIC,
+                            'lsiLogicsas': LSI_LOGIC_SAS,
+                            'ide': IDE}
+
+    @staticmethod
+    def get_controller_type(adapter_type):
+        """Get the disk controller type based on the given adapter type.
+
+        :param adapter_type: disk adapter type
+        :return: controller type corresponding to the given adapter type
+        :raises: InvalidAdapterTypeException
+        """
+        if adapter_type in ControllerType.CONTROLLER_TYPE_DICT:
+            return ControllerType.CONTROLLER_TYPE_DICT[adapter_type]
+        raise error_util.InvalidAdapterTypeException(invalid_type=adapter_type)
+
+    @staticmethod
+    def is_scsi_controller(controller_type):
+        """Check if the given controller is a SCSI controller.
+
+        :param controller_type: controller type
+        :return: True if the controller is a SCSI controller
+        """
+        return controller_type in [ControllerType.LSI_LOGIC,
+                                   ControllerType.BUS_LOGIC,
+                                   ControllerType.LSI_LOGIC_SAS]
+
+
 class VMwareVolumeOps(object):
     """Manages volume operations."""
 
@@ -348,22 +385,21 @@ class VMwareVolumeOps(object):
                    "%(size)s GB."),
                  {'name': name, 'size': requested_size_in_gb})
 
-    def _get_create_spec(self, name, size_kb, disk_type, ds_name,
-                         profileId=None):
-        """Return spec for creating volume backing.
+    def _create_specs_for_disk_add(self, size_kb, disk_type, adapter_type):
+        """Create controller and disk specs for adding a new disk.
 
-        :param name: Name of the backing
-        :param size_kb: Size in KB of the backing
-        :param disk_type: VMDK type for the disk
-        :param ds_name: Datastore name where the disk is to be provisioned
-        :param profileId: storage profile ID for the backing
-        :return: Spec for creation
+        :param size_kb: disk size in KB
+        :param disk_type: disk provisioning type
+        :param adapter_type: disk adapter type
+        :return: list containing controller and disk specs
         """
         cf = self._session.vim.client.factory
-        controller_device = cf.create('ns0:VirtualLsiLogicController')
+        controller_type = ControllerType.get_controller_type(adapter_type)
+        controller_device = cf.create('ns0:%s' % controller_type)
         controller_device.key = -100
         controller_device.busNumber = 0
-        controller_device.sharedBus = 'noSharing'
+        if ControllerType.is_scsi_controller(controller_type):
+            controller_device.sharedBus = 'noSharing'
         controller_spec = cf.create('ns0:VirtualDeviceConfigSpec')
         controller_spec.operation = 'add'
         controller_spec.device = controller_device
@@ -387,6 +423,17 @@ class VMwareVolumeOps(object):
         disk_spec.fileOperation = 'create'
         disk_spec.device = disk_device
 
+        return [controller_spec, disk_spec]
+
+    def _get_create_spec_disk_less(self, name, ds_name, profileId=None):
+        """Return spec for creating disk-less backing.
+
+        :param name: Name of the backing
+        :param ds_name: Datastore name where the disk is to be provisioned
+        :param profileId: storage profile ID for the backing
+        :return: Spec for creation
+        """
+        cf = self._session.vim.client.factory
         vm_file_info = cf.create('ns0:VirtualMachineFileInfo')
         vm_file_info.vmPathName = '[%s]' % ds_name
 
@@ -395,7 +442,6 @@ class VMwareVolumeOps(object):
         create_spec.guestId = 'otherGuest'
         create_spec.numCPUs = 1
         create_spec.memoryMB = 128
-        create_spec.deviceChange = [controller_spec, disk_spec]
         create_spec.files = vm_file_info
         # set the Hardware version to the lowest version supported by ESXi5.0
         # and compatible with vCenter Server 5.0
@@ -408,11 +454,38 @@ class VMwareVolumeOps(object):
             vmProfile.profileId = profileId
             create_spec.vmProfile = [vmProfile]
 
-        LOG.debug("Spec for creating the backing: %s." % create_spec)
         return create_spec
 
+    def get_create_spec(self, name, size_kb, disk_type, ds_name,
+                        profileId=None, adapter_type='lsiLogic'):
+        """Return spec for creating backing with a single disk.
+
+        :param name: name of the backing
+        :param size_kb: disk size in KB
+        :param disk_type: disk provisioning type
+        :param ds_name: datastore name where the disk is to be provisioned
+        :param profileId: storage profile ID for the backing
+        :param adapter_type: disk adapter type
+        :return: spec for creation
+        """
+        create_spec = self._get_create_spec_disk_less(name, ds_name, profileId)
+        create_spec.deviceChange = self._create_specs_for_disk_add(
+            size_kb, disk_type, adapter_type)
+        return create_spec
+
+    def _create_backing_int(self, folder, resource_pool, host, create_spec):
+        """Helper for create backing methods."""
+        LOG.debug("Creating volume backing with spec: %s.", create_spec)
+        task = self._session.invoke_api(self._session.vim, 'CreateVM_Task',
+                                        folder, config=create_spec,
+                                        pool=resource_pool, host=host)
+        task_info = self._session.wait_for_task(task)
+        backing = task_info.result
+        LOG.info(_("Successfully created volume backing: %s."), backing)
+        return backing
+
     def create_backing(self, name, size_kb, disk_type, folder, resource_pool,
-                       host, ds_name, profileId=None):
+                       host, ds_name, profileId=None, adapter_type='lsiLogic'):
         """Create backing for the volume.
 
         Creates a VM with one VMDK based on the given inputs.
@@ -425,26 +498,51 @@ class VMwareVolumeOps(object):
         :param host: Host reference
         :param ds_name: Datastore name where the disk is to be provisioned
         :param profileId: storage profile ID to be associated with backing
+        :param adapter_type: Disk adapter type
         :return: Reference to the created backing entity
         """
-        LOG.debug("Creating volume backing name: %(name)s "
-                  "disk_type: %(disk_type)s size_kb: %(size_kb)s at "
-                  "folder: %(folder)s resourse pool: %(resource_pool)s "
-                  "datastore name: %(ds_name)s profileId: %(profile)s." %
+        LOG.debug("Creating volume backing with name: %(name)s "
+                  "disk_type: %(disk_type)s size_kb: %(size_kb)s "
+                  "adapter_type: %(adapter_type)s profileId: %(profile)s at "
+                  "folder: %(folder)s resource_pool: %(resource_pool)s "
+                  "host: %(host)s datastore_name: %(ds_name)s.",
                   {'name': name, 'disk_type': disk_type, 'size_kb': size_kb,
                    'folder': folder, 'resource_pool': resource_pool,
-                   'ds_name': ds_name, 'profile': profileId})
+                   'ds_name': ds_name, 'profile': profileId, 'host': host,
+                   'adapter_type': adapter_type})
 
-        create_spec = self._get_create_spec(name, size_kb, disk_type, ds_name,
-                                            profileId)
-        task = self._session.invoke_api(self._session.vim, 'CreateVM_Task',
-                                        folder, config=create_spec,
-                                        pool=resource_pool, host=host)
-        LOG.debug("Initiated creation of volume backing: %s." % name)
-        task_info = self._session.wait_for_task(task)
-        backing = task_info.result
-        LOG.info(_("Successfully created volume backing: %s.") % backing)
-        return backing
+        create_spec = self.get_create_spec(name, size_kb, disk_type, ds_name,
+                                           profileId, adapter_type)
+        return self._create_backing_int(folder, resource_pool, host,
+                                        create_spec)
+
+    def create_backing_disk_less(self, name, folder, resource_pool,
+                                 host, ds_name, profileId=None):
+        """Create disk-less volume backing.
+
+        This type of backing is useful for creating volume from image. The
+        downloaded image from the image service can be copied to a virtual
+        disk of desired provisioning type and added to the backing VM.
+
+        :param name: Name of the backing
+        :param folder: Folder where the backing is created
+        :param resource_pool: Resource pool reference
+        :param host: Host reference
+        :param ds_name: Name of the datastore used for VM storage
+        :param profileId: Storage profile ID to be associated with backing
+        :return: Reference to the created backing entity
+        """
+        LOG.debug("Creating disk-less volume backing with name: %(name)s "
+                  "profileId: %(profile)s at folder: %(folder)s "
+                  "resource pool: %(resource_pool)s host: %(host)s "
+                  "datastore_name: %(ds_name)s.",
+                  {'name': name, 'profile': profileId, 'folder': folder,
+                   'resource_pool': resource_pool, 'host': host,
+                   'ds_name': ds_name})
+
+        create_spec = self._get_create_spec_disk_less(name, ds_name, profileId)
+        return self._create_backing_int(folder, resource_pool, host,
+                                        create_spec)
 
     def get_datastore(self, backing):
         """Get datastore where the backing resides.