cinder/cinder/tests/unit/windows/test_iscsi.py
Lucian Petrut 0914b850f9 Rename 'WindowsDriver' to 'WindowsISCSIDriver'
This was the first Cinder Volume driver available on Windows,
for which reason it was simply called 'WindowsDriver'.

As we've added another driver available on Windows, the SMB driver,
this has caused quite some confusion.

For this reason, we're now renaming it to 'WindowsISCSIDriver'.
The new location will be:
    cinder.volume.drivers.windows.iscsi.WindowsISCSIDriver

Change-Id: I3877491463dce3d46f7ac0e194ffdf46a0e7c84c
2018-01-19 14:10:03 +02:00

481 lines
20 KiB
Python

# Copyright 2012 Pedro Navarro Perez
# Copyright 2015 Cloudbase Solutions SRL
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Unit tests for Windows Server 2012 OpenStack Cinder volume driver
"""
import os
import ddt
import mock
from oslo_utils import fileutils
from oslo_utils import units
from cinder import context
from cinder import exception
from cinder.image import image_utils
from cinder import test
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit import fake_volume
from cinder.tests.unit.windows import db_fakes
from cinder.volume import configuration as conf
from cinder.volume.drivers.windows import iscsi as windows_iscsi
@ddt.ddt
class TestWindowsISCSIDriver(test.TestCase):
@mock.patch.object(windows_iscsi, 'utilsfactory')
def setUp(self, mock_utilsfactory):
super(TestWindowsISCSIDriver, self).setUp()
self.configuration = conf.Configuration(None)
self.configuration.append_config_values(windows_iscsi.windows_opts)
self.flags(windows_iscsi_lun_path='fake_iscsi_lun_path')
self.flags(image_conversion_dir='fake_image_conversion_dir')
self._driver = windows_iscsi.WindowsISCSIDriver(
configuration=self.configuration)
@mock.patch.object(fileutils, 'ensure_tree')
def test_do_setup(self, mock_ensure_tree):
self._driver.do_setup(mock.sentinel.context)
mock_ensure_tree.assert_has_calls(
[mock.call('fake_iscsi_lun_path'),
mock.call('fake_image_conversion_dir')])
@mock.patch.object(windows_iscsi.WindowsISCSIDriver, '_get_portals')
def test_check_for_setup_error(self, mock_get_portals):
self._driver.check_for_setup_error()
mock_get_portals.assert_called_once_with()
@ddt.data(True, False)
def test_get_portals(self, portals_available=True):
iscsi_port = mock.sentinel.iscsi_port
available_ips = ['fake_ip0', 'fake_ip1', 'fake_unrequested_ip']
requested_ips = available_ips[:-1] + ['fake_inexistent_ips']
available_portals = ([":".join([ip_addr, str(iscsi_port)])
for ip_addr in available_ips]
if portals_available else [])
self._driver.configuration = mock.Mock()
self._driver.configuration.target_port = iscsi_port
self._driver.configuration.target_ip_address = requested_ips[0]
self._driver.configuration.iscsi_secondary_ip_addresses = (
requested_ips[1:])
self._driver._tgt_utils.get_portal_locations.return_value = (
available_portals)
if portals_available:
portals = self._driver._get_portals()
self.assertEqual(set(available_portals[:-1]), set(portals))
else:
self.assertRaises(exception.VolumeDriverException,
self._driver._get_portals)
self._driver._tgt_utils.get_portal_locations.assert_called_once_with(
available_only=True,
fail_if_none_found=True)
@ddt.data(True, False)
@mock.patch.object(windows_iscsi.WindowsISCSIDriver, '_get_portals')
@mock.patch.object(windows_iscsi.WindowsISCSIDriver, '_get_target_name')
def test_get_host_information(self, multipath, mock_get_target_name,
mock_get_portals):
tgt_utils = self._driver._tgt_utils
fake_auth_meth = 'CHAP'
fake_chap_username = 'fake_chap_username'
fake_chap_password = 'fake_chap_password'
fake_target_iqn = 'fake_target_iqn'
fake_host_info = {'target_iqn': 'fake_target_iqn',
'fake_prop': 'fake_value'}
fake_provider_auth = "%s %s %s" % (fake_auth_meth,
fake_chap_username,
fake_chap_password)
fake_portals = [mock.sentinel.portal_location0,
mock.sentinel.portal_location1]
volume = fake_volume.fake_volume_obj(mock.sentinel.context,
provider_auth=fake_provider_auth)
mock_get_target_name.return_value = mock.sentinel.target_name
mock_get_portals.return_value = fake_portals
tgt_utils.get_target_information.return_value = fake_host_info
expected_host_info = dict(fake_host_info,
auth_method=fake_auth_meth,
auth_username=fake_chap_username,
auth_password=fake_chap_password,
target_discovered=False,
target_portal=fake_portals[0],
target_lun=0,
volume_id=volume.id)
if multipath:
expected_host_info['target_portals'] = fake_portals
expected_host_info['target_iqns'] = [fake_target_iqn] * 2
expected_host_info['target_luns'] = [0] * 2
host_info = self._driver._get_host_information(volume, multipath)
self.assertEqual(expected_host_info, host_info)
mock_get_target_name.assert_called_once_with(volume)
mock_get_portals.assert_called_once_with()
tgt_utils.get_target_information.assert_called_once_with(
mock.sentinel.target_name)
@mock.patch.object(windows_iscsi.WindowsISCSIDriver,
'_get_host_information')
def test_initialize_connection(self, mock_get_host_info):
tgt_utils = self._driver._tgt_utils
volume = fake_volume.fake_volume_obj(mock.sentinel.fake_context)
fake_initiator = db_fakes.get_fake_connector_info()
fake_initiator['multipath'] = mock.sentinel.multipath
fake_host_info = {'fake_host_prop': 'fake_value'}
mock_get_host_info.return_value = fake_host_info
expected_conn_info = {'driver_volume_type': 'iscsi',
'data': fake_host_info}
conn_info = self._driver.initialize_connection(volume,
fake_initiator)
self.assertEqual(expected_conn_info, conn_info)
mock_get_host_info.assert_called_once_with(
volume, mock.sentinel.multipath)
mock_associate = tgt_utils.associate_initiator_with_iscsi_target
mock_associate.assert_called_once_with(
fake_initiator['initiator'],
volume.provider_location)
def test_terminate_connection(self):
volume = fake_volume.fake_volume_obj(mock.sentinel.fake_context)
fake_initiator = db_fakes.get_fake_connector_info()
self._driver.terminate_connection(volume, fake_initiator)
self._driver._tgt_utils.deassociate_initiator.assert_called_once_with(
fake_initiator['initiator'], volume.provider_location)
@mock.patch.object(windows_iscsi.WindowsISCSIDriver, 'local_path')
def test_create_volume(self, mock_local_path):
volume = fake_volume.fake_volume_obj(mock.sentinel.fake_context)
self._driver.create_volume(volume)
mock_local_path.assert_called_once_with(volume)
self._driver._tgt_utils.create_wt_disk.assert_called_once_with(
mock_local_path.return_value,
volume.name,
size_mb=volume.size * 1024)
def test_local_path(self):
volume = fake_volume.fake_volume_obj(mock.sentinel.fake_context)
fake_lun_path = 'fake_lun_path'
self.flags(windows_iscsi_lun_path=fake_lun_path)
disk_format = 'vhd'
mock_get_fmt = self._driver._tgt_utils.get_supported_disk_format
mock_get_fmt.return_value = disk_format
disk_path = self._driver.local_path(volume)
expected_fname = "%s.%s" % (volume.name, disk_format)
expected_disk_path = os.path.join(fake_lun_path,
expected_fname)
self.assertEqual(expected_disk_path, disk_path)
mock_get_fmt.assert_called_once_with()
@mock.patch.object(windows_iscsi.WindowsISCSIDriver, 'local_path')
@mock.patch.object(fileutils, 'delete_if_exists')
def test_delete_volume(self, mock_delete_if_exists, mock_local_path):
volume = fake_volume.fake_volume_obj(mock.sentinel.fake_context)
self._driver.delete_volume(volume)
mock_local_path.assert_called_once_with(volume)
self._driver._tgt_utils.remove_wt_disk.assert_called_once_with(
volume.name)
mock_delete_if_exists.assert_called_once_with(
mock_local_path.return_value)
def test_create_snapshot(self):
volume = fake_volume.fake_volume_obj(context.get_admin_context())
snapshot = fake_snapshot.fake_snapshot_obj(context.get_admin_context(),
volume_id=volume.id)
snapshot.volume = volume
self._driver.create_snapshot(snapshot)
self._driver._tgt_utils.create_snapshot.assert_called_once_with(
snapshot.volume_name, snapshot.name)
@mock.patch.object(windows_iscsi.WindowsISCSIDriver, 'local_path')
def test_create_volume_from_snapshot(self, mock_local_path):
volume = fake_volume.fake_volume_obj(context.get_admin_context())
snapshot = fake_snapshot.fake_snapshot_obj(context.get_admin_context())
snapshot.volume = volume
self._driver.create_volume_from_snapshot(volume, snapshot)
self._driver._tgt_utils.export_snapshot.assert_called_once_with(
snapshot.name, mock_local_path.return_value)
self._driver._tgt_utils.import_wt_disk.assert_called_once_with(
mock_local_path.return_value, volume.name)
def test_delete_snapshot(self):
snapshot = fake_snapshot.fake_snapshot_obj(context.get_admin_context())
self._driver.delete_snapshot(snapshot)
self._driver._tgt_utils.delete_snapshot.assert_called_once_with(
snapshot.name)
def test_get_target_name(self):
volume = fake_volume.fake_volume_obj(mock.sentinel.fake_context)
expected_target_name = "%s%s" % (
self._driver.configuration.target_prefix,
volume.name)
target_name = self._driver._get_target_name(volume)
self.assertEqual(expected_target_name, target_name)
@mock.patch.object(windows_iscsi.WindowsISCSIDriver, '_get_target_name')
@mock.patch.object(windows_iscsi.utils, 'generate_username')
@mock.patch.object(windows_iscsi.utils, 'generate_password')
def test_create_export(self, mock_generate_password,
mock_generate_username,
mock_get_target_name):
tgt_utils = self._driver._tgt_utils
volume = fake_volume.fake_volume_obj(mock.sentinel.fake_context)
self._driver.configuration.chap_username = None
self._driver.configuration.chap_password = None
self._driver.configuration.use_chap_auth = True
fake_chap_username = 'fake_chap_username'
fake_chap_password = 'fake_chap_password'
mock_get_target_name.return_value = mock.sentinel.target_name
mock_generate_username.return_value = fake_chap_username
mock_generate_password.return_value = fake_chap_password
tgt_utils.iscsi_target_exists.return_value = False
vol_updates = self._driver.create_export(mock.sentinel.context,
volume,
mock.sentinel.connector)
mock_get_target_name.assert_called_once_with(volume)
tgt_utils.iscsi_target_exists.assert_called_once_with(
mock.sentinel.target_name)
tgt_utils.set_chap_credentials.assert_called_once_with(
mock.sentinel.target_name,
fake_chap_username,
fake_chap_password)
tgt_utils.add_disk_to_target.assert_called_once_with(
volume.name, mock.sentinel.target_name)
expected_provider_auth = ' '.join(('CHAP',
fake_chap_username,
fake_chap_password))
expected_vol_updates = dict(
provider_location=mock.sentinel.target_name,
provider_auth=expected_provider_auth)
self.assertEqual(expected_vol_updates, vol_updates)
@mock.patch.object(windows_iscsi.WindowsISCSIDriver, '_get_target_name')
def test_remove_export(self, mock_get_target_name):
volume = fake_volume.fake_volume_obj(mock.sentinel.fake_context)
self._driver.remove_export(mock.sentinel.context, volume)
mock_get_target_name.assert_called_once_with(volume)
self._driver._tgt_utils.delete_iscsi_target.assert_called_once_with(
mock_get_target_name.return_value)
@mock.patch.object(windows_iscsi.WindowsISCSIDriver, 'local_path')
@mock.patch.object(image_utils, 'temporary_file')
@mock.patch.object(image_utils, 'fetch_to_vhd')
@mock.patch('os.unlink')
def test_copy_image_to_volume(self, mock_unlink, mock_fetch_to_vhd,
mock_tmp_file, mock_local_path):
tgt_utils = self._driver._tgt_utils
volume = fake_volume.fake_volume_obj(mock.sentinel.fake_context)
mock_tmp_file.return_value.__enter__.return_value = (
mock.sentinel.tmp_vhd_path)
mock_local_path.return_value = mock.sentinel.vol_vhd_path
self._driver.copy_image_to_volume(mock.sentinel.context,
volume,
mock.sentinel.image_service,
mock.sentinel.image_id)
mock_local_path.assert_called_once_with(volume)
mock_tmp_file.assert_called_once_with(suffix='.vhd')
image_utils.fetch_to_vhd.assert_called_once_with(
mock.sentinel.context, mock.sentinel.image_service,
mock.sentinel.image_id, mock.sentinel.tmp_vhd_path,
self._driver.configuration.volume_dd_blocksize)
mock_unlink.assert_called_once_with(mock.sentinel.vol_vhd_path)
self._driver._vhdutils.convert_vhd.assert_called_once_with(
mock.sentinel.tmp_vhd_path,
mock.sentinel.vol_vhd_path,
tgt_utils.get_supported_vhd_type.return_value)
self._driver._vhdutils.resize_vhd.assert_called_once_with(
mock.sentinel.vol_vhd_path,
volume.size * units.Gi,
is_file_max_size=False)
tgt_utils.change_wt_disk_status.assert_has_calls(
[mock.call(volume.name, enabled=False),
mock.call(volume.name, enabled=True)])
@mock.patch.object(windows_iscsi.uuidutils, 'generate_uuid')
def test_temporary_snapshot(self, mock_generate_uuid):
tgt_utils = self._driver._tgt_utils
mock_generate_uuid.return_value = mock.sentinel.snap_uuid
expected_snap_name = '%s-tmp-snapshot-%s' % (
mock.sentinel.volume_name, mock.sentinel.snap_uuid)
with self._driver._temporary_snapshot(
mock.sentinel.volume_name) as snap_name:
self.assertEqual(expected_snap_name, snap_name)
tgt_utils.create_snapshot.assert_called_once_with(
mock.sentinel.volume_name, expected_snap_name)
tgt_utils.delete_snapshot.assert_called_once_with(
expected_snap_name)
@mock.patch.object(windows_iscsi.WindowsISCSIDriver, '_temporary_snapshot')
@mock.patch.object(image_utils, 'upload_volume')
@mock.patch.object(fileutils, 'delete_if_exists')
def test_copy_volume_to_image(self, mock_delete_if_exists,
mock_upload_volume,
mock_tmp_snap):
tgt_utils = self._driver._tgt_utils
disk_format = 'vhd'
fake_image_meta = db_fakes.get_fake_image_meta()
volume = fake_volume.fake_volume_obj(mock.sentinel.fake_context)
fake_img_conv_dir = 'fake_img_conv_dir'
self.flags(image_conversion_dir=fake_img_conv_dir)
tgt_utils.get_supported_disk_format.return_value = disk_format
mock_tmp_snap.return_value.__enter__.return_value = (
mock.sentinel.tmp_snap_name)
expected_tmp_vhd_path = os.path.join(
fake_img_conv_dir,
fake_image_meta['id'] + '.' + disk_format)
self._driver.copy_volume_to_image(
mock.sentinel.context, volume,
mock.sentinel.image_service,
fake_image_meta)
mock_tmp_snap.assert_called_once_with(volume.name)
tgt_utils.export_snapshot.assert_called_once_with(
mock.sentinel.tmp_snap_name,
expected_tmp_vhd_path)
mock_upload_volume.assert_called_once_with(
mock.sentinel.context, mock.sentinel.image_service,
fake_image_meta, expected_tmp_vhd_path, 'vhd')
mock_delete_if_exists.assert_called_once_with(
expected_tmp_vhd_path)
@mock.patch.object(windows_iscsi.WindowsISCSIDriver, '_temporary_snapshot')
@mock.patch.object(windows_iscsi.WindowsISCSIDriver, 'local_path')
def test_create_cloned_volume(self, mock_local_path,
mock_tmp_snap):
tgt_utils = self._driver._tgt_utils
volume = fake_volume.fake_volume_obj(mock.sentinel.fake_context)
src_volume = fake_volume.fake_volume_obj(mock.sentinel.fake_context)
mock_tmp_snap.return_value.__enter__.return_value = (
mock.sentinel.tmp_snap_name)
mock_local_path.return_value = mock.sentinel.vol_vhd_path
self._driver.create_cloned_volume(volume, src_volume)
mock_tmp_snap.assert_called_once_with(src_volume.name)
tgt_utils.export_snapshot.assert_called_once_with(
mock.sentinel.tmp_snap_name,
mock.sentinel.vol_vhd_path)
self._driver._vhdutils.resize_vhd.assert_called_once_with(
mock.sentinel.vol_vhd_path, volume.size * units.Gi,
is_file_max_size=False)
tgt_utils.import_wt_disk.assert_called_once_with(
mock.sentinel.vol_vhd_path, volume.name)
@mock.patch('os.path.splitdrive')
def test_get_capacity_info(self, mock_splitdrive):
mock_splitdrive.return_value = (mock.sentinel.drive,
mock.sentinel.path_tail)
fake_size_gb = 2
fake_free_space_gb = 1
self._driver._hostutils.get_volume_info.return_value = (
fake_size_gb * units.Gi,
fake_free_space_gb * units.Gi)
total_gb, free_gb = self._driver._get_capacity_info()
self.assertEqual(fake_size_gb, total_gb)
self.assertEqual(fake_free_space_gb, free_gb)
self._driver._hostutils.get_volume_info.assert_called_once_with(
mock.sentinel.drive)
mock_splitdrive.assert_called_once_with('fake_iscsi_lun_path')
@mock.patch.object(windows_iscsi.WindowsISCSIDriver, '_get_capacity_info')
def test_update_volume_stats(self, mock_get_capacity_info):
mock_get_capacity_info.return_value = (
mock.sentinel.size_gb,
mock.sentinel.free_space_gb)
self.flags(volume_backend_name='volume_backend_name')
self.flags(reserved_percentage=10)
expected_volume_stats = dict(
volume_backend_name='volume_backend_name',
vendor_name='Microsoft',
driver_version=self._driver.VERSION,
storage_protocol='iSCSI',
total_capacity_gb=mock.sentinel.size_gb,
free_capacity_gb=mock.sentinel.free_space_gb,
reserved_percentage=10,
QoS_support=False)
self._driver._update_volume_stats()
self.assertEqual(expected_volume_stats,
self._driver._stats)
def test_extend_volume(self):
volume = fake_volume.fake_volume_obj(mock.sentinel.fake_context)
new_size_gb = 2
expected_additional_sz_mb = 1024
self._driver.extend_volume(volume, new_size_gb)
self._driver._tgt_utils.extend_wt_disk.assert_called_once_with(
volume.name, expected_additional_sz_mb)