Merge "Add missing baremetal API tests"
diff --git a/tempest/api/baremetal/admin/test_chassis.py b/tempest/api/baremetal/admin/test_chassis.py
index 254a969..2131e78 100644
--- a/tempest/api/baremetal/admin/test_chassis.py
+++ b/tempest/api/baremetal/admin/test_chassis.py
@@ -75,3 +75,9 @@
description=new_description))
_, chassis = self.client.show_chassis(uuid)
self.assertEqual(chassis['description'], new_description)
+
+ @test.attr(type='smoke')
+ def test_chassis_node_list(self):
+ _, node = self.create_node(self.chassis['uuid'])
+ _, body = self.client.list_chassis_nodes(self.chassis['uuid'])
+ self.assertIn(node['uuid'], [n['uuid'] for n in body['nodes']])
diff --git a/tempest/api/baremetal/admin/test_nodes.py b/tempest/api/baremetal/admin/test_nodes.py
index b9b9b55..8ccd36b 100644
--- a/tempest/api/baremetal/admin/test_nodes.py
+++ b/tempest/api/baremetal/admin/test_nodes.py
@@ -13,6 +13,8 @@
import six
from tempest.api.baremetal.admin import base
+from tempest.common.utils import data_utils
+from tempest.common import waiters
from tempest import exceptions as exc
from tempest import test
@@ -33,6 +35,17 @@
self.assertIn(key, actual)
self.assertEqual(value, actual[key])
+ def _associate_node_with_instance(self):
+ self.client.set_node_power_state(self.node['uuid'], 'power off')
+ waiters.wait_for_bm_node_status(self.client, self.node['uuid'],
+ 'power_state', 'power off')
+ instance_uuid = data_utils.rand_uuid()
+ self.client.update_node(self.node['uuid'],
+ instance_uuid=instance_uuid)
+ self.addCleanup(self.client.update_node,
+ uuid=self.node['uuid'], instance_uuid=None)
+ return instance_uuid
+
@test.attr(type='smoke')
def test_create_node(self):
params = {'cpu_arch': 'x86_64',
@@ -63,6 +76,34 @@
[i['uuid'] for i in body['nodes']])
@test.attr(type='smoke')
+ def test_list_nodes_association(self):
+ _, body = self.client.list_nodes(associated=True)
+ self.assertNotIn(self.node['uuid'],
+ [n['uuid'] for n in body['nodes']])
+
+ self._associate_node_with_instance()
+
+ _, body = self.client.list_nodes(associated=True)
+ self.assertIn(self.node['uuid'], [n['uuid'] for n in body['nodes']])
+
+ _, body = self.client.list_nodes(associated=False)
+ self.assertNotIn(self.node['uuid'], [n['uuid'] for n in body['nodes']])
+
+ @test.attr(type='smoke')
+ def test_node_port_list(self):
+ _, port = self.create_port(self.node['uuid'],
+ data_utils.rand_mac_address())
+ _, body = self.client.list_node_ports(self.node['uuid'])
+ self.assertIn(port['uuid'],
+ [p['uuid'] for p in body['ports']])
+
+ @test.attr(type='smoke')
+ def test_node_port_list_no_ports(self):
+ _, node = self.create_node(self.chassis['uuid'])
+ _, body = self.client.list_node_ports(node['uuid'])
+ self.assertEmpty(body['ports'])
+
+ @test.attr(type='smoke')
def test_update_node(self):
props = {'cpu_arch': 'x86_64',
'cpu_num': '12',
@@ -120,3 +161,10 @@
_, body = self.client.get_console(self.node['uuid'])
self.assertEqual(True, body['console_enabled'])
+
+ @test.attr(type='smoke')
+ def test_get_node_by_instance_uuid(self):
+ instance_uuid = self._associate_node_with_instance()
+ _, body = self.client.show_node_by_instance_uuid(instance_uuid)
+ self.assertEqual(len(body['nodes']), 1)
+ self.assertIn(self.node['uuid'], [n['uuid'] for n in body['nodes']])
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index c4f1214..52568cb 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -131,3 +131,31 @@
if caller:
message = '(%s) %s' % (caller, message)
raise exceptions.TimeoutException(message)
+
+
+def wait_for_bm_node_status(client, node_id, attr, status):
+ """Waits for a baremetal node attribute to reach given status.
+
+ The client should have a show_node(node_uuid) method to get the node.
+ """
+ _, node = client.show_node(node_id)
+ start = int(time.time())
+
+ while node[attr] != status:
+ time.sleep(client.build_interval)
+ _, node = client.show_node(node_id)
+ if node[attr] == status:
+ return
+
+ if int(time.time()) - start >= client.build_timeout:
+ message = ('Node %(node_id)s failed to reach %(attr)s=%(status)s '
+ 'within the required time (%(timeout)s s).' %
+ {'node_id': node_id,
+ 'attr': attr,
+ 'status': status,
+ 'timeout': client.build_timeout})
+ message += ' Current state of %s: %s.' % (attr, node[attr])
+ caller = misc_utils.find_test_caller()
+ if caller:
+ message = '(%s) %s' % (caller, message)
+ raise exceptions.TimeoutException(message)
diff --git a/tempest/services/baremetal/base.py b/tempest/services/baremetal/base.py
index 0b97f74..4933300 100644
--- a/tempest/services/baremetal/base.py
+++ b/tempest/services/baremetal/base.py
@@ -95,9 +95,13 @@
for ch in get_change(value, path + '%s/' % name):
yield ch
else:
- yield {'path': path + name,
- 'value': value,
- 'op': 'replace'}
+ if value is None:
+ yield {'path': path + name,
+ 'op': 'remove'}
+ else:
+ yield {'path': path + name,
+ 'value': value,
+ 'op': 'replace'}
patch = [ch for ch in get_change(kw)
if ch['path'].lstrip('/') in allowed_attributes]
diff --git a/tempest/services/baremetal/v1/base_v1.py b/tempest/services/baremetal/v1/base_v1.py
index 032e1da..9359808 100644
--- a/tempest/services/baremetal/v1/base_v1.py
+++ b/tempest/services/baremetal/v1/base_v1.py
@@ -27,9 +27,9 @@
self.uri_prefix = 'v%s' % self.version
@base.handle_errors
- def list_nodes(self):
+ def list_nodes(self, **kwargs):
"""List all existing nodes."""
- return self._list_request('nodes')
+ return self._list_request('nodes', **kwargs)
@base.handle_errors
def list_chassis(self):
@@ -37,11 +37,21 @@
return self._list_request('chassis')
@base.handle_errors
+ def list_chassis_nodes(self, chassis_uuid):
+ """List all nodes associated with a chassis."""
+ return self._list_request('/chassis/%s/nodes' % chassis_uuid)
+
+ @base.handle_errors
def list_ports(self, **kwargs):
"""List all existing ports."""
return self._list_request('ports', **kwargs)
@base.handle_errors
+ def list_node_ports(self, uuid):
+ """List all ports associated with the node."""
+ return self._list_request('/nodes/%s/ports' % uuid)
+
+ @base.handle_errors
def list_nodestates(self, uuid):
"""List all existing states."""
return self._list_request('/nodes/%s/states' % uuid)
@@ -68,6 +78,21 @@
return self._show_request('nodes', uuid)
@base.handle_errors
+ def show_node_by_instance_uuid(self, instance_uuid):
+ """
+ Gets a node associated with given instance uuid.
+
+ :param uuid: Unique identifier of the node in UUID format.
+ :return: Serialized node as a dictionary.
+
+ """
+ uri = '/nodes/detail?instance_uuid=%s' % instance_uuid
+
+ return self._show_request('nodes',
+ uuid=None,
+ uri=uri)
+
+ @base.handle_errors
def show_chassis(self, uuid):
"""
Gets a specific chassis.
@@ -203,7 +228,8 @@
'properties/cpu_num',
'properties/storage',
'properties/memory',
- 'driver')
+ 'driver',
+ 'instance_uuid')
patch = self._make_patch(node_attributes, **kwargs)