Changes in getting image id from image name functionality

(types.ImageResourceType.transform method)

1. Changing sample scenario files to store image name as
regexp. This will help avoid further issues with current
image version of devstack and rally being out of sync.

2. Changing logic of _id_from_name method. name and regex
keys from resource_config dictionary are treated the same,
(as regexp) with name having priority. Going forward 'name'
key should always be used, and 'regexp' key is to there to
support legacy configurations. Also, exact check will be
performed on resource name.

3. Related unit test changed correspodently..

4. Added unit test for multiple maches of the same image name.

Change-Id: Ie0fc509445a652384f78864ad7d491e34b5a4d88
This commit is contained in:
Igor Pavlovic 2014-10-29 16:54:51 +00:00
parent beab98a853
commit dcf2d7b074
26 changed files with 91 additions and 53 deletions

View File

@ -4,7 +4,7 @@
"args": { "args": {
"volume_size": 10, "volume_size": 10,
"image": { "image": {
"name": "cirros-0.3.2-x86_64-uec" "name": "^cirros.*uec$"
}, },
"flavor": { "flavor": {
"name": "m1.nano" "name": "m1.nano"

View File

@ -4,7 +4,7 @@
args: args:
volume_size: 10 volume_size: 10
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
flavor: flavor:
name: "m1.nano" name: "m1.nano"
runner: runner:

View File

@ -6,7 +6,7 @@
"name": "m1.nano" "name": "m1.nano"
}, },
"image": { "image": {
"name": "cirros-0.3.1-x86_64-uec" "name": "^cirros.*uec$"
} }
}, },
"runner": { "runner": {

View File

@ -5,7 +5,7 @@
flavor: flavor:
name: "m1.nano" name: "m1.nano"
image: image:
name: "cirros-0.3.1-x86_64-uec" name: "^cirros.*uec$"
runner: runner:
type: "constant" type: "constant"
times: 10 times: 10

View File

@ -6,7 +6,7 @@
"name": "m1.nano" "name": "m1.nano"
}, },
"image": { "image": {
"name": "cirros-0.3.1-x86_64-uec" "name": "^cirros.*uec$"
}, },
"detailed": true "detailed": true
}, },

View File

@ -5,7 +5,7 @@
flavor: flavor:
name: "m1.nano" name: "m1.nano"
image: image:
name: "cirros-0.3.1-x86_64-uec" name: "^cirros.*uec$"
detailed: True detailed: True
runner: runner:
type: "constant" type: "constant"

View File

@ -6,7 +6,7 @@
"name": "m1.nano" "name": "m1.nano"
}, },
"image": { "image": {
"name": "cirros-0.3.1-x86_64-uec" "name": "^cirros.*uec$"
}, },
"actions": [ "actions": [
{"hard_reboot": 1}, {"hard_reboot": 1},

View File

@ -5,7 +5,7 @@
flavor: flavor:
name: "m1.nano" name: "m1.nano"
image: image:
name: "cirros-0.3.1-x86_64-uec" name: "^cirros.*uec$"
actions: actions:
- -
hard_reboot: 1 hard_reboot: 1

View File

@ -6,7 +6,7 @@
"name": "m1.nano" "name": "m1.nano"
}, },
"image": { "image": {
"name": "cirros-0.3.1-x86_64-uec" "name": "^cirros.*uec$"
}, },
"volume_size": 10 "volume_size": 10
}, },

View File

@ -5,7 +5,7 @@
flavor: flavor:
name: "m1.nano" name: "m1.nano"
image: image:
name: "cirros-0.3.1-x86_64-uec" name: "^cirros.*uec$"
volume_size: 10 volume_size: 10
runner: runner:
type: "constant" type: "constant"

View File

@ -6,7 +6,7 @@
"name": "m1.nano" "name": "m1.nano"
}, },
"image": { "image": {
"name": "cirros-0.3.1-x86_64-uec" "name": "^cirros.*uec$"
}, },
"volume_size": 10 "volume_size": 10
}, },

View File

@ -5,7 +5,7 @@
flavor: flavor:
name: "m1.nano" name: "m1.nano"
image: image:
name: "cirros-0.3.1-x86_64-uec" name: "^cirros.*uec$"
volume_size: 10 volume_size: 10
runner: runner:
type: "constant" type: "constant"

View File

@ -6,7 +6,7 @@
"name": "m1.nano" "name": "m1.nano"
}, },
"image": { "image": {
"name": "cirros-0.3.1-x86_64-uec" "name": "^cirros.*uec$"
} }
}, },
"runner": { "runner": {

View File

@ -5,7 +5,7 @@
flavor: flavor:
name: "m1.nano" name: "m1.nano"
image: image:
name: "cirros-0.3.1-x86_64-uec" name: "^cirros.*uec$"
runner: runner:
type: "constant" type: "constant"
times: 10 times: 10

View File

@ -6,7 +6,7 @@
"name": "m1.nano" "name": "m1.nano"
}, },
"image": { "image": {
"name": "cirros-0.3.1-x86_64-uec" "name": "^cirros.*uec$"
} }
}, },
"runner": { "runner": {

View File

@ -5,7 +5,7 @@
flavor: flavor:
name: "m1.nano" name: "m1.nano"
image: image:
name: "cirros-0.3.1-x86_64-uec" name: "^cirros.*uec$"
runner: runner:
type: "constant" type: "constant"
times: 10 times: 10

View File

@ -6,7 +6,7 @@
"name": "m1.nano" "name": "m1.nano"
}, },
"image": { "image": {
"name": "cirros-0.3.1-x86_64-uec" "name": "^cirros.*uec$"
}, },
"to_flavor": { "to_flavor": {
"name": "m1.small" "name": "m1.small"

View File

@ -5,7 +5,7 @@
flavor: flavor:
name: "m1.nano" name: "m1.nano"
image: image:
name: "cirros-0.3.1-x86_64-uec" name: "^cirros.*uec$"
to_flavor: to_flavor:
name: "m1.small" name: "m1.small"
confirm: true confirm: true

View File

@ -6,7 +6,7 @@
"name": "m1.nano" "name": "m1.nano"
}, },
"image": { "image": {
"name": "cirros-0.3.1-x86_64-uec" "name": "^cirros.*uec$"
}, },
"volume_args": { "volume_args": {
"size": 2 "size": 2

View File

@ -5,7 +5,7 @@
flavor: flavor:
name: "m1.nano" name: "m1.nano"
image: image:
name: "cirros-0.3.1-x86_64-uec" name: "^cirros.*uec$"
volume_args: volume_args:
size: 2 size: 2
fixed_network: "private" fixed_network: "private"

View File

@ -6,7 +6,7 @@
"name": "m1.nano" "name": "m1.nano"
}, },
"image": { "image": {
"name": "cirros-0.3.1-x86_64-uec" "name": "^cirros.*uec$"
}, },
"fixed_network": "private", "fixed_network": "private",
"floating_network": "public", "floating_network": "public",

View File

@ -5,7 +5,7 @@
flavor: flavor:
name: "m1.nano" name: "m1.nano"
image: image:
name: "cirros-0.3.1-x86_64-uec" name: "^cirros.*uec$"
fixed_network: "private" fixed_network: "private"
floating_network: "public" floating_network: "public"
use_floatingip: true use_floatingip: true

View File

@ -290,7 +290,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
runner: runner:
type: "constant" type: "constant"
times: 6 times: 6
@ -308,7 +308,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
runner: runner:
type: "constant" type: "constant"
times: 6 times: 6
@ -326,7 +326,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
detailed: True detailed: True
runner: runner:
type: "constant" type: "constant"
@ -345,7 +345,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
actions: actions:
- -
hard_reboot: 1 hard_reboot: 1
@ -372,7 +372,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
volume_size: 1 volume_size: 1
runner: runner:
type: "constant" type: "constant"
@ -391,7 +391,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
volume_size: 1 volume_size: 1
runner: runner:
type: "constant" type: "constant"
@ -410,7 +410,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
runner: runner:
type: "constant" type: "constant"
times: 2 times: 2
@ -428,7 +428,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
to_flavor: to_flavor:
name: "m1.small" name: "m1.small"
confirm: true confirm: true

View File

@ -668,7 +668,7 @@
args: args:
volume_size: 1 volume_size: 1
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
runner: runner:
@ -760,7 +760,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
runner: runner:
type: "constant" type: "constant"
times: 4 times: 4
@ -778,7 +778,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
detailed: True detailed: True
runner: runner:
type: "constant" type: "constant"
@ -797,7 +797,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
to_flavor: to_flavor:
name: "m1.small" name: "m1.small"
confirm: true confirm: true
@ -818,7 +818,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
actions: actions:
- -
hard_reboot: 1 hard_reboot: 1
@ -845,7 +845,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
volume_size: 1 volume_size: 1
runner: runner:
type: "constant" type: "constant"
@ -864,7 +864,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
volume_size: 1 volume_size: 1
runner: runner:
type: "constant" type: "constant"
@ -883,7 +883,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
runner: runner:
type: "constant" type: "constant"
times: 2 times: 2
@ -901,7 +901,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
auto_assign_nics: false auto_assign_nics: false
runner: runner:
type: "constant" type: "constant"
@ -918,7 +918,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
runner: runner:
type: "constant" type: "constant"
times: 4 times: 4
@ -936,7 +936,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
fixed_network: "private" fixed_network: "private"
floating_network: "public" floating_network: "public"
use_floatingip: true use_floatingip: true
@ -959,7 +959,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
volume_args: volume_args:
size: 2 size: 2
fixed_network: "private" fixed_network: "private"
@ -984,7 +984,7 @@
flavor: flavor:
name: "m1.tiny" name: "m1.tiny"
image: image:
name: "cirros-0.3.2-x86_64-uec" name: "^cirros.*uec$"
fixed_network: "private" fixed_network: "private"
use_floatingip: false use_floatingip: false
script: "/home/jenkins/.rally/extra/instance_dd_test.sh" script: "/home/jenkins/.rally/extra/instance_dd_test.sh"

View File

@ -79,8 +79,8 @@ class ResourceType(object):
def _id_from_name(resource_config, resources, typename): def _id_from_name(resource_config, resources, typename):
"""Return the id of the resource whose name matches the pattern. """Return the id of the resource whose name matches the pattern.
When resource_config contains `name`, an exact match is used. resource_config has to contain `name`, as it is used to lookup an id.
When resource_config contains `regex`, a pattern match is used. Value of the name will be treated as regexp.
An `InvalidScenarioArgument` is thrown if the pattern does An `InvalidScenarioArgument` is thrown if the pattern does
not match unambiguously. not match unambiguously.
@ -91,10 +91,25 @@ def _id_from_name(resource_config, resources, typename):
:returns: resource id uniquely mapped to `name` or `regex` :returns: resource id uniquely mapped to `name` or `regex`
""" """
if resource_config.get('name'): if "name" in resource_config:
patternstr = "^{0}$".format(resource_config.get('name')) # In a case of pattern string exactly maches resource name
elif resource_config.get('regex'): matching_exact = filter(lambda r: r.name == resource_config["name"],
patternstr = resource_config.get('regex') resources)
if len(matching_exact) == 1:
return matching_exact[0].id
elif len(matching_exact) > 1:
raise exceptions.InvalidScenarioArgument(
"{typename} with name '{pattern}' "
"is ambiguous, possible matches "
"by id: {ids}".format(typename=typename.title(),
pattern=resource_config["name"],
ids=", ".join(map(
operator.attrgetter("id"),
matching_exact))))
# Else look up as regex
patternstr = resource_config["name"]
elif "regex" in resource_config:
patternstr = resource_config["regex"]
else: else:
raise exceptions.InvalidScenarioArgument( raise exceptions.InvalidScenarioArgument(
"{typename} 'id', 'name', or 'regex' not found " "{typename} 'id', 'name', or 'regex' not found "
@ -153,7 +168,8 @@ class ImageResourceType(ResourceType):
if not resource_id: if not resource_id:
glanceclient = clients.glance() glanceclient = clients.glance()
resource_id = _id_from_name(resource_config=resource_config, resource_id = _id_from_name(resource_config=resource_config,
resources=glanceclient.images.list(), resources=list(
glanceclient.images.list()),
typename='image') typename='image')
return resource_id return resource_id
@ -201,4 +217,4 @@ class NeutronNetworkResourceType(ResourceType):
raise exceptions.InvalidScenarioArgument( raise exceptions.InvalidScenarioArgument(
"Neutron network with name '{name}' not found".format( "Neutron network with name '{name}' not found".format(
name=resource_config.get("name"))) name=resource_config.get("name")))

View File

@ -30,6 +30,10 @@ class FlavorResourceTypeTestCase(test.TestCase):
id="1")) id="1"))
self.clients.nova().flavors._cache(fakes.FakeResource(name='m1.nano', self.clients.nova().flavors._cache(fakes.FakeResource(name='m1.nano',
id="42")) id="42"))
self.clients.nova().flavors._cache(fakes.FakeResource(name='m1.large',
id="44"))
self.clients.nova().flavors._cache(fakes.FakeResource(name='m1.large',
id="45"))
def test_transform_by_id(self): def test_transform_by_id(self):
resource_config = {"id": "42"} resource_config = {"id": "42"}
@ -57,6 +61,12 @@ class FlavorResourceTypeTestCase(test.TestCase):
types.FlavorResourceType.transform, self.clients, types.FlavorResourceType.transform, self.clients,
resource_config) resource_config)
def test_transform_by_name_multiple_match(self):
resource_config = {"name": "m1.large"}
self.assertRaises(exceptions.InvalidScenarioArgument,
types.FlavorResourceType.transform, self.clients,
resource_config)
def test_transform_by_regex(self): def test_transform_by_regex(self):
resource_config = {"regex": "m(1|2)\.nano"} resource_config = {"regex": "m(1|2)\.nano"}
flavor_id = types.FlavorResourceType.transform( flavor_id = types.FlavorResourceType.transform(
@ -86,6 +96,12 @@ class ImageResourceTypeTestCase(test.TestCase):
self.clients.glance().images._cache(image1) self.clients.glance().images._cache(image1)
image2 = fakes.FakeResource(name="cirros-0.3.1-uec-ramdisk", id="101") image2 = fakes.FakeResource(name="cirros-0.3.1-uec-ramdisk", id="101")
self.clients.glance().images._cache(image2) self.clients.glance().images._cache(image2)
image3 = fakes.FakeResource(name="cirros-0.3.1-uec-ramdisk-copy",
id="102")
self.clients.glance().images._cache(image3)
image4 = fakes.FakeResource(name="cirros-0.3.1-uec-ramdisk-copy",
id="103")
self.clients.glance().images._cache(image4)
def test_transform_by_id(self): def test_transform_by_id(self):
resource_config = {"id": "100"} resource_config = {"id": "100"}
@ -95,7 +111,7 @@ class ImageResourceTypeTestCase(test.TestCase):
self.assertEqual(image_id, "100") self.assertEqual(image_id, "100")
def test_transform_by_name(self): def test_transform_by_name(self):
resource_config = {"name": "cirros-0.3.1-uec"} resource_config = {"name": "^cirros-0.3.1-uec$"}
image_id = types.ImageResourceType.transform( image_id = types.ImageResourceType.transform(
clients=self.clients, clients=self.clients,
resource_config=resource_config) resource_config=resource_config)
@ -107,6 +123,12 @@ class ImageResourceTypeTestCase(test.TestCase):
types.ImageResourceType.transform, self.clients, types.ImageResourceType.transform, self.clients,
resource_config) resource_config)
def test_transform_by_name_match_multiple(self):
resource_config = {"name": "cirros-0.3.1-uec-ramdisk-copy"}
self.assertRaises(exceptions.InvalidScenarioArgument,
types.ImageResourceType.transform, self.clients,
resource_config)
def test_transform_by_regex(self): def test_transform_by_regex(self):
resource_config = {"regex": "-uec$"} resource_config = {"regex": "-uec$"}
image_id = types.ImageResourceType.transform( image_id = types.ImageResourceType.transform(
@ -228,4 +250,4 @@ class PreprocessTestCase(test.TestCase):
attr_name="preprocessors") attr_name="preprocessors")
mock_osclients.Clients.assert_called_once_with( mock_osclients.Clients.assert_called_once_with(
context["admin"]["endpoint"]) context["admin"]["endpoint"])
self.assertEqual({"a": 20, "b": 20}, result) self.assertEqual({"a": 20, "b": 20}, result)