Add allow/deny access scenario to Manila

Change-Id: I556fa2d51aa524d79503b85bfe2ae166113a5262
This commit is contained in:
Luis Pigueiras 2017-06-06 15:10:51 +02:00
parent 64fff2da8b
commit e79bd95966
10 changed files with 502 additions and 4 deletions

View File

@ -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

View File

@ -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}}:
-

View File

@ -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}}:
-

View File

@ -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."),
]}

View File

@ -233,6 +233,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"]},

View File

@ -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.

View File

@ -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
}
}
}
]
}

View File

@ -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

View File

@ -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"},

View File

@ -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()