Limits API
The following sketches out limits API about OpenStack quota usage. Co-Authored-By: wangxiyuan<wangxiyuan@huawei.com> Co-Authored-By: Lance Bragstad<lbragstad@gmail.com> bp: unified-limits Change-Id: Ie1e046244cfb379775d241b83c80cd1f2fb9c637
This commit is contained in:
parent
faccbbd802
commit
a41c4a28a2
BIN
doc/source/DejaVuSans.ttf
Normal file
BIN
doc/source/DejaVuSans.ttf
Normal file
Binary file not shown.
@ -26,10 +26,15 @@ import subprocess
|
|||||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
extensions = ['sphinx.ext.autodoc',
|
extensions = ['sphinx.ext.autodoc',
|
||||||
'sphinx.ext.viewcode',
|
'sphinx.ext.viewcode',
|
||||||
|
'sphinxcontrib.blockdiag',
|
||||||
'oslosphinx',
|
'oslosphinx',
|
||||||
'yasfb',
|
'yasfb',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
blockdiag_html_image_format = 'SVG'
|
||||||
|
|
||||||
|
blockdiag_fontpath = 'DejaVuSans.ttf'
|
||||||
|
|
||||||
# Feed configuration for yasfb
|
# Feed configuration for yasfb
|
||||||
feed_base_url = 'http://specs.openstack.org/openstack/keystone-specs'
|
feed_base_url = 'http://specs.openstack.org/openstack/keystone-specs'
|
||||||
feed_author = 'OpenStack Identity Team'
|
feed_author = 'OpenStack Identity Team'
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
oslosphinx>=2.2.0.0a2
|
oslosphinx>=2.2.0.0a2
|
||||||
pbr>=2.0.0
|
pbr>=2.0.0
|
||||||
sphinx!=1.6.1,>=1.5.1
|
sphinx!=1.6.1,>=1.5.1
|
||||||
|
sphinxcontrib-blockdiag
|
||||||
testrepository>=0.0.18
|
testrepository>=0.0.18
|
||||||
testtools>=0.9.34
|
testtools>=0.9.34
|
||||||
yasfb>=0.5.1
|
yasfb>=0.5.1
|
||||||
|
874
specs/keystone/queens/limits-api.rst
Normal file
874
specs/keystone/queens/limits-api.rst
Normal file
@ -0,0 +1,874 @@
|
|||||||
|
..
|
||||||
|
This work is licensed under a Creative Commons Attribution 3.0 Unported
|
||||||
|
License.
|
||||||
|
|
||||||
|
http://creativecommons.org/licenses/by/3.0/legalcode
|
||||||
|
|
||||||
|
==================
|
||||||
|
Unified Limits API
|
||||||
|
==================
|
||||||
|
|
||||||
|
Detailed specification for the work necessary to associate resources limits to
|
||||||
|
projects.
|
||||||
|
|
||||||
|
`bp unified-limits <https://blueprints.launchpad.net/keystone/+spec/unified-limits>`_
|
||||||
|
|
||||||
|
Problem Description
|
||||||
|
===================
|
||||||
|
|
||||||
|
Today, resource quotas are maintained outside Keystone in each project, such as
|
||||||
|
Nova, Cinder or others. This leads to a problem where there is no strong
|
||||||
|
relationship between projects and their resources. For example, when a user
|
||||||
|
sets a quota in Nova like "project A can create 10 virtual machines", but if
|
||||||
|
project A doesn't exist in Keystone, Nova will still create the quota. If the
|
||||||
|
project A is deleted in Keystone, Nova doesn't know it and will still leave the
|
||||||
|
quota there. This problem is only exacerbated when dealing with project
|
||||||
|
hierarchies.
|
||||||
|
|
||||||
|
More information on this problem and the overall approach can be found in a
|
||||||
|
separate high-level `specification <http://specs.openstack.org/openstack/keystone-specs/specs/keystone/ongoing/unified-limits.html>`_.
|
||||||
|
|
||||||
|
Proposed Change
|
||||||
|
===============
|
||||||
|
|
||||||
|
An interface to create, read, update, delete limit definitions. It includes two
|
||||||
|
kinds of Limits: ``Registered Limits`` and ``Project Limits``.
|
||||||
|
``Registered Limits`` are the defaults limits. You can't set a project limit on
|
||||||
|
something that's not a registered limit.
|
||||||
|
``Project Limits`` are the limits that override registered limits for each
|
||||||
|
project.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This spec doesn't talk about the usage check of limits. It is up to the
|
||||||
|
consuming services to enforce usage.
|
||||||
|
|
||||||
|
Registered Limits
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The following API calls are specific to the management of Registered Limits.
|
||||||
|
|
||||||
|
Create Registered Limits
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Limits are registered with the Registered Limits endpoint. Because
|
||||||
|
limits definitions will often be created in bulk, this supports
|
||||||
|
sending a number of limit definitions at once. This is an admin only
|
||||||
|
action.
|
||||||
|
|
||||||
|
**Request:** ``POST /registered-limits``
|
||||||
|
|
||||||
|
**Request Parameters**
|
||||||
|
|
||||||
|
* ``service_id`` - The service that is responsible for the resource, which
|
||||||
|
should match a service in the service catalog.
|
||||||
|
* ``region_id (optional)`` - The region that the service is hosted in. If the
|
||||||
|
``region_id`` is specified, it should be keep the same with the consuming
|
||||||
|
service's. If not, Keystone will leave it empty like endpoint does.
|
||||||
|
* ``resource_name`` - The name of the resource, which should be unique compared
|
||||||
|
to other resource names for the same service and region.
|
||||||
|
* ``default_limit`` - The default limit for all projects to assume for that
|
||||||
|
resource.
|
||||||
|
|
||||||
|
**Request Body**
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"limits": [
|
||||||
|
{
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "cores",
|
||||||
|
"default_limit": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"resource_name": "ram_mb",
|
||||||
|
"default_limit": 20480
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
**Response**
|
||||||
|
|
||||||
|
A full list of all registered limits.
|
||||||
|
|
||||||
|
**Response Parameters**
|
||||||
|
|
||||||
|
* ``id`` - The unique uuid for each registered limit.
|
||||||
|
* ``service_id`` - The service that is responsible for the resource, which
|
||||||
|
should match a service in the service catalog.
|
||||||
|
* ``region_id (optional)`` - The region that the service is hosted in.
|
||||||
|
* ``resource_name`` - The name of the resource, which should be unique compared
|
||||||
|
to other resource names for the same service and region.
|
||||||
|
* ``default_limit`` - The default limit for all projects to assume for that
|
||||||
|
resource.
|
||||||
|
|
||||||
|
**Response Code**
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
* 400 - Bad Request - if dependent resources do not exist
|
||||||
|
* 403 - Forbidden - if the user is not authorized to create a registered limit
|
||||||
|
* 409 - Limits that already exist
|
||||||
|
|
||||||
|
**Response Body:**
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"limits": [
|
||||||
|
{
|
||||||
|
"id": "0681e10c01c044d78ef8e5cb592c6446",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "cores",
|
||||||
|
"default_limit": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1dc633fe5acd4182b63f68c9cc8e768a",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"resource_name": "ram_mb",
|
||||||
|
"default_limit": 20480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5c4182eb45304cb3ac89030b19ab5a81",
|
||||||
|
"service_id": "ae22fb0dfbd34464bf67e758977f4839",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "storage_gb",
|
||||||
|
"default_limit": 20
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Update Registered Limits
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Update is done similar to a POST however just the limits that you wish
|
||||||
|
to override are included. If the ``service_id``, ``region_id``, or
|
||||||
|
``resource_name`` doesn't already exist, an error is thrown.
|
||||||
|
|
||||||
|
**Request:** ``PUT /registered-limits``
|
||||||
|
|
||||||
|
**Request Parameters**
|
||||||
|
|
||||||
|
* ``service_id`` - The service that is responsible for the resource, which
|
||||||
|
should match a service in the service catalog.
|
||||||
|
* ``region_id (optional)`` - The region_id that the service is hosted in.
|
||||||
|
* ``resource_name`` - The name of the resource, which should be unique compared
|
||||||
|
to other resource names for the same service and region.
|
||||||
|
* ``default_limit`` - The default limit for all projects to assume for that
|
||||||
|
resource.
|
||||||
|
|
||||||
|
**Request Body**
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"limits":[
|
||||||
|
{
|
||||||
|
"id": "1dc633fe5acd4182b63f68c9cc8e768a",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"resource_name": "ram_mb",
|
||||||
|
"default_limit": 10240
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
A full list of all limits. That allows for double checking one's work.
|
||||||
|
|
||||||
|
**Response Code:**
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
* 400 - Bad Request - if dependent resources do not exist
|
||||||
|
* 403 - Forbidden - if the user is not authorized to update a registered limit
|
||||||
|
|
||||||
|
**Response Parameters**
|
||||||
|
|
||||||
|
* ``id`` - The unique uuid for each registered limit.
|
||||||
|
* ``service_id`` - The service that is responsible for the resource, which
|
||||||
|
should match a service in the service catalog.
|
||||||
|
* ``region_id (optional)`` - The region that the service is hosted in.
|
||||||
|
* ``resource_name`` - The name of the resource, which should be unique compared
|
||||||
|
to other resource names for the same service and region.
|
||||||
|
* ``default_limit`` - The default limit for all projects to assume for that
|
||||||
|
resource.
|
||||||
|
|
||||||
|
**Response Body:**
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"limits": [
|
||||||
|
{
|
||||||
|
"id": "0681e10c01c044d78ef8e5cb592c6446",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "cores",
|
||||||
|
"default_limit": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1dc633fe5acd4182b63f68c9cc8e768a",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"resource_name": "ram_mb",
|
||||||
|
"default_limit": 10240
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5c4182eb45304cb3ac89030b19ab5a81",
|
||||||
|
"service_id": "ae22fb0dfbd34464bf67e758977f4839",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "storage_gb",
|
||||||
|
"default_limit": 20
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
List all Registered Limits
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
Registered limits can be read by anyone with a valid token.
|
||||||
|
|
||||||
|
**Request:** ``GET /registered-limits``
|
||||||
|
|
||||||
|
**Request filter:**
|
||||||
|
|
||||||
|
Registered limits will also support filters to make it easier to see
|
||||||
|
just a subset. ``service_id``, ``region_id``, and ``resource_name``
|
||||||
|
will all be valid search parameters.
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
A full list of all registered limits.
|
||||||
|
|
||||||
|
**Response Code:**
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
* 403 - Forbidden - if the user is not authorized to list registered limits
|
||||||
|
|
||||||
|
**Response Parameters**
|
||||||
|
|
||||||
|
* ``id`` - The unique uuid for each registered limit.
|
||||||
|
* ``service_id`` - The service that is responsible for the resource, which
|
||||||
|
should match a service in the service catalog.
|
||||||
|
* ``region_id (optional)`` - The region that the service is hosted in.
|
||||||
|
* ``resource_name`` - The name of the resource, which should be unique compared
|
||||||
|
to other resource names for the same service and region.
|
||||||
|
* ``default_limit`` - The default limit for all projects to assume for that
|
||||||
|
resource.
|
||||||
|
|
||||||
|
**Response Body:**
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"limits": [
|
||||||
|
{
|
||||||
|
"id": "0681e10c01c044d78ef8e5cb592c6446",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "cores",
|
||||||
|
"default_limit": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1dc633fe5acd4182b63f68c9cc8e768a",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"resource_name": "ram_mb",
|
||||||
|
"default_limit": 20480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5c4182eb45304cb3ac89030b19ab5a81",
|
||||||
|
"service_id": "ae22fb0dfbd34464bf67e758977f4839",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "storage_gb",
|
||||||
|
"default_limit": 20
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Show a Registered Limits
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Registered limits can be read by anyone with a valid token.
|
||||||
|
|
||||||
|
**Request:** ``GET /registered-limits/{registered-limits-id}``
|
||||||
|
|
||||||
|
**Request Parameters**
|
||||||
|
|
||||||
|
* ``registered-limits-id`` - The id for the specified registered limit.
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
The specified registered limit.
|
||||||
|
|
||||||
|
**Response Code:**
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
* 403 - Forbidden - if the user is not authorized to retrieve a registered
|
||||||
|
limit
|
||||||
|
* 404 - Not Found - if the requested registered limit does not exist
|
||||||
|
|
||||||
|
**Response Parameters**
|
||||||
|
|
||||||
|
* ``id`` - The unique uuid for each registered limit.
|
||||||
|
* ``service_id`` - The service that is responsible for the resource, which
|
||||||
|
should match a service in the service catalog.
|
||||||
|
* ``region_id (optional)`` - The region that the service is hosted in.
|
||||||
|
* ``resource_name`` - The name of the resource, which should be unique compared
|
||||||
|
to other resource names for the same service and region.
|
||||||
|
* ``default_limit`` - The default limit for all projects to assume for that
|
||||||
|
resource.
|
||||||
|
|
||||||
|
**Response Body:**
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": "0681e10c01c044d78ef8e5cb592c6446",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "cores",
|
||||||
|
"default_limit": 10
|
||||||
|
}
|
||||||
|
|
||||||
|
Delete a Registered Limit
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
**Request:** ``DELETE /registered-limits/{registered-limits-id}``
|
||||||
|
|
||||||
|
**Request Parameters**
|
||||||
|
|
||||||
|
* ``registered-limits-id`` - The id for the specified registered limit.
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
No content.
|
||||||
|
|
||||||
|
**Response Code:**
|
||||||
|
|
||||||
|
* 204 - No Content
|
||||||
|
* 403 - Forbidden - if the user is not authorized to delete a registered limit
|
||||||
|
* 404 - Not Found - if the requested registered limit does not exist
|
||||||
|
|
||||||
|
|
||||||
|
Project Limits
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The following API calls are specific to the management of Project Limits. They
|
||||||
|
are project administrator only (system admin as well) APIs.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The initial implementation will only support a "flat" hierarchical model. In
|
||||||
|
this model, the limits associated to a project will be validated as a flat
|
||||||
|
structure. This means limits won't be enforced or validated according to
|
||||||
|
the parents, childred, or peers of the project. All limits will be
|
||||||
|
independent of those relationships. This is referred to as a "flat"
|
||||||
|
enforcement model. Future work will elaborate on more complex enforcement
|
||||||
|
models that understand project hierarchies.
|
||||||
|
|
||||||
|
Create Project Limits
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Overriding Registered Limits with Project Limits.
|
||||||
|
|
||||||
|
**Request:** ``POST /limits``
|
||||||
|
|
||||||
|
**Request Parameters**
|
||||||
|
|
||||||
|
* ``project_id (optional)`` - The project which assume the limit. If omit,
|
||||||
|
Keystone will get the project_id from token (context).
|
||||||
|
* ``service_id`` - The service that is responsible for the resource, which
|
||||||
|
should match a service in the service catalog.
|
||||||
|
* ``region_id (optional)`` - The region that the service is hosted in. It
|
||||||
|
should use same ``region_id`` of the registered limit which will be
|
||||||
|
overridden.
|
||||||
|
* ``resource_name`` - The name of the resource, which should be unique compared
|
||||||
|
to other resource names for the same service and region.
|
||||||
|
* ``resource_limit`` - The override limit for the project to assume for that
|
||||||
|
resource.
|
||||||
|
|
||||||
|
**Request Body**
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"limits":[
|
||||||
|
{
|
||||||
|
"project_id": "95541dbfaa054cab86510e0d0a87896a",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "ram_mb",
|
||||||
|
"resource_limit": 10240,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"project_id": "95541dbfaa054cab86510e0d0a87896a",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "cores",
|
||||||
|
"resource_limit": 10,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
We return the entire limits structure, including defaults without overrides.
|
||||||
|
|
||||||
|
**Response Code:**
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
* 400 - Bad Request - if dependent resources do not exist
|
||||||
|
* 403 - Forbidden - if the user is not authorized to change the limit for that
|
||||||
|
project
|
||||||
|
* 409 - Limits that already exist
|
||||||
|
|
||||||
|
**Response Parameters**
|
||||||
|
|
||||||
|
* ``id`` - The id for the specified limit.
|
||||||
|
* ``project_id`` - The project which assume the limit.
|
||||||
|
* ``service_id`` - The service that is responsible for the resource, which
|
||||||
|
should match a service in the service catalog.
|
||||||
|
* ``region_id (optional)`` - The region that the service is hosted in.
|
||||||
|
* ``resource_name`` - The name of the resource, which should be unique compared
|
||||||
|
to other resource names for the same service and region.
|
||||||
|
* ``resource_limit`` - The override limit for the project to assume for that
|
||||||
|
resource.
|
||||||
|
|
||||||
|
**Response Body:**
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"limits":[
|
||||||
|
{
|
||||||
|
"id": "aaab50e9c36f4a84bab98dfc117c9836",
|
||||||
|
"project_id": "95541dbfaa054cab86510e0d0a87896a",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "ram_mb",
|
||||||
|
"resource_limit": 10240,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e08fcb2756be48e387e821bd79e29538",
|
||||||
|
"project_id": "95541dbfaa054cab86510e0d0a87896a",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "cores",
|
||||||
|
"resource_limit": 10,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Update Project Limits
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Update Project Limits. Once the project limit is created, The only property
|
||||||
|
that can be changed is ``resource_limit``.
|
||||||
|
|
||||||
|
**Request:** ``PUT /limits``
|
||||||
|
|
||||||
|
**Request Parameters:**
|
||||||
|
|
||||||
|
* ``resource_limit`` - The override limit for the project to assume for that
|
||||||
|
resource.
|
||||||
|
|
||||||
|
**Request Body:**
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"limits":[
|
||||||
|
{
|
||||||
|
"id": "aaab50e9c36f4a84bab98dfc117c9836",
|
||||||
|
"resource_limit": 5120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e08fcb2756be48e387e821bd79e29538",
|
||||||
|
"resource_limit": 5,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
We return the entire limits structure, including defaults without overrides.
|
||||||
|
|
||||||
|
**Response Code:**
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
* 400 - Bad Request - if registered limit matching the resource name or the
|
||||||
|
project limit with the given ID do not exist
|
||||||
|
* 403 - Forbidden - if the user is not authorized to change the limit for that
|
||||||
|
project
|
||||||
|
|
||||||
|
**Response Parameters**
|
||||||
|
|
||||||
|
* ``id`` - The id for the specified limit.
|
||||||
|
* ``project_id`` - The project which assume the limit.
|
||||||
|
* ``service_id`` - The service that is responsible for the resource, which
|
||||||
|
should match a service in the service catalog.
|
||||||
|
* ``region_id (optional)`` - The region that the service is hosted in.
|
||||||
|
* ``resource_name`` - The name of the resource, which should be unique compared
|
||||||
|
to other resource names for the same service and region.
|
||||||
|
* ``resource_limit`` - The override limit for the project to assume for that
|
||||||
|
resource.
|
||||||
|
|
||||||
|
**Response Body:**
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"limits":[
|
||||||
|
{
|
||||||
|
"id": "aaab50e9c36f4a84bab98dfc117c9836",
|
||||||
|
"project_id": "95541dbfaa054cab86510e0d0a87896a",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "ram_mb",
|
||||||
|
"resource_limit": 5120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e08fcb2756be48e387e821bd79e29538",
|
||||||
|
"project_id": "95541dbfaa054cab86510e0d0a87896a",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "cores",
|
||||||
|
"resource_limit": 5,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
List Project Limits
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
**Request:** ``GET /limits``
|
||||||
|
|
||||||
|
|
||||||
|
**Request filter:**
|
||||||
|
|
||||||
|
* ``project_id`` - Only used for cloud admin to filter limits with the
|
||||||
|
specified project_id. Project admin can only list the limits for their own
|
||||||
|
projects.
|
||||||
|
|
||||||
|
limits will also support filters to make it easier to see
|
||||||
|
just a subset. ``service_id``, ``region_id``, and ``resource_name``
|
||||||
|
will all be valid search parameters.
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
A list of all limits in a project.
|
||||||
|
|
||||||
|
**Response Code:**
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
* 403 - Forbidden - if the user is not authorized to list limits for that
|
||||||
|
project
|
||||||
|
|
||||||
|
**Response Parameters**
|
||||||
|
|
||||||
|
* ``id`` - The id for the specified limit.
|
||||||
|
* ``project_id`` - The project which assume the limit.
|
||||||
|
* ``service_id`` - The service that is responsible for the resource, which
|
||||||
|
should match a service in the service catalog.
|
||||||
|
* ``region_id (optional)`` - The region that the service is hosted in.
|
||||||
|
* ``resource_name`` - The name of the resource, which should be unique compared
|
||||||
|
to other resource names for the same service and region.
|
||||||
|
* ``resource_limit`` - The override limit for the project to assume for that
|
||||||
|
resource.
|
||||||
|
|
||||||
|
**Response Body:**
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"limits":[
|
||||||
|
{
|
||||||
|
"project_id": "95541dbfaa054cab86510e0d0a87896a",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "ram_mb",
|
||||||
|
"resource_limit": 10240,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"project_id": "95541dbfaa054cab86510e0d0a87896a",
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "cores",
|
||||||
|
"resource_limit": 10,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Show a Project Limit
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
**Request:** ``GET /limits/{limit-id}``
|
||||||
|
|
||||||
|
**Request Parameters:**
|
||||||
|
|
||||||
|
* ``limit-id`` - The id for the specified limit.
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
The detail of the specified limit.
|
||||||
|
|
||||||
|
**Response Code:**
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
* 403 - Forbidden - if the user is not authorized to retrieve that project
|
||||||
|
limit
|
||||||
|
* 404 - Not Found - if the requested project limit does not exist
|
||||||
|
|
||||||
|
**Response Parameters**
|
||||||
|
|
||||||
|
* ``id`` - The id for the specified limit.
|
||||||
|
* ``project_id`` - The project which assume the limit.
|
||||||
|
* ``service_id`` - The service that is responsible for the resource, which
|
||||||
|
should match a service in the service catalog.
|
||||||
|
* ``region_id (optional)`` - The region that the service is hosted in.
|
||||||
|
* ``resource_name`` - The name of the resource, which should be unique compared
|
||||||
|
to other resource names for the same service and region.
|
||||||
|
* ``resource_limit`` - The override limit for the project to assume for that
|
||||||
|
resource.
|
||||||
|
|
||||||
|
**Response Body:**
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"project_id": "95541dbfaa054cab86510e0d0a87896a"
|
||||||
|
"service_id": "77232e5107074dfe801657000348e8c9",
|
||||||
|
"region_id": "regionOne",
|
||||||
|
"resource_name": "ram_mb",
|
||||||
|
"resource_limit": 10240,
|
||||||
|
}
|
||||||
|
|
||||||
|
Delete a Project Limit
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
**Request:** ``DELETE /limits/{limit-id}``
|
||||||
|
|
||||||
|
**Request Parameters**
|
||||||
|
|
||||||
|
* ``limit-id`` - The id for the specified limit.
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
|
||||||
|
No content
|
||||||
|
|
||||||
|
**Response Code:**
|
||||||
|
|
||||||
|
* 204 - No Content
|
||||||
|
* 403 - Forbidden - if the user is not authorized to delete a limit for that
|
||||||
|
project
|
||||||
|
* 404 - Not Found - if the requested project limit does not exist
|
||||||
|
|
||||||
|
Flat Hierarchy Enforcement
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
Keystone supports hierarchical multi-tenancy, where projects can be grouped
|
||||||
|
into tree structures and have parents, siblings, and children. It's possible to
|
||||||
|
think of various ways where a project limit interacts differently depending on
|
||||||
|
the limits of other projects in the tree. The initial implementation of project
|
||||||
|
limits documented in this specification is going to account for a flat
|
||||||
|
structure. This means the limit information and validation does **not** account
|
||||||
|
for other projects in the hierarchy. Each project has it's own limit.
|
||||||
|
|
||||||
|
Assume project ``P`` is a child of project ``F``, which is a child of project
|
||||||
|
``A``. A default is set on a limit, all projects get that effective default.
|
||||||
|
|
||||||
|
Assuming we have a default limit of 10
|
||||||
|
|
||||||
|
.. blockdiag::
|
||||||
|
|
||||||
|
blockdiag {
|
||||||
|
orientation = portrait;
|
||||||
|
|
||||||
|
A [label="A (10)"];
|
||||||
|
F [label="F (10)"];
|
||||||
|
P [label="P (10)"];
|
||||||
|
}
|
||||||
|
|
||||||
|
And then we ``UPDATE LIMIT on A to 20``
|
||||||
|
|
||||||
|
.. blockdiag::
|
||||||
|
|
||||||
|
blockdiag {
|
||||||
|
orientation = portrait;
|
||||||
|
|
||||||
|
A [label="A (20)", textcolor = "#FF0000"];
|
||||||
|
F [label="F (10)"];
|
||||||
|
P [label="P (10)"];
|
||||||
|
}
|
||||||
|
|
||||||
|
Or we can ``UPDATE LIMIT on P to 30``
|
||||||
|
|
||||||
|
.. blockdiag::
|
||||||
|
|
||||||
|
blockdiag {
|
||||||
|
orientation = portrait;
|
||||||
|
|
||||||
|
A [label="A (20)"];
|
||||||
|
F [label="F (10)"];
|
||||||
|
P [label="P (30)", textcolor = "#FF0000"];
|
||||||
|
}
|
||||||
|
|
||||||
|
This is allowed with flat enforcement because the hierarchy is not taken into
|
||||||
|
consideration during limit validation. In the future, we will introduce a model
|
||||||
|
that has the ability to validate limits with respect to project hierarchies.
|
||||||
|
It is important to note that switching between enforcement models will require
|
||||||
|
extremely careful planning and possibly lead to API changes depending on the
|
||||||
|
request being made and the new enforcement model. Deployments need to be aware
|
||||||
|
of this, understand the ramifications of switching enforcement models, and the
|
||||||
|
impacts it can have on existing limits.
|
||||||
|
|
||||||
|
Keystone will also expose a ``GET /limits-model`` endpoint that is responsible
|
||||||
|
for returning the enforcement model selected by the deployment. This is key to
|
||||||
|
allowing discoverable limit models and perserving interoperability between
|
||||||
|
OpenStack deployments with different enforcement models.
|
||||||
|
|
||||||
|
Alternatives
|
||||||
|
------------
|
||||||
|
|
||||||
|
One alternative that's already been taken by at least one project is to attempt
|
||||||
|
to implement hierarchical quotas in the service itself. Since understanding the
|
||||||
|
hierarchy can be confusing, not duplicating that logic is what lead us to this
|
||||||
|
approach, which keeps the limit closely associated to the hierarchy.
|
||||||
|
|
||||||
|
Another alternative is that we can add limits inside projects. The API will be
|
||||||
|
like /projects/{project_id}/limits/{limit_id}. These APIs has ways of showing
|
||||||
|
a project hierarchy already. In this way, we can reuse it easily.
|
||||||
|
|
||||||
|
Security Impact
|
||||||
|
---------------
|
||||||
|
|
||||||
|
The enforcement and validation of limits targeted in this work is specific to
|
||||||
|
flat hierarchies. This means that limits are associated to project
|
||||||
|
independently, regardless of parent, children, or peer projects. For example,
|
||||||
|
assume project ``alpha`` is a parent of projects ``bravo`` and ``charlie``. A
|
||||||
|
flat hierarchy would allow ``bravo`` to have a limit of 10 instances while
|
||||||
|
``charlie`` and ``alpha`` may only have a limit of 5 instances. From the
|
||||||
|
perspective of a project hierarchy, this may feel unintuitive. This is the
|
||||||
|
first enforcement model implementation and once we build knowledge and collect
|
||||||
|
usage feedback, there will be an effort to develop more sophisticated
|
||||||
|
enforcement models that account for project hierarchies.
|
||||||
|
|
||||||
|
Registered limits should be considered public information and discoverable.
|
||||||
|
Project limits should be available to members of the project. A user with a
|
||||||
|
role on project ``alpha`` should be able to list limits for the project, but
|
||||||
|
not for ``bravo`` or ``charlie``. This case will become more complicated in the
|
||||||
|
future when we start developing enforcement models that account for
|
||||||
|
hierarchies.
|
||||||
|
|
||||||
|
When more complicated models are introduced, we will need a way to provide
|
||||||
|
sufficient information to the user to allow them to understand why a limit
|
||||||
|
update has failed or why a resource request brings them over quota without
|
||||||
|
divulging too much information about related projects. This will not need to be
|
||||||
|
addressed with this initial "flat" implementation.
|
||||||
|
|
||||||
|
Notifications Impact
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Registered Limits and Project Limits should be subject to the same
|
||||||
|
notifications as other resources in keystone.
|
||||||
|
|
||||||
|
Other End User Impact
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
None. End users will be able to query keystone for limit information. This
|
||||||
|
improves usability because they can see what the limit is and gather more
|
||||||
|
information when requesting help from an administrator.
|
||||||
|
|
||||||
|
Performance Impact
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The internal performance impact of the initial flat hierarchy design should be
|
||||||
|
negligible. This will likely become more complicated once development for
|
||||||
|
hierarchical enforcement models starts (e.g. calculating limits of a project
|
||||||
|
with respect to its parent(s), children, and peers). Keystone will then have to
|
||||||
|
compute more complicated limit structure.
|
||||||
|
|
||||||
|
Other services will be required to make additional calls to keystone to
|
||||||
|
retrieve limit information in order to do quota enforcement. This will add some
|
||||||
|
overhead to the overall performance of the API call.
|
||||||
|
|
||||||
|
It is also worth noting that both Registered Limits and Project Limits are not
|
||||||
|
expected to change frequently. This means the data is safe to cache for some
|
||||||
|
period of time. Caching will be implemented internally to keystone, similar to
|
||||||
|
how keystone caches responses for other resources. But, caching can also be
|
||||||
|
done client-side to avoid making frequent calls to keystone for relatively
|
||||||
|
static limit information.
|
||||||
|
|
||||||
|
Other Deployer Impact
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Deployments looking to have Registered Limits and Project Limits in keystone
|
||||||
|
will have to set that up at installation time. This creates an extra step for
|
||||||
|
operators, similar to how they register services in the service catalog.
|
||||||
|
|
||||||
|
Developer Impact
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Developers from other projects will likely have the following questions:
|
||||||
|
|
||||||
|
* What the difference between a Registered Limits and Project Limit?
|
||||||
|
* What information is relayed in the limit?
|
||||||
|
* How do I enforce usage based on the information about a limit?
|
||||||
|
* Is there a library to do this for me?
|
||||||
|
|
||||||
|
There are a lot of things we'll have to make sure we communicate to
|
||||||
|
developers looking to implement hierarchical quotas. Keystone's
|
||||||
|
really just the information point here. We need to be available on
|
||||||
|
the other side to help them consume that information.
|
||||||
|
|
||||||
|
These questions, among others, will likely have to be answered in developer
|
||||||
|
documentation within keystone.
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
==============
|
||||||
|
|
||||||
|
Assignee(s)
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Primary assignee:
|
||||||
|
|
||||||
|
* wangxiyuan <wangxiyuan@huawei.com> wxy
|
||||||
|
|
||||||
|
Other contributors:
|
||||||
|
|
||||||
|
* Lance Bragstad <lbragstad@gmail.com> lbragstad
|
||||||
|
* Colleen Murphy <colleen@gazlene.net> cmurphy
|
||||||
|
|
||||||
|
Work Items
|
||||||
|
----------
|
||||||
|
|
||||||
|
1. Implement unified limits, add the new APIs mentioned above to Keystone.
|
||||||
|
2. Implement client support for unified limits.
|
||||||
|
3. Document limit models, Document unified limits, add related developer and
|
||||||
|
user DOC.
|
||||||
|
|
||||||
|
The `epic <https://trello.com/c/OMtxcBeh/16-unified-limits>`_ tracking this
|
||||||
|
work can be found in keystone's Queens roadmap.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Make sure the APIs are generic enough so that we can support more quota
|
||||||
|
model in the future.
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
============
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
Documentation Impact
|
||||||
|
====================
|
||||||
|
|
||||||
|
The usage of the new limit APIs should be addressed.
|
||||||
|
|
||||||
|
References
|
||||||
|
==========
|
||||||
|
|
||||||
|
High-level `overview <http://specs.openstack.org/openstack/keystone-specs/specs/keystone/ongoing/unified-limits.html>`_
|
||||||
|
of limits.
|
Loading…
Reference in New Issue
Block a user