Support flavor ids with leading '0'

When Trove moved to support alphanumeric flavor ids, the case of having
a numeric string id with leading zeros was not taken into account. The
behavior on the client side is to see if the id is all digits, and if so
it is converted to an int. That means that a flavor of '01' will be
incorrectly interpreted as '1'.

This behavior has been fixed and unit tests created.

Change-Id: I5acdec576a2e7da6cbfbb1cfc61c49fbbf7379af
Partial-Bug: #1603187
This commit is contained in:
Peter Stachowski
2016-07-14 22:30:10 +00:00
parent 107b601475
commit f067cf83c2
4 changed files with 45 additions and 12 deletions

View File

@@ -163,7 +163,7 @@ class FakeHTTPClient(base_client.HTTPClient):
"status": "ACTIVE",
"ip": ["10.0.0.13"],
"volume": {"size": 2},
"flavor": {"id": "2"},
"flavor": {"id": "02"},
"datastore": {"version": "5.6", "type": "mysql"}},
{
"id": "5678",
@@ -213,7 +213,12 @@ class FakeHTTPClient(base_client.HTTPClient):
"str_id": "7d0d16e5-875f-4198-b6da-90ab2d3e899e",
"ram": 8192,
"id": None,
"name": "m1.uuid"}]})
"name": "m1.uuid"},
{
"str_id": "02",
"ram": 1024,
"id": None,
"name": "m1.leading-zero"}]})
def get_datastores_mysql_versions_some_version_id_flavors(self, **kw):
return self.get_flavors()
@@ -238,6 +243,14 @@ class FakeHTTPClient(base_client.HTTPClient):
r = {'flavor': self.get_flavors()[2]['flavors'][4]}
return (200, {}, r)
def get_flavors_02(self, **kw):
r = {'flavor': self.get_flavors()[2]['flavors'][5]}
return (200, {}, r)
def get_flavors_m1_leading_zero(self, **kw):
r = {'flavor': self.get_flavors()[2]['flavors'][5]}
return (200, {}, r)
def get_clusters(self, **kw):
return (200, {}, {"clusters": [
{
@@ -246,7 +259,7 @@ class FakeHTTPClient(base_client.HTTPClient):
"type": "member",
"id": "member-1",
"ip": ["10.0.0.3"],
"flavor": {"id": "2"},
"flavor": {"id": "02"},
"name": "test-clstr-member-1"
},
{

View File

@@ -230,6 +230,10 @@ class ShellTest(utils.TestCase):
self.run_command('flavor-show 1')
self.assert_called('GET', '/flavors/1')
def test_flavor_show_leading_zero(self):
self.run_command('flavor-show 02')
self.assert_called('GET', '/flavors/02')
def test_flavor_show_by_name(self):
self.run_command('flavor-show m1.tiny') # defined in fakes.py
self.assert_called('GET', '/flavors/m1.tiny')
@@ -287,6 +291,17 @@ class ShellTest(utils.TestCase):
'name': 'test-member-1'
}})
def test_boot_by_flavor_leading_zero(self):
self.run_command(
'create test-member-zero 02 --size 1 --volume_type lvm')
self.assert_called_anytime(
'POST', '/instances',
{'instance': {
'volume': {'size': 1, 'type': 'lvm'},
'flavorRef': '02',
'name': 'test-member-zero'
}})
def test_boot_repl_set(self):
self.run_command('create repl-1 1 --size 1 --locality=anti-affinity '
'--replica_count=4')
@@ -377,7 +392,7 @@ class ShellTest(utils.TestCase):
def test_cluster_create(self):
cmd = ('cluster-create test-clstr vertica 7.1 '
'--instance flavor=2,volume=2 '
'--instance flavor=02,volume=2 '
'--instance flavor=2,volume=1 '
'--instance flavor=2,volume=1,volume_type=my-type-1')
self.run_command(cmd)
@@ -387,7 +402,7 @@ class ShellTest(utils.TestCase):
'instances': [
{
'volume': {'size': '2'},
'flavorRef': '2'
'flavorRef': '02'
},
{
'volume': {'size': '1'},
@@ -403,7 +418,7 @@ class ShellTest(utils.TestCase):
def test_cluster_create_by_flavor_name(self):
cmd = ('cluster-create test-clstr vertica 7.1 '
'--instance flavor=m1.small,volume=2 '
'--instance flavor=m1.small,volume=1')
'--instance flavor=m1.leading-zero,volume=1')
self.run_command(cmd)
self.assert_called_anytime(
'POST', '/clusters',
@@ -415,7 +430,7 @@ class ShellTest(utils.TestCase):
},
{
'volume': {'size': '1'},
'flavorRef': '2'
'flavorRef': '02'
}],
'datastore': {'version': '7.1', 'type': 'vertica'},
'name': 'test-clstr'}})
@@ -430,7 +445,7 @@ class ShellTest(utils.TestCase):
def test_cluster_grow(self):
cmd = ('cluster-grow cls-1234 '
'--instance flavor=2,volume=2 '
'--instance flavor=2,volume=1')
'--instance flavor=02,volume=1')
self.run_command(cmd)
self.assert_called('POST', '/clusters/cls-1234')
@@ -442,7 +457,7 @@ class ShellTest(utils.TestCase):
def test_cluster_create_with_locality(self):
cmd = ('cluster-create test-clstr2 redis 3.0 --locality=affinity '
'--instance flavor=2,volume=1 '
'--instance flavor=2,volume=1 '
'--instance flavor=02,volume=1 '
'--instance flavor=2,volume=1 ')
self.run_command(cmd)
self.assert_called_anytime(
@@ -451,7 +466,7 @@ class ShellTest(utils.TestCase):
'instances': [
{'flavorRef': '2',
'volume': {'size': '1'}},
{'flavorRef': '2',
{'flavorRef': '02',
'volume': {'size': '1'}},
{'flavorRef': '2',
'volume': {'size': '1'}},

View File

@@ -209,7 +209,9 @@ def find_resource(manager, name_or_id):
"""Helper for the _find_* methods."""
# first try to get entity as integer id
if isinstance(name_or_id, int) or name_or_id.isdigit():
# if the 'id' starts with '0' don't treat it as an int
if isinstance(name_or_id, int) or (
name_or_id.isdigit() and not name_or_id.startswith('0')):
name_or_id = int(name_or_id)
elif sys.version_info <= (3, 0):
name_or_id = encodeutils.safe_decode(name_or_id)

View File

@@ -224,7 +224,8 @@ def do_flavor_list(cs, args):
labels={'ram': 'RAM'})
@utils.arg('flavor', metavar='<flavor>', help='ID or name of the flavor.')
@utils.arg('flavor', metavar='<flavor>', type=str,
help='ID or name of the flavor.')
@utils.service_type('database')
def do_flavor_show(cs, args):
"""Shows details of a flavor."""
@@ -417,6 +418,7 @@ def do_update(cs, args):
help="Volume type. Optional when volume support is enabled.")
@utils.arg('flavor',
metavar='<flavor>',
type=str,
help='A flavor name or ID.')
@utils.arg('--databases', metavar='<database>',
help='Optional list of databases.',
@@ -747,6 +749,7 @@ def do_cluster_create(cs, args):
help='ID or name of the instance.')
@utils.arg('flavor',
metavar='<flavor>',
type=str,
help='New flavor of the instance.')
@utils.service_type('database')
def do_resize_instance(cs, args):