Merge "Refactor ImageGenerator and validation"
This commit is contained in:
commit
8995027941
@ -894,6 +894,54 @@
|
|||||||
failure_rate:
|
failure_rate:
|
||||||
max: 0
|
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:
|
args:
|
||||||
flavor:
|
flavor:
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
from rally.benchmark.context import base
|
from rally.benchmark.context import base
|
||||||
from rally.benchmark.context.cleanup import manager as resource_manager
|
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.benchmark.scenarios.glance import utils as glance_utils
|
||||||
from rally.common.i18n import _
|
from rally.common.i18n import _
|
||||||
from rally.common import log as logging
|
from rally.common import log as logging
|
||||||
@ -44,6 +43,17 @@ class ImageGenerator(base.Context):
|
|||||||
"image_container": {
|
"image_container": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
|
"image_name": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"min_ram": { # megabytes
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"min_disk": { # gigabytes
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
"images_per_tenant": {
|
"images_per_tenant": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"minimum": 1
|
"minimum": 1
|
||||||
@ -63,20 +73,27 @@ class ImageGenerator(base.Context):
|
|||||||
image_type = self.config["image_type"]
|
image_type = self.config["image_type"]
|
||||||
image_container = self.config["image_container"]
|
image_container = self.config["image_container"]
|
||||||
images_per_tenant = self.config["images_per_tenant"]
|
images_per_tenant = self.config["images_per_tenant"]
|
||||||
|
image_name = self.config.get("image_name")
|
||||||
|
|
||||||
for user, tenant_id in rutils.iterate_per_tenants(
|
for user, tenant_id in rutils.iterate_per_tenants(
|
||||||
self.context["users"]):
|
self.context["users"]):
|
||||||
current_images = []
|
current_images = []
|
||||||
clients = osclients.Clients(user["endpoint"])
|
clients = osclients.Clients(user["endpoint"])
|
||||||
glance_util_class = glance_utils.GlanceScenario(
|
glance_scenario = glance_utils.GlanceScenario(
|
||||||
clients=clients)
|
clients=clients)
|
||||||
for i in range(images_per_tenant):
|
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 = glance_scenario._create_image(
|
||||||
image_container,
|
cur_name, image_container, image_url, image_type,
|
||||||
image_url,
|
min_ram=self.config.get("min_ram", 0),
|
||||||
image_type)
|
min_disk=self.config.get("min_disk", 0))
|
||||||
current_images.append(image.id)
|
current_images.append(image.id)
|
||||||
|
|
||||||
self.context["tenants"][tenant_id]["images"] = current_images
|
self.context["tenants"][tenant_id]["images"] = current_images
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
import functools
|
import functools
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
from glanceclient import exc as glance_exc
|
from glanceclient import exc as glance_exc
|
||||||
from novaclient import exceptions as nova_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):
|
def _get_validated_image(config, clients, param_name):
|
||||||
image_value = config.get("args", {}).get(param_name)
|
image_context = config.get("context", {}).get("images", {})
|
||||||
if not image_value:
|
image_args = config.get("args", {}).get(param_name)
|
||||||
msg = "Parameter %s is not specified." % 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)
|
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:
|
try:
|
||||||
image_id = types.ImageResourceType.transform(
|
image_id = types.ImageResourceType.transform(
|
||||||
clients=clients, resource_config=image_value)
|
clients=clients, resource_config=image_args)
|
||||||
image = clients.glance().images.get(image=image_id)
|
image = clients.glance().images.get(image=image_id).to_dict()
|
||||||
return (ValidationResult(True), image)
|
return (ValidationResult(True), image)
|
||||||
except (glance_exc.HTTPNotFound, exceptions.InvalidScenarioArgument):
|
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)
|
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:
|
if not valid_result.is_valid:
|
||||||
return valid_result
|
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 "
|
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)
|
return ValidationResult(False, message)
|
||||||
|
|
||||||
if flavor.disk:
|
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 "
|
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)
|
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 "
|
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)
|
return ValidationResult(False, message)
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ def print_list(objs, fields, formatters=None, sortby_index=0,
|
|||||||
if len(field_labels) != len(fields):
|
if len(field_labels) != len(fields):
|
||||||
raise ValueError(_("Field labels list %(labels)s has different number "
|
raise ValueError(_("Field labels list %(labels)s has different number "
|
||||||
"of elements than fields list %(fields)s"),
|
"of elements than fields list %(fields)s"),
|
||||||
{'labels': field_labels, 'fields': fields})
|
{"labels": field_labels, "fields": fields})
|
||||||
|
|
||||||
if sortby_index is None:
|
if sortby_index is None:
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
|
@ -44,6 +44,9 @@ class ImageGeneratorTestCase(test.TestCase):
|
|||||||
"image_type": "qcow2",
|
"image_type": "qcow2",
|
||||||
"image_container": "bare",
|
"image_container": "bare",
|
||||||
"images_per_tenant": 4,
|
"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_type": "qcow2",
|
||||||
"image_container": "bare",
|
"image_container": "bare",
|
||||||
"images_per_tenant": images_per_tenant,
|
"images_per_tenant": images_per_tenant,
|
||||||
|
"image_name": "some_name",
|
||||||
|
"min_ram": 128,
|
||||||
|
"min_disk": 1,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
@ -143,6 +149,9 @@ class ImageGeneratorTestCase(test.TestCase):
|
|||||||
"image_type": "qcow2",
|
"image_type": "qcow2",
|
||||||
"image_container": "bare",
|
"image_container": "bare",
|
||||||
"images_per_tenant": 5,
|
"images_per_tenant": 5,
|
||||||
|
"image_name": "some_name",
|
||||||
|
"min_ram": 128,
|
||||||
|
"min_disk": 1,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
|
@ -120,19 +120,47 @@ class ValidatorsTestCase(test.TestCase):
|
|||||||
result = validation._get_validated_image({}, None, "non_existing")
|
result = validation._get_validated_image({}, None, "non_existing")
|
||||||
self.assertFalse(result[0].is_valid, result[0].msg)
|
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")
|
@mock.patch("rally.benchmark.validation.types.ImageResourceType.transform")
|
||||||
def test__get_validated_image(self, mock_transform):
|
def test__get_validated_image(self, mock_transform):
|
||||||
mock_transform.return_value = "image_id"
|
mock_transform.return_value = "image_id"
|
||||||
clients = mock.MagicMock()
|
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")
|
clients, "a")
|
||||||
self.assertTrue(result[0].is_valid, result[0].msg)
|
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,
|
mock_transform.assert_called_once_with(clients=clients,
|
||||||
resource_config="test")
|
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")
|
@mock.patch("rally.benchmark.validation.types.ImageResourceType.transform")
|
||||||
def test__get_validated_image_transform_error(self, mock_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")
|
@mock.patch("rally.benchmark.validation.types.ImageResourceType.transform")
|
||||||
def test__get_validated_image_not_found(self, mock_transform):
|
def test__get_validated_image_not_found(self, mock_transform):
|
||||||
clients = mock.MagicMock()
|
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"}},
|
result = validation._get_validated_image({"args": {"a": "test"}},
|
||||||
clients, "a")
|
clients, "a")
|
||||||
self.assertFalse(result[0].is_valid, result[0].msg)
|
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_image")
|
||||||
@mock.patch("rally.benchmark.validation._get_validated_flavor")
|
@mock.patch("rally.benchmark.validation._get_validated_flavor")
|
||||||
def test_image_valid_on_flavor(self, mock_get_flavor, mock_get_image):
|
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()
|
flavor = mock.MagicMock()
|
||||||
success = validation.ValidationResult(True)
|
success = validation.ValidationResult(True)
|
||||||
mock_get_flavor.return_value = (success, flavor)
|
mock_get_flavor.return_value = (success, flavor)
|
||||||
@ -265,27 +299,27 @@ class ValidatorsTestCase(test.TestCase):
|
|||||||
# test ram
|
# test ram
|
||||||
flavor.disk = None
|
flavor.disk = None
|
||||||
flavor.ram = 2
|
flavor.ram = 2
|
||||||
image.min_ram = None
|
image["min_ram"] = None
|
||||||
result = validator(None, None, None)
|
result = validator(None, None, None)
|
||||||
self.assertTrue(result.is_valid, result.msg)
|
self.assertTrue(result.is_valid, result.msg)
|
||||||
image.min_ram = 4
|
image["min_ram"] = 4
|
||||||
result = validator(None, None, None)
|
result = validator(None, None, None)
|
||||||
self.assertFalse(result.is_valid, result.msg)
|
self.assertFalse(result.is_valid, result.msg)
|
||||||
image.min_ram = 1
|
image["min_ram"] = 1
|
||||||
result = validator(None, None, None)
|
result = validator(None, None, None)
|
||||||
self.assertTrue(result.is_valid, result.msg)
|
self.assertTrue(result.is_valid, result.msg)
|
||||||
|
|
||||||
# test disk (flavor.disk not None)
|
# test disk (flavor.disk not None)
|
||||||
image.size = 2
|
image["size"] = 2
|
||||||
image.min_disk = 0
|
image["min_disk"] = 0
|
||||||
flavor.disk = 5.0 / (1024 ** 3)
|
flavor.disk = 5.0 / (1024 ** 3)
|
||||||
result = validator(None, None, None)
|
result = validator(None, None, None)
|
||||||
self.assertTrue(result.is_valid, result.msg)
|
self.assertTrue(result.is_valid, result.msg)
|
||||||
image.min_disk = flavor.disk * 2
|
image["min_disk"] = flavor.disk * 2
|
||||||
result = validator(None, None, None)
|
result = validator(None, None, None)
|
||||||
self.assertFalse(result.is_valid, result.msg)
|
self.assertFalse(result.is_valid, result.msg)
|
||||||
image.min_disk = flavor.disk / 4
|
image["min_disk"] = flavor.disk / 4
|
||||||
image.size = 1000
|
image["size"] = 1000
|
||||||
result = validator(None, None, None)
|
result = validator(None, None, None)
|
||||||
self.assertFalse(result.is_valid, result.msg)
|
self.assertFalse(result.is_valid, result.msg)
|
||||||
|
|
||||||
@ -297,7 +331,7 @@ class ValidatorsTestCase(test.TestCase):
|
|||||||
clients = mock.MagicMock()
|
clients = mock.MagicMock()
|
||||||
clients.nova().flavors.get.side_effect = nova_exc.NotFound("")
|
clients.nova().flavors.get.side_effect = nova_exc.NotFound("")
|
||||||
|
|
||||||
image = mock.MagicMock()
|
image = {"min_ram": 24, "id": "fake_id"}
|
||||||
success = validation.ValidationResult(True)
|
success = validation.ValidationResult(True)
|
||||||
mock_get_image.return_value = (success, image)
|
mock_get_image.return_value = (success, image)
|
||||||
|
|
||||||
@ -314,11 +348,11 @@ class ValidatorsTestCase(test.TestCase):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# test ram
|
# test ram
|
||||||
image.min_ram = None
|
image["min_ram"] = None
|
||||||
result = validator(config, clients, None)
|
result = validator(config, clients, None)
|
||||||
self.assertTrue(result.is_valid, result.msg)
|
self.assertTrue(result.is_valid, result.msg)
|
||||||
|
|
||||||
image.min_ram = 64
|
image["min_ram"] = 64
|
||||||
result = validator(config, clients, None)
|
result = validator(config, clients, None)
|
||||||
self.assertFalse(result.is_valid, result.msg)
|
self.assertFalse(result.is_valid, result.msg)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user