summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nova/api/metadata/handler.py6
-rw-r--r--nova/compute/resource_tracker.py2
-rw-r--r--nova/scheduler/filter_scheduler.py2
-rw-r--r--nova/tests/compute/test_resource_tracker.py13
-rw-r--r--nova/tests/scheduler/test_filter_scheduler.py2
-rw-r--r--nova/tests/test_metadata.py22
-rw-r--r--nova/tests/virt/hyperv/db_fakes.py22
-rw-r--r--nova/tests/virt/hyperv/test_hypervapi.py4
-rw-r--r--nova/tests/virt/hyperv/test_volumeutils.py33
-rw-r--r--nova/tests/virt/hyperv/test_volumeutilsv2.py29
-rw-r--r--nova/virt/hyperv/volumeops.py14
-rw-r--r--nova/virt/hyperv/volumeutils.py6
-rw-r--r--nova/virt/hyperv/volumeutilsv2.py12
-rw-r--r--test-requirements.txt2
14 files changed, 129 insertions, 40 deletions
diff --git a/nova/api/metadata/handler.py b/nova/api/metadata/handler.py
index 9ae64b7242..9862128ee0 100644
--- a/nova/api/metadata/handler.py
+++ b/nova/api/metadata/handler.py
@@ -133,7 +133,11 @@ class MetadataRequestHandler(wsgi.Application):
return data(req, meta_data)
resp = base.ec2_md_print(data)
- req.response.body = resp
+ if isinstance(resp, six.text_type):
+ req.response.text = resp
+ else:
+ req.response.body = resp
+
req.response.content_type = meta_data.get_mimetype()
return req.response
diff --git a/nova/compute/resource_tracker.py b/nova/compute/resource_tracker.py
index 6aaadc9d49..aee8b75650 100644
--- a/nova/compute/resource_tracker.py
+++ b/nova/compute/resource_tracker.py
@@ -292,7 +292,7 @@ class ResourceTracker(object):
try:
metrics += monitor.get_metrics(nodename=nodename)
except Exception:
- LOG.warn(_("Cannot get the metrics from %s."), monitors)
+ LOG.warn(_("Cannot get the metrics from %s."), monitor)
if metrics:
metrics_info['nodename'] = nodename
metrics_info['metrics'] = metrics
diff --git a/nova/scheduler/filter_scheduler.py b/nova/scheduler/filter_scheduler.py
index 25fd106a31..8a0612e686 100644
--- a/nova/scheduler/filter_scheduler.py
+++ b/nova/scheduler/filter_scheduler.py
@@ -213,7 +213,7 @@ class FilterScheduler(driver.Scheduler):
group_hint = scheduler_hints.get('group', None)
if group_hint:
group = objects.InstanceGroup.get_by_hint(context, group_hint)
- policies = set(('anti-affinity', 'affinity'))
+ policies = set(('anti-affinity', 'affinity', 'legacy'))
if any((policy in policies) for policy in group.policies):
if ('affinity' in group.policies and
not self._supports_affinity):
diff --git a/nova/tests/compute/test_resource_tracker.py b/nova/tests/compute/test_resource_tracker.py
index 6bb36fe96d..9626955152 100644
--- a/nova/tests/compute/test_resource_tracker.py
+++ b/nova/tests/compute/test_resource_tracker.py
@@ -1366,6 +1366,19 @@ class ComputeMonitorTestCase(BaseTestCase):
self.node_name)
self.assertTrue(len(metrics) > 0)
+ @mock.patch.object(resource_tracker.LOG, 'warn')
+ def test_get_host_metrics_exception(self, mock_LOG_warn):
+ self.flags(compute_monitors=['FakeMontorClass1'])
+ class1 = test_monitors.FakeMonitorClass1(self.tracker)
+ self.tracker.monitors = [class1]
+ with mock.patch.object(class1, 'get_metrics',
+ side_effect=test.TestingException()):
+ metrics = self.tracker._get_host_metrics(self.context,
+ self.node_name)
+ mock_LOG_warn.assert_called_once_with(
+ u'Cannot get the metrics from %s.', class1)
+ self.assertEqual(0, len(metrics))
+
def test_get_host_metrics(self):
self.flags(compute_monitors=['FakeMonitorClass1', 'FakeMonitorClass2'])
class1 = test_monitors.FakeMonitorClass1(self.tracker)
diff --git a/nova/tests/scheduler/test_filter_scheduler.py b/nova/tests/scheduler/test_filter_scheduler.py
index d91b668818..6b890beaf1 100644
--- a/nova/tests/scheduler/test_filter_scheduler.py
+++ b/nova/tests/scheduler/test_filter_scheduler.py
@@ -410,7 +410,7 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
self.assertEqual([policy], filter_properties['group_policies'])
def test_group_details_in_filter_properties(self):
- for policy in ['affinity', 'anti-affinity']:
+ for policy in ['affinity', 'anti-affinity', 'legacy']:
group = self._create_server_group(policy)
self._group_details_in_filter_properties(group, func='get_by_uuid',
hint=group.uuid,
diff --git a/nova/tests/test_metadata.py b/nova/tests/test_metadata.py
index 7bf28e1131..d36a711e9c 100644
--- a/nova/tests/test_metadata.py
+++ b/nova/tests/test_metadata.py
@@ -789,6 +789,28 @@ class MetadataHandlerTestCase(test.TestCase):
'X-Instance-ID-Signature': signed})
self.assertEqual(response.status_int, 500)
+ def test_get_metadata(self):
+ def _test_metadata_path(relpath):
+ # recursively confirm a http 200 from all meta-data elements
+ # available at relpath.
+ response = fake_request(self.stubs, self.mdinst,
+ relpath=relpath)
+ for item in response.body.split('\n'):
+ if 'public-keys' in relpath:
+ # meta-data/public-keys/0=keyname refers to
+ # meta-data/public-keys/0
+ item = item.split('=')[0]
+ if item.endswith('/'):
+ path = relpath + '/' + item
+ _test_metadata_path(path)
+ continue
+
+ path = relpath + '/' + item
+ response = fake_request(self.stubs, self.mdinst, relpath=path)
+ self.assertEqual(response.status_int, 200, message=path)
+
+ _test_metadata_path('/2009-04-04/meta-data')
+
class MetadataPasswordTestCase(test.TestCase):
def setUp(self):
diff --git a/nova/tests/virt/hyperv/db_fakes.py b/nova/tests/virt/hyperv/db_fakes.py
index 9e8249323e..f9d8a21421 100644
--- a/nova/tests/virt/hyperv/db_fakes.py
+++ b/nova/tests/virt/hyperv/db_fakes.py
@@ -61,27 +61,23 @@ def get_fake_volume_info_data(target_portal, volume_id):
return {
'driver_volume_type': 'iscsi',
'data': {
- 'volume_id': 1,
+ 'volume_id': volume_id,
'target_iqn': 'iqn.2010-10.org.openstack:volume-' + volume_id,
'target_portal': target_portal,
'target_lun': 1,
'auth_method': 'CHAP',
- }
+ 'auth_username': 'fake_username',
+ 'auth_password': 'fake_password',
+ 'target_discovered': False,
+ },
+ 'mount_device': 'vda',
+ 'delete_on_termination': False
}
def get_fake_block_device_info(target_portal, volume_id):
- return {'block_device_mapping': [{'connection_info': {
- 'driver_volume_type': 'iscsi',
- 'data': {'target_lun': 1,
- 'volume_id': volume_id,
- 'target_iqn':
- 'iqn.2010-10.org.openstack:volume-' +
- volume_id,
- 'target_portal': target_portal,
- 'target_discovered': False}},
- 'mount_device': 'vda',
- 'delete_on_termination': False}],
+ connection_info = get_fake_volume_info_data(target_portal, volume_id)
+ return {'block_device_mapping': [{'connection_info': connection_info}],
'root_device_name': 'fake_root_device_name',
'ephemerals': [],
'swap': None
diff --git a/nova/tests/virt/hyperv/test_hypervapi.py b/nova/tests/virt/hyperv/test_hypervapi.py
index 09749826bf..1b4085074d 100644
--- a/nova/tests/virt/hyperv/test_hypervapi.py
+++ b/nova/tests/virt/hyperv/test_hypervapi.py
@@ -1209,7 +1209,9 @@ class HyperVAPITestCase(HyperVAPIBaseTestCase):
volumeutils.VolumeUtils.login_storage_target(target_lun,
target_iqn,
- target_portal)
+ target_portal,
+ 'fake_username',
+ 'fake_password')
self._mock_get_mounted_disk_from_lun(target_iqn, target_lun,
fake_mounted_disk,
diff --git a/nova/tests/virt/hyperv/test_volumeutils.py b/nova/tests/virt/hyperv/test_volumeutils.py
index f44ee14594..7ce371a87d 100644
--- a/nova/tests/virt/hyperv/test_volumeutils.py
+++ b/nova/tests/virt/hyperv/test_volumeutils.py
@@ -73,12 +73,19 @@ class VolumeUtilsTestCase(test_basevolumeutils.BaseVolumeUtilsTestCase):
def test_login_new_portal(self):
self._test_login_target_portal(False)
- def _test_login_target(self, target_connected, raise_exception=False):
+ def _test_login_target(self, target_connected=False, raise_exception=False,
+ use_chap=False):
fake_portal = '%s:%s' % (self._FAKE_PORTAL_ADDR,
self._FAKE_PORTAL_PORT)
self._volutils.execute = mock.MagicMock()
self._volutils._login_target_portal = mock.MagicMock()
+ if use_chap:
+ username, password = (mock.sentinel.username,
+ mock.sentinel.password)
+ else:
+ username, password = None, None
+
if target_connected:
self._volutils.execute.return_value = self._FAKE_TARGET
elif raise_exception:
@@ -90,28 +97,34 @@ class VolumeUtilsTestCase(test_basevolumeutils.BaseVolumeUtilsTestCase):
if raise_exception:
self.assertRaises(vmutils.HyperVException,
self._volutils.login_storage_target,
- self._FAKE_LUN, self._FAKE_TARGET, fake_portal)
+ self._FAKE_LUN, self._FAKE_TARGET,
+ fake_portal, username, password)
else:
self._volutils.login_storage_target(self._FAKE_LUN,
self._FAKE_TARGET,
- fake_portal)
-
- call_list = self._volutils.execute.call_args_list
- all_call_args = [arg for call in call_list for arg in call[0]]
+ fake_portal,
+ username, password)
if target_connected:
+ call_list = self._volutils.execute.call_args_list
+ all_call_args = [arg for call in call_list for arg in call[0]]
self.assertNotIn('qlogintarget', all_call_args)
else:
- self.assertIn('qlogintarget', all_call_args)
+ self._volutils.execute.assert_any_call(
+ 'iscsicli.exe', 'qlogintarget',
+ self._FAKE_TARGET, username, password)
def test_login_connected_target(self):
- self._test_login_target(True)
+ self._test_login_target(target_connected=True)
def test_login_disconncted_target(self):
- self._test_login_target(False)
+ self._test_login_target()
def test_login_target_exception(self):
- self._test_login_target(False, True)
+ self._test_login_target(raise_exception=True)
+
+ def test_login_target_using_chap(self):
+ self._test_login_target(use_chap=True)
def _test_execute_wrapper(self, raise_exception):
fake_cmd = ('iscsicli.exe', 'ListTargetPortals')
diff --git a/nova/tests/virt/hyperv/test_volumeutilsv2.py b/nova/tests/virt/hyperv/test_volumeutilsv2.py
index 1c242b71f8..261cce0ee7 100644
--- a/nova/tests/virt/hyperv/test_volumeutilsv2.py
+++ b/nova/tests/virt/hyperv/test_volumeutilsv2.py
@@ -68,7 +68,8 @@ class VolumeUtilsV2TestCase(test.NoDBTestCase):
def test_login_new_portal(self):
self._test_login_target_portal(False)
- def _test_login_target(self, target_connected, raise_exception=False):
+ def _test_login_target(self, target_connected=False, raise_exception=False,
+ use_chap=False):
fake_portal = '%s:%s' % (self._FAKE_PORTAL_ADDR,
self._FAKE_PORTAL_PORT)
@@ -88,6 +89,18 @@ class VolumeUtilsV2TestCase(test.NoDBTestCase):
self._volutilsv2._conn_storage.MSFT_iSCSITarget = (
fake_target_object)
+ if use_chap:
+ username, password = (mock.sentinel.username,
+ mock.sentinel.password)
+ auth = {
+ 'AuthenticationType': self._volutilsv2._CHAP_AUTH_TYPE,
+ 'ChapUsername': username,
+ 'ChapSecret': password,
+ }
+ else:
+ username, password = None, None
+ auth = {}
+
if raise_exception:
self.assertRaises(vmutils.HyperVException,
self._volutilsv2.login_storage_target,
@@ -95,22 +108,26 @@ class VolumeUtilsV2TestCase(test.NoDBTestCase):
else:
self._volutilsv2.login_storage_target(self._FAKE_LUN,
self._FAKE_TARGET,
- fake_portal)
+ fake_portal,
+ username, password)
if target_connected:
fake_target_object.Update.assert_called_with()
else:
fake_target_object.Connect.assert_called_once_with(
- IsPersistent=True, NodeAddress=self._FAKE_TARGET)
+ IsPersistent=True, NodeAddress=self._FAKE_TARGET, **auth)
def test_login_connected_target(self):
- self._test_login_target(True)
+ self._test_login_target(target_connected=True)
def test_login_disconncted_target(self):
- self._test_login_target(False)
+ self._test_login_target()
def test_login_target_exception(self):
- self._test_login_target(False, True)
+ self._test_login_target(raise_exception=True)
+
+ def test_login_target_using_chap(self):
+ self._test_login_target(use_chap=True)
def test_logout_storage_target(self):
mock_msft_target = self._volutilsv2._conn_storage.MSFT_iSCSITarget
diff --git a/nova/virt/hyperv/volumeops.py b/nova/virt/hyperv/volumeops.py
index f1908e0ab9..7bc9b9918b 100644
--- a/nova/virt/hyperv/volumeops.py
+++ b/nova/virt/hyperv/volumeops.py
@@ -94,6 +94,17 @@ class VolumeOps(object):
target_lun = data['target_lun']
target_iqn = data['target_iqn']
target_portal = data['target_portal']
+ auth_method = data.get('auth_method')
+ auth_username = data.get('auth_username')
+ auth_password = data.get('auth_password')
+
+ if auth_method and auth_method.upper() != 'CHAP':
+ raise vmutils.HyperVException(
+ _("Cannot log in target %(target_iqn)s. Unsupported iSCSI "
+ "authentication method: %(auth_method)s.") %
+ {'target_iqn': target_iqn,
+ 'auth_method': auth_method})
+
# Check if we already logged in
if self._volutils.get_device_number_for_target(target_iqn, target_lun):
LOG.debug("Already logged in on storage target. No need to "
@@ -108,7 +119,8 @@ class VolumeOps(object):
{'target_portal': target_portal,
'target_iqn': target_iqn, 'target_lun': target_lun})
self._volutils.login_storage_target(target_lun, target_iqn,
- target_portal)
+ target_portal, auth_username,
+ auth_password)
# Wait for the target to be mounted
self._get_mounted_disk_from_lun(target_iqn, target_lun, True)
diff --git a/nova/virt/hyperv/volumeutils.py b/nova/virt/hyperv/volumeutils.py
index 05be31af90..7c9c8f8df8 100644
--- a/nova/virt/hyperv/volumeutils.py
+++ b/nova/virt/hyperv/volumeutils.py
@@ -70,7 +70,8 @@ class VolumeUtils(basevolumeutils.BaseVolumeUtils):
'*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*',
'*', '*')
- def login_storage_target(self, target_lun, target_iqn, target_portal):
+ def login_storage_target(self, target_lun, target_iqn, target_portal,
+ auth_username=None, auth_password=None):
"""Ensure that the target is logged in."""
self._login_target_portal(target_portal)
@@ -90,7 +91,8 @@ class VolumeUtils(basevolumeutils.BaseVolumeUtils):
session_info = self.execute('iscsicli.exe', 'SessionList')
if session_info.find(target_iqn) == -1:
# Sending login
- self.execute('iscsicli.exe', 'qlogintarget', target_iqn)
+ self.execute('iscsicli.exe', 'qlogintarget', target_iqn,
+ auth_username, auth_password)
else:
return
except vmutils.HyperVException as exc:
diff --git a/nova/virt/hyperv/volumeutilsv2.py b/nova/virt/hyperv/volumeutilsv2.py
index ae2a7f6b2e..7eb27e3875 100644
--- a/nova/virt/hyperv/volumeutilsv2.py
+++ b/nova/virt/hyperv/volumeutilsv2.py
@@ -37,6 +37,8 @@ CONF = cfg.CONF
class VolumeUtilsV2(basevolumeutils.BaseVolumeUtils):
+ _CHAP_AUTH_TYPE = 'ONEWAYCHAP'
+
def __init__(self, host='.'):
super(VolumeUtilsV2, self).__init__(host)
@@ -62,7 +64,8 @@ class VolumeUtilsV2(basevolumeutils.BaseVolumeUtils):
portal.New(TargetPortalAddress=target_address,
TargetPortalPortNumber=target_port)
- def login_storage_target(self, target_lun, target_iqn, target_portal):
+ def login_storage_target(self, target_lun, target_iqn, target_portal,
+ auth_username=None, auth_password=None):
"""Ensure that the target is logged in."""
self._login_target_portal(target_portal)
@@ -88,8 +91,13 @@ class VolumeUtilsV2(basevolumeutils.BaseVolumeUtils):
return
try:
target = self._conn_storage.MSFT_iSCSITarget
+ auth = {}
+ if auth_username and auth_password:
+ auth['AuthenticationType'] = self._CHAP_AUTH_TYPE
+ auth['ChapUsername'] = auth_username
+ auth['ChapSecret'] = auth_password
target.Connect(NodeAddress=target_iqn,
- IsPersistent=True)
+ IsPersistent=True, **auth)
time.sleep(CONF.hyperv.volume_attach_retry_interval)
except wmi.x_wmi as exc:
LOG.debug("Attempt %(attempt)d to connect to target "
diff --git a/test-requirements.txt b/test-requirements.txt
index 519088ae6e..993607716e 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -19,4 +19,4 @@ sphinx>=1.1.2,!=1.2.0,<1.3
oslosphinx>=2.2.0 # Apache-2.0
oslotest>=1.1.0 # Apache-2.0
testrepository>=0.0.18
-testtools>=0.9.34
+testtools>=0.9.34,!=1.4.0