[Heat] Pass parameters, files and env for heat stacks

Some heat templates can contain parameters, files and
environment dependencies that cannot be used with the current
scenario realization in rally. So the patch provides
"parameters", "files" and "environment" input parameters
in rally scenarios that allow to use these inputs
for stack create/update operations.

Change-Id: I6639d002a140659f677a6ed6f08b7741713a4e5f
This commit is contained in:
kairat_kushaev 2015-04-29 14:52:27 +03:00 committed by Kairat Kushaev
parent b1ee60eef2
commit a1b5aa7bc5
6 changed files with 186 additions and 37 deletions

View File

@ -353,3 +353,23 @@ class FileType(ResourceType):
with open(resource_config, "r") as f:
return f.read()
class FileTypeDict(ResourceType):
@classmethod
def transform(cls, clients, resource_config):
"""Returns the dictionary of items with file path and file content.
:param clients: openstack admin client handles
:param resource_config: list of file paths
:return: dictionary {file_path: file_content, ...}
"""
file_type_dict = {}
for file_path in resource_config:
with open(file_path, "r") as f:
file_type_dict[file_path] = f.read()
return file_type_dict

View File

@ -26,19 +26,23 @@ class HeatStacks(utils.HeatScenario):
RESOURCE_NAME_PREFIX = "rally_stack_"
RESOURCE_NAME_LENGTH = 7
@types.set(template_path=types.FileType)
@types.set(template_path=types.FileType, files=types.FileTypeDict)
@validation.required_services(consts.Service.HEAT)
@validation.required_openstack(users=True)
@base.scenario(context={"cleanup": ["heat"]})
def create_and_list_stack(self, template_path):
def create_and_list_stack(self, template_path, parameters=None,
files=None, environment=None):
"""Add a stack and then list all stacks.
Measure the "heat stack-create" and "heat stack-list" commands
performance.
:param template_path: path to stack template file
:param parameters: parameters to use in heat template
:param files: files used in template
:param environment: stack environment definition
"""
self._create_stack(template_path)
self._create_stack(template_path, parameters, files, environment)
self._list_stacks()
@validation.required_services(consts.Service.HEAT)
@ -53,27 +57,33 @@ class HeatStacks(utils.HeatScenario):
for stack in stacks:
self.clients("heat").resources.list(stack.id)
@types.set(template_path=types.FileType)
@types.set(template_path=types.FileType, files=types.FileTypeDict)
@validation.required_services(consts.Service.HEAT)
@validation.required_openstack(users=True)
@base.scenario(context={"cleanup": ["heat"]})
def create_and_delete_stack(self, template_path):
def create_and_delete_stack(self, template_path, parameters=None,
files=None, environment=None):
"""Add and then delete a stack.
Measure the "heat stack-create" and "heat stack-delete" commands
performance.
:param template_path: path to stack template file
:param parameters: parameters to use in heat template
:param files: files used in template
:param environment: stack environment definition
"""
stack = self._create_stack(template_path)
stack = self._create_stack(template_path, parameters,
files, environment)
self._delete_stack(stack)
@types.set(template_path=types.FileType)
@types.set(template_path=types.FileType, files=types.FileTypeDict)
@validation.required_services(consts.Service.HEAT)
@validation.required_openstack(users=True)
@base.scenario(context={"cleanup": ["heat"]})
def create_check_delete_stack(self, template_path):
def create_check_delete_stack(self, template_path, parameters=None,
files=None, environment=None):
"""Create, check and delete a stack.
Measure the performance of the following commands:
@ -82,18 +92,28 @@ class HeatStacks(utils.HeatScenario):
- heat stack-delete
:param template_path: path to stack template file
:param parameters: parameters to use in heat template
:param files: files used in template
:param environment: stack environment definition
"""
stack = self._create_stack(template_path)
stack = self._create_stack(template_path, parameters,
files, environment)
self._check_stack(stack)
self._delete_stack(stack)
@types.set(template_path=types.FileType,
updated_template_path=types.FileType)
updated_template_path=types.FileType,
files=types.FileTypeDict,
updated_files=types.FileTypeDict)
@validation.required_services(consts.Service.HEAT)
@validation.required_openstack(users=True)
@base.scenario(context={"cleanup": ["heat"]})
def create_update_delete_stack(self, template_path, updated_template_path):
def create_update_delete_stack(self, template_path,
updated_template_path,
parameters=None, updated_parameters=None,
files=None, updated_files=None,
environment=None, updated_environment=None):
"""Add, update and then delete a stack.
Measure the "heat stack-create", "heat stack-update"
@ -101,17 +121,32 @@ class HeatStacks(utils.HeatScenario):
:param template_path: path to stack template file
:param updated_template_path: path to updated stack template file
:param parameters: parameters to use in heat template
:param updated_parameters: parameters to use in updated heat template
If not specified then parameters will be
used instead
:param files: files used in template
:param updated_files: files used in updated template. If not specified
files value will be used instead
:param environment: stack environment definition
:param updated_environment: environment definition for updated stack
"""
stack = self._create_stack(template_path)
self._update_stack(stack, updated_template_path)
stack = self._create_stack(template_path, parameters,
files, environment)
self._update_stack(stack, updated_template_path,
updated_parameters or parameters,
updated_files or files,
updated_environment or environment)
self._delete_stack(stack)
@types.set(template_path=types.FileType)
@types.set(template_path=types.FileType, files=types.FileTypeDict)
@validation.required_services(consts.Service.HEAT)
@validation.required_openstack(users=True)
@base.scenario(context={"cleanup": ["heat"]})
def create_suspend_resume_delete_stack(self, template_path):
def create_suspend_resume_delete_stack(self, template_path,
parameters=None, files=None,
environment=None):
"""Create, suspend-resume and then delete a stack.
Measure performance of the following commands:
@ -121,9 +156,12 @@ class HeatStacks(utils.HeatScenario):
heat stack-delete
:param template_path: path to stack template file
:param parameters: parameters to use in heat template
:param files: files used in template
:param environment: stack environment definition
"""
s = self._create_stack(template_path)
s = self._create_stack(template_path, parameters, files, environment)
self._suspend_stack(s)
self._resume_stack(s)
self._delete_stack(s)

View File

@ -89,10 +89,14 @@ class HeatScenario(base.Scenario):
return list(self.clients("heat").stacks.list())
@base.atomic_action_timer("heat.create_stack")
def _create_stack(self, template):
def _create_stack(self, template, parameters=None,
files=None, environment=None):
"""Create a new stack.
:param template: template with stack description.
:param parameters: template parameters used during stack creation
:param files: additional files used in template
:param environment: stack environment definition
:returns: object of stack
"""
@ -100,10 +104,10 @@ class HeatScenario(base.Scenario):
kw = {
"stack_name": stack_name,
"disable_rollback": True,
"parameters": {},
"parameters": parameters or {},
"template": template,
"files": {},
"environment": {}
"files": files or {},
"environment": environment or {}
}
# heat client returns body instead manager object, so we should
@ -123,21 +127,26 @@ class HeatScenario(base.Scenario):
return stack
@base.atomic_action_timer("heat.update_stack")
def _update_stack(self, stack, template):
def _update_stack(self, stack, template, parameters=None,
files=None, environment=None):
"""Update an existing stack
:param stack: stack that need to be updated
:param template: Updated template
:param parameters: template parameters for stack update
:param files: additional files used in template
:param environment: stack environment definition
:returns: object of updated stack
"""
kw = {
"stack_name": stack.stack_name,
"disable_rollback": True,
"parameters": {},
"parameters": parameters or {},
"template": template,
"files": {},
"environment": {}
"files": files or {},
"environment": environment or {}
}
self.clients("heat").stacks.update(stack.id, **kw)

View File

@ -381,3 +381,25 @@ class FileTypeTestCase(test.TestCase):
types.FileType.transform,
clients=None,
resource_config=resource_config)
class FileTypeDictTestCase(test.TestCase):
@mock.patch("rally.benchmark.types.open",
side_effect=mock.mock_open(read_data="file_context"),
create=True)
def test_transform_by_path(self, mock_open):
resource_config = ["file.yaml"]
file_context = types.FileTypeDict.transform(
clients=None,
resource_config=resource_config)
self.assertEqual(file_context, {"file.yaml": "file_context"})
@mock.patch("rally.benchmark.types.open",
side_effect=IOError, create=True)
def test_transform_by_path_no_match(self, mock_open):
resource_config = ["nonexistant.yaml"]
self.assertRaises(IOError,
types.FileTypeDict.transform,
clients=None,
resource_config=resource_config)

View File

@ -26,6 +26,9 @@ class HeatStacksTestCase(test.TestCase):
def setUp(self):
super(HeatStacksTestCase, self).setUp()
self.default_template = "heat_template_version: 2013-05-23"
self.default_parameters = {"dummy_param": "dummy_key"}
self.default_files = ["dummy_file.yaml"]
self.default_environment = {"env": "dummy_env"}
@mock.patch(HEAT_STACKS + "._generate_random_name")
@mock.patch(HEAT_STACKS + "._list_stacks")
@ -35,8 +38,15 @@ class HeatStacksTestCase(test.TestCase):
heat_scenario = stacks.HeatStacks()
mock_random_name.return_value = "test-rally-stack"
heat_scenario.create_and_list_stack(
template_path=self.default_template)
mock_create.assert_called_once_with(self.default_template)
template_path=self.default_template,
parameters=self.default_parameters,
files=self.default_files,
environment=self.default_environment
)
mock_create.assert_called_once_with(self.default_template,
self.default_parameters,
self.default_files,
self.default_environment)
mock_list.assert_called_once_with()
@mock.patch(HEAT_STACKS + ".clients")
@ -71,9 +81,16 @@ class HeatStacksTestCase(test.TestCase):
mock_create.return_value = fake_stack
mock_random_name.return_value = "test-rally-stack"
heat_scenario.create_and_delete_stack(
template_path=self.default_template)
template_path=self.default_template,
parameters=self.default_parameters,
files=self.default_files,
environment=self.default_environment
)
mock_create.assert_called_once_with(self.default_template)
mock_create.assert_called_once_with(self.default_template,
self.default_parameters,
self.default_files,
self.default_environment)
mock_delete.assert_called_once_with(fake_stack)
@mock.patch(HEAT_STACKS + "._delete_stack")
@ -84,8 +101,15 @@ class HeatStacksTestCase(test.TestCase):
heat_scenario = stacks.HeatStacks()
mock_create.return_value = "fake_stack_create_check_delete"
heat_scenario.create_check_delete_stack(
template_path=self.default_template)
mock_create.assert_called_once_with(self.default_template)
template_path=self.default_template,
parameters=self.default_parameters,
files=self.default_files,
environment=self.default_environment
)
mock_create.assert_called_once_with(self.default_template,
self.default_parameters,
self.default_files,
self.default_environment)
mock_check.assert_called_once_with("fake_stack_create_check_delete")
mock_delete.assert_called_once_with("fake_stack_create_check_delete")
@ -101,10 +125,20 @@ class HeatStacksTestCase(test.TestCase):
mock_random_name.return_value = "test-rally-stack"
heat_scenario.create_update_delete_stack(
template_path=self.default_template,
updated_template_path=self.default_template)
parameters=self.default_parameters,
updated_template_path=self.default_template,
files=self.default_files,
environment=self.default_environment
)
mock_create.assert_called_once_with(self.default_template)
mock_update.assert_called_once_with(fake_stack, self.default_template)
mock_create.assert_called_once_with(self.default_template,
self.default_parameters,
self.default_files,
self.default_environment)
mock_update.assert_called_once_with(fake_stack, self.default_template,
self.default_parameters,
self.default_files,
self.default_environment)
mock_delete.assert_called_once_with(fake_stack)
@mock.patch(HEAT_STACKS + "._delete_stack")
@ -119,9 +153,16 @@ class HeatStacksTestCase(test.TestCase):
heat_scenario = stacks.HeatStacks()
mock_create.return_value = "fake_stack_create_suspend_resume_delete"
heat_scenario.create_suspend_resume_delete_stack(
template_path=self.default_template)
template_path=self.default_template,
parameters=self.default_parameters,
files=self.default_files,
environment=self.default_environment
)
mock_create.assert_called_once_with(self.default_template)
mock_create.assert_called_once_with(self.default_template,
self.default_parameters,
self.default_files,
self.default_environment)
mock_suspend.assert_called_once_with(
"fake_stack_create_suspend_resume_delete")
mock_resume.assert_called_once_with(

View File

@ -43,6 +43,9 @@ class HeatScenarioTestCase(test.TestCase):
self.useFixture(mockpatch.Patch("time.sleep"))
self.scenario = utils.HeatScenario()
self.default_template = "heat_template_version: 2013-05-23"
self.dummy_parameters = {"dummy_param": "dummy_key"}
self.dummy_files = ["dummy_file.yaml"]
self.dummy_environment = {"dummy_env": "dummy_env_value"}
@mock.patch(HEAT_UTILS + ".HeatScenario.clients")
def test_list_stacks(self, mock_clients):
@ -61,7 +64,15 @@ class HeatScenarioTestCase(test.TestCase):
}
mock_clients("heat").stacks.get.return_value = self.stack
scenario = utils.HeatScenario()
return_stack = scenario._create_stack(self.default_template)
return_stack = scenario._create_stack(self.default_template,
self.dummy_parameters,
self.dummy_files,
self.dummy_environment)
args, kwargs = mock_clients("heat").stacks.create.call_args
self.assertIn(self.dummy_parameters, kwargs.values())
self.assertIn(self.default_template, kwargs.values())
self.assertIn(self.dummy_files, kwargs.values())
self.assertIn(self.dummy_environment, kwargs.values())
self.wait_for.mock.assert_called_once_with(
self.stack,
update_resource=self.gfm(),
@ -77,7 +88,15 @@ class HeatScenarioTestCase(test.TestCase):
def test_update_stack(self, mock_clients):
mock_clients("heat").stacks.update.return_value = None
scenario = utils.HeatScenario()
scenario._update_stack(self.stack, self.default_template)
scenario._update_stack(self.stack, self.default_template,
self.dummy_parameters, self.dummy_files,
self.dummy_environment)
args, kwargs = mock_clients("heat").stacks.update.call_args
self.assertIn(self.dummy_parameters, kwargs.values())
self.assertIn(self.default_template, kwargs.values())
self.assertIn(self.dummy_files, kwargs.values())
self.assertIn(self.dummy_environment, kwargs.values())
self.assertIn(self.stack.id, args)
self.wait_for.mock.assert_called_once_with(
self.stack,
update_resource=self.gfm(),