Prevent updating an RP's parent to form a loop

Placement had RP loop detection for RP creation but if an RP is created
without a parent (e.g. root RP) then the parent can be set later with a
PUT /resource_providers/{uuid} request by providing the UUID of the
parent. In this code path the loop detection was missing from the
validation. Moreover there are different loop cases for create than for
set. For create the only possible loop is when the RP being created is
points to itself as a parent. However when the parent is provided later
in a PUT the RP being updated can have descendant RPs. Setting a parent
to a descendant also creates a loop.

This patch adds the missing check and returns HTTP 400 if loop is detected.

Closes-Bug: #1779635
Change-Id: I42c91f5f752f0a4fba8b1d95489fc3f87a1c5b6e
This commit is contained in:
Balazs Gibizer 2018-07-02 15:21:17 +02:00
parent 16812e8979
commit 00b13a2e2f
2 changed files with 31 additions and 3 deletions

View File

@ -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

View File

@ -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.'