Add request id to returned objects
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Glance |
Triaged
|
Wishlist
|
Abhishek Kekane |
Bug Description
We are adding support for returning ‘x-openstack-
http://
Problem Description:
Cannot add a new property of list type to the warlock.model object.
The requirement we are trying to meet is to make the request id available to the user of the client library [3]. The user typically doesn't have access to the headers, so the request id needs to be part of the payload returned from each method. In other clients that work with simple data types, we've subclassed dict, list, etc. to add the extra property. This adds the request id to the return value without making a breaking change to the API of the client library.
How is a model object created:
Let’s take an example of glanceclient.
Here after getting the response we call model() method. This model() does the job of creating a warlock.model object(essentially a dict) based on the schema given as argument (image schema retrieved from glance in this case). Inside model() the raw() method simply return the image schema as JSON object. The advantage of this warlock.model object over a simple dict is that it validates any changes to object based on the rules specified in the reference schema. The keys of this model object are available as object properties to the caller.
Underlying reason:
The schema for different sub APIs is returned a bit differently. For images, metadef APIs glance.
So we can add extra properties of any type to the model object returned from members or tasks API but for images and metadef APIs we can only add properties which can be of type string. Also for the latter case we depend on the glance configuration to allow additional properties.
As per our analysis we have come up with two approaches for resolving this issue:
Approach #1: Inject request_ids property in the warlock model object in glance client
Here we do the following:
1. Inject the ‘request_ids’ as additional property into the model object(returned from model())
2. Return the model object which now contains request_ids property
Limitations:
1. Because the glance schemas for images and metadef only allows additional properties of type string, so even though natural type of request_ids should be list we have to make it as a comma separated ‘string’ of request ids as a compromise.
2. Lot of extra code is needed to wrap objects returned from the client API so that the caller can get request ids. For example we need to write wrapper classes for dict, list, str, tuple, generator.
3. Not a good design as we are adding a property which should actually be a base property but added as additional property as a compromise.
4. There is a dependency on glance whether to allow custom/additional properties or not. [2]
Approach #2: Add ‘request_ids’ property to all schema definitions in glance
Here we add ‘request_ids’ property as follows to the various APIs (schema):
“request_ids”: {
"type": "array",
"items": {
"type": "string"
}
}
Doing this will make changes in glance client very simple as compared to approach#1.
This also looks a better design as it will be consistent.
We simply need to modify the request_ids property in various API calls for example glanceclient.
[1] https:/
[2] https:/
[3] http://
Changed in glance: | |
status: | New → Triaged |
summary: |
- Add request_ids attribute to v2 schemas + Add request id to returned objects |
Couple of comments:
Approach #1: Inject request_ids property in the warlock model object in glance client
We've (well I've!) typically pushed back on this. Up until now we've managed to maintain a one-to-one mapping between the json returned by Glance and the subsequent warlock object. It's one of the few things we've managed to keep as originally intended.
Approach #2: Add ‘request_ids’ property to all schema definitions in glance
Glance would be returning the request_id in the body rather than the header (or in addition to the header). I'm not sure we should modify the server API to fix what is really a client (specifically, python client) issue.
Is the key thing here to give users of the library "something" they can use to read the request_ids generated by the particular method call?
If so, what about something like the following?
requests has a 'hook' capability (http:// docs.python- requests. org/en/ latest/ user/advanced/ #event- hooks):
------- ------- ------- -----
import functools
import requests
def append_ content_ length( target, r, *args, **kwargs): append( r.headers[ 'content- length' ])
target.
content_lengths = []
hook = functools. partial( append_ content_ length, content_lengths)
requests.get('http:// docs.openstack. org/developer/ nova', hooks=dict( response= hook)) docs.openstack. org/developer/ glance', hooks=dict( response= hook))
requests.get('http://
print content_lengths ------- ------- -------
-------
Running it gives:
$ python contentlength.py
['321', '17671', '323', '12710']
Glance client would do this by accepting an empty list, ie change:
def delete(image):
to
def delete(image, request_ id_list= None):
callers of the method would provide an empty list if they wanted the request ids:
request_ids = [] delete( image, request_ids)
glanceclient.
print request_ids
The client code would have to shepherd the hook function down to the calls to requests but wouldn't have to worry about returning anything back.