From 809e7f60a6eb311433623d082ce74a0a472e9c8d Mon Sep 17 00:00:00 2001 From: Cindia-blue Date: Fri, 5 Feb 2016 11:28:41 +0800 Subject: [PATCH] Adding check/recover actions to cluster nodes This patch adds node check and recover into the cluster service. Implements: blueprint support-health-management-customization Change-Id: I4a756f6e5ca63dbd82e0803d66184a53f6a9dcf0 --- openstack/cluster/v1/_proxy.py | 22 +++++++++++++ openstack/cluster/v1/node.py | 33 +++++++++++++++++++ openstack/tests/unit/cluster/v1/test_node.py | 29 ++++++++++++++++ openstack/tests/unit/cluster/v1/test_proxy.py | 18 ++++++++++ 4 files changed, 102 insertions(+) diff --git a/openstack/cluster/v1/_proxy.py b/openstack/cluster/v1/_proxy.py index 6dc40223..5b46a4ec 100644 --- a/openstack/cluster/v1/_proxy.py +++ b/openstack/cluster/v1/_proxy.py @@ -405,6 +405,28 @@ class Proxy(proxy.BaseProxy): """ self._delete(_node.Node, node, ignore_missing=ignore_missing) + def check_node(self, node, **params): + """check a node. + + :param node: The value can be either the ID of a node or a + :class:`~openstack.cluster.v1.node.Node` instance. + + :returns: A dictionary containing the action ID. + """ + obj = self._get_resource(_node.Node, node) + return obj.check(self.session, **params) + + def recover_node(self, node, **params): + """recover a node. + + :param node: The value can be either the ID of a node or a + :class:`~openstack.cluster.v1.node.Node` instance. + + :returns: A dictionary containing the action ID. + """ + obj = self._get_resource(_node.Node, node) + return obj.recover(self.session, **params) + def find_node(self, name_or_id, ignore_missing=True): """Find a single node. diff --git a/openstack/cluster/v1/node.py b/openstack/cluster/v1/node.py index 3daa23d0..f30d0ee3 100644 --- a/openstack/cluster/v1/node.py +++ b/openstack/cluster/v1/node.py @@ -14,6 +14,7 @@ from openstack.cluster import cluster_service from openstack.cluster.v1 import cluster as _cluster from openstack.cluster.v1 import profile as _profile from openstack import resource +from openstack import utils class Node(resource.Resource): @@ -68,3 +69,35 @@ class Node(resource.Resource): #: A map containing the details of the physical object this node #: represents details = resource.prop('details', type=dict) + + def _action(self, session, body): + """Procedure the invoke an action API. + + :param session: A session object used for sending request. + :param body: The body of action to be sent. + """ + url = utils.urljoin(self.base_path, self.id, 'actions') + resp = session.post(url, endpoint_filter=self.service, json=body) + return resp.json + + def check(self, session, **params): + """An action procedure for the node to check its health status. + + :param session: A session object used for sending request. + :returns: A dictionary containing the action ID. + """ + body = { + 'check': params + } + return self._action(session, body) + + def recover(self, session, **params): + """An action procedure for the node to recover. + + :param session: A session object used for sending request. + :returns: A dictionary containing the action ID. + """ + body = { + 'recover': params + } + return self._action(session, body) diff --git a/openstack/tests/unit/cluster/v1/test_node.py b/openstack/tests/unit/cluster/v1/test_node.py index 83895706..1985c692 100644 --- a/openstack/tests/unit/cluster/v1/test_node.py +++ b/openstack/tests/unit/cluster/v1/test_node.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import mock import testtools from openstack.cluster.v1 import node @@ -78,3 +79,31 @@ class TestNode(testtools.TestCase): self.assertEqual(FAKE['index'], sot.index) self.assertEqual(FAKE['role'], sot.role) self.assertEqual(FAKE['metadata'], sot.metadata) + + def test_check(self): + sot = node.Node(FAKE) + sot['id'] = 'IDENTIFIER' + + resp = mock.Mock() + resp.json = {'action': '1234-5678-abcd'} + sess = mock.Mock() + sess.post = mock.Mock(return_value=resp) + self.assertEqual(resp.json, sot.check(sess)) + url = 'nodes/%s/actions' % sot.id + body = {'check': {}} + sess.post.assert_called_once_with(url, endpoint_filter=sot.service, + json=body) + + def test_recover(self): + sot = node.Node(FAKE) + sot['id'] = 'IDENTIFIER' + + resp = mock.Mock() + resp.json = {'action': '2345-6789-bbbb'} + sess = mock.Mock() + sess.post = mock.Mock(return_value=resp) + self.assertEqual(resp.json, sot.recover(sess)) + url = 'nodes/%s/actions' % sot.id + body = {'recover': {}} + sess.post.assert_called_once_with(url, endpoint_filter=sot.service, + json=body) diff --git a/openstack/tests/unit/cluster/v1/test_proxy.py b/openstack/tests/unit/cluster/v1/test_proxy.py index bb25cf9f..b6861a8b 100644 --- a/openstack/tests/unit/cluster/v1/test_proxy.py +++ b/openstack/tests/unit/cluster/v1/test_proxy.py @@ -285,6 +285,24 @@ class TestClusterProxy(test_proxy_base.TestProxyBase): def test_node_update(self): self.verify_update(self.proxy.update_node, node.Node) + @mock.patch.object(proxy_base.BaseProxy, '_get_resource') + def test_node_check(self, mock_get): + mock_node = node.Node.from_id('FAKE_NODE') + mock_get.return_value = mock_node + self._verify("openstack.cluster.v1.node.Node.check", + self.proxy.check_node, + 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_recover(self, mock_get): + mock_node = node.Node.from_id('FAKE_NODE') + mock_get.return_value = mock_node + self._verify("openstack.cluster.v1.node.Node.recover", + self.proxy.recover_node, + method_args=["FAKE_NODE"]) + mock_get.assert_called_once_with(node.Node, "FAKE_NODE") + def test_policy_create(self): self.verify_create(self.proxy.create_policy, policy.Policy)