diff --git a/doc/samples/tasks/scenarios/sahara/create_and_list_node_group_templates.json b/doc/samples/tasks/scenarios/sahara/create_and_list_node_group_templates.json new file mode 100644 index 0000000000..fd5ebc3481 --- /dev/null +++ b/doc/samples/tasks/scenarios/sahara/create_and_list_node_group_templates.json @@ -0,0 +1,22 @@ +{ + "SaharaNodeGroupTemplates.create_and_list_node_group_templates": [ + { + "args": { + "flavor": { + "name": "m1.small" + } + }, + "runner": { + "type": "constant", + "times": 100, + "concurrency": 10 + }, + "context": { + "users": { + "tenants": 1, + "users_per_tenant": 1 + } + } + } + ] +} \ No newline at end of file diff --git a/doc/samples/tasks/scenarios/sahara/create_and_list_node_group_templates.yaml b/doc/samples/tasks/scenarios/sahara/create_and_list_node_group_templates.yaml new file mode 100644 index 0000000000..2b69b8c885 --- /dev/null +++ b/doc/samples/tasks/scenarios/sahara/create_and_list_node_group_templates.yaml @@ -0,0 +1,14 @@ +--- + SaharaNodeGroupTemplates.create_and_list_node_group_templates: + - + args: + flavor: + name: "m1.small" + runner: + type: "constant" + times: 100 + concurrency: 10 + context: + users: + tenants: 1 + users_per_tenant: 1 diff --git a/doc/samples/tasks/scenarios/sahara/create_delete_node_group_templates.json b/doc/samples/tasks/scenarios/sahara/create_delete_node_group_templates.json new file mode 100644 index 0000000000..3af8c15362 --- /dev/null +++ b/doc/samples/tasks/scenarios/sahara/create_delete_node_group_templates.json @@ -0,0 +1,22 @@ +{ + "SaharaNodeGroupTemplates.create_delete_node_group_templates": [ + { + "args": { + "flavor": { + "name": "m1.small" + } + }, + "runner": { + "type": "constant", + "times": 100, + "concurrency": 10 + }, + "context": { + "users": { + "tenants": 1, + "users_per_tenant": 1 + } + } + } + ] +} \ No newline at end of file diff --git a/doc/samples/tasks/scenarios/sahara/create_delete_node_group_templates.yaml b/doc/samples/tasks/scenarios/sahara/create_delete_node_group_templates.yaml new file mode 100644 index 0000000000..960bd74cd2 --- /dev/null +++ b/doc/samples/tasks/scenarios/sahara/create_delete_node_group_templates.yaml @@ -0,0 +1,14 @@ +--- + SaharaNodeGroupTemplates.create_delete_node_group_templates: + - + args: + flavor: + name: "m1.small" + runner: + type: "constant" + times: 100 + concurrency: 10 + context: + users: + tenants: 1 + users_per_tenant: 1 diff --git a/rally-scenarios/rally.yaml b/rally-scenarios/rally.yaml index 5bfc05c5f2..1985e4b34e 100644 --- a/rally-scenarios/rally.yaml +++ b/rally-scenarios/rally.yaml @@ -331,6 +331,34 @@ tenants: 2 users_per_tenant: 10 + SaharaNodeGroupTemplates.create_and_list_node_group_templates: + - + args: + flavor: + name: "m1.small" + runner: + type: "constant" + times: 100 + concurrency: 10 + context: + users: + tenants: 1 + users_per_tenant: 1 + + SaharaNodeGroupTemplates.create_delete_node_group_templates: + - + args: + flavor: + name: "m1.small" + runner: + type: "constant" + times: 100 + concurrency: 10 + context: + users: + tenants: 1 + users_per_tenant: 1 + Authenticate.validate_cinder: - args: diff --git a/rally/benchmark/scenarios/sahara/__init__.py b/rally/benchmark/scenarios/sahara/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/rally/benchmark/scenarios/sahara/node_group_templates.py b/rally/benchmark/scenarios/sahara/node_group_templates.py new file mode 100644 index 0000000000..d6915f3a18 --- /dev/null +++ b/rally/benchmark/scenarios/sahara/node_group_templates.py @@ -0,0 +1,92 @@ +# Copyright 2014: Mirantis Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from rally.benchmark.scenarios import base +from rally.benchmark.scenarios.sahara import utils +from rally.benchmark import types +from rally.benchmark import validation +from rally import consts + + +class SaharaNodeGroupTemplates(utils.SaharaScenario): + + @types.set(flavor=types.FlavorResourceType) + @validation.add(validation.flavor_exists('flavor')) + @base.scenario(context={"cleanup": ["sahara"]}) + @validation.required_services(consts.Service.SAHARA) + def create_and_list_node_group_templates(self, flavor, + plugin_name="vanilla", + hadoop_version="1.2.1"): + """Test the sahara Node Group Templates create and list commands. + + This scenario creates two Node Group Templates with different set of + node processes. The master Node Group Template contains Hadoop's + management processes. The worker Node Group Template contains + Haddop's worker processes. + + By default the templates are created for the vanilla Hadoop + provisioning plugin using the version 1.2.1 + + After the templates are created the list operation is called. + + :param flavor: The Nova flavor that will be for nodes in the + created node groups + :param plugin_name: The name of a provisioning plugin + :param hadoop_version: The version of Hadoop distribution supported by + the specified plugin. + """ + + self._create_master_node_group_template(flavor_id=flavor, + plugin_name=plugin_name, + hadoop_version=hadoop_version) + self._create_worker_node_group_template(flavor_id=flavor, + plugin_name=plugin_name, + hadoop_version=hadoop_version) + self._list_node_group_templates() + + @types.set(flavor=types.FlavorResourceType) + @validation.add(validation.flavor_exists('flavor')) + @base.scenario(context={"cleanup": ["sahara"]}) + @validation.required_services(consts.Service.SAHARA) + def create_delete_node_group_templates(self, flavor, + plugin_name="vanilla", + hadoop_version="1.2.1"): + """Test create and delete commands. + + This scenario creates and deletes two most common types of + Node Group Templates. + + By default the templates are created for the vanilla Hadoop + provisioning plugin using the version 1.2.1 + + :param flavor: The Nova flavor that will be for nodes in the + created node groups + :param plugin_name: The name of a provisioning plugin + :param hadoop_version: The version of Hadoop distribution supported by + the specified plugin. + """ + + master_ngt = self._create_master_node_group_template( + flavor_id=flavor, + plugin_name=plugin_name, + hadoop_version=hadoop_version) + + worker_ngt = self._create_worker_node_group_template( + flavor_id=flavor, + plugin_name=plugin_name, + hadoop_version=hadoop_version) + + self._delete_node_group_template(master_ngt) + self._delete_node_group_template(worker_ngt) \ No newline at end of file diff --git a/rally/benchmark/scenarios/sahara/utils.py b/rally/benchmark/scenarios/sahara/utils.py new file mode 100644 index 0000000000..d0a86ee288 --- /dev/null +++ b/rally/benchmark/scenarios/sahara/utils.py @@ -0,0 +1,98 @@ +# Copyright 2014: Mirantis Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from rally.benchmark.scenarios import base +from rally.benchmark.scenarios import utils + + +class SaharaScenario(base.Scenario): + + RESOURCE_NAME_LENGTH = 20 + + # TODO(nkonovalov): Add other provisioning plugins + NODE_PROCESSES = { + "vanilla": { + "1.2.1": { + "master": ["namenode", "jobtracker"], + "worker": ["datanode", "tasktracker"] + }, + "2.3.0": { + "master": ["namenode", "resourcemanager", "historyserver"], + "worker": ["datanode", "nodemanager"] + } + } + } + + @utils.atomic_action_timer('sahara.list_node_group_templates') + def _list_node_group_templates(self): + """Returns user Node Group Templates list.""" + + return self.clients("sahara").node_group_templates.list() + + @utils.atomic_action_timer( + 'sahara.create_master_node_group_template') + def _create_master_node_group_template(self, flavor_id, plugin_name, + hadoop_version): + """Creates a master Node Group Template with a random name. + + :param flavor_id: The required argument for the Template + :param plugin_name: Sahara provisioning plugin name + :param hadoop_version: The version of Hadoop distribution supported by + the plugin + :return: The created Template + """ + + name = self._generate_random_name(prefix="master-ngt-") + + return self.clients("sahara").node_group_templates.create( + name=name, + plugin_name=plugin_name, + hadoop_version=hadoop_version, + flavor_id=flavor_id, + node_processes=self.NODE_PROCESSES[plugin_name][hadoop_version] + ["master"]) + + @utils.atomic_action_timer( + 'sahara.create_worker_node_group_template') + def _create_worker_node_group_template(self, flavor_id, plugin_name, + hadoop_version): + """Creates a worker Node Group Template with a random name. + + :param flavor_id: The required argument for the Template + :param plugin_name: Sahara provisioning plugin name + :param hadoop_version: The version of Hadoop distribution supported by + the plugin + :return: The created Template + """ + + name = self._generate_random_name(prefix="worker-ngt-") + + return self.clients("sahara").node_group_templates.create( + name=name, + plugin_name=plugin_name, + hadoop_version=hadoop_version, + flavor_id=flavor_id, + node_processes=self.NODE_PROCESSES[plugin_name][hadoop_version] + ["worker"]) + + @utils.atomic_action_timer('sahara.delete_node_group_template') + def _delete_node_group_template(self, node_group): + """Deletes a Node Group Template by id. + + :param node_group: The Node Group Template to be deleted + :return: + """ + + self.clients("sahara").node_group_templates.delete(node_group.id) diff --git a/rally/consts.py b/rally/consts.py index d100ff849f..6694ef6812 100644 --- a/rally/consts.py +++ b/rally/consts.py @@ -90,6 +90,7 @@ class _Service(utils.ImmutableMixin, utils.EnumMixin): CEILOMETER = "ceilometer" S3 = "s3" TROVE = "trove" + SAHARA = "sahara" class _ServiceType(utils.ImmutableMixin, utils.EnumMixin): @@ -108,6 +109,7 @@ class _ServiceType(utils.ImmutableMixin, utils.EnumMixin): METERING = "metering" S3 = "s3" DATABASE = "database" + DATA_PROCESSING = "data_processing" def __init__(self): self.__names = { @@ -123,7 +125,8 @@ def __init__(self): self.NETWORK: _Service.NEUTRON, self.METERING: _Service.CEILOMETER, self.S3: _Service.S3, - self.DATABASE: _Service.TROVE + self.DATABASE: _Service.TROVE, + self.DATA_PROCESSING: _Service.SAHARA } def __getitem__(self, service_type): diff --git a/tests/benchmark/scenarios/sahara/__init__.py b/tests/benchmark/scenarios/sahara/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/benchmark/scenarios/sahara/test_node_group_templates.py b/tests/benchmark/scenarios/sahara/test_node_group_templates.py new file mode 100644 index 0000000000..f5ca768058 --- /dev/null +++ b/tests/benchmark/scenarios/sahara/test_node_group_templates.py @@ -0,0 +1,77 @@ +# Copyright 2014: Mirantis Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import mock + +from rally.benchmark.scenarios.sahara import node_group_templates as ngts +from tests import test + +SAHARA_NGTS = ("rally.benchmark.scenarios.sahara.node_group_templates" + ".SaharaNodeGroupTemplates") + + +class SaharaNodeGroupTemplatesTestCase(test.TestCase): + + @mock.patch(SAHARA_NGTS + "._list_node_group_templates") + @mock.patch(SAHARA_NGTS + "._create_master_node_group_template", + return_value=object()) + @mock.patch(SAHARA_NGTS + "._create_worker_node_group_template", + return_value=object) + def test_create_and_list_node_group_templates(self, mock_create_worker, + mock_create_master, + mock_list): + + ngts_scenario = ngts.SaharaNodeGroupTemplates() + ngts_scenario.create_and_list_node_group_templates("test_flavor", + "test_plugin", + "test_version") + + mock_create_master.assert_called_once_with( + flavor_id="test_flavor", + plugin_name="test_plugin", + hadoop_version="test_version") + mock_create_worker.assert_called_once_with( + flavor_id="test_flavor", + plugin_name="test_plugin", + hadoop_version="test_version") + mock_list.assert_called_once_with() + + @mock.patch(SAHARA_NGTS + "._delete_node_group_template") + @mock.patch(SAHARA_NGTS + "._create_master_node_group_template", + return_value=mock.MagicMock(id=1)) + @mock.patch(SAHARA_NGTS + "._create_worker_node_group_template", + return_value=mock.MagicMock(id=2)) + def test_create_delete_node_group_templates(self, mock_create_worker, + mock_create_master, + mock_delete): + + ngts_scenario = ngts.SaharaNodeGroupTemplates() + ngts_scenario.create_delete_node_group_templates( + "test_flavor", + "test_plugin", + "test_version") + + mock_create_master.assert_called_once_with( + flavor_id="test_flavor", + plugin_name="test_plugin", + hadoop_version="test_version") + mock_create_worker.assert_called_once_with( + flavor_id="test_flavor", + plugin_name="test_plugin", + hadoop_version="test_version") + + mock_delete.assert_has_calls(calls=[ + mock.call(mock_create_master.return_value), + mock.call(mock_create_worker.return_value)]) \ No newline at end of file diff --git a/tests/benchmark/scenarios/sahara/test_utils.py b/tests/benchmark/scenarios/sahara/test_utils.py new file mode 100644 index 0000000000..9555a2b800 --- /dev/null +++ b/tests/benchmark/scenarios/sahara/test_utils.py @@ -0,0 +1,110 @@ +# Copyright 2014: Mirantis Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import mock + +from rally.benchmark.scenarios.sahara import utils +from tests.benchmark.scenarios import test_utils +from tests import test + + +SAHARA_UTILS = 'rally.benchmark.scenarios.sahara.utils' + + +class SaharaNodeGroupTemplatesScenarioTestCase(test.TestCase): + + def _test_atomic_action_timer(self, atomic_actions, name): + action_duration = test_utils.get_atomic_action_timer_value_by_name( + atomic_actions, name) + self.assertIsNotNone(action_duration) + self.assertIsInstance(action_duration, float) + + @mock.patch(SAHARA_UTILS + '.SaharaScenario.clients') + def test_list_node_group_templates(self, mock_clients): + ngts = [] + mock_clients("sahara").node_group_templates.list.return_value = ngts + + scenario = utils.SaharaScenario() + return_ngts_list = scenario._list_node_group_templates() + + self.assertEqual(ngts, return_ngts_list) + self._test_atomic_action_timer(scenario.atomic_actions(), + 'sahara.list_node_group_templates') + + @mock.patch(SAHARA_UTILS + '.SaharaScenario._generate_random_name', + return_value="random_name") + @mock.patch(SAHARA_UTILS + '.SaharaScenario.clients') + def test_create_node_group_templates(self, mock_clients, mock_random_name): + + scenario = utils.SaharaScenario() + mock_processes = { + "test_plugin": { + "test_version": { + "master": ["p1"], + "worker": ["p2"] + } + } + } + + scenario.NODE_PROCESSES = mock_processes + + scenario._create_master_node_group_template( + flavor_id="test_flavor", + plugin_name="test_plugin", + hadoop_version="test_version" + ) + scenario._create_worker_node_group_template( + flavor_id="test_flavor", + plugin_name="test_plugin", + hadoop_version="test_version" + ) + + create_calls = [ + mock.call( + name="random_name", + plugin_name="test_plugin", + hadoop_version="test_version", + flavor_id="test_flavor", + node_processes=["p1"]), + mock.call( + name="random_name", + plugin_name="test_plugin", + hadoop_version="test_version", + flavor_id="test_flavor", + node_processes=["p2"] + )] + mock_clients("sahara").node_group_templates.create.assert_has_calls( + create_calls) + + self._test_atomic_action_timer( + scenario.atomic_actions(), + 'sahara.create_master_node_group_template') + self._test_atomic_action_timer( + scenario.atomic_actions(), + 'sahara.create_worker_node_group_template') + + @mock.patch(SAHARA_UTILS + '.SaharaScenario.clients') + def test_delete_node_group_templates(self, mock_clients): + + scenario = utils.SaharaScenario() + ng = mock.MagicMock(id=42) + + scenario._delete_node_group_template(ng) + + delete_mock = mock_clients("sahara").node_group_templates.delete + delete_mock.assert_called_once_with(42) + + self._test_atomic_action_timer(scenario.atomic_actions(), + 'sahara.delete_node_group_template')