summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBalazs Gibizer <balazs.gibizer@est.tech>2020-02-25 16:48:48 +0100
committerElod Illes <elod.illes@est.tech>2020-03-25 06:40:30 +0000
commitf5091a91d0a977dd43b939317ecdeb1cd5db1980 (patch)
tree30762630ba0ad5348372be8021c3247df1e52adb
parentabd7eac4e4add8c977b0a3cc058f8beabad94a77 (diff)
downloadnova-f5091a91d0a977dd43b939317ecdeb1cd5db1980.tar.gz
Avoid circular reference during serialization
When an instance with numa topology is re-scheduled the conductor migrate task blows with circular reference during request spec serialization. It happens because there are ovos in the request spec that jsonutils.dumps only serialize if requested explicitly. This patch makes the explicit request. This is a stable only bug fix as the borken code was removed in Stein by the feature patch I4244f7dd8fe74565180f73684678027067b4506e Conflicts: nova/tests/unit/conductor/tasks/test_migrate.py The unit test case was re-implemented the test refactoring in I57568e9a01664ee373ea00a8db3164109c982909 is missing from pike. Closes-Bug: #1864665 Change-Id: I1942bfa9bd1baf8738d34c287216db7b59000a36 (cherry picked from commit 3871b38fe03aee7a1ffbbdfdf8a60b8c09e0ba76) (cherry picked from commit 54ca5d9afb11867ea022464d7ecad9f1ce13e453)
-rw-r--r--nova/conductor/tasks/migrate.py13
-rw-r--r--nova/tests/unit/conductor/tasks/test_migrate.py42
2 files changed, 54 insertions, 1 deletions
diff --git a/nova/conductor/tasks/migrate.py b/nova/conductor/tasks/migrate.py
index f472fabe85..0f0f5dda4a 100644
--- a/nova/conductor/tasks/migrate.py
+++ b/nova/conductor/tasks/migrate.py
@@ -9,6 +9,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
+import functools
from oslo_log import log as logging
from oslo_serialization import jsonutils
@@ -84,7 +85,17 @@ class MigrationTask(base.TaskBase):
# oslo.messaging #1529084 to transform datetime values into strings.
# tl;dr: datetimes in dicts are not accepted as correct values by the
# rpc fake driver.
- legacy_spec = jsonutils.loads(jsonutils.dumps(legacy_spec))
+ # NOTE(gibi): convert_instances=True is needed as the legacy_spec might
+ # contain ovo instances in the numa_topology field and those are
+ # causing circular reference during serialization otherwise.
+ legacy_spec = jsonutils.loads(
+ jsonutils.dumps(
+ legacy_spec,
+ default=functools.partial(
+ jsonutils.to_primitive, convert_instances=True
+ ),
+ )
+ )
self.compute_rpcapi.prep_resize(
self.context, self.instance, legacy_spec['image'],
diff --git a/nova/tests/unit/conductor/tasks/test_migrate.py b/nova/tests/unit/conductor/tasks/test_migrate.py
index 6086eb2c5c..9772641e49 100644
--- a/nova/tests/unit/conductor/tasks/test_migrate.py
+++ b/nova/tests/unit/conductor/tasks/test_migrate.py
@@ -10,8 +10,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+import functools
import mock
+from oslo_serialization import jsonutils
+
from nova.compute import rpcapi as compute_rpcapi
from nova.conductor.tasks import migrate
from nova import objects
@@ -75,3 +78,42 @@ class MigrationTaskTestCase(test.NoDBTestCase):
filter_properties=self.filter_properties,
node=self.hosts[0]['nodename'], clean_shutdown=self.clean_shutdown)
az_mock.assert_called_once_with(self.context, 'host1')
+
+ @mock.patch('nova.availability_zones.get_host_availability_zone')
+ @mock.patch.object(scheduler_utils, 'setup_instance_group')
+ @mock.patch.object(scheduler_client.SchedulerClient, 'select_destinations')
+ @mock.patch.object(compute_rpcapi.ComputeAPI, 'prep_resize')
+ def test_execute_with_cpu_topoloy(
+ self, prep_resize_mock, sel_dest_mock, sig_mock, az_mock):
+ self.request_spec = objects.RequestSpec(
+ numa_topology=objects.InstanceNUMATopology(
+ cells=[
+ objects.InstanceNUMACell(
+ cpu_topology=objects.VirtCPUTopology()
+ )
+ ]
+ )
+ )
+ sel_dest_mock.return_value = self.hosts
+ az_mock.return_value = 'myaz'
+ task = self._generate_task()
+ legacy_request_spec = jsonutils.loads(
+ jsonutils.dumps(
+ self.request_spec.to_legacy_request_spec_dict(),
+ default=functools.partial(
+ jsonutils.to_primitive, convert_instances=True
+ ),
+ )
+ )
+ task.execute()
+
+ sig_mock.assert_called_once_with(self.context, self.request_spec)
+ task.scheduler_client.select_destinations.assert_called_once_with(
+ self.context, self.request_spec, [self.instance.uuid])
+ prep_resize_mock.assert_called_once_with(
+ self.context, self.instance, legacy_request_spec['image'],
+ self.flavor, self.hosts[0]['host'], self.reservations,
+ request_spec=legacy_request_spec,
+ filter_properties=self.filter_properties,
+ node=self.hosts[0]['nodename'], clean_shutdown=self.clean_shutdown)
+ az_mock.assert_called_once_with(self.context, 'host1')