Support to node-adopt and node-adopt-preview

This adds support to adopt and adopt-preview API added to Senlin
API (microversion 1.7)

Change-Id: Ic3a11a094ba36d6875953cf10da11aae563e10a4
This commit is contained in:
tengqm 2017-07-17 21:31:10 -04:00
parent 1213ccb00f
commit d946438a34
5 changed files with 101 additions and 0 deletions

View File

@ -125,6 +125,7 @@ Node Operations
.. automethod:: openstack.cluster.v1._proxy.Proxy.recover_node
.. automethod:: openstack.cluster.v1._proxy.Proxy.perform_operation_on_node
.. automethod:: openstack.cluster.v1._proxy.Proxy.adopt_node
.. automethod:: openstack.cluster.v1._proxy.Proxy.node_operation

View File

@ -722,6 +722,38 @@ class Proxy(proxy2.BaseProxy):
obj = self._get_resource(_node.Node, node)
return obj.recover(self._session, **params)
def adopt_node(self, preview=False, **attrs):
"""Adopting an existing resource as a node.
:param preview: A boolean indicating whether this is a "preview"
operation which means only the profile to be used is returned
rather than creating a node object using that profile.
:param dict attrs: Keyword parameters for node adoption. Valid
parameters include:
* type: (Required) A string containing the profile type and
version to be used for node adoption. For example,
``os.nova.sever-1.0``.
* identity: (Required) A string including the name or ID of an
OpenStack resource to be adopted as a Senlin node.
* name: (Optional) The name of of node to be created. Omitting
this parameter will have the node named automatically.
* snapshot: (Optional) A boolean indicating whether a snapshot
of the target resource should be created if possible. Default
is False.
* metadata: (Optional) A dictionary of arbitrary key-value pairs
to be associated with the adopted node.
* overrides: (Optional) A dictionary of key-value pairs to be used
to override attributes derived from the target resource.
:returns: The result of node adoption. If `preview` is set to False
(default), returns a :class:`~openstack.cluster.v1.node.Node`
object, otherwise a Dict is returned containing the profile to
be used for the new node.
"""
node = self._get_resource(_node.Node, None)
return node.adopt(self._session, preview=preview, **attrs)
@utils.deprecated(deprecated_in="0.9.14", removed_in="1.0",
details="Use perform_operation_on_node instead")
def node_operation(self, node, operation, **params):

View File

@ -125,6 +125,24 @@ class Node(resource.Resource):
json={operation: params})
return resp.json()
def adopt(self, session, preview=False, **params):
"""Adopt a node for management.
:param session: A session object used for sending request.
:param preview: A boolean indicating whether the adoption is a
preview. A "preview" does not create the node object.
:param dict params: A dict providing the details of a node to be
adopted.
"""
path = "adopt-preview" if preview else "adopt"
url = utils.urljoin(self.base_path, path)
resp = session.post(url, endpoint_filter=self.service, json=params)
if preview:
return resp.json()
self._translate_response(resp)
return self
class NodeDetail(Node):
base_path = '/nodes/%(node_id)s?show_details=True'

View File

@ -104,6 +104,34 @@ class TestNode(testtools.TestCase):
sess.post.assert_called_once_with(url, endpoint_filter=sot.service,
json={'dance': {'style': 'tango'}})
def test_adopt_preview(self):
sot = node.Node.new()
resp = mock.Mock()
resp.headers = {}
resp.json = mock.Mock(return_value={"foo": "bar"})
sess = mock.Mock()
sess.post = mock.Mock(return_value=resp)
res = sot.adopt(sess, True, param="value")
self.assertEqual({"foo": "bar"}, res)
sess.post.assert_called_once_with("nodes/adopt-preview",
endpoint_filter=sot.service,
json={"param": "value"})
def test_adopt(self):
sot = node.Node.new()
resp = mock.Mock()
resp.headers = {}
resp.json = mock.Mock(return_value={"foo": "bar"})
sess = mock.Mock()
sess.post = mock.Mock(return_value=resp)
res = sot.adopt(sess, False, param="value")
self.assertEqual(sot, res)
sess.post.assert_called_once_with("nodes/adopt",
endpoint_filter=sot.service,
json={"param": "value"})
class TestNodeDetail(testtools.TestCase):

View File

@ -391,6 +391,28 @@ class TestClusterProxy(test_proxy_base2.TestProxyBase):
method_args=["FAKE_NODE"])
mock_get.assert_called_once_with(node.Node, "FAKE_NODE")
@mock.patch.object(proxy_base.BaseProxy, '_get_resource')
def test_node_adopt(self, mock_get):
mock_node = node.Node.new()
mock_get.return_value = mock_node
self._verify("openstack.cluster.v1.node.Node.adopt",
self.proxy.adopt_node,
method_kwargs={"preview": False, "foo": "bar"},
expected_kwargs={"preview": False, "foo": "bar"})
mock_get.assert_called_once_with(node.Node, None)
@mock.patch.object(proxy_base.BaseProxy, '_get_resource')
def test_node_adopt_preview(self, mock_get):
mock_node = node.Node.new()
mock_get.return_value = mock_node
self._verify("openstack.cluster.v1.node.Node.adopt",
self.proxy.adopt_node,
method_kwargs={"preview": True, "foo": "bar"},
expected_kwargs={"preview": True, "foo": "bar"})
mock_get.assert_called_once_with(node.Node, None)
@deprecation.fail_if_not_removed
@mock.patch.object(proxy_base.BaseProxy, '_get_resource')
def test_node_operation(self, mock_get):