Merge "Followup for grouping imports"
diff --git a/.zuul.yaml b/.zuul.yaml
index 41d2d33..40fe0e2 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -94,6 +94,19 @@
         RBAC_TEST_ROLES: reader
 
 - job:
+    name: patrole-member-ussuri
+    parent: patrole-member
+    override-checkout: stable/ussuri
+
+- job:
+    name: patrole-member-train
+    parent: patrole-member
+    override-checkout: stable/train
+    vars:
+      devstack_localrc:
+        USE_PYTHON3: True
+
+- job:
     name: patrole-member-stein
     parent: patrole-member
     override-checkout: stable/stein
@@ -102,23 +115,6 @@
         USE_PYTHON3: True
 
 - job:
-    name: patrole-member-rocky
-    nodeset: openstack-single-node-xenial
-    parent: patrole-member
-    override-checkout: stable/rocky
-    vars:
-      devstack_localrc:
-        TEMPEST_PLUGINS: /opt/stack/patrole
-        USE_PYTHON3: True
-    # NOTE(gmann): pin patrole for rocky
-    # job which is on Xenial node with py3.5.
-    # Patrole master need py3.6 as min version
-    # of python.
-    required-projects:
-      - name: openstack/patrole
-        override-checkout: 0.8.0
-
-- job:
     name: patrole-multinode-admin
     parent: patrole-base-multinode
     voting: false
@@ -200,7 +196,7 @@
     templates:
       - openstack-cover-jobs
       - openstack-lower-constraints-jobs
-      - openstack-python3-ussuri-jobs
+      - openstack-python3-victoria-jobs
       - check-requirements
       - publish-openstack-docs-pti
       - release-notes-jobs-python3
@@ -209,8 +205,9 @@
         - patrole-admin
         - patrole-member
         - patrole-reader
+        - patrole-member-ussuri
+        - patrole-member-train
         - patrole-member-stein
-        - patrole-member-rocky
         - patrole-multinode-admin
         - patrole-multinode-member
         - patrole-extension-admin
@@ -221,5 +218,6 @@
         - patrole-member
     periodic-stable:
       jobs:
+        - patrole-member-ussuri
+        - patrole-member-train
         - patrole-member-stein
-        - patrole-member-rocky
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
new file mode 100644
index 0000000..a138d66
--- /dev/null
+++ b/CONTRIBUTING.rst
@@ -0,0 +1,19 @@
+The source repository for this project can be found at:
+
+   https://opendev.org/openstack/patrole
+
+Pull requests submitted through GitHub are not monitored.
+
+To start contributing to OpenStack, follow the steps in the contribution guide
+to set up and use Gerrit:
+
+   https://docs.openstack.org/contributors/code-and-documentation/quick-start.html
+
+Bugs should be filed on Storyboard:
+
+   https://storyboard.openstack.org/#!/project/1040
+
+For more specific information about contributing to this repository, see the
+Patrole contributor guide:
+
+   https://docs.openstack.org/patrole/latest/contributor/contributing.html
diff --git a/devstack/plugin.sh b/devstack/plugin.sh
index af71066..9daf285 100644
--- a/devstack/plugin.sh
+++ b/devstack/plugin.sh
@@ -105,6 +105,11 @@
        iniset $TEMPEST_CONFIG policy-feature-enabled changed_nova_policies_ussuri False
     fi
 
+    if [[ ${DEVSTACK_SERIES} == 'train' ]]; then
+       # Remove this once stable/train becomes EOL.
+       iniset $TEMPEST_CONFIG policy-feature-enabled changed_nova_policies_ussuri False
+    fi
+
     iniset $TEMPEST_CONFIG patrole rbac_test_roles $RBAC_TEST_ROLES
 }
 
diff --git a/doc/requirements.txt b/doc/requirements.txt
index ae644f5..d155165 100644
--- a/doc/requirements.txt
+++ b/doc/requirements.txt
@@ -1,8 +1,8 @@
 # The order of packages is significant, because pip processes them in the order
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
-sphinx!=1.6.6,!=1.6.7,!=2.1.0,>=1.6.2 # BSD
-openstackdocstheme>=1.20.0 # Apache-2.0
+sphinx>=2.0.0,!=2.1.0 # BSD
+openstackdocstheme>=2.0.0 # Apache-2.0
 reno>=2.5.0 # Apache-2.0
 sphinxcontrib-apidoc>=0.2.0  # BSD
 sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 4fa65e6..12c20ec 100755
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -89,9 +89,6 @@
 bug_project = 'patrole'
 bug_tag = ''
 
-# Must set this variable to include year, month, day, hours, and minutes.
-html_last_updated_fmt = '%Y-%m-%d %H:%M'
-
 # Output file base name for HTML help builder.
 htmlhelp_basename = 'patroledoc'
 
@@ -109,4 +106,4 @@
 ]
 
 # Disable usage of xindy https://bugzilla.redhat.com/show_bug.cgi?id=1643664
-latex_use_xindy = False
\ No newline at end of file
+latex_use_xindy = False
diff --git a/doc/source/contributor/contributing.rst b/doc/source/contributor/contributing.rst
new file mode 100644
index 0000000..d0e5a21
--- /dev/null
+++ b/doc/source/contributor/contributing.rst
@@ -0,0 +1,57 @@
+============================
+So You Want to Contribute...
+============================
+
+For general information on contributing to OpenStack, please check out the
+`contributor guide <https://docs.openstack.org/contributors/>`_ to get started.
+It covers all the basics that are common to all OpenStack projects: the accounts
+you need, the basics of interacting with our Gerrit review system, how we
+communicate as a community, etc.
+
+Below will cover the more project specific information you need to get started
+with Tempest.
+
+Communication
+~~~~~~~~~~~~~
+* IRC channel ``#openstack-qa`` at FreeNode
+* Mailing list (prefix subjects with ``[qa]`` for faster responses)
+  http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-discuss
+
+Contacting the Core Team
+~~~~~~~~~~~~~~~~~~~~~~~~
+Please refer to the `Patrole Core Team
+<https://review.opendev.org/#/admin/groups/1673,members>`_ contacts.
+
+New Feature Planning
+~~~~~~~~~~~~~~~~~~~~
+If you want to propose a new feature please read `Feature Proposal Process`_
+Patrole features are tracked on `Storyboard <https://storyboard.openstack.org/#!/project/1040>`_.
+
+Task Tracking
+~~~~~~~~~~~~~
+We track our tasks in `Storyboard <https://storyboard.openstack.org/#!/project/1040>`_.
+
+If you're looking for some smaller, easier work item to pick up and get started
+on, search for the 'low-hanging-fruit' tag.
+
+Reporting a Bug
+~~~~~~~~~~~~~~~
+You found an issue and want to make sure we are aware of it? You can do so on
+`StoryBoard <https://storyboard.openstack.org/#!/project/1040>`_.
+
+Getting Your Patch Merged
+~~~~~~~~~~~~~~~~~~~~~~~~~
+All changes proposed to the Patrole requires one ``Code-Review +2`` votes from
+Patrole core reviewers before one of the core reviewers can approve patch by
+giving ``Workflow +1`` vote. More detailed guidelines for reviewers are available
+at :doc:`../REVIEWING`.
+
+Project Team Lead Duties
+~~~~~~~~~~~~~~~~~~~~~~~~
+All common PTL duties are enumerated in the `PTL guide
+<https://docs.openstack.org/project-team-guide/ptl.html>`_.
+
+The Release Process for QA is documented in `QA Release Process
+<https://wiki.openstack.org/wiki/QA/releases>`_.
+
+.. _Feature Proposal Process: https://wiki.openstack.org/wiki/QA#Feature_Proposal_.26_Design_discussions
diff --git a/doc/source/index.rst b/doc/source/index.rst
index c7251ee..d24f517 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -47,6 +47,16 @@
    field_guide/index
    field_guide/rbac
 
+For Contributors
+================
+
+* If you are a new contributor to Patrole please refer: :doc:`contributor/contributing`
+
+.. toctree::
+   :hidden:
+
+   contributor/contributing
+
 Developer's Guide
 =================
 
diff --git a/lower-constraints.txt b/lower-constraints.txt
index 0c7cab1..efbb043 100644
--- a/lower-constraints.txt
+++ b/lower-constraints.txt
@@ -16,9 +16,7 @@
 extras==1.0.0
 fasteners==0.14.1
 fixtures==3.0.0
-flake8==2.6.2
 future==0.16.0
-hacking==1.0.0
 idna==2.6
 imagesize==1.0.0
 iso8601==0.1.12
@@ -35,7 +33,7 @@
 netifaces==0.10.6
 nose==1.3.7
 nosexcover==1.0.10
-openstackdocstheme==1.20.0
+openstackdocstheme==2.0.0
 os-client-config==1.29.0
 oslo.concurrency==3.26.0
 oslo.config==5.2.0
@@ -48,11 +46,9 @@
 oslotest==3.2.0
 paramiko==2.4.1
 pbr==2.0.0
-pep8==1.5.7
 prettytable==0.7.2
 pyasn1==0.4.2
 pycparser==2.18
-pyflakes==0.8.1
 Pygments==2.2.0
 pyinotify==0.9.6
 PyNaCl==1.2.1
@@ -69,7 +65,7 @@
 rfc3986==1.1.0
 six==1.11.0
 snowballstemmer==1.2.1
-Sphinx==1.6.5
+Sphinx==2.0.0
 sphinxcontrib-websupport==1.0.1
 stestr==2.0.0
 stevedore==1.20.0
diff --git a/patrole_tempest_plugin/policy_authority.py b/patrole_tempest_plugin/policy_authority.py
index 1defa6d..afa358a 100644
--- a/patrole_tempest_plugin/policy_authority.py
+++ b/patrole_tempest_plugin/policy_authority.py
@@ -186,9 +186,10 @@
             }
         )
         LOG.warn(deprecated_msg)
-        check_str = '(%s) or (%s)' % (default.check_str,
-                                      deprecated_rule.check_str)
-        return policy.RuleDefault(default.name, check_str)
+        default.check = policy.OrCheck(
+            [policy._parser.parse_rule(cs) for cs in
+                [default.check_str,
+                 deprecated_rule.check_str]])
 
     def get_rules(self):
         rules = policy.Rules()
@@ -229,7 +230,7 @@
                             # The `DocumentedRuleDefault` object has no
                             # `deprecated_rule` attribute in Pike
                             if getattr(rule, 'deprecated_rule', False):
-                                rule = self._handle_deprecated_rule(rule)
+                                self._handle_deprecated_rule(rule)
                         rules[rule.name] = rule.check
                     elif str(rule.check) != str(rules[rule.name]):
                         msg = ("The same policy name: %s was found in the "
diff --git a/patrole_tempest_plugin/tests/api/compute/test_security_groups_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_security_groups_rbac.py
index 471d7da..f81262a 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_security_groups_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_security_groups_rbac.py
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
@@ -20,6 +21,17 @@
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
 
+CONF = config.CONF
+
+if CONF.policy_feature_enabled.changed_nova_policies_ussuri:
+    _SG_LIST = "os_compute_api:os-security-groups:list"
+    _SG_ADD = "os_compute_api:os-security-groups:add"
+    _SG_REMOVE = "os_compute_api:os-security-groups:remove"
+else:
+    _SG_LIST = "os_compute_api:os-security-groups"
+    _SG_ADD = "os_compute_api:os-security-groups"
+    _SG_REMOVE = "os_compute_api:os-security-groups"
+
 
 class SecurtiyGroupsRbacTest(rbac_base.BaseV2ComputeRbacTest):
     """Tests non-deprecated security group policies. Requires network service.
@@ -55,7 +67,7 @@
 
     @rbac_rule_validation.action(
         service="nova",
-        rules=["os_compute_api:os-security-groups"])
+        rules=[_SG_LIST])
     @decorators.idempotent_id('3db159c6-a467-469f-9a25-574197885520')
     def test_list_security_groups_by_server(self):
         with self.override_role():
@@ -64,7 +76,7 @@
 
     @rbac_rule_validation.action(
         service="nova",
-        rules=["os_compute_api:os-security-groups"])
+        rules=[_SG_ADD])
     @decorators.idempotent_id('ea1ca73f-2d1d-43cb-9a46-900d7927b357')
     def test_create_security_group_for_server(self):
         sg_name = self.create_security_group()['name']
@@ -78,7 +90,7 @@
 
     @rbac_rule_validation.action(
         service="nova",
-        rules=["os_compute_api:os-security-groups"])
+        rules=[_SG_REMOVE])
     @decorators.idempotent_id('0ad2e856-e2d3-4ac5-a620-f93d0d3d2626')
     def test_remove_security_group_from_server(self):
         sg_name = self.create_security_group()['name']
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 7bdd3da..95544b4 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
@@ -36,11 +36,15 @@
     _ATTACH_INTERFACES_LIST = "os_compute_api:os-attach-interfaces:list"
     _ATTACH_INTERFACES_SHOW = "os_compute_api:os-attach-interfaces:show"
     _INSTANCE_ACTIONS_LIST = "os_compute_api:os-instance-actions:list"
+    _SERVER_PASSWORD_SHOW = "os_compute_api:os-server-password:show"
+    _SERVER_PASSWORD_CLEAR = "os_compute_api:os-server-password:clear"
 else:
     _DEFERRED_FORCE = "os_compute_api:os-deferred-delete"
     _ATTACH_INTERFACES_LIST = "os_compute_api:os-attach-interfaces"
     _ATTACH_INTERFACES_SHOW = "os_compute_api:os-attach-interfaces"
     _INSTANCE_ACTIONS_LIST = "os_compute_api:os-instance-actions"
+    _SERVER_PASSWORD_SHOW = "os_compute_api:os-server-password"
+    _SERVER_PASSWORD_CLEAR = "os_compute_api:os-server-password"
 
 
 class MiscPolicyActionsRbacTest(rbac_base.BaseV2ComputeRbacTest):
@@ -493,7 +497,7 @@
     @decorators.idempotent_id('aaf43f78-c178-4581-ac18-14afd3f1f6ba')
     @rbac_rule_validation.action(
         service="nova",
-        rules=["os_compute_api:os-server-password"])
+        rules=[_SERVER_PASSWORD_CLEAR])
     def test_delete_server_password(self):
         """Test delete server password, part of os-server-password."""
         with self.override_role():
@@ -502,7 +506,7 @@
     @utils.requires_ext(extension='os-server-password', service='compute')
     @rbac_rule_validation.action(
         service="nova",
-        rules=["os_compute_api:os-server-password"])
+        rules=[_SERVER_PASSWORD_SHOW])
     @decorators.idempotent_id('f677971a-7d20-493c-977f-6ff0a74b5b2c')
     def test_get_server_password(self):
         """Test show server password, part of os-server-password."""
diff --git a/releasenotes/notes/adopt_nova_new_policies-c61d1c3751ff1bf9.yaml b/releasenotes/notes/adopt_nova_new_policies-c61d1c3751ff1bf9.yaml
index 67f28bc..545c544 100644
--- a/releasenotes/notes/adopt_nova_new_policies-c61d1c3751ff1bf9.yaml
+++ b/releasenotes/notes/adopt_nova_new_policies-c61d1c3751ff1bf9.yaml
@@ -13,3 +13,6 @@
       - os_compute_api:os-instance-usage-audit-log
       - os_compute_api:os-agents
       - os_compute_api:os-hypervisors
+      - os_compute_api:os-instance-actions
+      - os_compute_api:os-security-groups
+      - os_compute_api:os-server-password
diff --git a/releasenotes/notes/patrole-ussuri-release-6a2ec4e5c357fb19.yaml b/releasenotes/notes/patrole-ussuri-release-6a2ec4e5c357fb19.yaml
new file mode 100644
index 0000000..d4a262e
--- /dev/null
+++ b/releasenotes/notes/patrole-ussuri-release-6a2ec4e5c357fb19.yaml
@@ -0,0 +1,16 @@
+---
+prelude: >
+    This release is to tag the Patrole for OpenStack Ussuri release.
+    This release marks the start of Ussuri release support in Patrole.
+    After this release, Patrole will support below OpenStack Releases:
+
+      * Ussuri
+      * Train
+      * Stein
+
+    Current development of Patrole is for OpenStack Victoria development
+    cycle. Every Patrole commit is also tested against master during
+    the Victoria cycle. However, this does not necessarily mean that using
+    Patrole as of this tag will work against a Victoria (or future release)
+    cloud.
+    To be on safe side, use this tag to test the OpenStack Ussuri release.
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
index 1aeff4b..402c686 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -145,10 +145,6 @@
 # directly to the root of the documentation.
 # html_extra_path = []
 
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-html_last_updated_fmt = '%Y-%m-%d %H:%M'
-
 # If true, SmartyPants will be used to convert quotes and dashes to
 # typographically correct entities.
 # html_use_smartypants = True
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index 32f74ec..b3922e6 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -6,6 +6,7 @@
    :maxdepth: 1
 
    unreleased
+   v0.9.0
    v0.8.0
    v0.7.0
    v0.6.0
diff --git a/releasenotes/source/v0.9.0.rst b/releasenotes/source/v0.9.0.rst
new file mode 100644
index 0000000..364bd3a
--- /dev/null
+++ b/releasenotes/source/v0.9.0.rst
@@ -0,0 +1,6 @@
+====================
+v0.9.0 Release Notes
+====================
+
+.. release-notes:: 0.9.0 Release Notes
+   :version: 0.9.0
diff --git a/setup.cfg b/setup.cfg
index f8f0257..e4b9f91 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -14,22 +14,17 @@
     License :: OSI Approved :: Apache Software License
     Operating System :: POSIX :: Linux
     Programming Language :: Python
+    Programming Language :: Python :: Implementation :: CPython
+    Programming Language :: Python :: 3 :: Only
     Programming Language :: Python :: 3
     Programming Language :: Python :: 3.6
     Programming Language :: Python :: 3.7
+    Programming Language :: Python :: 3.8
 
 [files]
 packages =
     patrole_tempest_plugin
 
-[upload_sphinx]
-upload-dir = doc/build/html
-
-[build_releasenotes]
-all_files = 1
-build-dir = releasenotes/build
-source-dir = releasenotes/source
-
 [entry_points]
 tempest.test_plugins =
     patrole_tests = patrole_tempest_plugin.plugin:PatroleTempestPlugin
diff --git a/setup.py b/setup.py
index 566d844..cd35c3c 100644
--- a/setup.py
+++ b/setup.py
@@ -13,17 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
 import setuptools
 
-# In python < 2.7.4, a lazy loading of package `pbr` will break
-# setuptools if some other modules registered functions in `atexit`.
-# solution from: http://bugs.python.org/issue15881#msg170215
-try:
-    import multiprocessing  # noqa
-except ImportError:
-    pass
-
 setuptools.setup(
     setup_requires=['pbr>=2.0.0'],
     pbr=True)
diff --git a/tox.ini b/tox.ini
index f42a5b5..bb5f0d7 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,13 +1,12 @@
 [tox]
 minversion = 3.1.1
-envlist = pep8,py36,py37
+envlist = pep8,py36,py38
 skipsdist = True
 ignore_basepython_conflict = True
 
 [testenv]
 basepython = python3
 usedevelop = True
-install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} {opts} {packages}
 setenv =
    VIRTUAL_ENV={envdir}
    OS_TEST_PATH=./patrole_tempest_plugin/tests/unit
@@ -16,8 +15,10 @@
    PYTHONWARNINGS=default::DeprecationWarning
 passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
 whitelist_externals = find
-deps = -r{toxinidir}/requirements.txt
-       -r{toxinidir}/test-requirements.txt
+deps =
+    -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
+    -r{toxinidir}/requirements.txt
+    -r{toxinidir}/test-requirements.txt
 commands =
     find . -type f -name "*.pyc" -delete
     stestr --test-path ./patrole_tempest_plugin/tests/unit run {posargs}
@@ -70,10 +71,7 @@
    make -C doc/build/pdf
 
 [testenv:releasenotes]
-deps =
-  -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
-  -r{toxinidir}/requirements.txt
-  -r{toxinidir}/doc/requirements.txt
+deps = {[testenv:docs]deps}
 commands =
   rm -rf releasenotes/build
   sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html