requirements authority: Use better exception/return code

This patch set makes some minor modifications to the requirements
authority module:

* return {} instead of None in RequirementsParser.parse since
  its return type is dict
* raise RbacParsingException if an invalid rule is passed to
  RequirementsAuthority.allowed since KeyError is a builtin type
  and is not specific enough
* change the exception message raise for the above case -- "API"
  is not the right word; the word should be "rule name" as that
  is what is being keyed into the roles_dict

Change-Id: Ia4408c0745d2b5ddb1c73c1eb9a6316ae0c1f646
diff --git a/patrole_tempest_plugin/requirements_authority.py b/patrole_tempest_plugin/requirements_authority.py
index 4697c3b..4d6f25b 100644
--- a/patrole_tempest_plugin/requirements_authority.py
+++ b/patrole_tempest_plugin/requirements_authority.py
@@ -18,9 +18,10 @@
 from oslo_log import log as logging
 
 from tempest import config
-from tempest.lib import exceptions
+from tempest.lib import exceptions as lib_exc
 
 from patrole_tempest_plugin.rbac_authority import RbacAuthority
+from patrole_tempest_plugin import rbac_exceptions
 
 CONF = config.CONF
 LOG = logging.getLogger(__name__)
@@ -81,7 +82,7 @@
         except yaml.parser.ParserError:
             LOG.error("Error while parsing the requirements YAML file. Did "
                       "you pass a valid component name from the test case?")
-        return None
+        return {}
 
 
 class RequirementsAuthority(RbacAuthority):
@@ -98,10 +99,10 @@
             Defaults to ``[patrole].custom_requirements_file``.
         :param str component: Name of the OpenStack service to be validated.
         """
-        filepath = filepath or CONF.patrole.custom_requirements_file
-
+        self.filepath = filepath or CONF.patrole.custom_requirements_file
         if component is not None:
-            self.roles_dict = RequirementsParser(filepath).parse(component)
+            self.roles_dict = RequirementsParser(self.filepath).parse(
+                component)
         else:
             self.roles_dict = None
 
@@ -116,33 +117,34 @@
         :returns: True if ``role`` is allowed to perform ``rule_name``, else
             False.
         :rtype: bool
-        :raises KeyError: If ``rule_name`` does not exist among the keyed
-            policy names in the custom requirements file.
+        :raises RbacParsingException: If ``rule_name`` does not exist among the
+            keyed policy names in the custom requirements file.
         """
-        if self.roles_dict is None:
-            raise exceptions.InvalidConfiguration(
+        if not self.roles_dict:
+            raise lib_exc.InvalidConfiguration(
                 "Roles dictionary parsed from requirements YAML file is "
                 "empty. Ensure the requirements YAML file is correctly "
                 "formatted.")
         try:
             requirement_roles = self.roles_dict[rule_name]
-
-            for role_reqs in requirement_roles:
-                required_roles = [
-                    role for role in role_reqs if not role.startswith("!")]
-                forbidden_roles = [
-                    role[1:] for role in role_reqs if role.startswith("!")]
-
-                # User must have all required roles
-                required_passed = all([r in roles for r in required_roles])
-                # User must not have any forbidden roles
-                forbidden_passed = all([r not in forbidden_roles
-                                        for r in roles])
-
-                if required_passed and forbidden_passed:
-                    return True
-
-            return False
         except KeyError:
-            raise KeyError("'%s' API is not defined in the requirements YAML "
-                           "file" % rule_name)
+            raise rbac_exceptions.RbacParsingException(
+                "'%s' rule name is not defined in the requirements YAML file: "
+                "%s" % (rule_name, self.filepath))
+
+        for role_reqs in requirement_roles:
+            required_roles = [
+                role for role in role_reqs if not role.startswith("!")]
+            forbidden_roles = [
+                role[1:] for role in role_reqs if role.startswith("!")]
+
+            # User must have all required roles
+            required_passed = all([r in roles for r in required_roles])
+            # User must not have any forbidden roles
+            forbidden_passed = all([r not in forbidden_roles
+                                    for r in roles])
+
+            if required_passed and forbidden_passed:
+                return True
+
+        return False