]> xenbits.xensource.com Git - osstest/openstack-nova.git/commitdiff
Handle MarkerNotFound from cell0 database
authorMatt Riedemann <mriedem@us.ibm.com>
Mon, 5 Dec 2016 21:24:05 +0000 (16:24 -0500)
committerMatt Riedemann <mriedem@us.ibm.com>
Tue, 6 Dec 2016 22:14:29 +0000 (17:14 -0500)
When listing instances in the cellv2 world we look them up
from three locations:

1. Build requests which exist before the instances are created
   in the cell database (after the scheduler picks a host to
   build the instance). Currently instances and build requests
   are both created before casting to conductor, but that's going
   away in Ocata with the support for multiple cellsv2 cells.
2. The cell0 database for instances which failed to get scheduled
   to a compute host (and therefore a cell).
3. The actual cell database that the instance lives in. Currently
   that's only a single traditional nova database, but could be one
   of multiple cellsv2 cells when we add that support in Ocata.

If a marker is passed in when listing instances, if the instance
lives in an actual cell database, we'll get a MarkerNotFound failure
from cell0 because the instance doesn't exist in cell0, but we check
cell0 before we check the cell database. This makes the instance
listing short-circuit and fail with a 400 from the REST API.

This patch simply handles the MarkerNotFound when listing instances
from the cell0 database and ignores it so we can continue onto the
cell database.

Closes-Bug: #1647464

Change-Id: I977497be262fb7f2333e32fb7313b29624323422

nova/compute/api.py
nova/tests/unit/compute/test_compute_api.py

index b3d89b466664fe929c1be5cb00fc1c59ce7eea82..6cd25fecedf155a4204ca7ef3baa3df6e62206e7 100644 (file)
@@ -2393,10 +2393,14 @@ class API(base.Base):
             cell0_instances = objects.InstanceList(objects=[])
         else:
             with nova_context.target_cell(context, cell0_mapping):
-                cell0_instances = self._get_instances_by_filters(
-                    context, filters, limit=limit, marker=marker,
-                    expected_attrs=expected_attrs, sort_keys=sort_keys,
-                    sort_dirs=sort_dirs)
+                try:
+                    cell0_instances = self._get_instances_by_filters(
+                        context, filters, limit=limit, marker=marker,
+                        expected_attrs=expected_attrs, sort_keys=sort_keys,
+                        sort_dirs=sort_dirs)
+                except exception.MarkerNotFound:
+                    # We can ignore this since we need to look in the cell DB
+                    cell0_instances = objects.InstanceList(objects=[])
         # Only subtract from limit if it is not None
         limit = (limit - len(cell0_instances)) if limit else limit
 
index 5f4ecaf6e55246a951b2fdbe92d8d3b2c7c8d3c1..b83f9efd654373ea77732c5b43fef256b8a262b9 100644 (file)
@@ -4572,6 +4572,53 @@ class _ComputeAPIUnitTestMixIn(object):
                                          cell_instances):
                 self.assertEqual(instance, instances[i])
 
+    @mock.patch.object(context, 'target_cell')
+    @mock.patch.object(objects.BuildRequestList, 'get_by_filters',
+                       return_value=objects.BuildRequestList(objects=[]))
+    @mock.patch.object(objects.CellMapping, 'get_by_uuid')
+    def test_get_all_cell0_marker_not_found(self, mock_cell_mapping_get,
+                                            mock_buildreq_get,
+                                            mock_target_cell):
+        """Tests that we handle a MarkerNotFound raised from the cell0 database
+        and continue looking for instances from the normal cell database.
+        """
+
+        cell_instances = self._list_of_instances(2)
+
+        cell_mapping = objects.CellMapping()
+        mock_cell_mapping_get.return_value = cell_mapping
+        marker = uuids.marker
+
+        with mock.patch.object(self.compute_api,
+                               '_get_instances_by_filters') as mock_inst_get:
+            # simulate calling _get_instances_by_filters twice, once for cell0
+            # which raises a MarkerNotFound and once from the cell DB which
+            # returns two instances
+            mock_inst_get.side_effect = [
+                exception.MarkerNotFound(marker=marker),
+                objects.InstanceList(self.context, objects=cell_instances)]
+
+            instances = self.compute_api.get_all(
+                self.context, search_opts={'foo': 'bar'},
+                limit=10, marker=marker, sort_keys=['baz'],
+                sort_dirs=['desc'])
+
+            mock_target_cell.assert_called_once_with(self.context,
+                                                     cell_mapping)
+            inst_get_calls = [mock.call(self.context, {'foo': 'bar'},
+                                        limit=10, marker=marker,
+                                        expected_attrs=None, sort_keys=['baz'],
+                                        sort_dirs=['desc']),
+                              mock.call(self.context, {'foo': 'bar'},
+                                        limit=10, marker=marker,
+                                        expected_attrs=None, sort_keys=['baz'],
+                                        sort_dirs=['desc'])
+                              ]
+            self.assertEqual(2, mock_inst_get.call_count)
+            mock_inst_get.assert_has_calls(inst_get_calls)
+            for i, instance in enumerate(cell_instances):
+                self.assertEqual(instance, instances[i])
+
     @mock.patch.object(objects.BuildRequest, 'get_by_instance_uuid')
     @mock.patch.object(objects.InstanceMapping, 'get_by_instance_uuid')
     def test_update_existing_instance_not_in_cell(self, mock_instmap_get,