diff options
-rw-r--r-- | nova/api/metadata/handler.py | 6 | ||||
-rw-r--r-- | nova/compute/resource_tracker.py | 2 | ||||
-rw-r--r-- | nova/scheduler/filter_scheduler.py | 2 | ||||
-rw-r--r-- | nova/tests/compute/test_resource_tracker.py | 13 | ||||
-rw-r--r-- | nova/tests/scheduler/test_filter_scheduler.py | 2 | ||||
-rw-r--r-- | nova/tests/test_metadata.py | 22 | ||||
-rw-r--r-- | nova/tests/virt/hyperv/db_fakes.py | 22 | ||||
-rw-r--r-- | nova/tests/virt/hyperv/test_hypervapi.py | 4 | ||||
-rw-r--r-- | nova/tests/virt/hyperv/test_volumeutils.py | 33 | ||||
-rw-r--r-- | nova/tests/virt/hyperv/test_volumeutilsv2.py | 29 | ||||
-rw-r--r-- | nova/virt/hyperv/volumeops.py | 14 | ||||
-rw-r--r-- | nova/virt/hyperv/volumeutils.py | 6 | ||||
-rw-r--r-- | nova/virt/hyperv/volumeutilsv2.py | 12 | ||||
-rw-r--r-- | test-requirements.txt | 2 |
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 |