deb-cinder/cinder/tests/unit/windows/test_windows.py
Lucian Petrut dde4d72511 Refactor Windows drivers using os-win
A common library abstracting Windows specific operations has been
created in order to remove duplicated code among OpenStack projects,
also being easier to maintain.

This patch refactors Windows drivers, leveraging the os-win library.

The Windows iSCSI driver unit tests needed to be updated, for which
reason those where rewritten using mock.

Implements: blueprint windows-os-win

Change-Id: I234835eebac83baab9c3e13b6cf069734137bbc2
2016-01-14 19:27:05 +02:00

427 lines
18 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 mock
import os
from oslo_utils import fileutils
from oslo_utils import units
from cinder.image import image_utils
from cinder import test
from cinder.tests.unit.windows import db_fakes
from cinder.volume import configuration as conf
from cinder.volume.drivers.windows import windows
class TestWindowsDriver(test.TestCase):
@mock.patch.object(windows, 'utilsfactory')
def setUp(self, mock_utilsfactory):
super(TestWindowsDriver, self).setUp()
configuration = conf.Configuration(None)
configuration.append_config_values(windows.windows_opts)
self.flags(windows_iscsi_lun_path=mock.sentinel.iscsi_lun_path)
self.flags(image_conversion_dir=mock.sentinel.image_conversion_dir)
self._driver = windows.WindowsDriver(configuration=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(mock.sentinel.iscsi_lun_path),
mock.call(mock.sentinel.image_conversion_dir)])
def test_check_for_setup_error(self):
self._driver.check_for_setup_error()
self._driver._tgt_utils.get_portal_locations.assert_called_once_with(
available_only=True, fail_if_none_found=True)
@mock.patch.object(windows.WindowsDriver, '_get_target_name')
def test_get_host_information(self, mock_get_target_name):
tgt_utils = self._driver._tgt_utils
fake_auth_meth = 'CHAP'
fake_chap_username = 'fake_chap_username'
fake_chap_password = 'fake_chap_password'
fake_host_info = {'fake_prop': 'fake_value'}
fake_volume = db_fakes.get_fake_volume_info()
fake_volume['provider_auth'] = "%s %s %s" % (fake_auth_meth,
fake_chap_username,
fake_chap_password)
mock_get_target_name.return_value = mock.sentinel.target_name
tgt_utils.get_portal_locations.return_value = [
mock.sentinel.portal_location]
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=mock.sentinel.portal_location,
target_lun=0,
volume_id=fake_volume['id'])
host_info = self._driver._get_host_information(fake_volume)
self.assertEqual(expected_host_info, host_info)
mock_get_target_name.assert_called_once_with(fake_volume)
tgt_utils.get_portal_locations.assert_called_once_with()
tgt_utils.get_target_information.assert_called_once_with(
mock.sentinel.target_name)
@mock.patch.object(windows.WindowsDriver, '_get_host_information')
def test_initialize_connection(self, mock_get_host_info):
tgt_utils = self._driver._tgt_utils
fake_volume = db_fakes.get_fake_volume_info()
fake_initiator = db_fakes.get_fake_connector_info()
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(fake_volume,
fake_initiator)
self.assertEqual(expected_conn_info, conn_info)
mock_associate = tgt_utils.associate_initiator_with_iscsi_target
mock_associate.assert_called_once_with(
fake_initiator['initiator'],
fake_volume['provider_location'])
def test_terminate_connection(self):
fake_volume = db_fakes.get_fake_volume_info()
fake_initiator = db_fakes.get_fake_connector_info()
self._driver.terminate_connection(fake_volume, fake_initiator)
self._driver._tgt_utils.deassociate_initiator.assert_called_once_with(
fake_initiator['initiator'], fake_volume['provider_location'])
@mock.patch.object(windows.WindowsDriver, 'local_path')
def test_create_volume(self, mock_local_path):
fake_volume = db_fakes.get_fake_volume_info()
self._driver.create_volume(fake_volume)
mock_local_path.assert_called_once_with(fake_volume)
self._driver._tgt_utils.create_wt_disk.assert_called_once_with(
mock_local_path.return_value,
fake_volume['name'],
size_mb=fake_volume['size'] * 1024)
def test_local_path(self):
fake_volume = db_fakes.get_fake_volume_info()
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(fake_volume)
expected_fname = "%s.%s" % (fake_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.WindowsDriver, 'local_path')
@mock.patch.object(fileutils, 'delete_if_exists')
def test_delete_volume(self, mock_delete_if_exists, mock_local_path):
fake_volume = db_fakes.get_fake_volume_info()
self._driver.delete_volume(fake_volume)
mock_local_path.assert_called_once_with(fake_volume)
self._driver._tgt_utils.remove_wt_disk.assert_called_once_with(
fake_volume['name'])
mock_delete_if_exists.assert_called_once_with(
mock_local_path.return_value)
def test_create_snapshot(self):
fake_snapshot = db_fakes.get_fake_snapshot_info()
self._driver.create_snapshot(fake_snapshot)
self._driver._tgt_utils.create_snapshot.assert_called_once_with(
fake_snapshot['volume_name'], fake_snapshot['name'])
@mock.patch.object(windows.WindowsDriver, 'local_path')
def test_create_volume_from_snapshot(self, mock_local_path):
fake_volume = db_fakes.get_fake_volume_info()
fake_snapshot = db_fakes.get_fake_snapshot_info()
self._driver.create_volume_from_snapshot(fake_volume, fake_snapshot)
self._driver._tgt_utils.export_snapshot.assert_called_once_with(
fake_snapshot['name'],
mock_local_path.return_value)
self._driver._tgt_utils.import_wt_disk.assert_called_once_with(
mock_local_path.return_value,
fake_volume['name'])
def test_delete_snapshot(self):
fake_snapshot = db_fakes.get_fake_snapshot_info()
self._driver.delete_snapshot(fake_snapshot)
self._driver._tgt_utils.delete_snapshot.assert_called_once_with(
fake_snapshot['name'])
def test_get_target_name(self):
fake_volume = db_fakes.get_fake_volume_info()
expected_target_name = "%s%s" % (
self._driver.configuration.iscsi_target_prefix,
fake_volume['name'])
target_name = self._driver._get_target_name(fake_volume)
self.assertEqual(expected_target_name, target_name)
@mock.patch.object(windows.WindowsDriver, '_get_target_name')
@mock.patch.object(windows.utils, 'generate_username')
@mock.patch.object(windows.utils, 'generate_password')
def test_create_export(self, mock_generate_password,
mock_generate_username,
mock_get_target_name):
tgt_utils = self._driver._tgt_utils
fake_volume = db_fakes.get_fake_volume_info()
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,
fake_volume,
mock.sentinel.connector)
mock_get_target_name.assert_called_once_with(fake_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(
fake_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.WindowsDriver, '_get_target_name')
def test_remove_export(self, mock_get_target_name):
fake_volume = db_fakes.get_fake_volume_info()
self._driver.remove_export(mock.sentinel.context, fake_volume)
mock_get_target_name.assert_called_once_with(fake_volume)
self._driver._tgt_utils.delete_iscsi_target.assert_called_once_with(
mock_get_target_name.return_value)
@mock.patch.object(windows.WindowsDriver, '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
fake_volume = db_fakes.get_fake_volume_info()
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,
fake_volume,
mock.sentinel.image_service,
mock.sentinel.image_id)
mock_local_path.assert_called_once_with(fake_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,
fake_volume['size'] * units.Gi,
is_file_max_size=False)
tgt_utils.change_wt_disk_status.assert_has_calls(
[mock.call(fake_volume['name'], enabled=False),
mock.call(fake_volume['name'], enabled=True)])
@mock.patch.object(windows.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.WindowsDriver, '_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()
fake_volume = db_fakes.get_fake_volume_info()
fake_img_conv_dir = 'fake_img_conv_dir'
self._driver.configuration.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, fake_volume,
mock.sentinel.image_service,
fake_image_meta)
mock_tmp_snap.assert_called_once_with(fake_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.WindowsDriver, '_temporary_snapshot')
@mock.patch.object(windows.WindowsDriver, 'local_path')
def test_create_cloned_volume(self, mock_local_path,
mock_tmp_snap):
tgt_utils = self._driver._tgt_utils
fake_volume = db_fakes.get_fake_volume_info()
fake_src_volume = db_fakes.get_fake_volume_info_cloned()
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(fake_volume, fake_src_volume)
mock_tmp_snap.assert_called_once_with(fake_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, fake_volume['size'] * units.Gi,
is_file_max_size=False)
tgt_utils.import_wt_disk.assert_called_once_with(
mock.sentinel.vol_vhd_path, fake_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(
mock.sentinel.iscsi_lun_path)
@mock.patch.object(windows.WindowsDriver, '_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=mock.sentinel.backend_name)
self.flags(reserved_percentage=mock.sentinel.reserved_percentage)
expected_volume_stats = dict(
volume_backend_name=mock.sentinel.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=mock.sentinel.reserved_percentage,
QoS_support=False)
self._driver._update_volume_stats()
self.assertEqual(expected_volume_stats,
self._driver._stats)
def test_extend_volume(self):
fake_volume = db_fakes.get_fake_volume_info()
new_size_gb = 2
expected_additional_sz_mb = 1024
self._driver.extend_volume(fake_volume, new_size_gb)
self._driver._tgt_utils.extend_wt_disk.assert_called_once_with(
fake_volume['name'], expected_additional_sz_mb)