diff --git a/nova/tests/functional/regressions/test_bug_2125935.py b/nova/tests/functional/regressions/test_bug_2125935.py new file mode 100644 index 0000000000..7308e75a36 --- /dev/null +++ b/nova/tests/functional/regressions/test_bug_2125935.py @@ -0,0 +1,112 @@ +# 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. + +from unittest import mock + +from nova.scheduler import weights +from nova.tests.functional import integrated_helpers + + +class HostNameWeigher(weights.BaseHostWeigher): + # We want to predictabilly have host1 first + _weights = {'host1': 1, 'host2': 0} + + def _weigh_object(self, host_state, weight_properties): + # Any undefined host gets no weight. + return self._weights.get(host_state.host, 0) + + +class TestImagePropsWeigher(integrated_helpers._IntegratedTestBase): + """Tests for image props weigher """ + + compute_driver = 'fake.MediumFakeDriver' + microversion = 'latest' + ADMIN_API = True + + def _setup_compute_service(self): + # Override to prevent the default 'compute' service from starting + pass + + def setUp(self): + weight_classes = [ + __name__ + '.HostNameWeigher', + 'nova.scheduler.weights.image_props.ImagePropertiesWeigher' + ] + self.flags(weight_classes=weight_classes, + group='filter_scheduler') + self.flags(image_props_weight_multiplier=2.0, group='filter_scheduler') + super(TestImagePropsWeigher, self).setUp() + + # Start only the compute services we want for testing + self.compute1 = self._start_compute('host1') + self.compute2 = self._start_compute('host2') + + @mock.patch('nova.weights.LOG.debug') + def test_boot(self, mock_debug): + server1 = self._create_server( + name='inst1', + networks='none', + ) + + # the weigher sees that there are no existing instances on both hosts + # with the same image props + mock_debug.assert_any_call( + "%s: raw weights %s", + "ImagePropertiesWeigher", + {('host2', 'host2'): 0.0, ('host1', 'host1'): 0.0}) + # because of the HostNameWeigher, we're sure that the instance lands + # on host1 + self.assertEqual('host1', server1['OS-EXT-SRV-ATTR:host']) + # let's make sure that we don't assert the calls from the previous + # schedules. + mock_debug.reset_mock() + + server2 = self._create_server( + name='inst2', + host='host2', + networks='none', + ) + # Since we force to a host, the weigher will not be called + self.assertEqual('host2', server2['OS-EXT-SRV-ATTR:host']) + + server3 = self._create_server( + name='inst3', + networks='none', + ) + + # The weigher is called but it says that there are no existing + # instances on both the hosts with the same image props, while we are + # sure that the values should be 1.0 for both hosts. + # FIXME(sbauza): That's due to bug/2125935 + mock_debug.assert_any_call( + "%s: raw weights %s", + "ImagePropertiesWeigher", + {('host2', 'host2'): 0.0, ('host1', 'host1'): 0.0}) + mock_debug.reset_mock() + # server3 is now on the same host than host1 as the weigh multiplier + # makes the scheduler to pack instances sharing the same image props. + self.assertEqual('host1', server3['OS-EXT-SRV-ATTR:host']) + + server4 = self._create_server( + name='inst4', + networks='none', + ) + # FIXME(sbauza): Same issue. The values should be 2.0 for host1 and 1.0 + # for host2. That said, due to the fact the HostState is refreshed + # already for the previous schedule, the system metadata is existing + # for this instance so that's why the weight is 1.0 for host1. + mock_debug.assert_any_call( + "%s: raw weights %s", + "ImagePropertiesWeigher", + {('host2', 'host2'): 0.0, ('host1', 'host1'): 1.0}) + # server4 is now packed with server1 and server3. + self.assertEqual('host1', server4['OS-EXT-SRV-ATTR:host'])