From 18325aebc609a4cf2b4b7b939716c982411b31b6 Mon Sep 17 00:00:00 2001 From: Vipin Balachandran Date: Mon, 11 Jul 2016 22:38:08 +0530 Subject: [PATCH] VMware: Send additional connection info Change I743e676372703e74178c79683dd622d530981e04 removed volume backend driver calls for creating and restoring volume backups. The overridden methods for creating and restoring backups in the VMDK driver is no longer called and this breaks the backup- restore of volumes created by the VMDK driver. Now backup and restore of volumes use os-brick connectors. Change Ia1a20f93780593b1efbb74484c3fdd3ca3564290 added a new connector in os-brick to support vmdk volumes. The new vmdk connector requires additional connection info so that it can connect to vCenter server and access the volume vmdk to perform volume connect and disconnect. Closes-bug: #1602660 Change-Id: I66a30366ccdae74e13f7a0e35cd7bfdfed2785be --- .../volume/drivers/vmware/test_vmware_vmdk.py | 70 ++++++++++++++++--- cinder/volume/drivers/vmware/vmdk.py | 60 ++++++++++++---- .../vmdk_backup_restore-41f807b7bc8e0ae8.yaml | 4 ++ 3 files changed, 112 insertions(+), 22 deletions(-) create mode 100644 releasenotes/notes/vmdk_backup_restore-41f807b7bc8e0ae8.yaml diff --git a/cinder/tests/unit/volume/drivers/vmware/test_vmware_vmdk.py b/cinder/tests/unit/volume/drivers/vmware/test_vmware_vmdk.py index 24722fdf26d..061059d7084 100644 --- a/cinder/tests/unit/volume/drivers/vmware/test_vmware_vmdk.py +++ b/cinder/tests/unit/volume/drivers/vmware/test_vmware_vmdk.py @@ -1681,13 +1681,67 @@ class VMwareVcVmdkDriverTestCase(test.TestCase): vops.get_dc.assert_called_once_with(rp) get_volume_group_folder.assert_called_once_with(dc, vol['project_id']) + @mock.patch.object(VMDK_DRIVER, 'volumeops') + def _test_get_connection_info(self, vops, vmdk_connector=False): + volume = self._create_volume_obj() + backing = mock.Mock(value='ref-1') + if vmdk_connector: + vmdk_path = mock.sentinel.vmdk_path + vops.get_vmdk_path.return_value = vmdk_path + + datastore = mock.Mock(value='ds-1') + vops.get_datastore.return_value = datastore + + datacenter = mock.Mock(value='dc-1') + vops.get_dc.return_value = datacenter + + connector = {'platform': mock.sentinel.platform, + 'os_type': mock.sentinel.os_type} + else: + connector = {'instance': 'vm-1'} + ret = self._driver._get_connection_info(volume, backing, connector) + + self.assertEqual('vmdk', ret['driver_volume_type']) + self.assertEqual('ref-1', ret['data']['volume']) + self.assertEqual(volume.id, ret['data']['volume_id']) + self.assertEqual(volume.name, ret['data']['name']) + + if vmdk_connector: + self.assertEqual(volume.size * units.Gi, ret['data']['vmdk_size']) + self.assertEqual(vmdk_path, ret['data']['vmdk_path']) + self.assertEqual('ds-1', ret['data']['datastore']) + self.assertEqual('dc-1', ret['data']['datacenter']) + + config = self._driver.configuration + exp_config = { + 'vmware_host_ip': config.vmware_host_ip, + 'vmware_host_port': config.vmware_host_port, + 'vmware_host_username': config.vmware_host_username, + 'vmware_host_password': config.vmware_host_password, + 'vmware_api_retry_count': config.vmware_api_retry_count, + 'vmware_task_poll_interval': config.vmware_task_poll_interval, + 'vmware_ca_file': config.vmware_ca_file, + 'vmware_insecure': config.vmware_insecure, + 'vmware_tmp_dir': config.vmware_tmp_dir, + 'vmware_image_transfer_timeout_secs': + config.vmware_image_transfer_timeout_secs, + } + self.assertEqual(exp_config, ret['data']['config']) + + def test_get_connection_info(self): + self._test_get_connection_info() + + def test_get_connection_info_vmdk_connector(self): + self._test_get_connection_info(vmdk_connector=True) + @mock.patch.object(VMDK_DRIVER, 'volumeops') @mock.patch('oslo_vmware.vim_util.get_moref') @mock.patch.object(VMDK_DRIVER, '_create_backing') @mock.patch.object(VMDK_DRIVER, '_relocate_backing') + @mock.patch.object(VMDK_DRIVER, '_get_connection_info') def _test_initialize_connection( - self, relocate_backing, create_backing, get_moref, vops, - backing_exists=True, instance_exists=True): + self, get_connection_info, relocate_backing, create_backing, + get_moref, vops, backing_exists=True, instance_exists=True): backing_val = mock.sentinel.backing_val backing = mock.Mock(value=backing_val) @@ -1709,14 +1763,13 @@ class VMwareVcVmdkDriverTestCase(test.TestCase): else: connector = {} + conn_info = mock.sentinel.conn_info + get_connection_info.return_value = conn_info + volume = self._create_volume_obj() - conn_info = self._driver.initialize_connection(volume, connector) - - self.assertEqual('vmdk', conn_info['driver_volume_type']) - self.assertEqual(backing_val, conn_info['data']['volume']) - self.assertEqual(volume.id, conn_info['data']['volume_id']) - self.assertEqual(volume.name, conn_info['data']['name']) + ret = self._driver.initialize_connection(volume, connector) + self.assertEqual(conn_info, ret) if instance_exists: vops.get_host.assert_called_once_with(instance_moref) if backing_exists: @@ -1731,6 +1784,7 @@ class VMwareVcVmdkDriverTestCase(test.TestCase): else: create_backing.assert_not_called() relocate_backing.assert_not_called() + get_connection_info.assert_called_once_with(volume, backing, connector) def test_initialize_connection_with_instance_and_backing(self): self._test_initialize_connection() diff --git a/cinder/volume/drivers/vmware/vmdk.py b/cinder/volume/drivers/vmware/vmdk.py index ceb4c7d3873..7b7ed359731 100644 --- a/cinder/volume/drivers/vmware/vmdk.py +++ b/cinder/volume/drivers/vmware/vmdk.py @@ -502,6 +502,51 @@ class VMwareVcVmdkDriver(driver.VolumeDriver): return (host_ref, resource_pool, folder, summary) + def _get_connection_info(self, volume, backing, connector): + connection_info = {'driver_volume_type': 'vmdk'} + connection_info['data'] = { + 'volume': backing.value, + 'volume_id': volume.id, + 'name': volume.name, + } + + # vmdk connector in os-brick needs additional connection info. + if 'platform' in connector and 'os_type' in connector: + connection_info['data']['vmdk_size'] = volume['size'] * units.Gi + + vmdk_path = self.volumeops.get_vmdk_path(backing) + connection_info['data']['vmdk_path'] = vmdk_path + + datastore = self.volumeops.get_datastore(backing) + connection_info['data']['datastore'] = datastore.value + + datacenter = self.volumeops.get_dc(backing) + connection_info['data']['datacenter'] = datacenter.value + + config = self.configuration + vmdk_connector_config = { + 'vmware_host_ip': config.vmware_host_ip, + 'vmware_host_port': config.vmware_host_port, + 'vmware_host_username': config.vmware_host_username, + 'vmware_host_password': config.vmware_host_password, + 'vmware_api_retry_count': config.vmware_api_retry_count, + 'vmware_task_poll_interval': config.vmware_task_poll_interval, + 'vmware_ca_file': config.vmware_ca_file, + 'vmware_insecure': config.vmware_insecure, + 'vmware_tmp_dir': config.vmware_tmp_dir, + 'vmware_image_transfer_timeout_secs': + config.vmware_image_transfer_timeout_secs, + } + connection_info['data']['config'] = vmdk_connector_config + + LOG.debug("Returning connection_info (volume: '%(volume)s', volume_id:" + " '%(volume_id)s') for connector: %(connector)s.", + {'volume': connection_info['data']['volume'], + 'volume_id': volume.id, + 'connector': connector}) + + return connection_info + def _initialize_connection(self, volume, connector): """Get information of volume's backing. @@ -511,8 +556,6 @@ class VMwareVcVmdkDriver(driver.VolumeDriver): :param connector: Connector information :return: Return connection information """ - connection_info = {'driver_volume_type': 'vmdk'} - backing = self.volumeops.get_backing(volume.name) if 'instance' in connector: # The instance exists @@ -543,18 +586,7 @@ class VMwareVcVmdkDriver(driver.VolumeDriver): # Create backing backing = self._create_backing(volume) - # Set volume ID and backing moref value and name. - connection_info['data'] = {'volume': backing.value, - 'volume_id': volume.id, - 'name': volume.name} - - LOG.info(_LI("Returning connection_info: %(info)s for volume: " - "%(volume)s with connector: %(connector)s."), - {'info': connection_info, - 'volume': volume.name, - 'connector': connector}) - - return connection_info + return self._get_connection_info(volume, backing, connector) def initialize_connection(self, volume, connector): """Allow connection to connector and return connection info. diff --git a/releasenotes/notes/vmdk_backup_restore-41f807b7bc8e0ae8.yaml b/releasenotes/notes/vmdk_backup_restore-41f807b7bc8e0ae8.yaml new file mode 100644 index 00000000000..05ae0c92f04 --- /dev/null +++ b/releasenotes/notes/vmdk_backup_restore-41f807b7bc8e0ae8.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - Fixed backup and restore of volumes in VMware VMDK driver. +