Merge "Refactor ImageGenerator and validation"
This commit is contained in:
commit
8995027941
@ -894,6 +894,54 @@
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
||||
-
|
||||
args:
|
||||
flavor:
|
||||
name: "m1.tiny"
|
||||
image:
|
||||
name: "from_context_uploaded"
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 1
|
||||
concurrency: 1
|
||||
context:
|
||||
users:
|
||||
tenants: 1
|
||||
users_per_tenant: 1
|
||||
images:
|
||||
image_name: "from_context_uploaded"
|
||||
image_url: "http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-disk.img"
|
||||
image_type: "qcow2"
|
||||
image_container: "bare"
|
||||
images_per_tenant: 1
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
||||
-
|
||||
args:
|
||||
flavor:
|
||||
name: "m1.tiny"
|
||||
image:
|
||||
regex: "^from_context_uploaded$"
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 1
|
||||
concurrency: 1
|
||||
context:
|
||||
users:
|
||||
tenants: 1
|
||||
users_per_tenant: 1
|
||||
images:
|
||||
image_name: "from_context_uploaded"
|
||||
image_url: "http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-disk.img"
|
||||
image_type: "qcow2"
|
||||
image_container: "bare"
|
||||
images_per_tenant: 1
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
||||
-
|
||||
args:
|
||||
flavor:
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
from rally.benchmark.context import base
|
||||
from rally.benchmark.context.cleanup import manager as resource_manager
|
||||
from rally.benchmark.scenarios import base as scenario_base
|
||||
from rally.benchmark.scenarios.glance import utils as glance_utils
|
||||
from rally.common.i18n import _
|
||||
from rally.common import log as logging
|
||||
@ -44,6 +43,17 @@ class ImageGenerator(base.Context):
|
||||
"image_container": {
|
||||
"type": "string",
|
||||
},
|
||||
"image_name": {
|
||||
"type": "string",
|
||||
},
|
||||
"min_ram": { # megabytes
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"min_disk": { # gigabytes
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"images_per_tenant": {
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
@ -63,20 +73,27 @@ class ImageGenerator(base.Context):
|
||||
image_type = self.config["image_type"]
|
||||
image_container = self.config["image_container"]
|
||||
images_per_tenant = self.config["images_per_tenant"]
|
||||
image_name = self.config.get("image_name")
|
||||
|
||||
for user, tenant_id in rutils.iterate_per_tenants(
|
||||
self.context["users"]):
|
||||
current_images = []
|
||||
clients = osclients.Clients(user["endpoint"])
|
||||
glance_util_class = glance_utils.GlanceScenario(
|
||||
glance_scenario = glance_utils.GlanceScenario(
|
||||
clients=clients)
|
||||
for i in range(images_per_tenant):
|
||||
rnd_name = scenario_base.Scenario._generate_random_name()
|
||||
if image_name and i > 0:
|
||||
cur_name = image_name + str(i)
|
||||
elif image_name:
|
||||
cur_name = image_name
|
||||
else:
|
||||
cur_name = glance_scenario._generate_random_name(
|
||||
prefix="rally_ctx_image_")
|
||||
|
||||
image = glance_util_class._create_image(rnd_name,
|
||||
image_container,
|
||||
image_url,
|
||||
image_type)
|
||||
image = glance_scenario._create_image(
|
||||
cur_name, image_container, image_url, image_type,
|
||||
min_ram=self.config.get("min_ram", 0),
|
||||
min_disk=self.config.get("min_disk", 0))
|
||||
current_images.append(image.id)
|
||||
|
||||
self.context["tenants"][tenant_id]["images"] = current_images
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
import functools
|
||||
import os
|
||||
import re
|
||||
|
||||
from glanceclient import exc as glance_exc
|
||||
from novaclient import exceptions as nova_exc
|
||||
@ -151,17 +152,33 @@ def file_exists(config, clients, deployment, param_name, mode=os.R_OK):
|
||||
|
||||
|
||||
def _get_validated_image(config, clients, param_name):
|
||||
image_value = config.get("args", {}).get(param_name)
|
||||
if not image_value:
|
||||
msg = "Parameter %s is not specified." % param_name
|
||||
image_context = config.get("context", {}).get("images", {})
|
||||
image_args = config.get("args", {}).get(param_name)
|
||||
image_ctx_name = image_context.get("image_name")
|
||||
|
||||
if not image_args:
|
||||
msg = _("Parameter %s is not specified.") % param_name
|
||||
return (ValidationResult(False, msg), None)
|
||||
if "image_name" in image_context:
|
||||
# NOTE(rvasilets) check string is "exactly equal to" a regex
|
||||
# or image name from context equal to image name from args
|
||||
if "regex" in image_args:
|
||||
match = re.match(image_args.get("regex"), image_ctx_name)
|
||||
if image_ctx_name == image_args.get("name") or (
|
||||
"regex" in image_args and match):
|
||||
image = {
|
||||
"size": image_context.get("min_disk", 0),
|
||||
"min_ram": image_context.get("min_ram", 0),
|
||||
"min_disk": image_context.get("min_disk", 0)
|
||||
}
|
||||
return (ValidationResult(True), image)
|
||||
try:
|
||||
image_id = types.ImageResourceType.transform(
|
||||
clients=clients, resource_config=image_value)
|
||||
image = clients.glance().images.get(image=image_id)
|
||||
clients=clients, resource_config=image_args)
|
||||
image = clients.glance().images.get(image=image_id).to_dict()
|
||||
return (ValidationResult(True), image)
|
||||
except (glance_exc.HTTPNotFound, exceptions.InvalidScenarioArgument):
|
||||
message = _("Image '%s' not found") % image_value
|
||||
message = _("Image '%s' not found") % image_args
|
||||
return (ValidationResult(False, message), None)
|
||||
|
||||
|
||||
@ -240,20 +257,20 @@ def image_valid_on_flavor(config, clients, deployment, flavor_name,
|
||||
if not valid_result.is_valid:
|
||||
return valid_result
|
||||
|
||||
if flavor.ram < (image.min_ram or 0):
|
||||
if flavor.ram < (image["min_ram"] or 0):
|
||||
message = _("The memory size for flavor '%s' is too small "
|
||||
"for requested image '%s'") % (flavor.id, image.id)
|
||||
"for requested image '%s'") % (flavor.id, image["id"])
|
||||
return ValidationResult(False, message)
|
||||
|
||||
if flavor.disk:
|
||||
if (image.size or 0) > flavor.disk * (1024 ** 3):
|
||||
if (image["size"] or 0) > flavor.disk * (1024 ** 3):
|
||||
message = _("The disk size for flavor '%s' is too small "
|
||||
"for requested image '%s'") % (flavor.id, image.id)
|
||||
"for requested image '%s'") % (flavor.id, image["id"])
|
||||
return ValidationResult(False, message)
|
||||
|
||||
if (image.min_disk or 0) > flavor.disk:
|
||||
if (image["min_disk"] or 0) > flavor.disk:
|
||||
message = _("The disk size for flavor '%s' is too small "
|
||||
"for requested image '%s'") % (flavor.id, image.id)
|
||||
"for requested image '%s'") % (flavor.id, image["id"])
|
||||
return ValidationResult(False, message)
|
||||
|
||||
|
||||
|
@ -102,7 +102,7 @@ def print_list(objs, fields, formatters=None, sortby_index=0,
|
||||
if len(field_labels) != len(fields):
|
||||
raise ValueError(_("Field labels list %(labels)s has different number "
|
||||
"of elements than fields list %(fields)s"),
|
||||
{'labels': field_labels, 'fields': fields})
|
||||
{"labels": field_labels, "fields": fields})
|
||||
|
||||
if sortby_index is None:
|
||||
kwargs = {}
|
||||
|
@ -44,6 +44,9 @@ class ImageGeneratorTestCase(test.TestCase):
|
||||
"image_type": "qcow2",
|
||||
"image_container": "bare",
|
||||
"images_per_tenant": 4,
|
||||
"image_name": "some_name",
|
||||
"min_ram": 128,
|
||||
"min_disk": 1,
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,6 +96,9 @@ class ImageGeneratorTestCase(test.TestCase):
|
||||
"image_type": "qcow2",
|
||||
"image_container": "bare",
|
||||
"images_per_tenant": images_per_tenant,
|
||||
"image_name": "some_name",
|
||||
"min_ram": 128,
|
||||
"min_disk": 1,
|
||||
}
|
||||
},
|
||||
"admin": {
|
||||
@ -143,6 +149,9 @@ class ImageGeneratorTestCase(test.TestCase):
|
||||
"image_type": "qcow2",
|
||||
"image_container": "bare",
|
||||
"images_per_tenant": 5,
|
||||
"image_name": "some_name",
|
||||
"min_ram": 128,
|
||||
"min_disk": 1,
|
||||
}
|
||||
},
|
||||
"admin": {
|
||||
|
@ -120,19 +120,47 @@ class ValidatorsTestCase(test.TestCase):
|
||||
result = validation._get_validated_image({}, None, "non_existing")
|
||||
self.assertFalse(result[0].is_valid, result[0].msg)
|
||||
|
||||
def test__get_validated_image_from_context(self):
|
||||
clients = mock.MagicMock()
|
||||
image = {
|
||||
"size": 0,
|
||||
"min_ram": 0,
|
||||
"min_disk": 0
|
||||
}
|
||||
result = validation._get_validated_image({"args": {
|
||||
"image": {"name": "foo"}}, "context": {
|
||||
"images": {
|
||||
"image_name": "foo"}
|
||||
}}, clients, "image")
|
||||
|
||||
self.assertTrue(result[0].is_valid, result[0].msg)
|
||||
self.assertEqual(result[1], image)
|
||||
|
||||
result = validation._get_validated_image({"args": {
|
||||
"image": {"regex": r"^foo$"}}, "context": {
|
||||
"images": {
|
||||
"image_name": "foo"}
|
||||
}}, clients, "image")
|
||||
|
||||
self.assertTrue(result[0].is_valid, result[0].msg)
|
||||
self.assertEqual(result[1], image)
|
||||
|
||||
@mock.patch("rally.benchmark.validation.types.ImageResourceType.transform")
|
||||
def test__get_validated_image(self, mock_transform):
|
||||
mock_transform.return_value = "image_id"
|
||||
clients = mock.MagicMock()
|
||||
clients.glance().images.get.return_value = "image"
|
||||
clients.glance().images.get().to_dict.return_value = {
|
||||
"image": "image_id"}
|
||||
|
||||
result = validation._get_validated_image({"args": {"a": "test"}},
|
||||
result = validation._get_validated_image({"args": {"a": "test"},
|
||||
"context": {
|
||||
"image_name": "foo"}},
|
||||
clients, "a")
|
||||
self.assertTrue(result[0].is_valid, result[0].msg)
|
||||
self.assertEqual(result[1], "image")
|
||||
self.assertEqual(result[1], {"image": "image_id"})
|
||||
mock_transform.assert_called_once_with(clients=clients,
|
||||
resource_config="test")
|
||||
clients.glance().images.get.assert_called_once_with(image="image_id")
|
||||
clients.glance().images.get.assert_called_with(image="image_id")
|
||||
|
||||
@mock.patch("rally.benchmark.validation.types.ImageResourceType.transform")
|
||||
def test__get_validated_image_transform_error(self, mock_transform):
|
||||
@ -144,7 +172,8 @@ class ValidatorsTestCase(test.TestCase):
|
||||
@mock.patch("rally.benchmark.validation.types.ImageResourceType.transform")
|
||||
def test__get_validated_image_not_found(self, mock_transform):
|
||||
clients = mock.MagicMock()
|
||||
clients.glance().images.get.side_effect = glance_exc.HTTPNotFound("")
|
||||
clients.glance().images.get().to_dict.side_effect = (
|
||||
glance_exc.HTTPNotFound(""))
|
||||
result = validation._get_validated_image({"args": {"a": "test"}},
|
||||
clients, "a")
|
||||
self.assertFalse(result[0].is_valid, result[0].msg)
|
||||
@ -254,7 +283,12 @@ class ValidatorsTestCase(test.TestCase):
|
||||
@mock.patch("rally.benchmark.validation._get_validated_image")
|
||||
@mock.patch("rally.benchmark.validation._get_validated_flavor")
|
||||
def test_image_valid_on_flavor(self, mock_get_flavor, mock_get_image):
|
||||
image = mock.MagicMock()
|
||||
image = {
|
||||
"id": "fake_id",
|
||||
"min_ram": None,
|
||||
"size": 2,
|
||||
"min_disk": 0
|
||||
}
|
||||
flavor = mock.MagicMock()
|
||||
success = validation.ValidationResult(True)
|
||||
mock_get_flavor.return_value = (success, flavor)
|
||||
@ -265,27 +299,27 @@ class ValidatorsTestCase(test.TestCase):
|
||||
# test ram
|
||||
flavor.disk = None
|
||||
flavor.ram = 2
|
||||
image.min_ram = None
|
||||
image["min_ram"] = None
|
||||
result = validator(None, None, None)
|
||||
self.assertTrue(result.is_valid, result.msg)
|
||||
image.min_ram = 4
|
||||
image["min_ram"] = 4
|
||||
result = validator(None, None, None)
|
||||
self.assertFalse(result.is_valid, result.msg)
|
||||
image.min_ram = 1
|
||||
image["min_ram"] = 1
|
||||
result = validator(None, None, None)
|
||||
self.assertTrue(result.is_valid, result.msg)
|
||||
|
||||
# test disk (flavor.disk not None)
|
||||
image.size = 2
|
||||
image.min_disk = 0
|
||||
image["size"] = 2
|
||||
image["min_disk"] = 0
|
||||
flavor.disk = 5.0 / (1024 ** 3)
|
||||
result = validator(None, None, None)
|
||||
self.assertTrue(result.is_valid, result.msg)
|
||||
image.min_disk = flavor.disk * 2
|
||||
image["min_disk"] = flavor.disk * 2
|
||||
result = validator(None, None, None)
|
||||
self.assertFalse(result.is_valid, result.msg)
|
||||
image.min_disk = flavor.disk / 4
|
||||
image.size = 1000
|
||||
image["min_disk"] = flavor.disk / 4
|
||||
image["size"] = 1000
|
||||
result = validator(None, None, None)
|
||||
self.assertFalse(result.is_valid, result.msg)
|
||||
|
||||
@ -297,7 +331,7 @@ class ValidatorsTestCase(test.TestCase):
|
||||
clients = mock.MagicMock()
|
||||
clients.nova().flavors.get.side_effect = nova_exc.NotFound("")
|
||||
|
||||
image = mock.MagicMock()
|
||||
image = {"min_ram": 24, "id": "fake_id"}
|
||||
success = validation.ValidationResult(True)
|
||||
mock_get_image.return_value = (success, image)
|
||||
|
||||
@ -314,11 +348,11 @@ class ValidatorsTestCase(test.TestCase):
|
||||
}
|
||||
|
||||
# test ram
|
||||
image.min_ram = None
|
||||
image["min_ram"] = None
|
||||
result = validator(config, clients, None)
|
||||
self.assertTrue(result.is_valid, result.msg)
|
||||
|
||||
image.min_ram = 64
|
||||
image["min_ram"] = 64
|
||||
result = validator(config, clients, None)
|
||||
self.assertFalse(result.is_valid, result.msg)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user