[openstack-dev] [horizon] REST and Django

Tripp, Travis S travis.tripp at hp.com
Fri Dec 12 06:08:13 UTC 2014

I just re-read and I apologize for the hastily written email I previously
sent. I’ll try to salvage it with a bit of a revision below (please ignore
the previous email).

On 12/11/14, 7:02 PM, "Tripp, Travis S" <travis.tripp at hp.com> wrote

>Your comments in the patch were very helpful for me to understand your
>concerns about the ease of customizing without requiring upstream
>changes. It also reminded me that I’ve also previously questioned the
>python middleman.
>However, here are a couple of bullet points for Devil’s Advocate
>  *   Will we take on auto-discovery of API extensions in two spots
>(python for legacy and JS for new)?
>  *   The Horizon team will have to keep an even closer eye on every
>single project and be ready to react if there are changes to the API that
>break things. Right now in Glance, for example, they are working on some
>fixes to the v2 API (soon to become v2.3) that will allow them to
>deprecate v1 somewhat transparently to users of the client library.
>  *   The service API documentation almost always lags (although, helped
>by specs now) and the service team takes on the burden of exposing a
>programmatic way to access the API.  This is tested and easily consumable
>via the python clients, which removes some guesswork from using the
>  *   This is going to be an incremental approach with legacy support
>requirements anyway.  So, incorporating python side changes won’t just go
>  *   Which approach would be better if we introduce a server side
>caching mechanism or a new source of data such as elastic search to
>improve performance? Would the client side code have to be changed
>dramatically to take advantage of those improvements or could it be done
>transparently on the server side if we own the exposed API?
>I’m not sure I fully understood your example about Cinder.  Was it the
>cinder client that held up delivery of horizon support, the cinder API or
>both?  If the API isn’t in, then it would hold up delivery of the feature
>in any case. There still would be timing pressures to react and build a
>new view that supports it. For customization, with Richard’s approach new
>views could be supported by just dropping in a new REST API decorated
>module with the APIs you want, including direct pass through support if
>desired to new APIs. Downstream customizations / Upstream changes to
>views seem a bit like a bit of a related, but different issue to me as
>long as their is an easy way to drop in new API support.
>Finally, regarding the client making two calls to do an update:
>​>>Do we really need the lines:​
>>> project = api.keystone.tenant_get(request, id)
>>> kwargs = _tenant_kwargs_from_DATA(request.DATA, enabled=None)
>>I agree that if you already have all the data it may be bad to have to do
>another call. I do think there is room for discussing the reasoning,
>As far as I can tell, they do this so that if you are updating an entity,
>you have to be very specific about the fields you are changing. I
>actually see this as potentially a protectionary measure against data
>loss and sometimes a very nice to have feature. It perhaps was intended
>to *help* guard against race conditions (no locking and no transactions
>with many users simultaneously accessing the data).
>Here's an example: Admin user Joe has a Domain open and stares at it for
>15 minutes while he updates just the description. Admin user Bob is asked
>to go ahead and enable it. He opens the record, edits it, and then saves
>it. Joe finished perfecting the description and saves it. They could in
>effect both edit the same domain independently. Last man in still wins if
>he updates the same fields, but if they update different fields then both
>of their changes will take affect without them stomping on each other. Or
>maybe it is intended to encourage client users to compare their current
>and previous to see if they should issue a warning if the data changed
>between getting and updating the data. Or maybe like you said, it is just
>overhead API calls.

>From: Tihomir Trifonov <t.trifonov at gmail.com<mailto:t.trifonov at gmail.com>>
>Reply-To: OpenStack List
><openstack-dev at lists.openstack.org<mailto:openstack-dev at lists.openstack.or
>Date: Thursday, December 11, 2014 at 7:53 AM
>To: OpenStack List
><openstack-dev at lists.openstack.org<mailto:openstack-dev at lists.openstack.or
>Subject: Re: [openstack-dev] [horizon] REST and Django
>Client just needs to know which URL to hit in order to invoke a certain
>API, and does not need to know the procedure name or parameters ordering.
>​That's where the difference is. I think the client has to know the
>procedure name and parameters. Otherwise​ we have a translation factory
>pattern, that converts one naming convention to another. And you won't be
>able to call any service API if there is no code in the middleware to
>translate it to the service API procedure name and parameters. To avoid
>this - we can use a transparent proxy model - direct mapping of a client
>call to service API naming, which can be done if the client invokes the
>methods with the names in the service API, so that the middleware will
>just pass parameters, and will not translate. Instead of:
>updating user data:
>    <client: POST /user/ >   =>    <middleware: convert to
>/keystone/update/ >   =>   <keystone: update>
>we may use:
>    <client: POST /keystone/{ver:=x.0}/{method:=update} >   =>
><middleware: just forward to clients[ver].getattr("method")(**kwargs) >
>=>   <keystone: update>
>​The idea here is that if we have keystone 4.0 client, ​we will have to
>just add it to the clients [] list and nothing more is required at the
>middleware level. Just create the frontend code to use the new Keystone
>4.0 methods. Otherwise we will have to add all new/different signatures
>of 4.0 against 2.0/3.0 in the middleware in order to use Keystone 4.0.
>There is also a great example of using a pluggable/new feature in
>Horizon. Do you remember the volume types support patch? The patch was
>pending in Gerrit for few months - first waiting the cinder support for
>volume types to go upstream, then waiting few more weeks for review. I am
>not sure, but as far as I remember, the Horizon patch even missed a
>release milestone and was introduced in the next release.
>If we have a transparent middleware - this will be no more an issue. As
>long as someone has written the frontend modules(which should be easy to
>add and customize), and they install the required version of the service
>API - they will not need updated Horizon to start using the feature.
>Maybe I am not the right person to give examples here, but how many of
>you had some kind of Horizon customization being locally merged/patched
>in your local distros/setups, until the patch is being pushed upstream?
>I will say it again. Nova, Keystone, Cinder, Glance etc. already have
>stable public APIs. Why do we want to add the translation middleware and
>to introduce another level of REST API? This layer will often hide new
>features, added to the service APIs and will delay their appearance in
>Horizon. That's simply not needed. I believe it is possible to just wrap
>the authentication in the middleware REST, but not to translate anything
>as RPC methods/parameters.
>​And one more example:
>def put(self, request, id):
>    """Update a single project.
>        The POST data should be an application/json object containing the
>        parameters to update: "name" (string),  "description" (string),
>        "domain_id" (string) and "enabled" (boolean, defaults to true).
>        Additional, undefined parameters may also be provided, but you'll
>        to look deep into keystone to figure out what they might be.
>        This method returns HTTP 204 (no content) on success.
>        """
>        project = api.keystone.tenant_get(request, id)
>        kwargs = _tenant_kwargs_from_DATA(request.DATA, enabled=None)
>        api.keystone.tenant_update(request, project, **kwargs)
>​Do we really need the lines:​
>project = api.keystone.tenant_get(request, id)
>kwargs = _tenant_kwargs_from_DATA(request.DATA, enabled=None)
>>? ​Since we update the project on the client, it is obvious that we
>already fetched the project data. So we can simply send:
>POST /keystone/3.0/tenant_update
>Content-Type: application/json
>{"id": cached.id<http://cached.id>, "domain_id": cached.domain_id,
>"name": "new name", "description": "new description", "enabled":
>Fewer requests, faster application.

More information about the OpenStack-dev mailing list