Merge "Add 'fixed ips' APIs policy tests"
diff --git a/doc/source/conf.py b/doc/source/conf.py
index ddb1d45..88c1bea 100755
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -22,10 +22,15 @@
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'sphinx.ext.autodoc',
- #'sphinx.ext.intersphinx',
- 'openstackdocstheme'
+ 'sphinx.ext.todo',
+ 'sphinx.ext.viewcode',
+ 'openstackdocstheme',
+ 'oslo_config.sphinxconfiggen',
]
+config_generator_config_file = '../../etc/config-generator.patrole.conf'
+sample_config_basename = '_static/patrole'
+
# autodoc generation is a bit aggressive and a nuisance when doing heavy
# text edit cycles.
# execute "export SPHINX_DEBUG=1" in your terminal to disable
@@ -55,7 +60,7 @@
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
# html_theme_path = ["."]
-# html_static_path = ['static']
+html_static_path = ['_static']
html_theme = 'openstackdocs'
# openstackdocstheme options
diff --git a/doc/source/sampleconf.rst b/doc/source/sampleconf.rst
index 94ebc4d..ee848b5 100644
--- a/doc/source/sampleconf.rst
+++ b/doc/source/sampleconf.rst
@@ -3,49 +3,16 @@
Sample Configuration File
==========================
-The following is a sample Patrole configuration for adaptation and use.
+The following is a sample Patrole configuration for adaptation and use. It is
+auto-generated from Patrole when this documentation is built, so
+if you are having issues with an option, please compare your version of
+Patrole with the version of this documentation.
-.. code-block:: ini
+Note that the Patrole configuration options actually live inside the Tempest
+configuration file; at runtime, Tempest populates its own configuration
+file with Patrole groups and options, assuming that Patrole is correctly
+installed and recognized as a plugin.
- [patrole]
+The sample configuration can also be viewed in `file form <_static/patrole.conf.sample>`_.
- # The role that you want the RBAC tests to use for RBAC testing
- # This needs to be edited to run the test as a different role.
- rbac_test_role = Member
-
- # Enables RBAC Tempest tests if set to True. Otherwise, they are
- # skipped.
- enable_rbac = True
-
- # If set to True, tests throw a RbacParsingException for policies
- # not found in the policy file. Otherwise, they throw a skipException.
- strict_policy_check = False
-
- # List of the paths to search for policy files. Each policy path assumes that
- # the service name is included in the path once. Also assumes Patrole is on the
- # same host as the policy files. The paths should be ordered by precedence,
- # with high-priority paths before low-priority paths. The first path that is
- # found to contain the service's policy file will be used.
- custom_policy_files = /etc/nova/policy.json,/etc/neutron/policy.json
-
- # This option determines whether Patrole should run against a
- # `custom_requirements_file` which defines RBAC requirements. The
- # purpose of setting this flag to True is to verify that RBAC policy
- # is in accordance to requirements. The idea is that the
- # `custom_requirements_file` perfectly defines what the RBAC requirements
- # are.
- test_custom_requirements = False
-
- # File path of the yaml file that defines your RBAC requirements. This
- # file must be located on the same host that Patrole runs on. The yaml
- # file should be written as follows:
- custom_requirements_file = patrole/requirements.txt
-
- # DEPRECATED: The following config options set the location of the service's
- # policy file. For services that have their policy in code (e.g., Nova),
- # this would be the location of a custom policy.json, if one exists.
- cinder_policy_file = /etc/cinder/policy.json
- glance_policy_file = /etc/glance/policy.json
- keystone_policy_file = /etc/keystone/policy.json
- neutron_policy_file = /etc/neutron/policy.json
- nova_policy_file = /etc/nova/policy.json
+.. literalinclude:: _static/patrole.conf.sample
diff --git a/etc/config-generator.patrole.conf b/etc/config-generator.patrole.conf
new file mode 100644
index 0000000..8988ae0
--- /dev/null
+++ b/etc/config-generator.patrole.conf
@@ -0,0 +1,3 @@
+[DEFAULT]
+output_file = etc/patrole.conf.sample
+namespace = patrole.config
diff --git a/etc/patrole.conf.sample b/etc/patrole.conf.sample
new file mode 100644
index 0000000..370ca8d
--- /dev/null
+++ b/etc/patrole.conf.sample
@@ -0,0 +1,276 @@
+[DEFAULT]
+
+
+[patrole]
+
+#
+# From patrole.config
+#
+
+# The current RBAC role against which to run Patrole
+# tests. (string value)
+#rbac_test_role = admin
+
+# Enables RBAC tests. (boolean value)
+#enable_rbac = true
+
+# If true, throws RbacParsingException for policies which
+# don't exist or are not included in the service's policy file. If
+# false, throws
+# skipException. (boolean value)
+#strict_policy_check = false
+
+# List of the paths to search for policy files. Each
+# policy path assumes that the service name is included in the path
+# once. Also
+# assumes Patrole is on the same host as the policy files. The paths
+# should be
+# ordered by precedence, with high-priority paths before low-priority
+# paths. The
+# first path that is found to contain the service's policy file will
+# be used.
+# (list value)
+#custom_policy_files = /etc/%s/policy.json
+
+# DEPRECATED: Location of the Cinder policy file. Assumed to be on
+# the same host as Patrole. (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: It is better to use `custom_policy_files` which supports any
+# OpenStack service.
+#cinder_policy_file = /etc/cinder/policy.json
+
+# DEPRECATED: Location of the Glance policy file. Assumed to be on
+# the same host as Patrole. (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: It is better to use `custom_policy_files` which supports any
+# OpenStack service.
+#glance_policy_file = /etc/glance/policy.json
+
+# DEPRECATED: Location of the custom Keystone policy file. Assumed to
+# be on the same host as Patrole. (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: It is better to use `custom_policy_files` which supports any
+# OpenStack service.
+#keystone_policy_file = /etc/keystone/policy.json
+
+# DEPRECATED: Location of the Neutron policy file. Assumed to be on
+# the same host as Patrole. (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: It is better to use `custom_policy_files` which supports any
+# OpenStack service.
+#neutron_policy_file = /etc/neutron/policy.json
+
+# DEPRECATED: Location of the custom Nova policy file. Assumed to be
+# on the same host as Patrole. (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: It is better to use `custom_policy_files` which supports any
+# OpenStack service.
+#nova_policy_file = /etc/nova/policy.json
+
+#
+# This option determines whether Patrole should run against a
+# `custom_requirements_file` which defines RBAC requirements. The
+# purpose of setting this flag to True is to verify that RBAC policy
+# is in accordance to requirements. The idea is that the
+# `custom_requirements_file` perfectly defines what the RBAC
+# requirements are.
+#
+# Here are the possible outcomes when running the Patrole tests
+# against
+# a `custom_requirements_file`:
+#
+# YAML definition: allowed
+# test run: allowed
+# test result: pass
+#
+# YAML definition: allowed
+# test run: not allowed
+# test result: fail (under-permission)
+#
+# YAML definition: not allowed
+# test run: allowed
+# test result: fail (over-permission)
+# (boolean value)
+#test_custom_requirements = false
+
+#
+# File path of the yaml file that defines your RBAC requirements. This
+# file must be located on the same host that Patrole runs on. The yaml
+# file should be written as follows:
+#
+# ```
+# <service>:
+# <api_action>:
+# - <allowed_role>
+# - <allowed_role>
+# - <allowed_role>
+# <api_action>:
+# - <allowed_role>
+# - <allowed_role>
+# <service>
+# <api_action>:
+# - <allowed_role>
+# ```
+# Where:
+# service = the service that is being tested (cinder, nova, etc)
+# api_action = the policy action that is being tested. Examples:
+# - volume:create
+# - os_compute_api:servers:start
+# - add_image
+# allowed_role = the Keystone role that is allowed to perform the API
+# (string value)
+#custom_requirements_file = <None>
+
+
+[patrole_log]
+
+#
+# From patrole.config
+#
+
+# Enables reporting on RBAC expected and actual test results for each
+# Patrole test (boolean value)
+#enable_reporting = false
+
+# Name of file where output from 'enable_reporting' is logged. Note
+# that this file is recreated on each invocation of patrole (string
+# value)
+#report_log_name = patrole.log
+
+# Path (relative or absolute) where the output from 'enable_reporting'
+# is logged. This is combined withreport_log_name to generate the full
+# path. (string value)
+#report_log_path = .
+
+
+[rbac]
+# This group is deprecated and will be removed in the next release.
+# Use the [patrole] group instead.
+
+#
+# From patrole.config
+#
+
+# The current RBAC role against which to run Patrole
+# tests. (string value)
+#rbac_test_role = admin
+
+# Enables RBAC tests. (boolean value)
+#enable_rbac = true
+
+# If true, throws RbacParsingException for policies which
+# don't exist or are not included in the service's policy file. If
+# false, throws
+# skipException. (boolean value)
+#strict_policy_check = false
+
+# List of the paths to search for policy files. Each
+# policy path assumes that the service name is included in the path
+# once. Also
+# assumes Patrole is on the same host as the policy files. The paths
+# should be
+# ordered by precedence, with high-priority paths before low-priority
+# paths. The
+# first path that is found to contain the service's policy file will
+# be used.
+# (list value)
+#custom_policy_files = /etc/%s/policy.json
+
+# DEPRECATED: Location of the Cinder policy file. Assumed to be on
+# the same host as Patrole. (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: It is better to use `custom_policy_files` which supports any
+# OpenStack service.
+#cinder_policy_file = /etc/cinder/policy.json
+
+# DEPRECATED: Location of the Glance policy file. Assumed to be on
+# the same host as Patrole. (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: It is better to use `custom_policy_files` which supports any
+# OpenStack service.
+#glance_policy_file = /etc/glance/policy.json
+
+# DEPRECATED: Location of the custom Keystone policy file. Assumed to
+# be on the same host as Patrole. (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: It is better to use `custom_policy_files` which supports any
+# OpenStack service.
+#keystone_policy_file = /etc/keystone/policy.json
+
+# DEPRECATED: Location of the Neutron policy file. Assumed to be on
+# the same host as Patrole. (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: It is better to use `custom_policy_files` which supports any
+# OpenStack service.
+#neutron_policy_file = /etc/neutron/policy.json
+
+# DEPRECATED: Location of the custom Nova policy file. Assumed to be
+# on the same host as Patrole. (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: It is better to use `custom_policy_files` which supports any
+# OpenStack service.
+#nova_policy_file = /etc/nova/policy.json
+
+#
+# This option determines whether Patrole should run against a
+# `custom_requirements_file` which defines RBAC requirements. The
+# purpose of setting this flag to True is to verify that RBAC policy
+# is in accordance to requirements. The idea is that the
+# `custom_requirements_file` perfectly defines what the RBAC
+# requirements are.
+#
+# Here are the possible outcomes when running the Patrole tests
+# against
+# a `custom_requirements_file`:
+#
+# YAML definition: allowed
+# test run: allowed
+# test result: pass
+#
+# YAML definition: allowed
+# test run: not allowed
+# test result: fail (under-permission)
+#
+# YAML definition: not allowed
+# test run: allowed
+# test result: fail (over-permission)
+# (boolean value)
+#test_custom_requirements = false
+
+#
+# File path of the yaml file that defines your RBAC requirements. This
+# file must be located on the same host that Patrole runs on. The yaml
+# file should be written as follows:
+#
+# ```
+# <service>:
+# <api_action>:
+# - <allowed_role>
+# - <allowed_role>
+# - <allowed_role>
+# <api_action>:
+# - <allowed_role>
+# - <allowed_role>
+# <service>
+# <api_action>:
+# - <allowed_role>
+# ```
+# Where:
+# service = the service that is being tested (cinder, nova, etc)
+# api_action = the policy action that is being tested. Examples:
+# - volume:create
+# - os_compute_api:servers:start
+# - add_image
+# allowed_role = the Keystone role that is allowed to perform the API
+# (string value)
+#custom_requirements_file = <None>
diff --git a/patrole_tempest_plugin/config.py b/patrole_tempest_plugin/config.py
index fcf29af..d309d60 100644
--- a/patrole_tempest_plugin/config.py
+++ b/patrole_tempest_plugin/config.py
@@ -46,46 +46,6 @@
ordered by precedence, with high-priority paths before low-priority paths. The
first path that is found to contain the service's policy file will be used.
"""),
- cfg.StrOpt('cinder_policy_file',
- default='/etc/cinder/policy.json',
- help="""Location of the Cinder policy file. Assumed to be on
-the same host as Patrole.""",
- deprecated_group='rbac',
- deprecated_for_removal=True,
- deprecated_reason="It is better to use `custom_policy_files` "
- "which supports any OpenStack service."),
- cfg.StrOpt('glance_policy_file',
- default='/etc/glance/policy.json',
- help="""Location of the Glance policy file. Assumed to be on
-the same host as Patrole.""",
- deprecated_group='rbac',
- deprecated_for_removal=True,
- deprecated_reason="It is better to use `custom_policy_files` "
- "which supports any OpenStack service."),
- cfg.StrOpt('keystone_policy_file',
- default='/etc/keystone/policy.json',
- help="""Location of the custom Keystone policy file. Assumed to
-be on the same host as Patrole.""",
- deprecated_group='rbac',
- deprecated_for_removal=True,
- deprecated_reason="It is better to use `custom_policy_files` "
- "which supports any OpenStack service."),
- cfg.StrOpt('neutron_policy_file',
- default='/etc/neutron/policy.json',
- help="""Location of the Neutron policy file. Assumed to be on
-the same host as Patrole.""",
- deprecated_group='rbac',
- deprecated_for_removal=True,
- deprecated_reason="It is better to use `custom_policy_files` "
- "which supports any OpenStack service."),
- cfg.StrOpt('nova_policy_file',
- default='/etc/nova/policy.json',
- help="""Location of the custom Nova policy file. Assumed to be
-on the same host as Patrole.""",
- deprecated_group='rbac',
- deprecated_for_removal=True,
- deprecated_reason="It is better to use `custom_policy_files` "
- "which supports any OpenStack service."),
cfg.BoolOpt('test_custom_requirements',
default=False,
deprecated_group='rbac',
@@ -167,3 +127,18 @@
"'enable_reporting' is logged. This is combined with"
"report_log_name to generate the full path."),
]
+
+
+def list_opts():
+ """Return a list of oslo.config options available.
+
+ The purpose of this is to allow tools like the Oslo sample config file
+ generator to discover the options exposed to users.
+ """
+ opt_list = [
+ (patrole_group, PatroleGroup),
+ (patrole_log_group, PatroleLogGroup),
+ (rbac_group, PatroleGroup)
+ ]
+
+ return opt_list
diff --git a/patrole_tempest_plugin/policy_authority.py b/patrole_tempest_plugin/policy_authority.py
index d2d07c0..3f4236b 100644
--- a/patrole_tempest_plugin/policy_authority.py
+++ b/patrole_tempest_plugin/policy_authority.py
@@ -107,12 +107,10 @@
# Prioritize dynamically searching for policy files over relying on
# deprecated service-specific policy file locations.
+ self.path = None
if CONF.patrole.custom_policy_files:
self.discover_policy_files()
self.path = self.policy_files.get(service)
- else:
- self.path = getattr(CONF.patrole, '%s_policy_file' % str(service),
- None)
self.rules = policy.Rules.load(self._get_policy_data(service),
'default')
@@ -225,7 +223,7 @@
try:
policy_data = json.dumps(policy_data)
- except ValueError:
+ except (TypeError, ValueError):
error_message = 'Policy file for {0} service is invalid.'.format(
service)
raise rbac_exceptions.RbacParsingException(error_message)
diff --git a/patrole_tempest_plugin/rbac_rule_validation.py b/patrole_tempest_plugin/rbac_rule_validation.py
index 540d006..927c803 100644
--- a/patrole_tempest_plugin/rbac_rule_validation.py
+++ b/patrole_tempest_plugin/rbac_rule_validation.py
@@ -17,6 +17,7 @@
import sys
import testtools
+from oslo_utils import excutils
import six
from tempest import config
@@ -158,14 +159,14 @@
raise exceptions.Forbidden(
"%s Exception was: %s" % (msg, e))
except Exception as e:
- exc_info = sys.exc_info()
- error_details = exc_info[1].__str__()
- msg = ("An unexpected exception has occurred during test: %s. "
- "Exception was: %s"
- % (test_func.__name__, error_details))
- test_status = ('Error, %s' % (error_details))
- LOG.error(msg)
- six.reraise(exc_info[0], exc_info[0](msg), exc_info[2])
+ with excutils.save_and_reraise_exception():
+ exc_info = sys.exc_info()
+ error_details = six.text_type(exc_info[1])
+ msg = ("An unexpected exception has occurred during test: "
+ "%s. Exception was: %s" % (test_func.__name__,
+ error_details))
+ test_status = 'Error, %s' % (error_details)
+ LOG.error(msg)
else:
if not allowed:
LOG.error("Role %s was allowed to perform %s",
diff --git a/patrole_tempest_plugin/tests/api/compute/test_floating_ip_pools_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_floating_ip_pools_rbac.py
index 936aa1b..15891d7 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_floating_ip_pools_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_floating_ip_pools_rbac.py
@@ -42,6 +42,8 @@
msg = "%s skipped as os-floating-ip-pools extension not enabled." \
% cls.__name__
raise cls.skipException(msg)
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
@decorators.idempotent_id('c1a17153-b25d-4444-a721-5897d7737482')
@rbac_rule_validation.action(
diff --git a/patrole_tempest_plugin/tests/api/compute/test_floating_ips_bulk_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_floating_ips_bulk_rbac.py
index 1f33b18..e149bf2 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_floating_ips_bulk_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_floating_ips_bulk_rbac.py
@@ -42,6 +42,8 @@
msg = "%s skipped as os-floating-ips-bulk extension not enabled." \
% cls.__name__
raise cls.skipException(msg)
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
@decorators.idempotent_id('3b5c8a02-005d-4256-8a95-6fa2f389c6cf')
@rbac_rule_validation.action(
diff --git a/patrole_tempest_plugin/tests/api/compute/test_floating_ips_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_floating_ips_rbac.py
index cddba13..8ab5a51 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_floating_ips_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_floating_ips_rbac.py
@@ -15,6 +15,7 @@
from tempest.common import utils
from tempest import config
+from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
from patrole_tempest_plugin import rbac_rule_validation
@@ -37,6 +38,8 @@
msg = "%s skipped as os-floating-ips extension not enabled." \
% cls.__name__
raise cls.skipException(msg)
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
@decorators.idempotent_id('ac1b3053-f755-4cda-85a0-30e88b88d7ba')
@rbac_rule_validation.action(
@@ -45,3 +48,39 @@
def test_list_floating_ips(self):
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
self.floating_ips_client.list_floating_ips()['floating_ips']
+
+ @decorators.idempotent_id('bebe52b3-5269-4e72-80c8-5a4a39c3bfa6')
+ @rbac_rule_validation.action(
+ service="nova",
+ rule="os_compute_api:os-floating-ips")
+ def test_show_floating_ip(self):
+ body = self.floating_ips_client.create_floating_ip(
+ pool=CONF.network.floating_network_name)['floating_ip']
+ self.addCleanup(
+ self.floating_ips_client.delete_floating_ip, body['id'])
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.floating_ips_client.show_floating_ip(body['id'])['floating_ip']
+
+ @decorators.idempotent_id('2bfb8745-c329-4ee9-95f6-c165a1989dbf')
+ @rbac_rule_validation.action(
+ service="nova",
+ rule="os_compute_api:os-floating-ips")
+ def test_create_floating_ips(self):
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ body = self.floating_ips_client.create_floating_ip(
+ pool=CONF.network.floating_network_name)['floating_ip']
+ self.addCleanup(
+ self.floating_ips_client.delete_floating_ip, body['id'])
+
+ @decorators.idempotent_id('d3028373-5027-4e7a-b761-01c515403ecb')
+ @rbac_rule_validation.action(
+ service="nova",
+ rule="os_compute_api:os-floating-ips")
+ def test_delete_floating_ip(self):
+ body = self.floating_ips_client.create_floating_ip(
+ pool=CONF.network.floating_network_name)['floating_ip']
+ self.addCleanup(
+ test_utils.call_and_ignore_notfound_exc,
+ self.floating_ips_client.delete_floating_ip, body['id'])
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.floating_ips_client.delete_floating_ip(body['id'])
diff --git a/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py
index e315623..0ba1282 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.common import image as common_image
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
@@ -49,10 +50,10 @@
@classmethod
def setup_clients(cls):
super(ImagesRbacTest, cls).setup_clients()
- if CONF.image_feature_enabled.api_v1:
- cls.glance_image_client = cls.os_primary.image_client
- elif CONF.image_feature_enabled.api_v2:
+ if CONF.image_feature_enabled.api_v2:
cls.glance_image_client = cls.os_primary.image_client_v2
+ elif CONF.image_feature_enabled.api_v1:
+ cls.glance_image_client = cls.os_primary.image_client
else:
raise lib_exc.InvalidConfiguration(
'Either api_v1 or api_v2 must be True in '
@@ -61,8 +62,11 @@
@classmethod
def resource_setup(cls):
super(ImagesRbacTest, cls).resource_setup()
- cls.image = cls.glance_image_client.create_image(
- name=data_utils.rand_name(cls.__name__ + '-image'))
+ params = {'name': data_utils.rand_name(cls.__name__ + '-image')}
+ if CONF.image_feature_enabled.api_v1:
+ params = {'headers': common_image.image_meta_to_headers(**params)}
+
+ cls.image = cls.glance_image_client.create_image(**params)
cls.addClassResourceCleanup(
cls.glance_image_client.wait_for_resource_deletion,
cls.image['id'])
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py
index 02ebccf..2bc267b 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py
@@ -54,8 +54,8 @@
server = self.create_test_server(wait_until='ACTIVE')
self.__class__.server_id = server['id']
except Exception:
- # Rebuilding the server in case something happened during a test
- self.__class__.server_id = self.rebuild_server(self.server_id)
+ # Recreating the server in case something happened during a test
+ self.__class__.server_id = self.recreate_server(self.server_id)
def _stop_server(self):
self.servers_client.stop_server(self.server_id)
@@ -72,6 +72,57 @@
waiters.wait_for_server_status(
self.os_admin.servers_client, self.server_id, 'ACTIVE')
+ def _shelve_server(self):
+ self.servers_client.shelve_server(self.server_id)
+ self.addCleanup(self._cleanup_server_actions,
+ self.servers_client.unshelve_server,
+ self.server_id)
+ offload_time = CONF.compute.shelved_offload_time
+ if offload_time >= 0:
+ waiters.wait_for_server_status(self.os_admin.servers_client,
+ self.server_id,
+ 'SHELVED_OFFLOADED',
+ extra_timeout=offload_time)
+ else:
+ waiters.wait_for_server_status(self.os_admin.servers_client,
+ self.server_id, 'SHELVED')
+
+ def _pause_server(self):
+ self.servers_client.pause_server(self.server_id)
+ self.addCleanup(self._cleanup_server_actions,
+ self.servers_client.unpause_server,
+ self.server_id)
+ waiters.wait_for_server_status(
+ self.os_admin.servers_client, self.server_id, 'PAUSED')
+
+ def _cleanup_server_actions(self, function, server_id, **kwargs):
+ server = self.servers_client.show_server(server_id)['server']
+ if server['status'] != 'ACTIVE':
+ function(server_id, **kwargs)
+
+ @decorators.idempotent_id('117f4ff2-8544-437b-824f-5e41cb6640ee')
+ @testtools.skipUnless(CONF.compute_feature_enabled.pause,
+ 'Pause is not available.')
+ @rbac_rule_validation.action(
+ service="nova",
+ rule="os_compute_api:os-pause-server:pause")
+ def test_pause_server(self):
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self._pause_server()
+
+ @decorators.idempotent_id('087008cf-82fa-4eeb-ae8b-32c4126456ad')
+ @testtools.skipUnless(CONF.compute_feature_enabled.pause,
+ 'Pause is not available.')
+ @rbac_rule_validation.action(
+ service="nova",
+ rule="os_compute_api:os-pause-server:unpause")
+ def test_unpause_server(self):
+ self._pause_server()
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.servers_client.unpause_server(self.server_id)
+ waiters.wait_for_server_status(
+ self.os_admin.servers_client, self.server_id, 'ACTIVE')
+
@rbac_rule_validation.action(
service="nova",
rule="os_compute_api:servers:stop")
@@ -267,6 +318,27 @@
glance_admin_client.delete_image, image_id)
waiters.wait_for_image_status(glance_admin_client, image_id, 'active')
+ @decorators.attr(type='slow')
+ @decorators.idempotent_id('0b70c527-af75-4bed-9ccf-4f1310a8b60f')
+ @rbac_rule_validation.action(
+ service="nova",
+ rule="os_compute_api:os-shelve:shelve")
+ def test_shelve_server(self):
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self._shelve_server()
+
+ @decorators.attr(type='slow')
+ @decorators.idempotent_id('4b6e849a-9182-49ff-9257-e97e751b475e')
+ @rbac_rule_validation.action(
+ service="nova",
+ rule="os_compute_api:os-shelve:unshelve")
+ def test_unshelve_server(self):
+ self._shelve_server()
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.servers_client.unshelve_server(self.server_id)
+ waiters.wait_for_server_status(
+ self.os_admin.servers_client, self.server_id, 'ACTIVE')
+
class ServerActionsV214RbacTest(rbac_base.BaseV2ComputeRbacTest):
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py
index 9ce4ba0..48df4a3 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py
@@ -419,6 +419,21 @@
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
self.servers_client.rescue_server(self.server['id'])
+ @decorators.idempotent_id('ac2d956f-d6a3-4184-b814-b44d05c9574c')
+ @utils.requires_ext(extension='os-rescue', service='compute')
+ @rbac_rule_validation.action(
+ service="nova",
+ rule="os_compute_api:os-rescue")
+ def test_unrescue_server(self):
+ """Test unrescue server, part of os-rescue."""
+ self.servers_client.rescue_server(self.server['id'])
+ waiters.wait_for_server_status(
+ self.os_admin.servers_client, self.server['id'], 'RESCUE')
+
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.servers_client.unrescue_server(self.server['id'])
+ # `setUp` will wait for the server to reach 'ACTIVE' for next test.
+
@utils.requires_ext(extension='os-server-diagnostics', service='compute')
@rbac_rule_validation.action(
service="nova",
@@ -508,8 +523,8 @@
def test_resume_server(self):
"""Test resume server, part of os-suspend-server."""
self.servers_client.suspend_server(self.server['id'])
- waiters.wait_for_server_status(self.servers_client, self.server['id'],
- 'SUSPENDED')
+ waiters.wait_for_server_status(
+ self.os_admin.servers_client, self.server['id'], 'SUSPENDED')
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
self.servers_client.resume_server(self.server['id'])
@@ -571,6 +586,20 @@
self.interfaces_client.list_interfaces(
self.server['id'])['interfaceAttachments']
+ @decorators.idempotent_id('1b9cf7db-dc50-48a2-8eb9-8c25af5e934a')
+ @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
+ "Interface attachment is not available.")
+ @utils.requires_ext(extension='os-attach-interfaces', service='compute')
+ @rbac_rule_validation.action(
+ service="nova",
+ rule="os_compute_api:os-attach-interfaces")
+ def test_show_interface(self):
+ """Test show interfaces, part of os-attach-interfaces."""
+ interface = self._attach_interface_to_server()
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.interfaces_client.show_interface(
+ self.server['id'], interface['port_id'])['interfaceAttachment']
+
@testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
"Interface attachment is not available.")
@utils.requires_ext(extension='os-attach-interfaces', service='compute')
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_auth_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_auth_rbac.py
index bc096ce..6a26f2b 100644
--- a/patrole_tempest_plugin/tests/api/identity/v3/test_auth_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_auth_rbac.py
@@ -26,8 +26,8 @@
https://github.com/openstack/keystone/blob/master/keystone/common/policies/auth.py
"""
- # TODO(felipemonteiro): Add tests for identity:get_auth_catalog and
- # identity:get_auth_domains once the endpoints are implemented in Tempest's
+ # TODO(felipemonteiro): Add tests for identity:get_auth_catalog
+ # once the endpoints are implemented in Tempest's
# identity v3 client.
@decorators.idempotent_id('2a9fbf7f-6feb-4161-ae4b-faf7d6421b1a')
@@ -36,3 +36,10 @@
def test_list_auth_projects(self):
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
self.identity_client.list_auth_projects()['projects']
+
+ @decorators.idempotent_id('6a40af0d-7265-4657-b6b2-87a2828e263e')
+ @rbac_rule_validation.action(service="keystone",
+ rule="identity:get_auth_domains")
+ def test_list_auth_domain(self):
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.identity_client.list_auth_domains()
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_trusts_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_trusts_rbac.py
index 82feff9..3639520 100644
--- a/patrole_tempest_plugin/tests/api/identity/v3/test_trusts_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_trusts_rbac.py
@@ -127,3 +127,11 @@
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
self.trusts_client.show_trust_role(
self.trust['id'], self.delegated_role_id)['role']
+
+ @decorators.idempotent_id('0184e0fb-641e-4b52-ab73-81c1ce6ca5c1')
+ @rbac_rule_validation.action(
+ service="keystone",
+ rule="identity:get_trust")
+ def test_show_trust(self):
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.trusts_client.show_trust(self.trust['id'])
diff --git a/patrole_tempest_plugin/tests/api/volume/test_limits_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_limits_rbac.py
new file mode 100644
index 0000000..fa92cad
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/volume/test_limits_rbac.py
@@ -0,0 +1,30 @@
+# Copyright 2017 AT&T Corporation.
+# 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 tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.volume import rbac_base
+
+
+class LimitsV3RbacTest(rbac_base.BaseVolumeRbacTest):
+ _api_version = 3
+
+ @decorators.idempotent_id('dab04510-5b86-4479-a633-6e496ff405af')
+ @rbac_rule_validation.action(service="cinder",
+ rule="limits_extension:used_limits")
+ def test_show_limits(self):
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.volume_limits_client.show_limits()
diff --git a/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py
index 81cd854..3737212 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py
@@ -80,6 +80,45 @@
self.snapshots_client.show_snapshot_metadata(
self.snapshot_id)['metadata']
+ @decorators.idempotent_id('7ea597f6-c544-4b10-aab0-ff68f595fb06')
+ @rbac_rule_validation.action(service="cinder",
+ rule="volume:update_snapshot_metadata")
+ def test_update_snapshot_metadata(self):
+ self._create_test_snapshot_metadata()
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ update = {"key3": "value3_update",
+ "key4": "value4"}
+ self.snapshots_client.update_snapshot_metadata(
+ self.snapshot['id'], metadata=update)
+
+ @decorators.idempotent_id('93068d02-0131-4dd3-af16-fc40d7128d93')
+ @rbac_rule_validation.action(service="cinder",
+ rule="volume:get_snapshot_metadata")
+ def test_show_snapshot_metadata_item(self):
+ self._create_test_snapshot_metadata()
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.snapshots_client.show_snapshot_metadata_item(
+ self.snapshot['id'], "key3")['meta']
+
+ @decorators.idempotent_id('1f8f43e7-da31-4128-bb3c-73fc548650e3')
+ @rbac_rule_validation.action(service="cinder",
+ rule="volume:update_snapshot_metadata")
+ def test_update_snapshot_metadata_item(self):
+ update_item = {"key3": "value3_update"}
+ self._create_test_snapshot_metadata()
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.snapshots_client.update_snapshot_metadata_item(
+ self.snapshot['id'], "key3", meta=update_item)['meta']
+
+ @decorators.idempotent_id('3ec32516-f7cd-4f88-b78a-ddee67492071')
+ @rbac_rule_validation.action(service="cinder",
+ rule="volume:delete_snapshot_metadata")
+ def test_delete_snapshot_metadata_item(self):
+ self._create_test_snapshot_metadata()
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.snapshots_client.delete_snapshot_metadata_item(
+ self.snapshot['id'], "key1")
+
class SnapshotMetadataV3RbacTest(SnapshotMetadataRbacTest):
_api_version = 3
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_actions_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_actions_rbac.py
index 466fb0c..88c5d82 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volume_actions_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_actions_rbac.py
@@ -69,7 +69,9 @@
self.admin_volumes_client, volume_id, 'available')
@utils.services('compute')
- @rbac_rule_validation.action(service="cinder", rule="volume:attach")
+ @rbac_rule_validation.action(
+ service="cinder",
+ rule="volume_extension:volume_actions:attach")
@decorators.idempotent_id('f97b10e4-2eed-4f8b-8632-71c02cb9fe42')
def test_attach_volume_to_instance(self):
server = self._create_server()
@@ -78,7 +80,9 @@
@utils.services('compute')
@decorators.attr(type='slow')
- @rbac_rule_validation.action(service="cinder", rule="volume:detach")
+ @rbac_rule_validation.action(
+ service="cinder",
+ rule="volume_extension:volume_actions:detach")
@decorators.idempotent_id('5a042f6a-688b-42e6-a02e-fe5c47b89b07')
def test_detach_volume_from_instance(self):
server = self._create_server()
@@ -141,15 +145,17 @@
bootable=True)
@decorators.idempotent_id('41566922-75a1-4484-99c7-9c8782ee99ac')
- @rbac_rule_validation.action(service="cinder",
- rule="volume:reserve_volume")
+ @rbac_rule_validation.action(
+ service="cinder",
+ rule="volume_extension:volume_actions:reserve")
def test_volume_reserve(self):
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
self.volumes_client.reserve_volume(self.volume['id'])
@decorators.idempotent_id('e5fa9564-77d9-4e57-b0c0-3e0ae4d08535')
- @rbac_rule_validation.action(service="cinder",
- rule="volume:unreserve_volume")
+ @rbac_rule_validation.action(
+ service="cinder",
+ rule="volume_extension:volume_actions:unreserve")
def test_volume_unreserve(self):
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
self.volumes_client.unreserve_volume(self.volume['id'])
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volumes_backup_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volumes_backup_rbac.py
index 7ca3d9f..d10c876 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volumes_backup_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volumes_backup_rbac.py
@@ -141,7 +141,7 @@
@decorators.attr(type='slow')
@rbac_rule_validation.action(service="cinder",
- rule="backup:backup-export")
+ rule="backup:export-import")
@decorators.idempotent_id('e984ec8d-e8eb-485c-98bc-f1856020303c')
def test_export_backup(self):
backup = self.create_backup(volume_id=self.volume['id'])
@@ -201,3 +201,31 @@
if expected_attr not in body:
raise rbac_exceptions.RbacMalformedResponse(
attribute=expected_attr)
+
+
+class VolumesBackupsV39RbacTest(rbac_base.BaseVolumeRbacTest):
+ _api_version = 3
+ min_microversion = '3.9'
+ max_microversion = 'latest'
+
+ @classmethod
+ def skip_checks(cls):
+ super(VolumesBackupsV39RbacTest, cls).skip_checks()
+ if not CONF.volume_feature_enabled.backup:
+ raise cls.skipException("Cinder backup feature disabled")
+
+ @decorators.attr(type='slow')
+ @decorators.idempotent_id('b45b0e98-6eb8-4c62-aa53-0f8c7c09faa6')
+ @rbac_rule_validation.action(
+ service="cinder",
+ rule="backup:update")
+ def test_backup_update(self):
+ volume = self.create_volume()
+ backup = self.create_backup(volume_id=volume['id'])
+ update_kwargs = {
+ 'name': data_utils.rand_name(self.__class__.__name__ + '-Backup'),
+ 'description': data_utils.rand_name("volume-backup-description")
+ }
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.backups_client.update_backup(backup['id'],
+ **update_kwargs)
diff --git a/patrole_tempest_plugin/tests/unit/test_rbac_rule_validation.py b/patrole_tempest_plugin/tests/unit/test_rbac_rule_validation.py
index 3065cfe..82f0428 100644
--- a/patrole_tempest_plugin/tests/unit/test_rbac_rule_validation.py
+++ b/patrole_tempest_plugin/tests/unit/test_rbac_rule_validation.py
@@ -203,17 +203,16 @@
def test_policy(*args):
raise exceptions.Forbidden('Test message')
- error_re = ("An unexpected exception has occurred during test: "
- "test_policy. Exception was: Forbidden\nDetails: Test "
- "message")
+ error_msg = ("An unexpected exception has occurred during test: "
+ "test_policy. Exception was: Forbidden\nDetails: Test "
+ "message")
for allowed in [True, False]:
mock_authority.PolicyAuthority.return_value.allowed.\
return_value = allowed
-
- self.assertRaisesRegex(exceptions.Forbidden, '.* ' + error_re,
+ self.assertRaisesRegex(exceptions.Forbidden, 'Test message',
test_policy, self.mock_test_args)
- self.assertIn(error_re, mock_log.error.mock_calls[0][1][0])
+ self.assertIn(error_msg, mock_log.error.mock_calls[0][1][0])
mock_log.error.reset_mock()
@mock.patch.object(rbac_rv, 'LOG', autospec=True)
diff --git a/releasenotes/notes/remove-named-policy-files-134f3045502e9ce9.yaml b/releasenotes/notes/remove-named-policy-files-134f3045502e9ce9.yaml
new file mode 100644
index 0000000..00245d7
--- /dev/null
+++ b/releasenotes/notes/remove-named-policy-files-134f3045502e9ce9.yaml
@@ -0,0 +1,13 @@
+---
+deprecations:
+ - |
+ Removed the following deprecated Patrole configuration options:
+
+ * cinder_policy_file
+ * glance_policy_file
+ * keystone_policy_file
+ * neutron_policy_file
+ * nova_policy_file
+
+ To specify the location of a custom policy file, use
+ ``[patrole] custom_policy_files`` instead.
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
index 7444c35..1aeff4b 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -58,15 +58,13 @@
project = u'Patrole Release Notes'
copyright = u'2017, Patrole Developers'
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-from patrole_tempest_plugin.version import version_info as patrole_version
+# Release do not need a version number in the title, they
+# cover multiple versions.
+
# The full version, including alpha/beta/rc tags.
-release = patrole_version.version_string_with_vcs()
+release = ''
# The short X.Y version.
-version = patrole_version.canonical_version_string()
+version = ''
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/requirements.txt b/requirements.txt
index 0e46596..ba2f2d5 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,5 +6,5 @@
oslo.log>=3.30.0 # Apache-2.0
oslo.config>=4.6.0 # Apache-2.0
oslo.policy>=1.23.0 # Apache-2.0
-tempest>=16.1.0 # Apache-2.0
+tempest>=17.1.0 # Apache-2.0
stevedore>=1.20.0 # Apache-2.0
diff --git a/setup.cfg b/setup.cfg
index b3f4312..d805f62 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -54,3 +54,5 @@
[entry_points]
tempest.test_plugins =
patrole_tempest_plugin = patrole_tempest_plugin.plugin:PatroleTempestPlugin
+oslo.config.opts =
+ patrole.config = patrole_tempest_plugin.config:list_opts
diff --git a/test-requirements.txt b/test-requirements.txt
index 1953685..a8a3044 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -14,4 +14,4 @@
oslotest>=1.10.0 # Apache-2.0
oslo.policy>=1.23.0 # Apache-2.0
oslo.log>=3.30.0 # Apache-2.0
-tempest>=16.1.0 # Apache-2.0
+tempest>=17.1.0 # Apache-2.0
diff --git a/tox.ini b/tox.ini
index 320eb4e..e95cadf 100644
--- a/tox.ini
+++ b/tox.ini
@@ -55,6 +55,9 @@
[testenv:debug]
commands = oslo_debug_helper -t patrole_tempest_plugin/tests {posargs}
+[testenv:genconfig]
+commands = oslo-config-generator --config-file etc/config-generator.patrole.conf
+
[flake8]
# [H106] Don’t put vim configuration in source files.
# [H203] Use assertIs(Not)None to check for None.