Merge "Adding compute server tests"
diff --git a/patrole_tempest_plugin/tests/api/compute/test_agents_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_agents_rbac.py
index e2122c4..0de5e47 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_agents_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_agents_rbac.py
@@ -14,6 +14,8 @@
 #    under the License.
 
 from tempest import config
+from tempest import test
+
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
@@ -27,7 +29,7 @@
     @classmethod
     def skip_checks(cls):
         super(AgentsRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
+        if not test.is_extension_enabled('os-agents', 'compute'):
             raise cls.skipException(
                 '%s skipped as no compute extensions enabled' % cls.__name__)
 
@@ -37,3 +39,16 @@
     def test_list_agents_rbac(self):
         self.rbac_utils.switch_role(self, switchToRbacRole=True)
         self.agents_client.list_agents()
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-agents")
+    @decorators.idempotent_id('77d6cae4-1ced-47f7-af2e-3d6a45958fd6')
+    def test_create_agent(self):
+        params = {'hypervisor': 'kvm', 'os': 'win', 'architecture': 'x86',
+                  'version': '7.0', 'url': 'xxx://xxxx/xxx/xxx',
+                  'md5hash': 'add6bb58e139be103324d04d82d8f545'}
+        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        body = self.agents_client.create_agent(**params)['agent']
+        self.addCleanup(self.agents_client.delete_agent,
+                        body['agent_id'])
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_migrations_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_migrations_rbac.py
new file mode 100644
index 0000000..39afb4a
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_migrations_rbac.py
@@ -0,0 +1,105 @@
+# 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.
+
+import testtools
+
+from tempest.common import waiters
+from tempest import config
+
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.compute import rbac_base as base
+
+CONF = config.CONF
+
+
+class MigrateServerRbacTest(base.BaseV2ComputeRbacTest):
+
+    @classmethod
+    def setup_clients(cls):
+        super(MigrateServerRbacTest, cls).setup_clients()
+        cls.client = cls.servers_client
+        cls.admin_servers_client = cls.os_adm.servers_client
+        cls.hosts_client = cls.os.hosts_client
+
+    def _get_server_details(self, server_id):
+        body = self.client.show_server(server_id)['server']
+        return body
+
+    def _get_host_for_server(self, server_id):
+        return self._get_server_details(server_id)['OS-EXT-SRV-ATTR:host']
+
+    def _get_host_other_than(self, host):
+        for target_host in self._get_compute_hostnames():
+            if host != target_host:
+                return target_host
+
+    def _get_compute_hostnames(self):
+        body = self.hosts_client.list_hosts()['hosts']
+        return [
+            host_record['host_name']
+            for host_record in body
+            if host_record['service'] == 'compute'
+        ]
+
+    def _migrate_server_to(self, server_id, dest_host, volume_backed=False):
+        kwargs = dict()
+        block_migration = getattr(self, 'block_migration', None)
+        if self.block_migration is None:
+            kwargs['disk_over_commit'] = False
+            block_migration = (CONF.compute_feature_enabled.
+                               block_migration_for_live_migration and
+                               not volume_backed)
+        self.client.live_migrate_server(
+            server_id, host=dest_host, block_migration=block_migration,
+            **kwargs)
+
+    @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
+                          'Cold migration not available.')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-migrate-server:migrate")
+    @decorators.idempotent_id('c6f1607c-9fed-4c00-807e-9ba675b98b1b')
+    def test_cold_migration(self):
+        if CONF.compute.min_compute_nodes < 2:
+            msg = "Less than 2 compute nodes, skipping multinode tests."
+            raise self.skipException(msg)
+
+        server = self.create_test_server(wait_until="ACTIVE")
+        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.client.migrate_server(server['id'])
+        waiters.wait_for_server_status(self.admin_servers_client,
+                                       server['id'], 'VERIFY_RESIZE')
+
+    @testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
+                          'Live migration feature is not enabled.')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-migrate-server:migrate_live")
+    @decorators.idempotent_id('33520834-72c8-4edb-a189-a2e0fc9eb0d3')
+    def test_migration_live(self):
+        if CONF.compute.min_compute_nodes < 2:
+            msg = "Less than 2 compute nodes, skipping multinode tests."
+            raise self.skipException(msg)
+
+        server_id = self.create_test_server(wait_until="ACTIVE",
+                                            volume_backed=False)['id']
+        actual_host = self._get_host_for_server(server_id)
+        target_host = self._get_host_other_than(actual_host)
+        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self._migrate_server_to(server_id, target_host, volume_backed=False)
+        waiters.wait_for_server_status(self.admin_servers_client,
+                                       server_id, "ACTIVE")
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_password_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_password_rbac.py
index 849a19a..5f90c97 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_server_password_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_password_rbac.py
@@ -44,6 +44,14 @@
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-server-password")
-    def test_delete_password(self):
+    def test_delete_server_password(self):
         self.rbac_utils.switch_role(self, switchToRbacRole=True)
         self.client.delete_password(self.server['id'])
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-server-password")
+    @decorators.idempotent_id('f677971a-7d20-493c-977f-6ff0a74b5b2c')
+    def test_get_server_password(self):
+        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.client.show_password(self.server['id'])
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py
new file mode 100644
index 0000000..66676d1
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py
@@ -0,0 +1,70 @@
+# 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 oslo_log import log
+
+from tempest.common import waiters
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions
+
+from patrole_tempest_plugin import rbac_exceptions
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.compute import rbac_base as base
+
+LOG = log.getLogger(__name__)
+
+
+class ComputeServersRbacTest(base.BaseV2ComputeRbacTest):
+
+    @classmethod
+    def setup_clients(cls):
+        super(ComputeServersRbacTest, cls).setup_clients()
+        cls.client = cls.servers_client
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:create")
+    @decorators.idempotent_id('4f34c73a-6ddc-4677-976f-71320fa855bd')
+    def test_create_server(self):
+        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.create_test_server(wait_until='ACTIVE')
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:delete")
+    @decorators.idempotent_id('062e3440-e873-4b41-9317-bf6d8be50c12')
+    def test_delete_server(self):
+        server = self.create_test_server(wait_until='ACTIVE')
+        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.client.delete_server(server['id'])
+        waiters.wait_for_server_termination(self.client, server['id'])
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:update")
+    @decorators.idempotent_id('077b17cb-5621-43b9-8adf-5725f0d7a863')
+    def test_update_server(self):
+        server = self.create_test_server(wait_until='ACTIVE')
+        new_name = data_utils.rand_name('server')
+        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        try:
+            self.client.update_server(server['id'], name=new_name)
+        except exceptions.ServerFault as e:
+            # Some other policy may have blocked it.
+            LOG.info("ServerFault exception caught. Some other policy "
+                     "blocked updating of server")
+            raise rbac_exceptions.RbacActionFailed(e)
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_virtual_interfaces_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_virtual_interfaces_rbac.py
new file mode 100644
index 0000000..c523e84
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_virtual_interfaces_rbac.py
@@ -0,0 +1,51 @@
+# 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 import config
+
+from tempest.lib import decorators
+from tempest.lib import exceptions
+
+from patrole_tempest_plugin import rbac_exceptions
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.compute import rbac_base as base
+
+CONF = config.CONF
+
+
+class ServerVirtualInterfacesRbacTest(base.BaseV2ComputeRbacTest):
+
+    @classmethod
+    def setup_clients(cls):
+        super(ServerVirtualInterfacesRbacTest, cls).setup_clients()
+        cls.client = cls.servers_client
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-virtual-interfaces")
+    @decorators.idempotent_id('fc719ae3-0f73-4689-8378-1b841f0f2818')
+    def test_list_virtual_interfaces(self):
+        server = self.create_test_server(wait_until='ACTIVE')
+        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        try:
+            self.client.list_virtual_interfaces(server['id'])
+        except exceptions.ServerFault as e:
+            raise rbac_exceptions.RbacActionFailed(e)
+        except exceptions.BadRequest as e:
+            msg = "Listing virtual interfaces is not supported by this cloud."
+            if msg == str(e.resp_body['message']):
+                raise self.skipException(msg)
+            else:
+                raise e