Add node traits support to baremetal
This patch adds add-trait, remove-trait and set-traits methods to the baremetal module. Change-Id: I9c2dd35c1c5f823d8c482f0177e87d49024242a4
This commit is contained in:
parent
a88328e90e
commit
f162b71cb8
@ -917,3 +917,44 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
res = self._get_resource(_allocation.Allocation, allocation)
|
||||
return res.wait(self, timeout=timeout, ignore_error=ignore_error)
|
||||
|
||||
def add_node_trait(self, node, trait):
|
||||
"""Add a trait to a node.
|
||||
|
||||
:param node: The value can be the name or ID of a node or a
|
||||
:class:`~openstack.baremetal.v1.node.Node` instance.
|
||||
:param trait: trait to remove from the node.
|
||||
:returns: The updated node
|
||||
"""
|
||||
res = self._get_resource(_node.Node, node)
|
||||
return res.add_trait(self, trait)
|
||||
|
||||
def remove_node_trait(self, node, trait, ignore_missing=True):
|
||||
"""Remove a trait from a node.
|
||||
|
||||
:param node: The value can be the name or ID of a node or a
|
||||
:class:`~openstack.baremetal.v1.node.Node` instance.
|
||||
:param trait: trait to remove from the node.
|
||||
:param bool ignore_missing: When set to ``False``, an exception
|
||||
:class:`~openstack.exceptions.ResourceNotFound` will be raised
|
||||
when the trait could not be found. When set to ``True``, no
|
||||
exception will be raised when attempting to delete a non-existent
|
||||
trait.
|
||||
:returns: The updated :class:`~openstack.baremetal.v1.node.Node`
|
||||
"""
|
||||
res = self._get_resource(_node.Node, node)
|
||||
return res.remove_trait(self, trait, ignore_missing=ignore_missing)
|
||||
|
||||
def set_node_traits(self, node, traits):
|
||||
"""Set traits for a node.
|
||||
|
||||
Removes any existing traits and adds the traits passed in to this
|
||||
method.
|
||||
|
||||
:param node: The value can be the name or ID of a node or a
|
||||
:class:`~openstack.baremetal.v1.node.Node` instance.
|
||||
:param traits: list of traits to add to the node.
|
||||
:returns: The updated :class:`~openstack.baremetal.v1.node.Node`
|
||||
"""
|
||||
res = self._get_resource(_node.Node, node)
|
||||
return res.set_traits(self, traits)
|
||||
|
@ -745,5 +745,89 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
.format(node=self.id))
|
||||
exceptions.raise_from_response(response, error_message=msg)
|
||||
|
||||
def add_trait(self, session, trait):
|
||||
"""Add a trait to a node.
|
||||
|
||||
:param session: The session to use for making this request.
|
||||
:param trait: The trait to add to the node.
|
||||
:returns: The updated :class:`~openstack.baremetal.v1.node.Node`
|
||||
"""
|
||||
session = self._get_session(session)
|
||||
version = utils.pick_microversion(session, '1.37')
|
||||
request = self._prepare_request(requires_id=True)
|
||||
request.url = utils.urljoin(request.url, 'traits', trait)
|
||||
response = session.put(
|
||||
request.url, json=None,
|
||||
headers=request.headers, microversion=version,
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
|
||||
|
||||
msg = ("Failed to add trait {trait} for node {node}"
|
||||
.format(trait=trait, node=self.id))
|
||||
exceptions.raise_from_response(response, error_message=msg)
|
||||
|
||||
self.traits = list(set(self.traits or ()) | {trait})
|
||||
|
||||
def remove_trait(self, session, trait, ignore_missing=True):
|
||||
"""Remove a trait from a node.
|
||||
|
||||
:param session: The session to use for making this request.
|
||||
:param trait: The trait to remove from the node.
|
||||
:param bool ignore_missing: When set to ``False``
|
||||
:class:`~openstack.exceptions.ResourceNotFound` will be
|
||||
raised when the trait does not exist.
|
||||
Otherwise, ``False`` is returned.
|
||||
:returns: The updated :class:`~openstack.baremetal.v1.node.Node`
|
||||
"""
|
||||
session = self._get_session(session)
|
||||
version = utils.pick_microversion(session, '1.37')
|
||||
request = self._prepare_request(requires_id=True)
|
||||
request.url = utils.urljoin(request.url, 'traits', trait)
|
||||
|
||||
response = session.delete(
|
||||
request.url, headers=request.headers, microversion=version,
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
|
||||
|
||||
if ignore_missing or response.status_code == 400:
|
||||
session.log.debug(
|
||||
'Trait %(trait)s was already removed from node %(node)s',
|
||||
{'trait': trait, 'node': self.id})
|
||||
return False
|
||||
|
||||
msg = ("Failed to remove trait {trait} from bare metal node {node}"
|
||||
.format(node=self.id, trait=trait))
|
||||
exceptions.raise_from_response(response, error_message=msg)
|
||||
|
||||
self.traits = list(set(self.traits) - {trait})
|
||||
|
||||
return True
|
||||
|
||||
def set_traits(self, session, traits):
|
||||
"""Set traits for a node.
|
||||
|
||||
Removes any existing traits and adds the traits passed in to this
|
||||
method.
|
||||
|
||||
:param session: The session to use for making this request.
|
||||
:param traits: list of traits to add to the node.
|
||||
:returns: The updated :class:`~openstack.baremetal.v1.node.Node`
|
||||
"""
|
||||
session = self._get_session(session)
|
||||
version = utils.pick_microversion(session, '1.37')
|
||||
request = self._prepare_request(requires_id=True)
|
||||
request.url = utils.urljoin(request.url, 'traits')
|
||||
|
||||
body = {'traits': traits}
|
||||
|
||||
response = session.put(
|
||||
request.url, json=body,
|
||||
headers=request.headers, microversion=version,
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
|
||||
|
||||
msg = ("Failed to set traits for node {node}"
|
||||
.format(node=self.id))
|
||||
exceptions.raise_from_response(response, error_message=msg)
|
||||
|
||||
self.traits = traits
|
||||
|
||||
|
||||
NodeDetail = Node
|
||||
|
@ -303,3 +303,49 @@ class TestBareMetalVif(base.BaseBaremetalTest):
|
||||
self.assertRaises(exceptions.ResourceNotFound,
|
||||
self.conn.baremetal.detach_vif_from_node,
|
||||
uuid, self.vif_id, ignore_missing=False)
|
||||
|
||||
|
||||
class TestTraits(base.BaseBaremetalTest):
|
||||
|
||||
min_microversion = '1.37'
|
||||
|
||||
def setUp(self):
|
||||
super(TestTraits, self).setUp()
|
||||
self.node = self.create_node()
|
||||
|
||||
def test_add_remove_node_trait(self):
|
||||
node = self.conn.baremetal.get_node(self.node)
|
||||
self.assertEqual([], node.traits)
|
||||
|
||||
self.conn.baremetal.add_node_trait(self.node, 'CUSTOM_FAKE')
|
||||
self.assertEqual(['CUSTOM_FAKE'], self.node.traits)
|
||||
node = self.conn.baremetal.get_node(self.node)
|
||||
self.assertEqual(['CUSTOM_FAKE'], node.traits)
|
||||
|
||||
self.conn.baremetal.add_node_trait(self.node, 'CUSTOM_REAL')
|
||||
self.assertEqual(['CUSTOM_FAKE', 'CUSTOM_REAL'], self.node.traits)
|
||||
node = self.conn.baremetal.get_node(self.node)
|
||||
self.assertEqual(['CUSTOM_FAKE', 'CUSTOM_REAL'], node.traits)
|
||||
|
||||
self.conn.baremetal.remove_node_trait(node, 'CUSTOM_FAKE',
|
||||
ignore_missing=False)
|
||||
self.assertEqual(['CUSTOM_REAL'], self.node.traits)
|
||||
node = self.conn.baremetal.get_node(self.node)
|
||||
self.assertEqual(['CUSTOM_REAL'], node.traits)
|
||||
|
||||
def test_set_node_traits(self):
|
||||
node = self.conn.baremetal.get_node(self.node)
|
||||
self.assertEqual([], node.traits)
|
||||
|
||||
traits1 = ['CUSTOM_FAKE', 'CUSTOM_REAL']
|
||||
traits2 = ['CUSTOM_FOOBAR']
|
||||
|
||||
self.conn.baremetal.set_node_traits(self.node, traits1)
|
||||
self.assertEqual(['CUSTOM_FAKE', 'CUSTOM_REAL'], self.node.traits)
|
||||
node = self.conn.baremetal.get_node(self.node)
|
||||
self.assertEqual(['CUSTOM_FAKE', 'CUSTOM_REAL'], node.traits)
|
||||
|
||||
self.conn.baremetal.set_node_traits(self.node, traits2)
|
||||
self.assertEqual(['CUSTOM_FOOBAR'], self.node.traits)
|
||||
node = self.conn.baremetal.get_node(self.node)
|
||||
self.assertEqual(['CUSTOM_FOOBAR'], node.traits)
|
||||
|
@ -702,3 +702,48 @@ class TestNodeSetBootDevice(base.TestCase):
|
||||
json={'boot_device': 'pxe', 'persistent': False},
|
||||
headers=mock.ANY, microversion=mock.ANY,
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
|
||||
|
||||
|
||||
@mock.patch.object(node.Node, 'fetch', lambda self, session: self)
|
||||
@mock.patch.object(exceptions, 'raise_from_response', mock.Mock())
|
||||
class TestNodeTraits(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestNodeTraits, self).setUp()
|
||||
self.node = node.Node(**FAKE)
|
||||
self.session = mock.Mock(spec=adapter.Adapter,
|
||||
default_microversion='1.37')
|
||||
self.session.log = mock.Mock()
|
||||
|
||||
def test_node_add_trait(self):
|
||||
self.node.add_trait(self.session, 'CUSTOM_FAKE')
|
||||
self.session.put.assert_called_once_with(
|
||||
'nodes/%s/traits/%s' % (self.node.id, 'CUSTOM_FAKE'),
|
||||
json=None,
|
||||
headers=mock.ANY, microversion='1.37',
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
|
||||
|
||||
def test_remove_trait(self):
|
||||
self.node.remove_trait(self.session, 'CUSTOM_FAKE')
|
||||
self.session.delete.assert_called_once_with(
|
||||
'nodes/%s/traits/%s' % (self.node.id, 'CUSTOM_FAKE'),
|
||||
headers=mock.ANY, microversion='1.37',
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
|
||||
|
||||
def test_remove_trait_missing(self):
|
||||
self.session.delete.return_value.status_code = 400
|
||||
self.assertFalse(self.node.remove_trait(self.session,
|
||||
'CUSTOM_MISSING'))
|
||||
self.session.delete.assert_called_once_with(
|
||||
'nodes/%s/traits/%s' % (self.node.id, 'CUSTOM_MISSING'),
|
||||
headers=mock.ANY, microversion='1.37',
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
|
||||
|
||||
def test_set_traits(self):
|
||||
traits = ['CUSTOM_FAKE', 'CUSTOM_REAL', 'CUSTOM_MISSING']
|
||||
self.node.set_traits(self.session, traits)
|
||||
self.session.put.assert_called_once_with(
|
||||
'nodes/%s/traits' % self.node.id,
|
||||
json={'traits': ['CUSTOM_FAKE', 'CUSTOM_REAL', 'CUSTOM_MISSING']},
|
||||
headers=mock.ANY, microversion='1.37',
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Implements add/remove/set traits API for bare metal nodes.
|
Loading…
Reference in New Issue
Block a user