Merge "Add releasenote to tag the end of support for Queens"
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_credentials_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_credentials_rbac.py
index 185dc8c..aa77aa3 100644
--- a/patrole_tempest_plugin/tests/api/identity/v3/test_credentials_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_credentials_rbac.py
@@ -45,6 +45,9 @@
         with self.override_role():
             self.setup_test_credential(user=user)
 
+    @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+                      'Skipped because environment has an immutable user '
+                      'source and solely provides read-only access to users.')
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:update_credential"])
     @decorators.idempotent_id('cfb05ce3-bffb-496e-a3c2-9515d730da63')
@@ -61,6 +64,9 @@
                 secret_key=new_keys[1],
                 project_id=credential['project_id'])
 
+    @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+                      'Skipped because environment has an immutable user '
+                      'source and solely provides read-only access to users.')
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:delete_credential"])
     @decorators.idempotent_id('87ab42af-8d41-401b-90df-21e72919fcde')
@@ -70,6 +76,9 @@
         with self.override_role():
             self.creds_client.delete_credential(credential['id'])
 
+    @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+                      'Skipped because environment has an immutable user '
+                      'source and solely provides read-only access to users.')
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:get_credential"])
     @decorators.idempotent_id('1b6eeae6-f1e8-4cdf-8903-1c002b1fc271')
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_groups_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_groups_rbac.py
index 7fc4a43..1e79501 100644
--- a/patrole_tempest_plugin/tests/api/identity/v3/test_groups_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_groups_rbac.py
@@ -13,12 +13,17 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
+from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.identity import rbac_base
 
+CONF = config.CONF
+
 
 class IdentityGroupsV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
 
@@ -82,6 +87,9 @@
         with self.override_role():
             self.groups_client.add_group_user(group['id'], user['id'])
 
+    @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+                      'Skipped because environment has an immutable user '
+                      'source and solely provides read-only access to users.')
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:remove_user_from_group"])
     @decorators.idempotent_id('8a60d11c-7d2b-47e5-a0f3-9ea900ca66fe')
@@ -100,6 +108,9 @@
         with self.override_role():
             self.groups_client.list_group_users(group['id'])
 
+    @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+                      'Skipped because environment has an immutable user '
+                      'source and solely provides read-only access to users.')
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:check_user_in_group"])
     @decorators.idempotent_id('d3603241-fd87-4a2d-94f9-f32469d1aaba')
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_roles_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_roles_rbac.py
index 4f447c0..c93afa1 100644
--- a/patrole_tempest_plugin/tests/api/identity/v3/test_roles_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_roles_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,8 @@
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.identity import rbac_base
 
+CONF = config.CONF
+
 
 class IdentityRolesV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
 
@@ -31,7 +34,6 @@
         cls.group = cls.setup_test_group()
         cls.role = cls.setup_test_role()
         cls.implies_role = cls.setup_test_role()
-        cls.user = cls.setup_test_user()
 
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:create_role"])
@@ -76,21 +78,6 @@
 
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:create_grant"])
-    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d909')
-    def test_create_user_role_on_project(self):
-        with self.override_role():
-            self.roles_client.create_user_role_on_project(
-                self.project['id'],
-                self.user['id'],
-                self.role['id'])
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.roles_client.delete_role_from_user_on_project,
-                        self.project['id'],
-                        self.user['id'],
-                        self.role['id'])
-
-    @rbac_rule_validation.action(service="keystone",
-                                 rules=["identity:create_grant"])
     @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90c')
     def test_create_group_role_on_project(self):
         with self.override_role():
@@ -106,21 +93,6 @@
 
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:create_grant"])
-    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90f')
-    def test_create_user_role_on_domain(self):
-        with self.override_role():
-            self.roles_client.create_user_role_on_domain(
-                self.domain['id'],
-                self.user['id'],
-                self.role['id'])
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.roles_client.delete_role_from_user_on_domain,
-                        self.domain['id'],
-                        self.user['id'],
-                        self.role['id'])
-
-    @rbac_rule_validation.action(service="keystone",
-                                 rules=["identity:create_grant"])
     @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d912')
     def test_create_group_role_on_domain(self):
         with self.override_role():
@@ -134,46 +106,6 @@
                         self.group['id'],
                         self.role['id'])
 
-    @rbac_rule_validation.action(service="keystone",
-                                 rules=["identity:check_grant"])
-    @decorators.idempotent_id('22921b1e-1a33-4026-bff9-f236d6dd149c')
-    def test_check_user_role_existence_on_project(self):
-        self.roles_client.create_user_role_on_project(
-            self.project['id'],
-            self.user['id'],
-            self.role['id'])
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.roles_client.delete_role_from_user_on_project,
-                        self.project['id'],
-                        self.user['id'],
-                        self.role['id'])
-
-        with self.override_role():
-            self.roles_client.check_user_role_existence_on_project(
-                self.project['id'],
-                self.user['id'],
-                self.role['id'])
-
-    @decorators.idempotent_id('92f8e67d-85bf-407d-9814-edd5664abc47')
-    @rbac_rule_validation.action(service="keystone",
-                                 rules=["identity:check_grant"])
-    def test_check_user_role_existence_on_domain(self):
-        self.roles_client.create_user_role_on_domain(
-            self.domain['id'],
-            self.user['id'],
-            self.role['id'])
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.roles_client.delete_role_from_user_on_domain,
-                        self.domain['id'],
-                        self.user['id'],
-                        self.role['id'])
-
-        with self.override_role():
-            self.roles_client.check_user_role_existence_on_domain(
-                self.domain['id'],
-                self.user['id'],
-                self.role['id'])
-
     @decorators.idempotent_id('8738d3d2-8c84-4423-b36c-7c59eaa08b73')
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:check_grant"])
@@ -216,26 +148,6 @@
 
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:revoke_grant"])
-    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90a')
-    def test_delete_role_from_user_on_project(self):
-        self.roles_client.create_user_role_on_project(
-            self.project['id'],
-            self.user['id'],
-            self.role['id'])
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.roles_client.delete_role_from_user_on_project,
-                        self.project['id'],
-                        self.user['id'],
-                        self.role['id'])
-
-        with self.override_role():
-            self.roles_client.delete_role_from_user_on_project(
-                self.project['id'],
-                self.user['id'],
-                self.role['id'])
-
-    @rbac_rule_validation.action(service="keystone",
-                                 rules=["identity:revoke_grant"])
     @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90d')
     def test_delete_role_from_group_on_project(self):
         self.roles_client.create_group_role_on_project(
@@ -256,26 +168,6 @@
 
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:revoke_grant"])
-    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d910')
-    def test_delete_role_from_user_on_domain(self):
-        self.roles_client.create_user_role_on_domain(
-            self.domain['id'],
-            self.user['id'],
-            self.role['id'])
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.roles_client.delete_role_from_user_on_domain,
-                        self.domain['id'],
-                        self.user['id'],
-                        self.role['id'])
-
-        with self.override_role():
-            self.roles_client.delete_role_from_user_on_domain(
-                self.domain['id'],
-                self.user['id'],
-                self.role['id'])
-
-    @rbac_rule_validation.action(service="keystone",
-                                 rules=["identity:revoke_grant"])
     @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d913')
     def test_delete_role_from_group_on_domain(self):
         self.roles_client.create_group_role_on_domain(
@@ -296,15 +188,6 @@
 
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:list_grants"])
-    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90b')
-    def test_list_user_roles_on_project(self):
-        with self.override_role():
-            self.roles_client.list_user_roles_on_project(
-                self.project['id'],
-                self.user['id'])
-
-    @rbac_rule_validation.action(service="keystone",
-                                 rules=["identity:list_grants"])
     @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90e')
     def test_list_group_roles_on_project(self):
         with self.override_role():
@@ -314,15 +197,6 @@
 
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:list_grants"])
-    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d911')
-    def test_list_user_roles_on_domain(self):
-        with self.override_role():
-            self.roles_client.list_user_roles_on_domain(
-                self.domain['id'],
-                self.user['id'])
-
-    @rbac_rule_validation.action(service="keystone",
-                                 rules=["identity:list_grants"])
     @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d914')
     def test_list_group_roles_on_domain(self):
         with self.override_role():
@@ -393,3 +267,156 @@
     def test_list_all_role_inference_rules(self):
         with self.override_role():
             self.roles_client.list_all_role_inference_rules()
+
+
+class IdentityRolesUserCreateV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
+    """Tests identity roles v3 API endpoints that require user creation.
+    This is in a separate class to better manage immutable user source feature
+    flag.
+    """
+
+    @classmethod
+    def skip_checks(cls):
+        super(IdentityRolesUserCreateV3RbacTest, cls).skip_checks()
+        if CONF.identity_feature_enabled.immutable_user_source:
+            raise cls.skipException('Skipped because environment has an '
+                                    'immutable user source and solely '
+                                    'provides read-only access to users.')
+
+    @classmethod
+    def resource_setup(cls):
+        super(IdentityRolesUserCreateV3RbacTest, cls).resource_setup()
+        cls.domain = cls.setup_test_domain()
+        cls.project = cls.setup_test_project()
+        cls.group = cls.setup_test_group()
+        cls.role = cls.setup_test_role()
+        cls.implies_role = cls.setup_test_role()
+        cls.user = cls.setup_test_user()
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rules=["identity:create_grant"])
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d909')
+    def test_create_user_role_on_project(self):
+        with self.override_role():
+            self.roles_client.create_user_role_on_project(
+                self.project['id'],
+                self.user['id'],
+                self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_user_on_project,
+                        self.project['id'],
+                        self.user['id'],
+                        self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rules=["identity:create_grant"])
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90f')
+    def test_create_user_role_on_domain(self):
+        with self.override_role():
+            self.roles_client.create_user_role_on_domain(
+                self.domain['id'],
+                self.user['id'],
+                self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_user_on_domain,
+                        self.domain['id'],
+                        self.user['id'],
+                        self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rules=["identity:check_grant"])
+    @decorators.idempotent_id('22921b1e-1a33-4026-bff9-f236d6dd149c')
+    def test_check_user_role_existence_on_project(self):
+        self.roles_client.create_user_role_on_project(
+            self.project['id'],
+            self.user['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_user_on_project,
+                        self.project['id'],
+                        self.user['id'],
+                        self.role['id'])
+
+        with self.override_role():
+            self.roles_client.check_user_role_existence_on_project(
+                self.project['id'],
+                self.user['id'],
+                self.role['id'])
+
+    @decorators.idempotent_id('92f8e67d-85bf-407d-9814-edd5664abc47')
+    @rbac_rule_validation.action(service="keystone",
+                                 rules=["identity:check_grant"])
+    def test_check_user_role_existence_on_domain(self):
+        self.roles_client.create_user_role_on_domain(
+            self.domain['id'],
+            self.user['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_user_on_domain,
+                        self.domain['id'],
+                        self.user['id'],
+                        self.role['id'])
+
+        with self.override_role():
+            self.roles_client.check_user_role_existence_on_domain(
+                self.domain['id'],
+                self.user['id'],
+                self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rules=["identity:revoke_grant"])
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90a')
+    def test_delete_role_from_user_on_project(self):
+        self.roles_client.create_user_role_on_project(
+            self.project['id'],
+            self.user['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_user_on_project,
+                        self.project['id'],
+                        self.user['id'],
+                        self.role['id'])
+
+        with self.override_role():
+            self.roles_client.delete_role_from_user_on_project(
+                self.project['id'],
+                self.user['id'],
+                self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rules=["identity:revoke_grant"])
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d910')
+    def test_delete_role_from_user_on_domain(self):
+        self.roles_client.create_user_role_on_domain(
+            self.domain['id'],
+            self.user['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_user_on_domain,
+                        self.domain['id'],
+                        self.user['id'],
+                        self.role['id'])
+
+        with self.override_role():
+            self.roles_client.delete_role_from_user_on_domain(
+                self.domain['id'],
+                self.user['id'],
+                self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rules=["identity:list_grants"])
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90b')
+    def test_list_user_roles_on_project(self):
+        with self.override_role():
+            self.roles_client.list_user_roles_on_project(
+                self.project['id'],
+                self.user['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rules=["identity:list_grants"])
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d911')
+    def test_list_user_roles_on_domain(self):
+        with self.override_role():
+            self.roles_client.list_user_roles_on_domain(
+                self.domain['id'],
+                self.user['id'])
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 bd34f9e..23c75c6 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
@@ -35,6 +35,10 @@
         if not CONF.identity_feature_enabled.trust:
             raise cls.skipException(
                 "%s skipped as trust feature isn't enabled" % cls.__name__)
+        if CONF.identity_feature_enabled.immutable_user_source:
+            raise cls.skipException('Skipped because environment has an '
+                                    'immutable user source and solely '
+                                    'provides read-only access to users.')
 
     @classmethod
     def resource_setup(cls):
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py
index 9f6f028..0d2a04d 100644
--- a/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py
@@ -13,12 +13,17 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
+from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.identity import rbac_base
 
+CONF = config.CONF
+
 
 class IdentityUserV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
 
@@ -27,6 +32,8 @@
         super(IdentityUserV3RbacTest, cls).resource_setup()
         cls.default_user_id = cls.os_primary.credentials.user_id
 
+    @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+                      "Configured to use an immutable user source")
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:create_user"])
     @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d904')
@@ -34,6 +41,8 @@
         with self.override_role():
             self.setup_test_user()
 
+    @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+                      "Configured to use an immutable user source")
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:update_user"])
     @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d905')
@@ -47,6 +56,8 @@
                                           name=user['name'],
                                           email=new_email)
 
+    @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+                      "Configured to use an immutable user source")
     @rbac_rule_validation.action(service="keystone",
                                  rules=["identity:delete_user"])
     @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d906')