diff --git a/nova/api/openstack/placement/objects/resource_provider.py b/nova/api/openstack/placement/objects/resource_provider.py index e41bc128a296..85e5d8923a9f 100644 --- a/nova/api/openstack/placement/objects/resource_provider.py +++ b/nova/api/openstack/placement/objects/resource_provider.py @@ -1041,6 +1041,23 @@ class ResourceProvider(base.VersionedObject, base.TimestampedObject): action='update', reason=_('re-parenting a provider is not ' 'currently allowed.')) + if my_ids.parent_uuid is None: + # So the user specifies a parent for an RP that doesn't + # have one. We have to check that by this new parent we + # don't create a loop in the tree. Basically the new parent + # cannot be the RP itself or one of its descendants. + # However as the RP's current parent is None the above + # condition is the same as "the new parent cannot be any RP + # from the current RP tree". + same_tree = ResourceProviderList.get_all_by_filters( + context, + filters={'in_tree': self.uuid}) + rp_uuids_in_the_same_tree = [rp.uuid for rp in same_tree] + if parent_uuid in rp_uuids_in_the_same_tree: + raise exception.ObjectActionError( + action='update', + reason=_('creating loop in the provider tree is ' + 'not allowed.')) updates['root_provider_id'] = parent_ids.root_id updates['parent_provider_id'] = parent_ids.id diff --git a/nova/tests/functional/api/openstack/placement/gabbits/resource-provider.yaml b/nova/tests/functional/api/openstack/placement/gabbits/resource-provider.yaml index c025ddc80dee..98e32268cde4 100644 --- a/nova/tests/functional/api/openstack/placement/gabbits/resource-provider.yaml +++ b/nova/tests/functional/api/openstack/placement/gabbits/resource-provider.yaml @@ -731,6 +731,17 @@ tests: data: name: parent parent_provider_uuid: $ENVIRON['PARENT_PROVIDER_UUID'] -# this reproduces bug 1779635 as this should be HTTP 400 as we have a loop now -# in the tree - status: 200 + status: 400 + response_strings: + - 'creating loop in the provider tree is not allowed.' + +- name: fail updating the parent to point to its child + PUT: /resource_providers/$ENVIRON['PARENT_PROVIDER_UUID'] + request_headers: + content-type: application/json + data: + name: parent + parent_provider_uuid: $ENVIRON['RP_UUID'] + status: 400 + response_strings: + - 'creating loop in the provider tree is not allowed.'