Merge "Use min_count to create servers in ListServersNegativeTestJSON"
diff --git a/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml b/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml
new file mode 100644
index 0000000..0de1803
--- /dev/null
+++ b/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Add show host API to the volume v2 hosts_client library.
+ This feature enables the possibility to show details for a host.
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index db24174..83447b6 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -24,6 +24,11 @@
class ImagesOneServerTestJSON(base.BaseV2ComputeTest):
@classmethod
+ def resource_setup(cls):
+ super(ImagesOneServerTestJSON, cls).resource_setup()
+ cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id']
+
+ @classmethod
def skip_checks(cls):
super(ImagesOneServerTestJSON, cls).skip_checks()
if not CONF.service_available.glance:
@@ -46,12 +51,10 @@
@decorators.idempotent_id('3731d080-d4c5-4872-b41a-64d0d0021314')
def test_create_delete_image(self):
- server_id = self.create_test_server(wait_until='ACTIVE')['id']
-
# Create a new image
name = data_utils.rand_name('image')
meta = {'image_type': 'test'}
- image = self.create_image_from_server(server_id, name=name,
+ image = self.create_image_from_server(self.server_id, name=name,
metadata=meta,
wait_until='ACTIVE')
@@ -76,8 +79,6 @@
@decorators.idempotent_id('3b7c6fe4-dfe7-477c-9243-b06359db51e6')
def test_create_image_specify_multibyte_character_image_name(self):
- server_id = self.create_test_server(wait_until='ACTIVE')['id']
-
# prefix character is:
# http://www.fileformat.info/info/unicode/char/1F4A9/index.htm
@@ -85,6 +86,6 @@
# #1370954 in glance which will 500 if mysql is used as the
# backend and it attempts to store a 4 byte utf-8 character
utf8_name = data_utils.rand_name(b'\xe2\x82\xa1'.decode('utf-8'))
- body = self.client.create_image(server_id, name=utf8_name)
+ body = self.client.create_image(self.server_id, name=utf8_name)
image_id = data_utils.parse_image_id(body.response['location'])
self.addCleanup(self.client.delete_image, image_id)
diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py
index 04d6cf9..e4ec442 100644
--- a/tempest/api/volume/admin/test_volume_hosts.py
+++ b/tempest/api/volume/admin/test_volume_hosts.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import random
+
from tempest.api.volume import base
from tempest.lib import decorators
@@ -22,5 +24,38 @@
@decorators.idempotent_id('d5f3efa2-6684-4190-9ced-1c2f526352ad')
def test_list_hosts(self):
hosts = self.admin_hosts_client.list_hosts()['hosts']
- self.assertGreaterEqual(len(hosts), 2, "No. of hosts are < 2,"
- "response of list hosts is: % s" % hosts)
+ self.assertGreaterEqual(len(hosts), 2,
+ "The count of volume hosts is < 2, "
+ "response of list hosts is: %s" % hosts)
+
+ # Check elements in volume hosts list
+ host_list_keys = ['service', 'host_name', 'last-update',
+ 'zone', 'service-status', 'service-state']
+ for host in hosts:
+ for key in host_list_keys:
+ self.assertIn(key, host)
+
+ @decorators.idempotent_id('21168d57-b373-4b71-a3ac-f2c88f0c5d31')
+ def test_show_host(self):
+ hosts = self.admin_hosts_client.list_hosts()['hosts']
+ self.assertGreaterEqual(len(hosts), 2,
+ "The count of volume hosts is < 2, "
+ "response of list hosts is: %s" % hosts)
+
+ # Note(jeremyZ): Host in volume is always presented in two formats:
+ # <host-name> or <host-name>@<driver-name>. Since Mitaka is EOL,
+ # both formats can be chosen for test.
+ host_names = [host['host_name'] for host in hosts]
+ self.assertNotEmpty(host_names, "No available volume host is found, "
+ "all hosts that found are: %s" % hosts)
+
+ # Choose a random host to get and check its elements
+ host_details = self.admin_hosts_client.show_host(
+ random.choice(host_names))['host']
+ self.assertNotEmpty(host_details)
+ host_detail_keys = ['project', 'volume_count', 'snapshot_count',
+ 'host', 'total_volume_gb', 'total_snapshot_gb']
+ for detail in host_details:
+ self.assertIn('resource', detail)
+ for key in host_detail_keys:
+ self.assertIn(key, detail['resource'])
diff --git a/tempest/lib/services/volume/v2/hosts_client.py b/tempest/lib/services/volume/v2/hosts_client.py
index dd7c482..8fcf4d0 100644
--- a/tempest/lib/services/volume/v2/hosts_client.py
+++ b/tempest/lib/services/volume/v2/hosts_client.py
@@ -34,3 +34,11 @@
body = json.loads(body)
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
+
+ def show_host(self, host_name):
+ """Show host details."""
+ url = 'os-hosts/%s' % host_name
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/tests/lib/services/volume/v2/test_hosts_client.py b/tempest/tests/lib/services/volume/v2/test_hosts_client.py
new file mode 100644
index 0000000..e107910
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v2/test_hosts_client.py
@@ -0,0 +1,97 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# 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.services.volume.v2 import hosts_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestQuotasClient(base.BaseServiceTest):
+ FAKE_LIST_HOSTS = {
+ "hosts": [
+ {
+ "service-status": "available",
+ "service": "cinder-scheduler",
+ "zone": "nova",
+ "service-state": "enabled",
+ "host_name": "fake-host",
+ "last-update": "2017-04-12T04:26:03.000000"
+ },
+ {
+ "service-status": "available",
+ "service": "cinder-volume",
+ "zone": "nova",
+ "service-state": "enabled",
+ "host_name": "fake-host@rbd",
+ "last-update": "2017-04-12T04:26:07.000000"
+ }
+ ]
+ }
+
+ FAKE_HOST_INFO = {
+ "host": [
+ {
+ "resource": {
+ "volume_count": "2",
+ "total_volume_gb": "2",
+ "total_snapshot_gb": "0",
+ "project": "(total)",
+ "host": "fake-host",
+ "snapshot_count": "0"
+ }
+ },
+ {
+ "resource": {
+ "volume_count": "2",
+ "total_volume_gb": "2",
+ "total_snapshot_gb": "0",
+ "project": "f21a9c86d7114bf99c711f4874d80474",
+ "host": "fake-host",
+ "snapshot_count": "0"
+ }
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestQuotasClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = hosts_client.HostsClient(fake_auth,
+ 'volume',
+ 'regionOne')
+
+ def _test_list_hosts(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_hosts,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_HOSTS, bytes_body)
+
+ def _test_show_host(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_host,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_HOST_INFO, bytes_body, host_name='fake-host')
+
+ def test_list_hosts_with_str_body(self):
+ self._test_list_hosts()
+
+ def test_list_hosts_with_bytes_body(self):
+ self._test_list_hosts(bytes_body=True)
+
+ def test_show_host_with_str_body(self):
+ self._test_show_host()
+
+ def test_show_host_with_bytes_body(self):
+ self._test_show_host(bytes_body=True)