Browse Source

Don't generate service UUID for deleted services

In Pike, we added a UUID field to services and during an upgrade from
Ocata => Pike, when instances are accessed joined with their associated
services, we generate a UUID for the services on-the-fly.

This causes a problem in the scenario where an operator upgrades their
cluster and has old, deleted services with hostnames matching existing
services associated with instances. When we go to generate the service
UUID for the old, deleted service, we hit a ServiceTooOld exception.

This addresses the problem by not bothering to generate a UUID for a
deleted service. One alternative would be to exclude deleted services
when we join the 'instances' and 'services' tables, but I'm not sure
whether that approach might cause unintended effects where service
information that used to be viewable for instances becomes hidden.

Closes-Bug: #1778305
Closes-Bug: #1764556

Conflicts:
      nova/tests/functional/regressions/test_bug_1764556.py

NOTE(mriedem): The conflict is due to eadd78efe3 removing the
func_fixtures import.

Change-Id: I347096a527c257075cefe7b81210622f6cd87daf
(cherry picked from commit 16e163053c)
(cherry picked from commit 8601ca75b1)
tags/18.2.2^0
melanie witt 1 year ago
parent
commit
72f9aa720f

+ 1
- 1
nova/objects/service.py View File

@@ -272,7 +272,7 @@ class Service(base.NovaPersistentObject, base.NovaObject,
272 272
         service.obj_reset_changes()
273 273
 
274 274
         # TODO(dpeschman): Drop this once all services have uuids in database
275
-        if 'uuid' not in service:
275
+        if 'uuid' not in service and not service.deleted:
276 276
             service.uuid = uuidutils.generate_uuid()
277 277
             LOG.debug('Generated UUID %(uuid)s for service %(id)i',
278 278
                       dict(uuid=service.uuid, id=service.id))

+ 3
- 10
nova/tests/functional/regressions/test_bug_1764556.py View File

@@ -10,13 +10,10 @@
10 10
 # License for the specific language governing permissions and limitations
11 11
 # under the License.
12 12
 
13
-import six
14
-
15 13
 from nova import context as nova_context
16 14
 from nova.db import api as db
17 15
 from nova import test
18 16
 from nova.tests import fixtures as nova_fixtures
19
-from nova.tests.functional.api import client as api_client
20 17
 from nova.tests.functional import integrated_helpers
21 18
 from nova.tests.unit.image import fake as fake_image
22 19
 from nova.tests.unit import policy_fixture
@@ -153,10 +150,6 @@ class InstanceListWithDeletedServicesTestCase(
153 150
 
154 151
         # Finally, list servers as an admin so it joins on services to get host
155 152
         # information.
156
-        # FIXME(mriedem): This is bug 1764556 where the join on the services
157
-        # table also pulls the deleted service that doesn't have a uuid and
158
-        # attempts to migrate that service to have a uuid, which fails because
159
-        # it's not using a read_deleted='yes' context.
160
-        ex = self.assertRaises(api_client.OpenStackApiException,
161
-                               self.admin_api.get_servers, detail=True)
162
-        self.assertIn('ServiceNotFound', six.text_type(ex))
153
+        servers = self.admin_api.get_servers(detail=True)
154
+        for server in servers:
155
+            self.assertEqual('UP', server['host_status'])

+ 9
- 15
nova/tests/functional/regressions/test_bug_1778305.py View File

@@ -49,19 +49,13 @@ class InstanceListWithOldDeletedServiceTestCase(test.TestCase):
49 49
                                 host='fake-host')
50 50
         inst.create()
51 51
 
52
-        # TODO(melwitt): Remove this assert when the bug is fixed.
53
-        self.assertRaises(nova.exception.ServiceTooOld,
54
-                          objects.InstanceList.get_by_filters,
55
-                          self.context, {}, expected_attrs=['services'])
56
-
57
-        # TODO(melwitt): Uncomment these asserts when the bug is fixed.
58
-        # insts = objects.InstanceList.get_by_filters(
59
-        #    self.context, {}, expected_attrs=['services'])
60
-        # self.assertEqual(1, len(insts))
61
-        # self.assertEqual(2, len(insts[0].services))
52
+        insts = objects.InstanceList.get_by_filters(
53
+            self.context, {}, expected_attrs=['services'])
54
+        self.assertEqual(1, len(insts))
55
+        self.assertEqual(2, len(insts[0].services))
62 56
         # Deleted service should not have a UUID
63
-        # for service in insts[0].services:
64
-        #    if service.deleted:
65
-        #        self.assertNotIn('uuid', service)
66
-        #    else:
67
-        #        self.assertIsNotNone(service.uuid)
57
+        for service in insts[0].services:
58
+            if service.deleted:
59
+                self.assertNotIn('uuid', service)
60
+            else:
61
+                self.assertIsNotNone(service.uuid)

Loading…
Cancel
Save