1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
|
..
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
====================
Making an API Change
====================
This document will guide you through the process of proposing and submitting
an API change to keystone.
Prerequisites
-------------
In order to follow this tutorial, it is assumed that you have read our
:doc:`index` and
:doc:`../getting-started/architecture` documents.
Proposing a change
------------------
You need to create a RFE bug report, submit a specification against the `keystone-specs`_
repository and bring it up to discussion with the `keystone core team`_ for
agreement. Please refer to the :ref:`guide for proposing features
<proposing_features>` to learn more about the process.
.. _`keystone-specs`: https://opendev.org/openstack/keystone-specs/
.. _`keystone core team`: https://review.opendev.org/#/admin/groups/9,members
Create
~~~~~~
#. `Create a RFE bug report`_ in launchpad;
#. git clone https://opendev.org/openstack/keystone-specs;
#. cp `specs/template.rst` `specs/backlog/<feature>.rst`;
#. Write the spec based on the template. Ensure the bug link points to the one
created in step 1;
#. Also update the documentation at `api/v3/identity-api-v3.rst` to reflect the
proposed API changes;
#. Push to gerrit for review;
#. Propose agenda items to the `keystone meeting`_, and make sure someone
who understands the subject can attend the meeting to answer questions.
.. _`Create a RFE bug report`: https://bugs.launchpad.net/keystone/+filebug
.. _`template`: https://opendev.org/openstack/keystone-specs/src/branch/master/specs/template.rst
.. _`keystone meeting`: https://wiki.openstack.org/wiki/Meetings/KeystoneMeeting
Agreement
~~~~~~~~~
The `keystone core team`_ will evaluate the specification and vote on accepting
it or not. If accepted, the proposal will be targeted to a release; otherwise,
the specification will be abandoned.
As soon as there is an agreement on the specification, the change may start
rolling out.
Implementing a change
---------------------
In this section, let's assume that a specification proposing the addition of a
`description` field to the roles API was accepted. In the next subsections, you
will find a detailed explanation on the needed code changes to the keystone
code to implement such change.
Architectural Recapitulation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As you saw in the :doc:`../getting-started/architecture` document, there are
three logical levels of code at which a request passes: the API routing and
request handling layer, the resource manager, and the driver.
For the role backend, the API resource can be found under the `keystone/api`
directory in the `roles.py` file, and the manager and driver can be found in
the `keystone/assignment` directory in the `core.py` and `role_backends/sql.py`
files, respectively (currently only the SQL driver is supported).
Changing the SQL Model and Driver
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. note::
The below guidance is out-of-date and refers to the legacy ``migrate_repo``
migration repository, which was removed in 21.0.0 (Yoga). Nowadays, for a
change like this, you would create an additive or "expand" migration in the
``expand_repo`` repository along with null migrations in the
``contract_repo`` and ``data_migration_repo`` repositories. For more
information, refer to :doc:`/contributor/database-migrations`.
.. todo::
Update this section to reflect the new migration model.
First, you need to change the role model to include the description attribute.
Go to `keystone/assignment/role_backends/sql.py` and update it like::
class RoleTable(sql.ModelBase, sql.ModelDictMixin):
attributes = ['id', 'name', 'domain_id', 'description']
description = sql.Column(sql.String(255), nullable=True)
...
Now, when keystone runs, the table will be created with the new attribute.
However, what about existing deployments which already have the role table
created? You need to migrate their database schema!
The directory `keystone/common/sql/migrate_repo/versions` owns all the
migrations since keystone day 1. Create a new file there with the next
migration number. For example, if the latest migration number there is `101`,
create yours as `102_add_role_description.py`, which will look like::
def upgrade(migrate_engine):
meta = sql.MetaData()
meta.bind = migrate_engine
role_table = sql.Table('role', meta, autoload=True)
description = sql.Column('description', sql.String(255),
nullable=True)
role_table.create_column(description)
Do not forget to add tests for your migration at
`keystone/tests/unit/test_sql_upgrade.py`, you may take other tests as example
and learn how to develop yours. In this case, you would need to upgrade to
`102` check the migration has added the `description` column to the role table.
Changing the role driver itself in `keystone/assignment/role_backends/sql.py`
will not be necessary, because the driver handles the role entities as Python
dictionaries, thus the new attribute will be handled automatically.
Changing the Manager
~~~~~~~~~~~~~~~~~~~~
Managers handle the business logic. Keystone provides the basic CRUD for role
entities, that means that the role manager simply calls the driver with the
arguments received from the API resource, and then returns the driver's result
back to API resource. Additionally, it handles the cache management.
Thus, there is no manager change needed to make it able to operate role
entities with the new `description` attribute.
However, you should add tests for the role CRUD operations with the new
attribute to `keystone/tests/unit/assignment/test_core.py`.
When trying to determine whether a change goes in the driver or in the manager,
the test is whether the code is business logic and/or needs to be executed for
each driver. Both common and business logics go in the manager, while backend
specific logic goes in the drivers.
Changing the API Interface
~~~~~~~~~~~~~~~~~~~~~~~~~~
Business logic should not go in the API resource. The API resource should be
viewed as a binding between the business logic and the HTTP protocol. Thus, it is in
charge of calling the appropriate manager call and wrapping responses into HTTP
format.
API resource use JSON schemas do determine whether a provided role is a
valid representation or not. Role create and role update schemas are available at
`keystone/assignment/schema.py`. You will need to update their properties to
include a `description` attribute::
_role_properties = {
'name': parameter_types.name,
'description': parameter_types.description
}
Besides doing the entity validation using such schemas, API resource pass and
accept all the attributes to and from the manager. Thus, there is no further
change needed at the API resource level.
You should add tests for API unit test to `keystone/tests/unit/test_v3_role.py`
and document about the new parameter in the `api-ref`_.
.. _api-ref: https://docs.openstack.org/api-ref/identity/
Furthermore, as role entities are passed in the request body to keystone calls,
the role routes do not need to be changed; i.e the routes still are::
POST /v3/roles
GET /v3/roles/{id}
HEAD /v3/roles/{id}
PATCH /v3/roles/{id}
DELETE /v3/roles/{id}
Conclusion
----------
At this point, keystone role entities contain a `description` attribute. In
order to make it happen, you have learned how the keystone architecture is,
what is the responsibility of each layer, how database migrations occur and the
way entities are represented into tables.
The pattern of the change made in this tutorial applies to other keystone
subsystems as well, such as `resource` and `identity`.
|