From 51e61a5d6b3b6d196ef46f1c3afb11249004d0dd Mon Sep 17 00:00:00 2001 From: Valeriy Ponomaryov Date: Thu, 11 Jun 2015 17:36:25 +0300 Subject: [PATCH] [Manila] Add scenario for creation and deletion of Manila shares List of changes: - Added support of 'create' and 'delete' operations for shares. - Added benchmark for creating and deleting shares without usage of share networks. Change-Id: I48adb06140f70c5d18139726f5af6d7e1ab93a47 --- etc/rally/rally.conf.sample | 18 +++++ rally-jobs/rally-manila-no-ss.yaml | 23 ++++++ .../openstack/scenarios/manila/shares.py | 26 ++++++ .../openstack/scenarios/manila/utils.py | 81 +++++++++++++++++++ ...are-without-share-networks-and-delete.json | 29 +++++++ ...are-without-share-networks-and-delete.yaml | 20 +++++ .../openstack/scenarios/manila/test_shares.py | 18 +++++ .../openstack/scenarios/manila/test_utils.py | 47 +++++++++-- 8 files changed, 256 insertions(+), 6 deletions(-) create mode 100644 samples/tasks/scenarios/manila/create-share-without-share-networks-and-delete.json create mode 100644 samples/tasks/scenarios/manila/create-share-without-share-networks-and-delete.yaml diff --git a/etc/rally/rally.conf.sample b/etc/rally/rally.conf.sample index 1b5691db..498618c8 100644 --- a/etc/rally/rally.conf.sample +++ b/etc/rally/rally.conf.sample @@ -207,6 +207,24 @@ # (floating point value) #heat_stack_resume_poll_interval = 1.0 +# Delay between creating Manila share and polling for its status. +# (floating point value) +#manila_share_create_prepoll_delay = 2.0 + +# Timeout for Manila share creation. (floating point value) +#manila_share_create_timeout = 300.0 + +# Interval between checks when waiting for Manila share creation. +# (floating point value) +#manila_share_create_poll_interval = 3.0 + +# Timeout for Manila share deletion. (floating point value) +#manila_share_delete_timeout = 180.0 + +# Interval between checks when waiting for Manila share deletion. +# (floating point value) +#manila_share_delete_poll_interval = 2.0 + # Time to sleep after start before polling for status (floating point # value) #nova_server_start_prepoll_delay = 0.0 diff --git a/rally-jobs/rally-manila-no-ss.yaml b/rally-jobs/rally-manila-no-ss.yaml index c9037bd5..87073a9b 100644 --- a/rally-jobs/rally-manila-no-ss.yaml +++ b/rally-jobs/rally-manila-no-ss.yaml @@ -32,3 +32,26 @@ sla: failure_rate: max: 0 + + ManilaShares.create_and_delete_share: + - + args: + share_proto: "nfs" + size: 1 + min_sleep: 1 + max_sleep: 2 + runner: + type: "constant" + times: 4 + concurrency: 4 + context: + quotas: + manila: + shares: -1 + gigabytes: -1 + users: + tenants: 2 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 diff --git a/rally/plugins/openstack/scenarios/manila/shares.py b/rally/plugins/openstack/scenarios/manila/shares.py index e77390da..b32b0f8b 100644 --- a/rally/plugins/openstack/scenarios/manila/shares.py +++ b/rally/plugins/openstack/scenarios/manila/shares.py @@ -22,6 +22,32 @@ from rally.plugins.openstack.scenarios.manila import utils class ManilaShares(utils.ManilaScenario): """Benchmark scenarios for Manila shares.""" + @validation.validate_share_proto() + @validation.required_services(consts.Service.MANILA) + @validation.required_openstack(users=True) + @base.scenario(context={"cleanup": ["manila"]}) + def create_and_delete_share(self, share_proto, size=1, min_sleep=0, + max_sleep=0, **kwargs): + """Create and delete a share. + + Optional 'min_sleep' and 'max_sleep' parameters allow the scenario + to simulate a pause between share creation and deletion + (of random duration from [min_sleep, max_sleep]). + + :param share_proto: share protocol, valid values are NFS, CIFS, + GlusterFS and HDFS + :param size: share size in GB, should be greater than 0 + :param min_sleep: minimum sleep time in seconds (non-negative) + :param max_sleep: maximum sleep time in seconds (non-negative) + :param kwargs: optional args to create a share + """ + share = self._create_share( + share_proto=share_proto, + size=size, + **kwargs) + self.sleep_between(min_sleep, max_sleep) + self._delete_share(share) + @validation.required_services(consts.Service.MANILA) @validation.required_openstack(users=True) @base.scenario() diff --git a/rally/plugins/openstack/scenarios/manila/utils.py b/rally/plugins/openstack/scenarios/manila/utils.py index 8d4a3ff8..c03f4b90 100644 --- a/rally/plugins/openstack/scenarios/manila/utils.py +++ b/rally/plugins/openstack/scenarios/manila/utils.py @@ -13,12 +13,93 @@ # License for the specific language governing permissions and limitations # under the License. +import time + +from oslo_config import cfg + from rally.benchmark.scenarios import base +from rally.benchmark import utils as bench_utils + + +MANILA_BENCHMARK_OPTS = [ + cfg.FloatOpt( + "manila_share_create_prepoll_delay", + default=2.0, + help="Delay between creating Manila share and polling for its " + "status."), + cfg.FloatOpt( + "manila_share_create_timeout", + default=300.0, + help="Timeout for Manila share creation."), + cfg.FloatOpt( + "manila_share_create_poll_interval", + default=3.0, + help="Interval between checks when waiting for Manila share " + "creation."), + cfg.FloatOpt( + "manila_share_delete_timeout", + default=180.0, + help="Timeout for Manila share deletion."), + cfg.FloatOpt( + "manila_share_delete_poll_interval", + default=2.0, + help="Interval between checks when waiting for Manila share " + "deletion."), +] + +CONF = cfg.CONF +benchmark_group = cfg.OptGroup(name="benchmark", title="benchmark options") +CONF.register_opts(MANILA_BENCHMARK_OPTS, group=benchmark_group) class ManilaScenario(base.Scenario): """Base class for Manila scenarios with basic atomic actions.""" + @base.atomic_action_timer("manila.create_share") + def _create_share(self, share_proto, size=1, **kwargs): + """Create a share. + + :param share_proto: share protocol for new share, + available values are NFS, CIFS, GlusterFS and HDFS. + :param size: size of a share in GB + :param snapshot_id: ID of the snapshot + :param name: name of new share + :param description: description of a share + :param metadata: optional metadata to set on share creation + :param share_network: either instance of ShareNetwork or str with ID + :param share_type: either instance of ShareType or str with ID + :param is_public: defines whether to set share as public or not. + :returns: instance of :class:`Share` + """ + if not kwargs.get("name"): + kwargs["name"] = self._generate_random_name() + + share = self.clients("manila").shares.create( + share_proto, size, **kwargs) + time.sleep(CONF.benchmark.manila_share_create_prepoll_delay) + share = bench_utils.wait_for( + share, + is_ready=bench_utils.resource_is("available"), + update_resource=bench_utils.get_from_manager(), + timeout=CONF.benchmark.manila_share_create_timeout, + check_interval=CONF.benchmark.manila_share_create_poll_interval, + ) + return share + + @base.atomic_action_timer("manila.delete_share") + def _delete_share(self, share): + """Delete the given share. + + :param share: :class:`Share` + """ + share.delete() + error_statuses = ("error_deleting", ) + bench_utils.wait_for_delete( + share, + update_resource=bench_utils.get_from_manager(error_statuses), + timeout=CONF.benchmark.manila_share_delete_timeout, + check_interval=CONF.benchmark.manila_share_delete_poll_interval) + @base.atomic_action_timer("manila.list_shares") def _list_shares(self, detailed=True, search_opts=None): """Returns user shares list. diff --git a/samples/tasks/scenarios/manila/create-share-without-share-networks-and-delete.json b/samples/tasks/scenarios/manila/create-share-without-share-networks-and-delete.json new file mode 100644 index 00000000..b2ef639c --- /dev/null +++ b/samples/tasks/scenarios/manila/create-share-without-share-networks-and-delete.json @@ -0,0 +1,29 @@ +{ + "ManilaShares.create_and_delete_share": [ + { + "args": { + "share_proto": "nfs", + "size": 1, + "min_sleep": 1, + "max_sleep": 2 + }, + "runner": { + "type": "constant", + "times": 2, + "concurrency": 2 + }, + "context": { + "quotas": { + "manila": { + "shares": -1, + "gigabytes": -1 + } + }, + "users": { + "tenants": 2, + "users_per_tenant": 1 + } + } + } + ] +} diff --git a/samples/tasks/scenarios/manila/create-share-without-share-networks-and-delete.yaml b/samples/tasks/scenarios/manila/create-share-without-share-networks-and-delete.yaml new file mode 100644 index 00000000..ad68069f --- /dev/null +++ b/samples/tasks/scenarios/manila/create-share-without-share-networks-and-delete.yaml @@ -0,0 +1,20 @@ +--- + ManilaShares.create_and_delete_share: + - + args: + share_proto: "nfs" + size: 1 + min_sleep: 1 + max_sleep: 2 + runner: + type: "constant" + times: 2 + concurrency: 2 + context: + quotas: + manila: + shares: -1 + gigabytes: -1 + users: + tenants: 2 + users_per_tenant: 1 diff --git a/tests/unit/plugins/openstack/scenarios/manila/test_shares.py b/tests/unit/plugins/openstack/scenarios/manila/test_shares.py index 2fa6a898..418156fd 100644 --- a/tests/unit/plugins/openstack/scenarios/manila/test_shares.py +++ b/tests/unit/plugins/openstack/scenarios/manila/test_shares.py @@ -23,6 +23,24 @@ from tests.unit import test @ddt.ddt class ManilaSharesTestCase(test.TestCase): + @ddt.data( + {"share_proto": "nfs", "size": 3}, + {"share_proto": "cifs", "size": 4, + "share_network": "foo", "share_type": "bar"}, + ) + def test_create_and_delete_share(self, params): + fake_share = mock.MagicMock() + scenario = shares.ManilaShares() + scenario._create_share = mock.MagicMock(return_value=fake_share) + scenario.sleep_between = mock.MagicMock() + scenario._delete_share = mock.MagicMock() + + scenario.create_and_delete_share(min_sleep=3, max_sleep=4, **params) + + scenario._create_share.assert_called_once_with(**params) + scenario.sleep_between.assert_called_once_with(3, 4) + scenario._delete_share.assert_called_once_with(fake_share) + @ddt.data( {}, {"detailed": True}, diff --git a/tests/unit/plugins/openstack/scenarios/manila/test_utils.py b/tests/unit/plugins/openstack/scenarios/manila/test_utils.py index 0c7b99c9..7d1a6dc8 100644 --- a/tests/unit/plugins/openstack/scenarios/manila/test_utils.py +++ b/tests/unit/plugins/openstack/scenarios/manila/test_utils.py @@ -19,30 +19,65 @@ import mock from rally.plugins.openstack.scenarios.manila import utils from tests.unit import test -MANILA_UTILS = "rally.plugins.openstack.scenarios.manila.utils.ManilaScenario." +BM_UTILS = "rally.benchmark.utils." @ddt.ddt -class ManilaScenarioTestCase(test.TestCase): +class ManilaScenarioTestCase(test.ClientsTestCase): def setUp(self): super(ManilaScenarioTestCase, self).setUp() self.scenario = utils.ManilaScenario() + @mock.patch("time.sleep") + @mock.patch(BM_UTILS + "wait_for") + @mock.patch(BM_UTILS + "get_from_manager") + @mock.patch(BM_UTILS + "resource_is") + def test__create_share(self, mock_resource_is, mock_get_from_manager, + mock_wait_for, mock_sleep): + fake_name = "fake_name" + fake_share = mock.Mock() + self.clients("manila").shares.create.return_value = fake_share + self.scenario._generate_random_name = mock.Mock(return_value=fake_name) + + self.scenario._create_share("nfs") + + self.clients("manila").shares.create.assert_called_once_with( + "nfs", 1, name=fake_name) + + mock_wait_for.assert_called_once_with( + fake_share, is_ready=mock.ANY, update_resource=mock.ANY, + timeout=300, check_interval=3) + mock_resource_is.assert_called_once_with("available") + mock_get_from_manager.assert_called_once_with() + self.assertTrue(mock_sleep.called) + + @mock.patch(BM_UTILS + "get_from_manager") + @mock.patch(BM_UTILS + "wait_for_delete") + def test__delete_share(self, mock_wait_for_delete, mock_get_from_manager): + fake_share = mock.MagicMock() + + self.scenario._delete_share(fake_share) + + fake_share.delete.assert_called_once_with() + mock_get_from_manager.assert_called_once_with(("error_deleting", )) + mock_wait_for_delete.assert_called_once_with( + fake_share, update_resource=mock.ANY, timeout=180, + check_interval=2) + @ddt.data( {}, {"detailed": False, "search_opts": None}, {"detailed": True, "search_opts": {"name": "foo_sn"}}, {"search_opts": {"project_id": "fake_project"}}, ) - @mock.patch(MANILA_UTILS + "clients") - def test__list_shares(self, params, mock_clients): + def test__list_shares(self, params): fake_shares = ["foo", "bar"] - mock_clients.return_value.shares.list.return_value = fake_shares + self.clients("manila").shares.list.return_value = fake_shares result = self.scenario._list_shares(**params) self.assertEqual(fake_shares, result) - mock_clients.return_value.shares.list.assert_called_once_with( + self.clients("manila").shares.list.assert_called_once_with( detailed=params.get("detailed", True), search_opts=params.get("search_opts", None))