diff --git a/doc/api_samples/os-hosts/host-get-resp.json b/doc/api_samples/os-hosts/host-get-resp.json
new file mode 100644
index 000000000000..83b5e38c6495
--- /dev/null
+++ b/doc/api_samples/os-hosts/host-get-resp.json
@@ -0,0 +1,31 @@
+{
+ "host": [
+ {
+ "resource": {
+ "cpu": 1,
+ "disk_gb": 1028,
+ "host": "5ca60c6792a1442f9471ff575443f94d",
+ "memory_mb": 8192,
+ "project": "(total)"
+ }
+ },
+ {
+ "resource": {
+ "cpu": 0,
+ "disk_gb": 0,
+ "host": "5ca60c6792a1442f9471ff575443f94d",
+ "memory_mb": 512,
+ "project": "(used_now)"
+ }
+ },
+ {
+ "resource": {
+ "cpu": 0,
+ "disk_gb": 0,
+ "host": "5ca60c6792a1442f9471ff575443f94d",
+ "memory_mb": 0,
+ "project": "(used_max)"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/doc/api_samples/os-hosts/host-get-resp.xml b/doc/api_samples/os-hosts/host-get-resp.xml
new file mode 100644
index 000000000000..197812c87500
--- /dev/null
+++ b/doc/api_samples/os-hosts/host-get-resp.xml
@@ -0,0 +1,24 @@
+
+
+
+ (total)
+ 8192
+ ecf3458ac6bf4a299cc2e0efa740f426
+ 1
+ 1028
+
+
+ (used_now)
+ 512
+ ecf3458ac6bf4a299cc2e0efa740f426
+ 0
+ 0
+
+
+ (used_max)
+ 0
+ ecf3458ac6bf4a299cc2e0efa740f426
+ 0
+ 0
+
+
\ No newline at end of file
diff --git a/doc/api_samples/os-hosts/hosts-list-resp.json b/doc/api_samples/os-hosts/hosts-list-resp.json
new file mode 100644
index 000000000000..760db64ff4bf
--- /dev/null
+++ b/doc/api_samples/os-hosts/hosts-list-resp.json
@@ -0,0 +1,24 @@
+{
+ "hosts": [
+ {
+ "host_name": "c5a4acad61bc463ab5f60d164d942516",
+ "service": "compute",
+ "zone": "nova"
+ },
+ {
+ "host_name": "9112426abe5f4934a81b494fcdee8c5b",
+ "service": "cert",
+ "zone": "nova"
+ },
+ {
+ "host_name": "d483b9e6124d47f2a6ad14e57716a778",
+ "service": "network",
+ "zone": "nova"
+ },
+ {
+ "host_name": "3f9c73ba6d634092a70d6640f53930c8",
+ "service": "scheduler",
+ "zone": "nova"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/doc/api_samples/os-hosts/hosts-list-resp.xml b/doc/api_samples/os-hosts/hosts-list-resp.xml
new file mode 100644
index 000000000000..7defe045734f
--- /dev/null
+++ b/doc/api_samples/os-hosts/hosts-list-resp.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/nova/api/openstack/compute/contrib/hosts.py b/nova/api/openstack/compute/contrib/hosts.py
index 237872405847..c319450cf210 100644
--- a/nova/api/openstack/compute/contrib/hosts.py
+++ b/nova/api/openstack/compute/contrib/hosts.py
@@ -34,11 +34,7 @@ authorize = extensions.extension_authorizer('compute', 'hosts')
class HostIndexTemplate(xmlutil.TemplateBuilder):
def construct(self):
- def shimmer(obj, do_raise=False):
- # A bare list is passed in; we need to wrap it in a dict
- return dict(hosts=obj)
-
- root = xmlutil.TemplateElement('hosts', selector=shimmer)
+ root = xmlutil.TemplateElement('hosts')
elem = xmlutil.SubTemplateElement(root, 'host', selector='hosts')
elem.set('host_name')
elem.set('service')
diff --git a/nova/tests/api/openstack/compute/contrib/test_hosts.py b/nova/tests/api/openstack/compute/contrib/test_hosts.py
index 9445947883e8..73c110dabdf8 100644
--- a/nova/tests/api/openstack/compute/contrib/test_hosts.py
+++ b/nova/tests/api/openstack/compute/contrib/test_hosts.py
@@ -26,11 +26,12 @@ from nova.openstack.common import log as logging
from nova import test
LOG = logging.getLogger(__name__)
-HOST_LIST = [
+HOST_LIST = {"hosts": [
{"host_name": "host_c1", "service": "compute", "zone": "nova"},
{"host_name": "host_c2", "service": "compute", "zone": "nonova"},
{"host_name": "host_v1", "service": "volume", "zone": "nova"},
{"host_name": "host_v2", "service": "volume", "zone": "nonova"}]
+ }
HOST_LIST_NOVA_ZONE = [
{"host_name": "host_c1", "service": "compute", "zone": "nova"},
{"host_name": "host_v1", "service": "volume", "zone": "nova"}]
@@ -130,10 +131,10 @@ class HostTestCase(test.TestCase):
def test_list_hosts(self):
"""Verify that the compute hosts are returned."""
hosts = os_hosts._list_hosts(self.req)
- self.assertEqual(hosts, HOST_LIST)
+ self.assertEqual(hosts, HOST_LIST['hosts'])
compute_hosts = os_hosts._list_hosts(self.req, "compute")
- expected = [host for host in HOST_LIST
+ expected = [host for host in HOST_LIST['hosts']
if host["service"] == "compute"]
self.assertEqual(compute_hosts, expected)
@@ -281,12 +282,12 @@ class HostSerializerTest(test.TestCase):
tree = etree.fromstring(text)
self.assertEqual('hosts', tree.tag)
- self.assertEqual(len(HOST_LIST), len(tree))
+ self.assertEqual(len(HOST_LIST['hosts']), len(tree))
for i in range(len(HOST_LIST)):
self.assertEqual('host', tree[i].tag)
- self.assertEqual(HOST_LIST[i]['host_name'],
+ self.assertEqual(HOST_LIST['hosts'][i]['host_name'],
tree[i].get('host_name'))
- self.assertEqual(HOST_LIST[i]['service'],
+ self.assertEqual(HOST_LIST['hosts'][i]['service'],
tree[i].get('service'))
def test_update_serializer_with_status(self):
diff --git a/nova/tests/integrated/api_samples/os-hosts/host-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-hosts/host-get-resp.json.tpl
new file mode 100644
index 000000000000..efb234b436ef
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-hosts/host-get-resp.json.tpl
@@ -0,0 +1,31 @@
+{
+ "host": [
+ {
+ "resource": {
+ "cpu": 1,
+ "disk_gb": 1028,
+ "host": "%(host_name)s",
+ "memory_mb": 8192,
+ "project": "(total)"
+ }
+ },
+ {
+ "resource": {
+ "cpu": 0,
+ "disk_gb": 0,
+ "host": "%(host_name)s",
+ "memory_mb": 512,
+ "project": "(used_now)"
+ }
+ },
+ {
+ "resource": {
+ "cpu": 0,
+ "disk_gb": 0,
+ "host": "%(host_name)s",
+ "memory_mb": 0,
+ "project": "(used_max)"
+ }
+ }
+ ]
+}
diff --git a/nova/tests/integrated/api_samples/os-hosts/host-get-resp.xml.tpl b/nova/tests/integrated/api_samples/os-hosts/host-get-resp.xml.tpl
new file mode 100644
index 000000000000..e162734ba340
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-hosts/host-get-resp.xml.tpl
@@ -0,0 +1,24 @@
+
+
+
+ (total)
+ 8192
+ %(host_name)s
+ 1
+ 1028
+
+
+ (used_now)
+ 512
+ %(host_name)s
+ 0
+ 0
+
+
+ (used_max)
+ 0
+ %(host_name)s
+ 0
+ 0
+
+
diff --git a/nova/tests/integrated/api_samples/os-hosts/hosts-list-resp.json.tpl b/nova/tests/integrated/api_samples/os-hosts/hosts-list-resp.json.tpl
new file mode 100644
index 000000000000..30444099dc95
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-hosts/hosts-list-resp.json.tpl
@@ -0,0 +1,24 @@
+{
+ "hosts": [
+ {
+ "host_name": "%(host_name)s",
+ "service": "compute",
+ "zone": "nova"
+ },
+ {
+ "host_name": "%(host_name)s",
+ "service": "cert",
+ "zone": "nova"
+ },
+ {
+ "host_name": "%(host_name)s",
+ "service": "network",
+ "zone": "nova"
+ },
+ {
+ "host_name": "%(host_name)s",
+ "service": "scheduler",
+ "zone": "nova"
+ }
+ ]
+}
diff --git a/nova/tests/integrated/api_samples/os-hosts/hosts-list-resp.xml.tpl b/nova/tests/integrated/api_samples/os-hosts/hosts-list-resp.xml.tpl
new file mode 100644
index 000000000000..4fc35a54b837
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-hosts/hosts-list-resp.xml.tpl
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py
index 62d49ad0a5b4..b5bd4bf0bcfd 100644
--- a/nova/tests/integrated/test_api_samples.py
+++ b/nova/tests/integrated/test_api_samples.py
@@ -244,6 +244,7 @@ class ApiSampleTestBase(integrated_helpers._IntegratedTestBase):
# '[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:'
# '[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}',
'host': self._get_host(),
+ 'host_name': '[0-9a-z]{32}',
'glance_host': self._get_glance_host(),
'compute_host': self.compute.host,
'text': text,
@@ -456,6 +457,24 @@ class FlavorsSampleXmlTest(FlavorsSampleJsonTest):
ctype = 'xml'
+class HostsSampleJsonTest(ApiSampleTestBase):
+ extension_name = "nova.api.openstack.compute.contrib.hosts.Hosts"
+
+ def test_host_get(self):
+ response = self._do_get('os-hosts/%s' % self.compute.host)
+ subs = self._get_regexes()
+ return self._verify_response('host-get-resp', subs, response)
+
+ def test_hosts_list(self):
+ response = self._do_get('os-hosts')
+ subs = self._get_regexes()
+ return self._verify_response('hosts-list-resp', subs, response)
+
+
+class HostsSampleXmlTest(HostsSampleJsonTest):
+ ctype = 'xml'
+
+
class FlavorsSampleAllExtensionJsonTest(FlavorsSampleJsonTest):
all_extensions = True