cinder/cinder/tests/unit/volume/drivers/vmware/test_vmware_datastore.py
Sean McGinnis 09654af518 Fix invalid escape sequence warnings
There are a lot of DeprecationWarning message emited when running
under python 3.6 due mostly to non-raw strings being used for
regex expressions.

DeprecationWarning: invalid escape sequence \

These had previously been ignored, but starting with python 3.6,
and the commit for issue 27364, these are now considered deprecated
and will no longer be supported going forward. Per the discussion
on that issue, these strings should really be raw strings any way:

https://bugs.python.org/issue27364#msg272696

Change-Id: If6ff206e4bbcf10ab52d2895f606dafad2936ddb
2018-06-20 16:22:26 -05:00

392 lines
16 KiB
Python

# Copyright (c) 2014 VMware, Inc.
# 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 datastore module.
"""
import re
import mock
from oslo_utils import units
from cinder import test
from cinder.volume.drivers.vmware import datastore as ds_sel
from cinder.volume.drivers.vmware import exceptions as vmdk_exceptions
class DatastoreTest(test.TestCase):
"""Unit tests for Datastore."""
def setUp(self):
super(DatastoreTest, self).setUp()
self._session = mock.Mock()
self._vops = mock.Mock()
self._ds_sel = ds_sel.DatastoreSelector(
self._vops, self._session, 1024)
@mock.patch('oslo_vmware.pbm.get_profile_id_by_name')
def test_get_profile_id(self, get_profile_id_by_name):
profile_id = mock.sentinel.profile_id
get_profile_id_by_name.return_value = profile_id
profile_name = mock.sentinel.profile_name
self.assertEqual(profile_id, self._ds_sel.get_profile_id(profile_name))
get_profile_id_by_name.assert_called_once_with(self._session,
profile_name)
self.assertEqual(profile_id,
self._ds_sel._profile_id_cache[profile_name])
@mock.patch('oslo_vmware.pbm.get_profile_id_by_name')
def test_get_profile_id_cache_hit(self, get_profile_id_by_name):
profile_id = mock.sentinel.profile_id
profile_name = mock.sentinel.profile_name
self._ds_sel._profile_id_cache[profile_name] = profile_id
self.assertEqual(profile_id, self._ds_sel.get_profile_id(profile_name))
self.assertFalse(get_profile_id_by_name.called)
@mock.patch('oslo_vmware.pbm.get_profile_id_by_name')
def test_get_profile_id_with_invalid_profile(self, get_profile_id_by_name):
get_profile_id_by_name.return_value = None
profile_name = mock.sentinel.profile_name
self.assertRaises(vmdk_exceptions.ProfileNotFoundException,
self._ds_sel.get_profile_id,
profile_name)
get_profile_id_by_name.assert_called_once_with(self._session,
profile_name)
def _create_datastore(self, value):
return mock.Mock(name=value, value=value)
def _create_summary(
self, ds, free_space=units.Mi, _type=ds_sel.DatastoreType.VMFS,
capacity=2 * units.Mi, accessible=True):
summary = mock.Mock(datastore=ds, freeSpace=free_space, type=_type,
capacity=capacity, accessible=accessible)
summary.name = ds.value
return summary
def _create_host(self, value):
host = mock.Mock(spec=['_type', 'value'], name=value)
host._type = 'HostSystem'
host.value = value
return host
@mock.patch('cinder.volume.drivers.vmware.datastore.DatastoreSelector.'
'_filter_by_profile')
def test_filter_datastores(self, filter_by_profile):
host1 = self._create_host('host-1')
host2 = self._create_host('host-2')
host3 = self._create_host('host-3')
host_mounts1 = [mock.Mock(key=host1)]
host_mounts2 = [mock.Mock(key=host2)]
host_mounts3 = [mock.Mock(key=host3)]
# empty summary
ds1 = self._create_datastore('ds-1')
ds1_props = {'host': host_mounts1}
# hard anti-affinity datastore
ds2 = self._create_datastore('ds-2')
ds2_props = {'summary': self._create_summary(ds2),
'host': host_mounts2}
# not enough free space
ds3 = self._create_datastore('ds-3')
ds3_props = {'summary': self._create_summary(ds3, free_space=128),
'host': host_mounts1}
# not connected to a valid host
ds4 = self._create_datastore('ds-4')
ds4_props = {'summary': self._create_summary(ds4),
'host': host_mounts3}
# invalid datastore type
ds5 = self._create_datastore('ds-5')
ds5_props = {'summary': self._create_summary(ds5, _type='foo'),
'host': host_mounts1}
# hard affinity datastore type
ds6 = self._create_datastore('ds-6')
ds6_props = {
'summary': self._create_summary(
ds6, _type=ds_sel.DatastoreType.VSAN),
'host': host_mounts2}
# inaccessible datastore
ds7 = self._create_datastore('ds-7')
ds7_props = {'summary': self._create_summary(ds7, accessible=False),
'host': host_mounts1}
def mock_in_maintenace(summary):
return summary.datastore.value == 'ds-8'
self._vops._in_maintenance.side_effect = mock_in_maintenace
# in-maintenance datastore
ds8 = self._create_datastore('ds-8')
ds8_props = {'summary': self._create_summary(ds8),
'host': host_mounts2}
# not compliant with profile
ds9 = self._create_datastore('ds-9')
ds9_props = {'summary': self._create_summary(ds9),
'host': host_mounts1}
# valid datastore
ds1a = self._create_datastore('ds-1a')
ds1a_props = {'summary': self._create_summary(ds1a),
'host': host_mounts1}
filter_by_profile.return_value = {ds1a: ds1a_props}
# datastore name not matching the regex filter
ds1b = self._create_datastore('ds-1b')
ds1b_props = {'summary': self._create_summary(ds1b),
'host': host_mounts1}
datastores = {ds1: ds1_props,
ds2: ds2_props,
ds3: ds3_props,
ds4: ds4_props,
ds5: ds5_props,
ds6: ds6_props,
ds7: ds7_props,
ds8: ds8_props,
ds9: ds9_props,
ds1a: ds1a_props,
ds1b: ds1b_props}
profile_id = mock.sentinel.profile_id
self._ds_sel._ds_regex = re.compile(r"ds-[1-9a]{1,2}$")
datastores = self._ds_sel._filter_datastores(
datastores,
512,
profile_id,
['ds-2'],
{ds_sel.DatastoreType.VMFS, ds_sel.DatastoreType.NFS},
valid_host_refs=[host1, host2])
self.assertEqual({ds1a: ds1a_props}, datastores)
filter_by_profile.assert_called_once_with(
{ds9: ds9_props, ds1a: ds1a_props},
profile_id)
def test_filter_datastores_with_empty_datastores(self):
self.assertIsNone(self._ds_sel._filter_datastores(
{}, 1024, None, None, None))
def _create_host_properties(
self, parent, connection_state='connected', in_maintenace=False):
return mock.Mock(connectionState=connection_state,
inMaintenanceMode=in_maintenace,
parent=parent)
@mock.patch('cinder.volume.drivers.vmware.datastore.DatastoreSelector.'
'_get_host_properties')
@mock.patch('cinder.volume.drivers.vmware.datastore.DatastoreSelector.'
'_get_resource_pool')
def test_select_best_datastore(self, get_resource_pool, get_host_props):
host1 = self._create_host('host-1')
host2 = self._create_host('host-2')
host3 = self._create_host('host-3')
host_mounts1 = [mock.Mock(key=host1,
mountInfo=mock.sentinel.ds1_mount_info1),
mock.Mock(key=host2,
mountInfo=mock.sentinel.ds1_mount_info2),
mock.Mock(key=host3,
mountInfo=mock.sentinel.ds1_mount_info3)]
host_mounts2 = [mock.Mock(key=host2,
mountInfo=mock.sentinel.ds2_mount_info2),
mock.Mock(key=host3,
mountInfo=mock.sentinel.ds2_mount_info3)]
host_mounts3 = [mock.Mock(key=host1,
mountInfo=mock.sentinel.ds3_mount_info1),
mock.Mock(key=host2,
mountInfo=mock.sentinel.ds3_mount_info2)]
host_mounts4 = [mock.Mock(key=host1,
mountInfo=mock.sentinel.ds4_mount_info1)]
ds1 = self._create_datastore('ds-1')
ds1_props = {'summary': self._create_summary(ds1),
'host': host_mounts1}
ds2 = self._create_datastore('ds-2')
ds2_props = {
'summary': self._create_summary(
ds2, free_space=1024, capacity=2048),
'host': host_mounts2}
ds3 = self._create_datastore('ds-3')
ds3_props = {
'summary': self._create_summary(
ds3, free_space=512, capacity=2048),
'host': host_mounts3}
ds4 = self._create_datastore('ds-3')
ds4_props = {'summary': self._create_summary(ds4),
'host': host_mounts4}
cluster_ref = mock.sentinel.cluster_ref
def mock_get_host_properties(host_ref):
self.assertIsNot(host1, host_ref)
if host_ref == host2:
in_maintenance = False
else:
in_maintenance = True
runtime = mock.Mock(spec=['connectionState', 'inMaintenanceMode'])
runtime.connectionState = 'connected'
runtime.inMaintenanceMode = in_maintenance
return {'parent': cluster_ref, 'runtime': runtime}
get_host_props.side_effect = mock_get_host_properties
def mock_is_usable(mount_info):
if (mount_info == mock.sentinel.ds1_mount_info2 or
mount_info == mock.sentinel.ds2_mount_info2):
return False
else:
return True
self._vops._is_usable.side_effect = mock_is_usable
rp = mock.sentinel.resource_pool
get_resource_pool.return_value = rp
# ds1 is mounted to 3 hosts: host1, host2 and host3; host1 is
# not a valid host, ds1 is not usable in host1, and host3 is
# in maintenance mode.
# ds2 and ds3 are mounted to same hosts, and ds2 has a low space
# utilization. But ds2 is not usable in host2, and host3 is in
# maintenance mode. Therefore, ds3 and host2 will be selected.
datastores = {ds1: ds1_props,
ds2: ds2_props,
ds3: ds3_props,
ds4: ds4_props}
ret = self._ds_sel._select_best_datastore(
datastores, valid_host_refs=[host2, host3])
self.assertEqual((host2, rp, ds3_props['summary']), ret)
self.assertItemsEqual([mock.call(mock.sentinel.ds1_mount_info2),
mock.call(mock.sentinel.ds1_mount_info3),
mock.call(mock.sentinel.ds2_mount_info2),
mock.call(mock.sentinel.ds2_mount_info3),
mock.call(mock.sentinel.ds3_mount_info2)],
self._vops._is_usable.call_args_list)
self.assertEqual([mock.call(host3), mock.call(host2)],
get_host_props.call_args_list)
get_resource_pool.assert_called_once_with(cluster_ref)
def test_select_best_datastore_with_empty_datastores(self):
self.assertIsNone(self._ds_sel._select_best_datastore({}))
@mock.patch('cinder.volume.drivers.vmware.datastore.DatastoreSelector.'
'get_profile_id')
@mock.patch('cinder.volume.drivers.vmware.datastore.DatastoreSelector.'
'_get_datastores')
@mock.patch('cinder.volume.drivers.vmware.datastore.DatastoreSelector.'
'_filter_datastores')
@mock.patch('cinder.volume.drivers.vmware.datastore.DatastoreSelector.'
'_select_best_datastore')
def test_select_datastore(
self, select_best_datastore, filter_datastores, get_datastores,
get_profile_id):
profile_id = mock.sentinel.profile_id
get_profile_id.return_value = profile_id
datastores = mock.sentinel.datastores
get_datastores.return_value = datastores
filtered_datastores = mock.sentinel.filtered_datastores
filter_datastores.return_value = filtered_datastores
best_datastore = mock.sentinel.best_datastore
select_best_datastore.return_value = best_datastore
size_bytes = 1024
req = {self._ds_sel.SIZE_BYTES: size_bytes}
aff_ds_types = [ds_sel.DatastoreType.VMFS]
req[ds_sel.DatastoreSelector.HARD_AFFINITY_DS_TYPE] = aff_ds_types
anti_affinity_ds = [mock.sentinel.ds]
req[ds_sel.DatastoreSelector.HARD_ANTI_AFFINITY_DS] = anti_affinity_ds
profile_name = mock.sentinel.profile_name
req[ds_sel.DatastoreSelector.PROFILE_NAME] = profile_name
hosts = mock.sentinel.hosts
self.assertEqual(best_datastore,
self._ds_sel.select_datastore(req, hosts))
get_datastores.assert_called_once_with()
filter_datastores.assert_called_once_with(
datastores, size_bytes, profile_id, anti_affinity_ds, aff_ds_types,
valid_host_refs=hosts)
select_best_datastore.assert_called_once_with(filtered_datastores,
valid_host_refs=hosts)
@mock.patch('cinder.volume.drivers.vmware.datastore.DatastoreSelector.'
'get_profile_id')
@mock.patch('cinder.volume.drivers.vmware.datastore.DatastoreSelector.'
'_filter_by_profile')
def test_is_datastore_compliant_true(
self, filter_by_profile, get_profile_id):
profile_name = mock.sentinel.profile_name
datastore = mock.sentinel.datastore
profile_id = mock.sentinel.profile_id
get_profile_id.return_value = profile_id
filter_by_profile.return_value = {datastore: None}
self.assertTrue(self._ds_sel.is_datastore_compliant(datastore,
profile_name))
get_profile_id.assert_called_once_with(profile_name)
filter_by_profile.assert_called_once_with({datastore: None},
profile_id)
@mock.patch('cinder.volume.drivers.vmware.datastore.DatastoreSelector.'
'get_profile_id')
@mock.patch('cinder.volume.drivers.vmware.datastore.DatastoreSelector.'
'_filter_by_profile')
def test_is_datastore_compliant_false(
self, filter_by_profile, get_profile_id):
profile_name = mock.sentinel.profile_name
datastore = mock.sentinel.datastore
profile_id = mock.sentinel.profile_id
get_profile_id.return_value = profile_id
filter_by_profile.return_value = {}
self.assertFalse(self._ds_sel.is_datastore_compliant(datastore,
profile_name))
get_profile_id.assert_called_once_with(profile_name)
filter_by_profile.assert_called_once_with({datastore: None},
profile_id)
def test_is_datastore_compliant_with_empty_profile(self):
self.assertTrue(self._ds_sel.is_datastore_compliant(
mock.sentinel.datastore, None))
@mock.patch('cinder.volume.drivers.vmware.datastore.DatastoreSelector.'
'get_profile_id')
def test_is_datastore_compliant_with_invalid_profile(self, get_profile_id):
profile_name = mock.sentinel.profile_name
get_profile_id.side_effect = vmdk_exceptions.ProfileNotFoundException
self.assertRaises(vmdk_exceptions.ProfileNotFoundException,
self._ds_sel.is_datastore_compliant,
mock.sentinel.datastore,
profile_name)
get_profile_id.assert_called_once_with(profile_name)