placement: adds REST API for nested providers
Adds a new microversion (1.14) to the placement REST API for supporting
nested resource providers.
For POST /resource_providers and PUT /resource_providers/{uuid}, a new
optional 'parent_provider_uuid' field is added to the request payload.
For GET /resource_providers/{uuid} responses, the
'parent_provider_uuid' field and a convenience field called
'root_provider_uuid' are provided.
For GET /resource_providers, a new '?in_tree=<rp_uuid>' parameter is
supported. This parameter accepts a UUID of a resource provider. This
will cause the resulting list of resource providers to be only the
providers within the same "provider tree" as the provider identified by
<rp_uuid>
Clients for the placement REST API can specify either
'OpenStack-API-Version: placement 1.14' or 'placement latest' to handle
the new 'parent_provider_uuid' attribute and to query for resource
providers in a provider tree.
Change-Id: I4db74e4dc682bc03df6ec94cd1c3a5f5dc927a7b
blueprint: nested-resource-providers
APIImpact
			
			
This commit is contained in:
		
				
					committed by
					
						
						Eric Fried
					
				
			
			
				
	
			
			
			
						parent
						
							6242a15e0c
						
					
				
				
					commit
					109f21f3c8
				
			@@ -41,13 +41,30 @@ POST_RESOURCE_PROVIDER_SCHEMA = {
 | 
			
		||||
    },
 | 
			
		||||
    "required": [
 | 
			
		||||
        "name"
 | 
			
		||||
     ],
 | 
			
		||||
    ],
 | 
			
		||||
    "additionalProperties": False,
 | 
			
		||||
}
 | 
			
		||||
# Remove uuid to create the schema for PUTting a resource provider
 | 
			
		||||
PUT_RESOURCE_PROVIDER_SCHEMA = copy.deepcopy(POST_RESOURCE_PROVIDER_SCHEMA)
 | 
			
		||||
PUT_RESOURCE_PROVIDER_SCHEMA['properties'].pop('uuid')
 | 
			
		||||
 | 
			
		||||
# Placement API microversion 1.14 adds an optional parent_provider_uuid field
 | 
			
		||||
# to the POST and PUT request schemas
 | 
			
		||||
POST_RP_SCHEMA_V1_14 = copy.deepcopy(POST_RESOURCE_PROVIDER_SCHEMA)
 | 
			
		||||
POST_RP_SCHEMA_V1_14["properties"]["parent_provider_uuid"] = {
 | 
			
		||||
    "anyOf": [
 | 
			
		||||
        {
 | 
			
		||||
            "type": "string",
 | 
			
		||||
            "format": "uuid",
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "type": "null",
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
PUT_RP_SCHEMA_V1_14 = copy.deepcopy(POST_RP_SCHEMA_V1_14)
 | 
			
		||||
PUT_RP_SCHEMA_V1_14['properties'].pop('uuid')
 | 
			
		||||
 | 
			
		||||
# Represents the allowed query string parameters to the GET /resource_providers
 | 
			
		||||
# API call
 | 
			
		||||
GET_RPS_SCHEMA_1_0 = {
 | 
			
		||||
@@ -80,6 +97,17 @@ GET_RPS_SCHEMA_1_4['properties']['resources'] = {
 | 
			
		||||
    "type": "string"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Placement API microversion 1.14 adds support for requesting resource
 | 
			
		||||
# providers within a tree of providers. The 'in_tree' query string parameter
 | 
			
		||||
# should be the UUID of a resource provider. The result of the GET call will
 | 
			
		||||
# include only those resource providers in the same "provider tree" as the
 | 
			
		||||
# provider with the UUID represented by 'in_tree'
 | 
			
		||||
GET_RPS_SCHEMA_1_14 = copy.deepcopy(GET_RPS_SCHEMA_1_4)
 | 
			
		||||
GET_RPS_SCHEMA_1_14['properties']['in_tree'] = {
 | 
			
		||||
    "type": "string",
 | 
			
		||||
    "format": "uuid",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _serialize_links(environ, resource_provider):
 | 
			
		||||
    url = util.resource_provider_url(environ, resource_provider)
 | 
			
		||||
@@ -97,20 +125,23 @@ def _serialize_links(environ, resource_provider):
 | 
			
		||||
    return links
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _serialize_provider(environ, resource_provider):
 | 
			
		||||
def _serialize_provider(environ, resource_provider, want_version):
 | 
			
		||||
    data = {
 | 
			
		||||
        'uuid': resource_provider.uuid,
 | 
			
		||||
        'name': resource_provider.name,
 | 
			
		||||
        'generation': resource_provider.generation,
 | 
			
		||||
        'links': _serialize_links(environ, resource_provider)
 | 
			
		||||
    }
 | 
			
		||||
    if want_version.matches((1, 14)):
 | 
			
		||||
        data['parent_provider_uuid'] = resource_provider.parent_provider_uuid
 | 
			
		||||
        data['root_provider_uuid'] = resource_provider.root_provider_uuid
 | 
			
		||||
    return data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _serialize_providers(environ, resource_providers):
 | 
			
		||||
def _serialize_providers(environ, resource_providers, want_version):
 | 
			
		||||
    output = []
 | 
			
		||||
    for provider in resource_providers:
 | 
			
		||||
        provider_data = _serialize_provider(environ, provider)
 | 
			
		||||
        provider_data = _serialize_provider(environ, provider, want_version)
 | 
			
		||||
        output.append(provider_data)
 | 
			
		||||
    return {"resource_providers": output}
 | 
			
		||||
 | 
			
		||||
@@ -124,12 +155,15 @@ def create_resource_provider(req):
 | 
			
		||||
    header pointing to the newly created resource provider.
 | 
			
		||||
    """
 | 
			
		||||
    context = req.environ['placement.context']
 | 
			
		||||
    data = util.extract_json(req.body, POST_RESOURCE_PROVIDER_SCHEMA)
 | 
			
		||||
    schema = POST_RESOURCE_PROVIDER_SCHEMA
 | 
			
		||||
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
 | 
			
		||||
    if want_version.matches((1, 14)):
 | 
			
		||||
        schema = POST_RP_SCHEMA_V1_14
 | 
			
		||||
    data = util.extract_json(req.body, schema)
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        uuid = data.get('uuid', uuidutils.generate_uuid())
 | 
			
		||||
        resource_provider = rp_obj.ResourceProvider(
 | 
			
		||||
            context, name=data['name'], uuid=uuid)
 | 
			
		||||
        uuid = data.setdefault('uuid', uuidutils.generate_uuid())
 | 
			
		||||
        resource_provider = rp_obj.ResourceProvider(context, **data)
 | 
			
		||||
        resource_provider.create()
 | 
			
		||||
    except db_exc.DBDuplicateEntry as exc:
 | 
			
		||||
        # Whether exc.columns has one or two entries (in the event
 | 
			
		||||
@@ -192,8 +226,9 @@ def get_resource_provider(req):
 | 
			
		||||
    resource_provider = rp_obj.ResourceProvider.get_by_uuid(
 | 
			
		||||
        context, uuid)
 | 
			
		||||
 | 
			
		||||
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
 | 
			
		||||
    req.response.body = encodeutils.to_utf8(jsonutils.dumps(
 | 
			
		||||
        _serialize_provider(req.environ, resource_provider)))
 | 
			
		||||
        _serialize_provider(req.environ, resource_provider, want_version)))
 | 
			
		||||
    req.response.content_type = 'application/json'
 | 
			
		||||
    return req.response
 | 
			
		||||
 | 
			
		||||
@@ -210,15 +245,17 @@ def list_resource_providers(req):
 | 
			
		||||
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
 | 
			
		||||
 | 
			
		||||
    schema = GET_RPS_SCHEMA_1_0
 | 
			
		||||
    if want_version == (1, 3):
 | 
			
		||||
        schema = GET_RPS_SCHEMA_1_3
 | 
			
		||||
    if want_version >= (1, 4):
 | 
			
		||||
    if want_version.matches((1, 14)):
 | 
			
		||||
        schema = GET_RPS_SCHEMA_1_14
 | 
			
		||||
    elif want_version.matches((1, 4)):
 | 
			
		||||
        schema = GET_RPS_SCHEMA_1_4
 | 
			
		||||
    elif want_version.matches((1, 3)):
 | 
			
		||||
        schema = GET_RPS_SCHEMA_1_3
 | 
			
		||||
 | 
			
		||||
    util.validate_query_params(req, schema)
 | 
			
		||||
 | 
			
		||||
    filters = {}
 | 
			
		||||
    for attr in ['uuid', 'name', 'member_of']:
 | 
			
		||||
    for attr in ['uuid', 'name', 'member_of', 'in_tree']:
 | 
			
		||||
        if attr in req.GET:
 | 
			
		||||
            value = req.GET[attr]
 | 
			
		||||
            # special case member_of to always make its value a
 | 
			
		||||
@@ -250,8 +287,8 @@ def list_resource_providers(req):
 | 
			
		||||
            {'error': exc})
 | 
			
		||||
 | 
			
		||||
    response = req.response
 | 
			
		||||
    response.body = encodeutils.to_utf8(
 | 
			
		||||
        jsonutils.dumps(_serialize_providers(req.environ, resource_providers)))
 | 
			
		||||
    response.body = encodeutils.to_utf8(jsonutils.dumps(
 | 
			
		||||
        _serialize_providers(req.environ, resource_providers, want_version)))
 | 
			
		||||
    response.content_type = 'application/json'
 | 
			
		||||
    return response
 | 
			
		||||
 | 
			
		||||
@@ -271,9 +308,16 @@ def update_resource_provider(req):
 | 
			
		||||
    resource_provider = rp_obj.ResourceProvider.get_by_uuid(
 | 
			
		||||
        context, uuid)
 | 
			
		||||
 | 
			
		||||
    data = util.extract_json(req.body, PUT_RESOURCE_PROVIDER_SCHEMA)
 | 
			
		||||
    schema = PUT_RESOURCE_PROVIDER_SCHEMA
 | 
			
		||||
    want_version = req.environ[microversion.MICROVERSION_ENVIRON]
 | 
			
		||||
    if want_version.matches((1, 14)):
 | 
			
		||||
        schema = PUT_RP_SCHEMA_V1_14
 | 
			
		||||
 | 
			
		||||
    resource_provider.name = data['name']
 | 
			
		||||
    data = util.extract_json(req.body, schema)
 | 
			
		||||
 | 
			
		||||
    for field in rp_obj.ResourceProvider.SETTABLE_FIELDS:
 | 
			
		||||
        if field in data:
 | 
			
		||||
            setattr(resource_provider, field, data[field])
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        resource_provider.save()
 | 
			
		||||
@@ -287,7 +331,7 @@ def update_resource_provider(req):
 | 
			
		||||
            {'rp_uuid': uuid, 'error': exc})
 | 
			
		||||
 | 
			
		||||
    req.response.body = encodeutils.to_utf8(jsonutils.dumps(
 | 
			
		||||
        _serialize_provider(req.environ, resource_provider)))
 | 
			
		||||
        _serialize_provider(req.environ, resource_provider, want_version)))
 | 
			
		||||
    req.response.status = 200
 | 
			
		||||
    req.response.content_type = 'application/json'
 | 
			
		||||
    return req.response
 | 
			
		||||
 
 | 
			
		||||
@@ -54,6 +54,9 @@ VERSIONS = [
 | 
			
		||||
             # as GET. The 'allocation_requests' format in GET
 | 
			
		||||
             # /allocation_candidates is updated to be the same as well.
 | 
			
		||||
    '1.13',  # Adds POST /allocations to set allocations for multiple consumers
 | 
			
		||||
             # as GET
 | 
			
		||||
    '1.14',  # Adds parent and root provider UUID on resource provider
 | 
			
		||||
             # representation and 'in_tree' filter on GET /resource_providers
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -178,3 +178,22 @@ with the new `PUT` format.
 | 
			
		||||
 | 
			
		||||
Version 1.13 gives the ability to set or clear allocations for more than
 | 
			
		||||
one consumer uuid with a request to ``POST /allocations``.
 | 
			
		||||
 | 
			
		||||
1.14 Add nested resource providers
 | 
			
		||||
----------------------------------
 | 
			
		||||
 | 
			
		||||
The 1.14 version introduces the concept of nested resource providers. The
 | 
			
		||||
resource provider resource now contains two new attributes:
 | 
			
		||||
 | 
			
		||||
* ``parent_provider_uuid`` indicates the provider's direct parent, or null if
 | 
			
		||||
  there is no parent. This attribute can be set in the call to ``POST
 | 
			
		||||
  /resource_providers`` and ``PUT /resource_providers/{uuid}`` if the attribute
 | 
			
		||||
  has not already been set to a non-NULL value (i.e. we do not support
 | 
			
		||||
  "reparenting" a provider)
 | 
			
		||||
* ``root_provider_uuid`` indicates the UUID of the root resource provider in
 | 
			
		||||
  the provider's tree. This is a read-only attribute
 | 
			
		||||
 | 
			
		||||
A new ``in_tree=<UUID>`` parameter is now available in the ``GET
 | 
			
		||||
/resource-providers`` API call. Supplying a UUID value for the ``in_tree``
 | 
			
		||||
parameter will cause all resource providers within the "provider tree" of the
 | 
			
		||||
provider matching ``<UUID>`` to be returned.
 | 
			
		||||
 
 | 
			
		||||
@@ -85,6 +85,8 @@ class APIFixture(fixture.GabbiFixture):
 | 
			
		||||
        os.environ['INSTANCE_UUID'] = uuidutils.generate_uuid()
 | 
			
		||||
        os.environ['MIGRATION_UUID'] = uuidutils.generate_uuid()
 | 
			
		||||
        os.environ['CONSUMER_UUID'] = uuidutils.generate_uuid()
 | 
			
		||||
        os.environ['PARENT_PROVIDER_UUID'] = uuidutils.generate_uuid()
 | 
			
		||||
        os.environ['ALT_PARENT_PROVIDER_UUID'] = uuidutils.generate_uuid()
 | 
			
		||||
 | 
			
		||||
    def stop_fixture(self):
 | 
			
		||||
        self.api_db_fixture.cleanup()
 | 
			
		||||
 
 | 
			
		||||
@@ -39,13 +39,13 @@ tests:
 | 
			
		||||
  response_json_paths:
 | 
			
		||||
      $.errors[0].title: Not Acceptable
 | 
			
		||||
 | 
			
		||||
- name: latest microversion is 1.13
 | 
			
		||||
- name: latest microversion is 1.14
 | 
			
		||||
  GET: /
 | 
			
		||||
  request_headers:
 | 
			
		||||
      openstack-api-version: placement latest
 | 
			
		||||
  response_headers:
 | 
			
		||||
      vary: /OpenStack-API-Version/
 | 
			
		||||
      openstack-api-version: placement 1.13
 | 
			
		||||
      openstack-api-version: placement 1.14
 | 
			
		||||
 | 
			
		||||
- name: other accept header bad version
 | 
			
		||||
  GET: /
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ defaults:
 | 
			
		||||
    request_headers:
 | 
			
		||||
        x-auth-token: admin
 | 
			
		||||
        accept: application/json
 | 
			
		||||
        openstack-api-version: placement latest
 | 
			
		||||
 | 
			
		||||
tests:
 | 
			
		||||
 | 
			
		||||
@@ -80,6 +81,7 @@ tests:
 | 
			
		||||
  response_json_paths:
 | 
			
		||||
      $.uuid: $ENVIRON['RP_UUID']
 | 
			
		||||
      $.name: $ENVIRON['RP_NAME']
 | 
			
		||||
      $.parent_provider_uuid: null
 | 
			
		||||
      $.generation: 0
 | 
			
		||||
      $.links[?rel = "self"].href: /resource_providers/$ENVIRON['RP_UUID']
 | 
			
		||||
      $.links[?rel = "inventories"].href: /resource_providers/$ENVIRON['RP_UUID']/inventories
 | 
			
		||||
@@ -107,6 +109,7 @@ tests:
 | 
			
		||||
      $.resource_providers[0].uuid: $ENVIRON['RP_UUID']
 | 
			
		||||
      $.resource_providers[0].name: $ENVIRON['RP_NAME']
 | 
			
		||||
      $.resource_providers[0].generation: 0
 | 
			
		||||
      $.resource_providers[0].parent_provider_uuid: null
 | 
			
		||||
      $.resource_providers[0].links[?rel = "self"].href: /resource_providers/$ENVIRON['RP_UUID']
 | 
			
		||||
      $.resource_providers[0].links[?rel = "inventories"].href: /resource_providers/$ENVIRON['RP_UUID']/inventories
 | 
			
		||||
      $.resource_providers[0].links[?rel = "usages"].href: /resource_providers/$ENVIRON['RP_UUID']/usages
 | 
			
		||||
@@ -174,7 +177,7 @@ tests:
 | 
			
		||||
      $.resource_providers[0].links[?rel = "inventories"].href: /resource_providers/$ENVIRON['RP_UUID']/inventories
 | 
			
		||||
      $.resource_providers[0].links[?rel = "usages"].href: /resource_providers/$ENVIRON['RP_UUID']/usages
 | 
			
		||||
 | 
			
		||||
- name: update a resource provider
 | 
			
		||||
- name: update a resource provider's name
 | 
			
		||||
  PUT: /resource_providers/$RESPONSE['$.resource_providers[0].uuid']
 | 
			
		||||
  request_headers:
 | 
			
		||||
      content-type: application/json
 | 
			
		||||
@@ -208,6 +211,174 @@ tests:
 | 
			
		||||
  response_json_paths:
 | 
			
		||||
      $.errors[0].title: Bad Request
 | 
			
		||||
 | 
			
		||||
# This section of tests validate nested resource provider relationships and
 | 
			
		||||
# constraints. We attempt to set the parent provider UUID for the primary
 | 
			
		||||
# resource provider to a UUID value of a provider we have not yet created and
 | 
			
		||||
# expect a failure. We then create that parent provider record and attempt to
 | 
			
		||||
# set the same parent provider UUID without also setting the root provider UUID
 | 
			
		||||
# to the same value, with an expected failure. Finally, we set the primary
 | 
			
		||||
# provider's root AND parent to the new provider UUID and verify success.
 | 
			
		||||
 | 
			
		||||
- name: test POST microversion limits nested providers
 | 
			
		||||
  POST: /resource_providers
 | 
			
		||||
  request_headers:
 | 
			
		||||
      openstack-api-version: placement 1.13
 | 
			
		||||
      content-type: application/json
 | 
			
		||||
  data:
 | 
			
		||||
      name: child
 | 
			
		||||
      parent_provider_uuid: $ENVIRON['PARENT_PROVIDER_UUID']
 | 
			
		||||
  status: 400
 | 
			
		||||
  response_strings:
 | 
			
		||||
      - 'JSON does not validate'
 | 
			
		||||
 | 
			
		||||
- name: test PUT microversion limits nested providers
 | 
			
		||||
  PUT: /resource_providers/$ENVIRON['RP_UUID']
 | 
			
		||||
  request_headers:
 | 
			
		||||
      openstack-api-version: placement 1.13
 | 
			
		||||
      content-type: application/json
 | 
			
		||||
  data:
 | 
			
		||||
      name: child
 | 
			
		||||
      parent_provider_uuid: $ENVIRON['PARENT_PROVIDER_UUID']
 | 
			
		||||
  status: 400
 | 
			
		||||
  response_strings:
 | 
			
		||||
      - 'JSON does not validate'
 | 
			
		||||
 | 
			
		||||
- name: fail trying to set a root provider UUID
 | 
			
		||||
  PUT: /resource_providers/$ENVIRON['RP_UUID']
 | 
			
		||||
  request_headers:
 | 
			
		||||
      content-type: application/json
 | 
			
		||||
  data:
 | 
			
		||||
      root_provider_uuid: $ENVIRON['PARENT_PROVIDER_UUID']
 | 
			
		||||
  status: 400
 | 
			
		||||
  response_strings:
 | 
			
		||||
      - 'JSON does not validate'
 | 
			
		||||
 | 
			
		||||
- name: fail trying to self-parent
 | 
			
		||||
  POST: /resource_providers
 | 
			
		||||
  request_headers:
 | 
			
		||||
      content-type: application/json
 | 
			
		||||
  data:
 | 
			
		||||
      name: child
 | 
			
		||||
      uuid: $ENVIRON['ALT_PARENT_PROVIDER_UUID']
 | 
			
		||||
      parent_provider_uuid: $ENVIRON['ALT_PARENT_PROVIDER_UUID']
 | 
			
		||||
  status: 400
 | 
			
		||||
  response_strings:
 | 
			
		||||
      - 'parent provider UUID cannot be same as UUID'
 | 
			
		||||
 | 
			
		||||
- name: update a parent provider UUID to non-existing provider
 | 
			
		||||
  PUT: /resource_providers/$ENVIRON['RP_UUID']
 | 
			
		||||
  request_headers:
 | 
			
		||||
      content-type: application/json
 | 
			
		||||
  data:
 | 
			
		||||
      name: parent
 | 
			
		||||
      parent_provider_uuid: $ENVIRON['PARENT_PROVIDER_UUID']
 | 
			
		||||
  status: 400
 | 
			
		||||
  response_strings:
 | 
			
		||||
      - 'parent provider UUID does not exist'
 | 
			
		||||
 | 
			
		||||
- name: now create the parent provider
 | 
			
		||||
  POST: /resource_providers
 | 
			
		||||
  request_headers:
 | 
			
		||||
      content-type: application/json
 | 
			
		||||
  data:
 | 
			
		||||
      name: parent
 | 
			
		||||
      uuid: $ENVIRON['PARENT_PROVIDER_UUID']
 | 
			
		||||
  status: 201
 | 
			
		||||
 | 
			
		||||
- name: get provider with old microversion no root provider UUID field
 | 
			
		||||
  GET: /resource_providers/$ENVIRON['PARENT_PROVIDER_UUID']
 | 
			
		||||
  request_headers:
 | 
			
		||||
      openstack-api-version: placement 1.13
 | 
			
		||||
      content-type: application/json
 | 
			
		||||
  response_json_paths:
 | 
			
		||||
      $.`len`: 4
 | 
			
		||||
      name: parent
 | 
			
		||||
  status: 200
 | 
			
		||||
 | 
			
		||||
- name: get provider has root provider UUID field
 | 
			
		||||
  GET: /resource_providers/$ENVIRON['PARENT_PROVIDER_UUID']
 | 
			
		||||
  request_headers:
 | 
			
		||||
      content-type: application/json
 | 
			
		||||
  response_json_paths:
 | 
			
		||||
      $.`len`: 6
 | 
			
		||||
      name: parent
 | 
			
		||||
      root_provider_uuid: $ENVIRON['PARENT_PROVIDER_UUID']
 | 
			
		||||
      parent_provider_uuid: null
 | 
			
		||||
  status: 200
 | 
			
		||||
 | 
			
		||||
- name: update a parent
 | 
			
		||||
  PUT: /resource_providers/$ENVIRON['RP_UUID']
 | 
			
		||||
  request_headers:
 | 
			
		||||
      content-type: application/json
 | 
			
		||||
  data:
 | 
			
		||||
      name: child
 | 
			
		||||
      parent_provider_uuid: $ENVIRON['PARENT_PROVIDER_UUID']
 | 
			
		||||
  status: 200
 | 
			
		||||
 | 
			
		||||
- name: get provider has new parent and root provider UUID field
 | 
			
		||||
  GET: /resource_providers/$ENVIRON['RP_UUID']
 | 
			
		||||
  request_headers:
 | 
			
		||||
      content-type: application/json
 | 
			
		||||
  response_json_paths:
 | 
			
		||||
      name: child
 | 
			
		||||
      root_provider_uuid: $ENVIRON['PARENT_PROVIDER_UUID']
 | 
			
		||||
      parent_provider_uuid: $ENVIRON['PARENT_PROVIDER_UUID']
 | 
			
		||||
  status: 200
 | 
			
		||||
 | 
			
		||||
- name: fail trying to un-parent
 | 
			
		||||
  PUT: /resource_providers/$ENVIRON['RP_UUID']
 | 
			
		||||
  request_headers:
 | 
			
		||||
      content-type: application/json
 | 
			
		||||
  data:
 | 
			
		||||
      name: child
 | 
			
		||||
      parent_provider_uuid: null
 | 
			
		||||
  status: 400
 | 
			
		||||
  response_strings:
 | 
			
		||||
      - 'un-parenting a provider is not currently allowed'
 | 
			
		||||
 | 
			
		||||
- name: list all resource providers in a tree that does not exist
 | 
			
		||||
  GET: /resource_providers?in_tree=$ENVIRON['ALT_PARENT_PROVIDER_UUID']
 | 
			
		||||
  response_json_paths:
 | 
			
		||||
      $.resource_providers.`len`: 0
 | 
			
		||||
 | 
			
		||||
- name: list all resource providers in a tree with multiple providers in tree
 | 
			
		||||
  GET: /resource_providers?in_tree=$ENVIRON['RP_UUID']
 | 
			
		||||
  response_json_paths:
 | 
			
		||||
      $.resource_providers.`len`: 2
 | 
			
		||||
      # Verify that we have both the parent and child in the list
 | 
			
		||||
      $.resource_providers[?uuid="$ENVIRON['PARENT_PROVIDER_UUID']"].root_provider_uuid: $ENVIRON['PARENT_PROVIDER_UUID']
 | 
			
		||||
      $.resource_providers[?uuid="$ENVIRON['RP_UUID']"].root_provider_uuid: $ENVIRON['PARENT_PROVIDER_UUID']
 | 
			
		||||
 | 
			
		||||
- name: create a new parent provider
 | 
			
		||||
  POST: /resource_providers
 | 
			
		||||
  request_headers:
 | 
			
		||||
    content-type: application/json
 | 
			
		||||
  data:
 | 
			
		||||
      name: altwparent
 | 
			
		||||
      uuid: $ENVIRON['ALT_PARENT_PROVIDER_UUID']
 | 
			
		||||
  status: 201
 | 
			
		||||
  response_headers:
 | 
			
		||||
      location: //resource_providers/[a-f0-9-]+/
 | 
			
		||||
  response_forbidden_headers:
 | 
			
		||||
      - content-type
 | 
			
		||||
 | 
			
		||||
- name: list all resource providers in a tree
 | 
			
		||||
  GET: /resource_providers?in_tree=$ENVIRON['ALT_PARENT_PROVIDER_UUID']
 | 
			
		||||
  response_json_paths:
 | 
			
		||||
      $.resource_providers.`len`: 1
 | 
			
		||||
      $.resource_providers[?uuid="$ENVIRON['ALT_PARENT_PROVIDER_UUID']"].root_provider_uuid: $ENVIRON['ALT_PARENT_PROVIDER_UUID']
 | 
			
		||||
 | 
			
		||||
- name: fail trying to re-parent to a different provider
 | 
			
		||||
  PUT: /resource_providers/$ENVIRON['RP_UUID']
 | 
			
		||||
  request_headers:
 | 
			
		||||
      content-type: application/json
 | 
			
		||||
  data:
 | 
			
		||||
      name: child
 | 
			
		||||
      parent_provider_uuid: $ENVIRON['ALT_PARENT_PROVIDER_UUID']
 | 
			
		||||
  status: 400
 | 
			
		||||
  response_strings:
 | 
			
		||||
      - 're-parenting a provider is not currently allowed'
 | 
			
		||||
 | 
			
		||||
- name: create a new provider
 | 
			
		||||
  POST: /resource_providers
 | 
			
		||||
  request_headers:
 | 
			
		||||
@@ -221,7 +392,7 @@ tests:
 | 
			
		||||
  request_headers:
 | 
			
		||||
      content-type: application/json
 | 
			
		||||
  data:
 | 
			
		||||
      name: new name
 | 
			
		||||
      name: child
 | 
			
		||||
  status: 409
 | 
			
		||||
  response_json_paths:
 | 
			
		||||
      $.errors[0].title: Conflict
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "NFS Share",
 | 
			
		||||
    "uuid": "7d2590ae-fb85-4080-9306-058b4c915e3f"
 | 
			
		||||
    "uuid": "7d2590ae-fb85-4080-9306-058b4c915e3f",
 | 
			
		||||
    "parent_provider_uuid": "542df8ed-9be2-49b9-b4db-6d3183ff8ec8"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -27,5 +27,7 @@
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "name": "Ceph Storage Pool",
 | 
			
		||||
    "uuid": "3b4005be-d64b-456f-ba36-0ffd02718868"
 | 
			
		||||
    "uuid": "3b4005be-d64b-456f-ba36-0ffd02718868",
 | 
			
		||||
    "parent_provider_uuid": "542df8ed-9be2-49b9-b4db-6d3183ff8ec8",
 | 
			
		||||
    "root_provider_uuid": "542df8ed-9be2-49b9-b4db-6d3183ff8ec8"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,9 @@
 | 
			
		||||
          "rel": "allocations"
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      "name": "vgr.localdomain"
 | 
			
		||||
      "name": "vgr.localdomain",
 | 
			
		||||
      "parent_provider_uuid": "542df8ed-9be2-49b9-b4db-6d3183ff8ec8",
 | 
			
		||||
      "root_provider_uuid": "542df8ed-9be2-49b9-b4db-6d3183ff8ec8"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "generation": 2,
 | 
			
		||||
@@ -60,7 +62,9 @@
 | 
			
		||||
          "rel": "allocations"
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      "name": "pony1"
 | 
			
		||||
      "name": "pony1",
 | 
			
		||||
      "parent_provider_uuid": null,
 | 
			
		||||
      "root_provider_uuid": "d0b381e9-8761-42de-8e6c-bba99a96d5f5"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -58,6 +58,14 @@ resource_provider_name_query:
 | 
			
		||||
  required: false
 | 
			
		||||
  description: >
 | 
			
		||||
    The name of a resource provider to filter the list.
 | 
			
		||||
resource_provider_tree_query:
 | 
			
		||||
  type: string
 | 
			
		||||
  in: query
 | 
			
		||||
  required: false
 | 
			
		||||
  description: >
 | 
			
		||||
    A UUID of a resource provider. The returned resource providers will be in
 | 
			
		||||
    the same "provider tree" as the specified provider.
 | 
			
		||||
  min_version: 1.14
 | 
			
		||||
resource_provider_uuid_query:
 | 
			
		||||
  <<: *resource_provider_uuid_path
 | 
			
		||||
  in: query
 | 
			
		||||
@@ -290,6 +298,34 @@ resource_provider_object:
 | 
			
		||||
  required: true
 | 
			
		||||
  description: >
 | 
			
		||||
    A dictionary which contains the UUID of the resource provider.
 | 
			
		||||
resource_provider_parent_provider_uuid:
 | 
			
		||||
  type: string
 | 
			
		||||
  in: body
 | 
			
		||||
  required: false
 | 
			
		||||
  description: >
 | 
			
		||||
    The UUID of the immediate parent of the resource provider.
 | 
			
		||||
  min_version: 1.14
 | 
			
		||||
resource_provider_parent_provider_uuid_required:
 | 
			
		||||
  type: string
 | 
			
		||||
  in: body
 | 
			
		||||
  required: true
 | 
			
		||||
  description: >
 | 
			
		||||
    The UUID of the immediate parent of the resource provider.
 | 
			
		||||
  min_version: 1.14
 | 
			
		||||
resource_provider_root_provider_uuid:
 | 
			
		||||
  type: string
 | 
			
		||||
  in: body
 | 
			
		||||
  required: false
 | 
			
		||||
  description: >
 | 
			
		||||
    Read-only UUID of the top-most provider in this provider tree.
 | 
			
		||||
  min_version: 1.14
 | 
			
		||||
resource_provider_root_provider_uuid_required:
 | 
			
		||||
  type: string
 | 
			
		||||
  in: body
 | 
			
		||||
  required: true
 | 
			
		||||
  description: >
 | 
			
		||||
    Read-only UUID of the top-most provider in this provider tree.
 | 
			
		||||
  min_version: 1.14
 | 
			
		||||
resource_provider_usages:
 | 
			
		||||
  type: object
 | 
			
		||||
  in: body
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,8 @@ Response
 | 
			
		||||
  - uuid: resource_provider_uuid
 | 
			
		||||
  - links: resource_provider_links
 | 
			
		||||
  - name: resource_provider_name
 | 
			
		||||
 | 
			
		||||
  - parent_provider_uuid: resource_provider_parent_provider_uuid_required
 | 
			
		||||
  - root_provider_uuid: resource_provider_root_provider_uuid_required
 | 
			
		||||
 | 
			
		||||
Response Example
 | 
			
		||||
----------------
 | 
			
		||||
@@ -63,6 +64,7 @@ Request
 | 
			
		||||
 | 
			
		||||
  - uuid: resource_provider_uuid_path
 | 
			
		||||
  - name: resource_provider_name
 | 
			
		||||
  - parent_provider_uuid: resource_provider_parent_provider_uuid
 | 
			
		||||
 | 
			
		||||
Request example
 | 
			
		||||
---------------
 | 
			
		||||
@@ -79,6 +81,8 @@ Response
 | 
			
		||||
  - uuid: resource_provider_uuid
 | 
			
		||||
  - links: resource_provider_links
 | 
			
		||||
  - name: resource_provider_name
 | 
			
		||||
  - parent_provider_uuid: resource_provider_parent_provider_uuid_required
 | 
			
		||||
  - root_provider_uuid: resource_provider_root_provider_uuid_required
 | 
			
		||||
 | 
			
		||||
Response Example
 | 
			
		||||
----------------
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@ of all filters are merged with a boolean `AND`.
 | 
			
		||||
  - uuid: resource_provider_uuid_query
 | 
			
		||||
  - member_of: member_of
 | 
			
		||||
  - resources: resources_query
 | 
			
		||||
  - in_tree: resource_provider_tree_query
 | 
			
		||||
 | 
			
		||||
Response
 | 
			
		||||
--------
 | 
			
		||||
@@ -39,7 +40,8 @@ Response
 | 
			
		||||
  - uuid: resource_provider_uuid
 | 
			
		||||
  - links: resource_provider_links
 | 
			
		||||
  - name: resource_provider_name
 | 
			
		||||
 | 
			
		||||
  - parent_provider_uuid: resource_provider_parent_provider_uuid
 | 
			
		||||
  - root_provider_uuid: resource_provider_root_provider_uuid
 | 
			
		||||
 | 
			
		||||
Response Example
 | 
			
		||||
----------------
 | 
			
		||||
@@ -69,6 +71,8 @@ Request
 | 
			
		||||
 | 
			
		||||
  - name: resource_provider_name
 | 
			
		||||
  - uuid: resource_provider_uuid_opt
 | 
			
		||||
  - parent_provider_uuid: resource_provider_parent_provider_uuid
 | 
			
		||||
  - root_provider_uuid: resource_provider_root_provider_uuid
 | 
			
		||||
 | 
			
		||||
Request example
 | 
			
		||||
---------------
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1,4 @@
 | 
			
		||||
 {"name": "Shared storage"}
 | 
			
		||||
 {
 | 
			
		||||
     "name": "Shared storage",
 | 
			
		||||
     "parent_provider_uuid": "542df8ed-9be2-49b9-b4db-6d3183ff8ec8"
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,13 @@
 | 
			
		||||
---
 | 
			
		||||
features:
 | 
			
		||||
  - New placement REST API microversion 1.14 is added to support nested
 | 
			
		||||
    resource providers. Users of the placement REST API can now pass a
 | 
			
		||||
    ``in_tree=<UUID>`` parameter to the ``GET /resource_providers`` REST API
 | 
			
		||||
    call.  This will trigger the placement service to return all resource
 | 
			
		||||
    provider records within the "provider tree" of the resource provider with
 | 
			
		||||
    the supplied UUID value. The resource provider representation now includes
 | 
			
		||||
    a ``parent_provider_uuid`` value that indicates the UUID of the immediate
 | 
			
		||||
    parent resource provider, or ``null`` if the provider has no parent. For
 | 
			
		||||
    convenience, the resource provider resource also contains a
 | 
			
		||||
    ``root_provider_uuid`` field that is populated with the UUID of the
 | 
			
		||||
    top-most resource provider in the provider tree.
 | 
			
		||||
		Reference in New Issue
	
	Block a user