diff --git a/etc/rally/rally.conf.sample b/etc/rally/rally.conf.sample index 332d823f32..7f9d4da3bf 100644 --- a/etc/rally/rally.conf.sample +++ b/etc/rally/rally.conf.sample @@ -48,6 +48,13 @@ # log_config_append is set. (boolean value) #use_syslog = false +# Enable journald for logging. If running in a systemd environment you +# may wish to enable journal support. Doing so will use the journal +# native protocol which includes structured metadata in addition to +# log messages.This option is ignored if log_config_append is set. +# (boolean value) +#use_journal = false + # Syslog facility to receive log lines. This option is ignored if # log_config_append is set. (string value) #syslog_log_facility = LOG_USER @@ -77,7 +84,7 @@ # List of package logging levels in logger=LEVEL pairs. This option is # ignored if log_config_append is set. (list value) -#default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN,taskflow=WARN,keystoneauth=WARN,oslo.cache=INFO,dogpile.core.dogpile=INFO +#default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,oslo_messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN,taskflow=WARN,keystoneauth=WARN,oslo.cache=INFO,dogpile.core.dogpile=INFO # Enables or disables publication of error events. (boolean value) #publish_errors = false @@ -267,6 +274,22 @@ # creation. (floating point value) #magnum_cluster_create_poll_interval = 1.0 +# Time(in sec) to wait for k8s pod to be created. (floating point +# value) +#k8s_pod_create_timeout = 600.0 + +# Time interval(in sec) between checks when waiting for k8s pod +# creation. (floating point value) +#k8s_pod_create_poll_interval = 1.0 + +# Time(in sec) to wait for k8s rc to be created. (floating point +# value) +#k8s_rc_create_timeout = 600.0 + +# Time interval(in sec) between checks when waiting for k8s rc +# creation. (floating point value) +#k8s_rc_create_poll_interval = 1.0 + # Delay between creating Manila share and polling for its status. # (floating point value) #manila_share_create_prepoll_delay = 2.0 @@ -285,6 +308,20 @@ # (floating point value) #manila_share_delete_poll_interval = 2.0 +# Timeout for Manila access creation. (floating point value) +#manila_access_create_timeout = 300.0 + +# Interval between checks when waiting for Manila access creation. +# (floating point value) +#manila_access_create_poll_interval = 3.0 + +# Timeout for Manila access deletion. (floating point value) +#manila_access_delete_timeout = 180.0 + +# Interval between checks when waiting for Manila access deletion. +# (floating point value) +#manila_access_delete_poll_interval = 2.0 + # mistral execution timeout (integer value) #mistral_execution_timeout = 200 @@ -516,6 +553,9 @@ # Nova volume detach poll interval (floating point value) #nova_detach_volume_poll_interval = 2.0 +# Enable or disable osprofiler to trace the scenarios (boolean value) +#enable_profiler = true + # A timeout in seconds for a cluster create operation (integer value) # Deprecated group/name - [benchmark]/cluster_create_timeout #sahara_cluster_create_timeout = 1800 @@ -580,8 +620,6 @@ # Neutron create loadbalancer poll interval (floating point value) #neutron_create_loadbalancer_poll_interval = 2.0 -# Enable or disable osprofiler to trace the scenarios -#enable_profiler = True [cleanup] @@ -626,6 +664,10 @@ # Example: mysql_sql_mode= (string value) #mysql_sql_mode = TRADITIONAL +# If True, transparently enables support for handling MySQL Cluster +# (NDB). (boolean value) +#mysql_enable_ndb = false + # Timeout before idle SQL connections are reaped. (integer value) # Deprecated group/name - [DEFAULT]/sql_idle_timeout # Deprecated group/name - [DATABASE]/sql_idle_timeout diff --git a/rally-jobs/rally-manila-no-ss.yaml b/rally-jobs/rally-manila-no-ss.yaml index 689e5298ce..bdf4a0491c 100644 --- a/rally-jobs/rally-manila-no-ss.yaml +++ b/rally-jobs/rally-manila-no-ss.yaml @@ -33,6 +33,29 @@ failure_rate: max: 0 + ManilaShares.create_share_then_allow_and_deny_access: + - + args: + share_proto: "nfs" + size: 1 + access: "127.0.0.1" + access_type: "ip" + runner: + type: "constant" + times: 2 + concurrency: 2 + context: + quotas: + manila: + shares: -1 + gigabytes: -1 + users: + tenants: 2 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + {% for s in ("create_and_delete_share", "create_and_list_share") %} ManilaShares.{{s}}: - diff --git a/rally-jobs/rally-manila.yaml b/rally-jobs/rally-manila.yaml index 500acfeec7..4a583bee78 100644 --- a/rally-jobs/rally-manila.yaml +++ b/rally-jobs/rally-manila.yaml @@ -88,6 +88,34 @@ failure_rate: max: 0 + ManilaShares.create_share_then_allow_and_deny_access: + - + args: + share_proto: "nfs" + size: 1 + share_type: "dhss_true" + access: "127.0.0.1" + access_type: "ip" + runner: + type: "constant" + times: 4 + concurrency: 4 + context: + quotas: + manila: + shares: -1 + gigabytes: -1 + share_networks: -1 + users: + tenants: 2 + users_per_tenant: 1 + user_choice_method: "round_robin" + manila_share_networks: + use_share_networks: True + sla: + failure_rate: + max: 0 + {% for s in ("create_and_delete_share", "create_and_list_share") %} ManilaShares.{{s}}: - diff --git a/rally/plugins/openstack/cfg/manila.py b/rally/plugins/openstack/cfg/manila.py index 4786601e87..71dc661a15 100644 --- a/rally/plugins/openstack/cfg/manila.py +++ b/rally/plugins/openstack/cfg/manila.py @@ -38,5 +38,23 @@ OPTS = {"benchmark": [ "manila_share_delete_poll_interval", default=2.0, help="Interval between checks when waiting for Manila share " - "deletion.") + "deletion."), + cfg.FloatOpt( + "manila_access_create_timeout", + default=300.0, + help="Timeout for Manila access creation."), + cfg.FloatOpt( + "manila_access_create_poll_interval", + default=3.0, + help="Interval between checks when waiting for Manila access " + "creation."), + cfg.FloatOpt( + "manila_access_delete_timeout", + default=180.0, + help="Timeout for Manila access deletion."), + cfg.FloatOpt( + "manila_access_delete_poll_interval", + default=2.0, + help="Interval between checks when waiting for Manila access " + "deletion."), ]} diff --git a/rally/plugins/openstack/scenarios/manila/shares.py b/rally/plugins/openstack/scenarios/manila/shares.py index c06a1b8e5d..4c02507858 100644 --- a/rally/plugins/openstack/scenarios/manila/shares.py +++ b/rally/plugins/openstack/scenarios/manila/shares.py @@ -241,6 +241,55 @@ class ListShareServers(utils.ManilaScenario): self._list_share_servers(search_opts=search_opts) +@validation.add("enum", param_name="share_proto", values=["nfs", "cephfs", + "cifs", "glusterfs", "hdfs"], missed=False, + case_insensitive=True) +@validation.required_services(consts.Service.MANILA) +@validation.required_openstack(users=True) +@scenario.configure( + context={"cleanup": ["manila"]}, + name="ManilaShares.create_share_then_allow_and_deny_access") +class CreateShareThenAllowAndDenyAccess(utils.ManilaScenario): + def run(self, share_proto, access_type, access, access_level="rw", size=1, + snapshot_id=None, description=None, metadata=None, + share_network=None, share_type=None, is_public=False, + availability_zone=None, share_group_id=None): + """Create a share and allow and deny access to it + + :param share_proto: share protocol for new share + available values are NFS, CIFS, CephFS, GlusterFS and HDFS. + :param access_type: represents the access type (e.g: 'ip', 'domain'...) + :param access: represents the object (e.g: '127.0.0.1'...) + :param access_level: access level to the share (e.g: 'rw', 'ro') + :param size: size in GiB + :param new_size: new size of the share in GiB + :param snapshot_id: ID of the snapshot + :param description: description of a share + :param metadata: optional metadata to set on share creation + :param share_network: either instance of ShareNetwork or text with ID + :param share_type: either instance of ShareType or text with ID + :param is_public: whether to set share as public or not. + :param availability_zone: availability zone of the share + :param share_group_id: ID of the share group to which the share + should belong + """ + share = self._create_share( + share_proto=share_proto, + size=size, + snapshot_id=snapshot_id, + description=description, + metadata=metadata, + share_network=share_network, + share_type=share_type, + is_public=is_public, + availability_zone=availability_zone, + share_group_id=share_group_id + ) + access_result = self._allow_access_share(share, access_type, access, + access_level) + self._deny_access_share(share, access_result["id"]) + + @validation.add("required_services", services=[consts.Service.MANILA]) @validation.add("required_platform", platform="openstack", users=True) @scenario.configure(context={"cleanup": ["manila"]}, diff --git a/rally/plugins/openstack/scenarios/manila/utils.py b/rally/plugins/openstack/scenarios/manila/utils.py index 407948d1ee..2aa435c3e3 100644 --- a/rally/plugins/openstack/scenarios/manila/utils.py +++ b/rally/plugins/openstack/scenarios/manila/utils.py @@ -86,6 +86,96 @@ class ManilaScenario(scenario.OpenStackScenario): timeout=CONF.benchmark.manila_share_delete_timeout, check_interval=CONF.benchmark.manila_share_delete_poll_interval) + def _get_access_from_share(self, share, access_id): + """Get access from share + + :param share: :class: `Share` + :param access_id: The id of the access we want to get + :returns: The access object from the share + :raises GetResourceNotFound: if the access is not in the share + """ + try: + return next(access for access in share.access_list() + if access.id == access_id) + except StopIteration: + raise exceptions.GetResourceNotFound(resource=access_id) + + def _update_resource_in_allow_access_share(self, share, access_id): + """Helper to update resource state in allow_access_share method + + :param share: :class:`Share` + :param access_id: id of the access + :returns: A function to be used in wait_for_status for the update + resource + """ + def _is_created(_): + return self._get_access_from_share(share, access_id) + + return _is_created + + @atomic.action_timer("manila.access_allow_share") + def _allow_access_share(self, share, access_type, access, access_level): + """Allow access to a share + + :param share: :class:`Share` + :param access_type: represents the access type (e.g: 'ip', 'domain'...) + :param access: represents the object (e.g: '127.0.0.1'...) + :param access_level: access level to the share (e.g: 'rw', 'ro') + """ + access_result = share.allow(access_type, access, access_level) + # Get access from the list of accesses of the share + access = next(access for access in share.access_list() + if access.id == access_result["id"]) + + fn = self._update_resource_in_allow_access_share(share, + access_result["id"]) + + # We check if the access in that access_list has the active state + utils.wait_for_status( + access, + ready_statuses=["active"], + update_resource=fn, + check_interval=CONF.benchmark.manila_access_create_poll_interval, + timeout=CONF.benchmark.manila_access_create_timeout) + + return access_result + + def _update_resource_in_deny_access_share(self, share, access_id): + """Helper to update resource state in deny_access_share method + + :param share: :class:`Share` + :param access_id: id of the access + :returns: A function to be used in wait_for_status for the update + resource + """ + def _is_deleted(_): + access = self._get_access_from_share(share, access_id) + return access + + return _is_deleted + + @atomic.action_timer("manila.access_deny_share") + def _deny_access_share(self, share, access_id): + """Deny access to a share + + :param share: :class:`Share` + :param access_id: id of the access to delete + """ + # Get the access element that was created in the first place + access = self._get_access_from_share(share, access_id) + share.deny(access_id) + + fn = self._update_resource_in_deny_access_share(share, + access_id) + + utils.wait_for_status( + access, + ready_statuses=["deleted"], + update_resource=fn, + check_deletion=True, + check_interval=CONF.benchmark.manila_access_delete_poll_interval, + timeout=CONF.benchmark.manila_access_delete_timeout) + @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-allow-and-deny-access.json b/samples/tasks/scenarios/manila/create-share-allow-and-deny-access.json new file mode 100644 index 0000000000..88f0578963 --- /dev/null +++ b/samples/tasks/scenarios/manila/create-share-allow-and-deny-access.json @@ -0,0 +1,34 @@ +{ + "ManilaShares.create_share_then_allow_and_deny_access": [ + { + "args": { + "share_proto": "nfs", + "size": 1, + "access": "127.0.0.1", + "access_type": "ip" + }, + "runner": { + "type": "constant", + "times": 2, + "concurrency": 2 + }, + "context": { + "quotas": { + "manila": { + "shares": -1, + "gigabytes": -1 + } + }, + "users": { + "tenants": 2, + "users_per_tenant": 1 + } + }, + "sla": { + "failure_rate": { + "max": 0 + } + } + } + ] +} diff --git a/samples/tasks/scenarios/manila/create-share-allow-and-deny-access.yaml b/samples/tasks/scenarios/manila/create-share-allow-and-deny-access.yaml new file mode 100644 index 0000000000..c98bac6079 --- /dev/null +++ b/samples/tasks/scenarios/manila/create-share-allow-and-deny-access.yaml @@ -0,0 +1,23 @@ +--- + ManilaShares.create_share_then_allow_and_deny_access: + - + args: + share_proto: "nfs" + size: 1 + access: "127.0.0.1" + access_type: "ip" + runner: + type: "constant" + times: 2 + concurrency: 2 + context: + quotas: + manila: + shares: -1 + gigabytes: -1 + users: + tenants: 2 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 diff --git a/tests/unit/plugins/openstack/scenarios/manila/test_shares.py b/tests/unit/plugins/openstack/scenarios/manila/test_shares.py index 0d51c2883e..a2d32cc55d 100644 --- a/tests/unit/plugins/openstack/scenarios/manila/test_shares.py +++ b/tests/unit/plugins/openstack/scenarios/manila/test_shares.py @@ -169,6 +169,71 @@ class ManilaSharesTestCase(test.ScenarioTestCase): ) scenario._shrink_share.assert_called_with(fake_share, new_size) + @ddt.data( + { + "share_proto": "nfs", + "size": 3, + "access": "127.0.0.1", + "access_type": "ip" + }, + { + "access": "1.2.3.4", + "access_type": "ip", + "access_level": "ro", + "share_proto": "cifs", + "size": 4, + "share_network": "foo", + "share_type": "bar", + "snapshot_id": "snapshot_foo", + "description": "foo_description", + "metadata": {"foo_metadata": "foo"}, + "share_network": "foo_network", + "share_type": "foo_type", + "is_public": True, + "availability_zone": "foo_avz", + "share_group_id": "foo_group_id" + } + ) + def test_create_share_and_allow_and_deny_access(self, params): + access = params["access"] + access_type = params["access_type"] + access_level = params.get("access_level", "rw") + size = params.get("size", 1) + share_group_id = params.get("share_group_id", None) + snapshot_id = params.get("snapshot_id", None) + description = params.get("description", None) + metadata = params.get("metadata", None) + share_network = params.get("share_network", None) + share_type = params.get("share_type", None) + is_public = params.get("is_public", False) + availability_zone = params.get("availability_zone", None) + fake_share = mock.MagicMock() + fake_access = {"id": "foo"} + + scenario = shares.CreateShareThenAllowAndDenyAccess(self.context) + scenario._create_share = mock.MagicMock(return_value=fake_share) + scenario._allow_access_share = mock.MagicMock(return_value=fake_access) + scenario._deny_access_share = mock.MagicMock() + + scenario.run(**params) + + scenario._create_share.assert_called_with( + share_proto=params["share_proto"], + size=size, + snapshot_id=snapshot_id, + description=description, + metadata=metadata, + share_network=share_network, + share_type=share_type, + is_public=is_public, + availability_zone=availability_zone, + share_group_id=share_group_id + ) + scenario._allow_access_share.assert_called_with( + fake_share, access_type, access, access_level) + scenario._deny_access_share.assert_called_with( + fake_share, fake_access["id"]) + @ddt.data( {}, {"description": "foo_description"}, diff --git a/tests/unit/plugins/openstack/scenarios/manila/test_utils.py b/tests/unit/plugins/openstack/scenarios/manila/test_utils.py index e425e21837..d4d48c1ffb 100644 --- a/tests/unit/plugins/openstack/scenarios/manila/test_utils.py +++ b/tests/unit/plugins/openstack/scenarios/manila/test_utils.py @@ -129,6 +129,132 @@ class ManilaScenarioTestCase(test.ScenarioTestCase): timeout=300, check_interval=3) self.mock_get_from_manager.mock.assert_called_once_with() + @ddt.data( + { + "access_type": "ip", + "access": "1.2.3.4", + "access_level": "rw", + "access_id": "foo" + }, + { + "access_type": "domain", + "access": "4.3.2.1", + "access_level": "ro", + "access_id": "bar" + } + ) + @ddt.unpack + def test__allow_access_share(self, access_type, access, access_level, + access_id): + fake_allow_result = {"id": access_id} + fake_access = mock.MagicMock() + fake_access.id = access_id + fake_update = mock.MagicMock() + self.scenario._update_resource_in_allow_access_share = mock.MagicMock( + return_value=fake_update) + + fake_share = mock.MagicMock() + fake_share.allow.return_value = fake_allow_result + fake_share.access_list.return_value = [fake_access] + + self.assertEqual(self.scenario._allow_access_share( + fake_share, access_type, access, access_level), fake_allow_result) + + self.scenario._update_resource_in_allow_access_share \ + .assert_called_with(fake_share, access_id) + self.mock_wait_for_status.mock.assert_called_once_with( + fake_access, + ready_statuses=["active"], + update_resource=fake_update, + check_interval=3.0, + timeout=300.0) + + def test__get_access_from_share_with_no_access_in_share(self): + access_id = "foo" + fake_share = mock.MagicMock() + fake_access = mock.MagicMock() + fake_access.id = access_id + fake_share.access_list.return_value = [] + + self.assertRaises(exceptions.GetResourceNotFound, + self.scenario._get_access_from_share, + fake_share, access_id) + + def test__get_access_from_share(self): + access_id = "foo" + fake_share = mock.MagicMock() + fake_access = mock.MagicMock() + fake_access.id = access_id + fake_share.access_list.return_value = [fake_access] + + access = self.scenario._get_access_from_share(fake_share, access_id) + + self.assertEqual(access, fake_access) + + def test__update_resource_in_allow_access_share(self): + access_id = "foo" + fake_share = mock.MagicMock() + fake_resource = mock.MagicMock() + fake_access = mock.MagicMock() + fake_access.id = access_id + fake_share.access_list.return_value = [fake_access] + + fn = self.scenario._update_resource_in_allow_access_share( + fake_share, access_id) + + self.assertEqual(fn(fake_resource), fake_access) + + def test__deny_access_share(self): + access_id = "foo" + fake_access = mock.MagicMock() + fake_access.id = access_id + fake_update = mock.MagicMock() + self.scenario._update_resource_in_deny_access_share = mock.MagicMock( + return_value=fake_update) + + fake_share = mock.MagicMock() + fake_share.access_list.return_value = [fake_access] + + self.scenario._deny_access_share(fake_share, access_id) + + self.scenario._update_resource_in_deny_access_share \ + .assert_called_with(fake_share, access_id) + + self.mock_wait_for_status.mock.assert_called_once_with( + fake_access, + check_deletion=True, + ready_statuses=["deleted"], + update_resource=fake_update, + check_interval=2.0, + timeout=180.0) + + def test__update_resource_in_deny_access_share(self): + access_id = "foo" + fake_share = mock.MagicMock() + fake_resource = mock.MagicMock() + fake_access = mock.MagicMock() + fake_access.id = access_id + fake_share.access_list.return_value = [fake_access] + + fn = self.scenario._update_resource_in_deny_access_share( + fake_share, access_id) + + assert fn(fake_resource) == fake_access + + def test__update_resource_in_deny_access_share_with_deleted_resource(self): + access_id = "foo" + fake_share = mock.MagicMock() + fake_resource = mock.MagicMock() + fake_access = mock.MagicMock() + fake_access.access_id = access_id + fake_share.access_list.return_value = [] + + fn = self.scenario._update_resource_in_deny_access_share( + fake_share, access_id) + + self.assertRaises(exceptions.GetResourceNotFound, + fn, fake_resource) + def test__create_share_network(self): fake_sn = mock.Mock() self.scenario.generate_random_name = mock.Mock()