Translate resource_id to UUID5 format.
Due to wsgi spec issue, webserver and webob decode "%2F" into "/" for PATH_INFO. Some webserver allows to change this behavior, but webob doesn't. Until we find a suitable better solution I propose that the client always translate the resource_id in uuid5 format. Related-bug: #1500890 Change-Id: Id3df57a54ad35b12e691eff2d4d3c40effe1f808
This commit is contained in:
parent
f107392374
commit
415050041b
|
@ -13,11 +13,13 @@
|
|||
import uuid
|
||||
|
||||
from gnocchiclient.tests.functional import base
|
||||
from gnocchiclient import utils
|
||||
|
||||
|
||||
class ResourceClientTest(base.ClientTestBase):
|
||||
RESOURCE_ID = str(uuid.uuid4())
|
||||
RESOURCE_ID2 = str(uuid.uuid4())
|
||||
RAW_RESOURCE_ID2 = str(uuid.uuid4()) + "/foo"
|
||||
RESOURCE_ID2 = utils.encode_resource_id(RAW_RESOURCE_ID2)
|
||||
PROJECT_ID = str(uuid.uuid4())
|
||||
|
||||
def test_help(self):
|
||||
|
@ -123,7 +125,7 @@ class ResourceClientTest(base.ClientTestBase):
|
|||
result = self.gnocchi(
|
||||
'resource', params=("create %s -t generic "
|
||||
"-a project_id:%s"
|
||||
) % (self.RESOURCE_ID2, self.PROJECT_ID))
|
||||
) % (self.RAW_RESOURCE_ID2, self.PROJECT_ID))
|
||||
resource2 = self.details_multiple(result)[0]
|
||||
self.assertEqual(self.RESOURCE_ID2, resource2["id"])
|
||||
self.assertEqual(self.PROJECT_ID, resource2["project_id"])
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import uuid
|
||||
|
||||
import pyparsing as pp
|
||||
import six
|
||||
|
||||
uninary_operators = ("not", )
|
||||
binary_operator = (u">=", u"<=", u"!=", u">", u"<", u"=", u"==", u"eq", u"ne",
|
||||
|
@ -26,8 +28,9 @@ null = pp.Regex("None|none|null").setParseAction(pp.replaceWith(None))
|
|||
boolean = "False|True|false|true"
|
||||
boolean = pp.Regex(boolean).setParseAction(lambda t: t[0].lower() == "true")
|
||||
hex_string = lambda n: pp.Word(pp.hexnums, exact=n)
|
||||
uuid = pp.Combine(hex_string(8) + (pp.Optional("-") + hex_string(4)) * 3 +
|
||||
pp.Optional("-") + hex_string(12))
|
||||
uuid_string = pp.Combine(hex_string(8) +
|
||||
(pp.Optional("-") + hex_string(4)) * 3 +
|
||||
pp.Optional("-") + hex_string(12))
|
||||
number = r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?"
|
||||
number = pp.Regex(number).setParseAction(lambda t: float(t[0]))
|
||||
identifier = pp.Word(pp.alphas, pp.alphanums + "_")
|
||||
|
@ -36,7 +39,7 @@ comparison_term = pp.Forward()
|
|||
in_list = pp.Group(pp.Suppress('[') +
|
||||
pp.Optional(pp.delimitedList(comparison_term)) +
|
||||
pp.Suppress(']'))("list")
|
||||
comparison_term << (null | boolean | uuid | identifier | number |
|
||||
comparison_term << (null | boolean | uuid_string | identifier | number |
|
||||
quoted_string | in_list)
|
||||
condition = pp.Group(comparison_term + operator + comparison_term)
|
||||
|
||||
|
@ -125,3 +128,24 @@ def dict_to_querystring(objs):
|
|||
return "&".join(["%s=%s" % (k, v)
|
||||
for k, v in objs.items()
|
||||
if v is not None])
|
||||
|
||||
|
||||
# uuid5 namespace for id transformation.
|
||||
# NOTE(chdent): This UUID must stay the same, forever, across all
|
||||
# of gnocchi to preserve its value as a URN namespace.
|
||||
RESOURCE_ID_NAMESPACE = uuid.UUID('0a7a15ff-aa13-4ac2-897c-9bdf30ce175b')
|
||||
|
||||
|
||||
def encode_resource_id(value):
|
||||
try:
|
||||
try:
|
||||
return str(uuid.UUID(value))
|
||||
except ValueError:
|
||||
if len(value) <= 255:
|
||||
if six.PY2:
|
||||
value = value.encode('utf-8')
|
||||
return str(uuid.uuid5(RESOURCE_ID_NAMESPACE, value))
|
||||
raise ValueError(
|
||||
'transformable resource id >255 max allowed characters')
|
||||
except Exception as e:
|
||||
raise ValueError(e)
|
||||
|
|
|
@ -51,6 +51,7 @@ class MetricManager(base.Manager):
|
|||
self._ensure_metric_is_uuid(metric)
|
||||
url = self.metric_url + metric
|
||||
else:
|
||||
resource_id = utils.encode_resource_id(resource_id)
|
||||
url = (self.resource_url % resource_id) + metric
|
||||
return self._get(url).json()
|
||||
|
||||
|
@ -79,6 +80,7 @@ class MetricManager(base.Manager):
|
|||
raise TypeError("metric_name is required if resource_id is set")
|
||||
|
||||
del metric['resource_id']
|
||||
resource_id = utils.encode_resource_id(resource_id)
|
||||
metric = {metric_name: metric}
|
||||
metric = self._post(
|
||||
self.resource_url % resource_id,
|
||||
|
@ -99,6 +101,7 @@ class MetricManager(base.Manager):
|
|||
self._ensure_metric_is_uuid(metric)
|
||||
url = self.metric_url + metric
|
||||
else:
|
||||
resource_id = utils.encode_resource_id(resource_id)
|
||||
url = self.resource_url % resource_id + metric
|
||||
self._delete(url)
|
||||
|
||||
|
@ -117,6 +120,7 @@ class MetricManager(base.Manager):
|
|||
self._ensure_metric_is_uuid(metric)
|
||||
url = self.metric_url + metric + "/measures"
|
||||
else:
|
||||
resource_id = utils.encode_resource_id(resource_id)
|
||||
url = self.resource_url % resource_id + metric + "/measures"
|
||||
return self._post(
|
||||
url, headers={'Content-Type': "application/json"},
|
||||
|
@ -153,6 +157,7 @@ class MetricManager(base.Manager):
|
|||
self._ensure_metric_is_uuid(metric)
|
||||
url = self.metric_url + metric + "/measures"
|
||||
else:
|
||||
resource_id = utils.encode_resource_id(resource_id)
|
||||
url = self.resource_url % resource_id + metric + "/measures"
|
||||
return self._get(url, params=params).json()
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
from oslo_serialization import jsonutils
|
||||
from six.moves.urllib import parse as urllib_parse
|
||||
|
||||
from gnocchiclient import utils
|
||||
from gnocchiclient.v1 import base
|
||||
|
||||
|
||||
|
@ -73,6 +74,7 @@ class ResourceManager(base.Manager):
|
|||
:type history: bool
|
||||
"""
|
||||
history = "/history" if history else ""
|
||||
resource_id = utils.encode_resource_id(resource_id)
|
||||
url = self.url + "%s/%s%s" % (resource_type, resource_id, history)
|
||||
return self._get(url).json()
|
||||
|
||||
|
@ -96,6 +98,7 @@ class ResourceManager(base.Manager):
|
|||
:type sorts: list of str
|
||||
"""
|
||||
qs = _get_pagination_options(details, False, limit, marker, sorts)
|
||||
resource_id = utils.encode_resource_id(resource_id)
|
||||
url = "%s%s/%s/history?%s" % (self.url, resource_type, resource_id, qs)
|
||||
return self._get(url).json()
|
||||
|
||||
|
@ -123,6 +126,7 @@ class ResourceManager(base.Manager):
|
|||
:type resource: dict
|
||||
"""
|
||||
|
||||
resource_id = utils.encode_resource_id(resource_id)
|
||||
return self._patch(
|
||||
self.url + resource_type + "/" + resource_id,
|
||||
headers={'Content-Type': "application/json"},
|
||||
|
@ -134,6 +138,7 @@ class ResourceManager(base.Manager):
|
|||
:param resource_id: ID of the resource
|
||||
:type resource_id: str
|
||||
"""
|
||||
resource_id = utils.encode_resource_id(resource_id)
|
||||
self._delete(self.url + "generic/" + resource_id)
|
||||
|
||||
def search(self, resource_type="generic", query=None, details=False,
|
||||
|
|
Loading…
Reference in New Issue