diff --git a/openstack/clustering/v1/_proxy.py b/openstack/clustering/v1/_proxy.py index 95e444b85..cb9aca317 100644 --- a/openstack/clustering/v1/_proxy.py +++ b/openstack/clustering/v1/_proxy.py @@ -196,21 +196,27 @@ class Proxy(proxy2.BaseProxy): """ return self._create(_cluster.Cluster, **attrs) - def delete_cluster(self, cluster, ignore_missing=True): + def delete_cluster(self, cluster, ignore_missing=True, force_delete=False): """Delete a cluster. :param cluster: The value can be either the name or ID of a cluster or - a :class:`~openstack.clustering.v1.cluster.Cluster` instance. + a :class:`~openstack.cluster.v1.cluster.Cluster` instance. :param bool ignore_missing: When set to ``False``, an exception :class:`~openstack.exceptions.ResourceNotFound` will be raised when the cluster could not be found. When set to ``True``, no exception will be raised when attempting to delete a non-existent cluster. + :param bool force_delete: When set to ``True``, the cluster deletion + will be forced immediately. :returns: The instance of the Cluster which was deleted. - :rtype: :class:`~openstack.clustering.v1.cluster.Cluster`. + :rtype: :class:`~openstack.cluster.v1.cluster.Cluster`. """ - return self._delete(_cluster.Cluster, cluster, - ignore_missing=ignore_missing) + if force_delete: + server = self._get_resource(_cluster.Cluster, cluster) + return server.force_delete(self) + else: + return self._delete(_cluster.Cluster, cluster, + ignore_missing=ignore_missing) def find_cluster(self, name_or_id, ignore_missing=True): """Find a single cluster. @@ -614,20 +620,27 @@ class Proxy(proxy2.BaseProxy): """ return self._create(_node.Node, **attrs) - def delete_node(self, node, ignore_missing=True): + def delete_node(self, node, ignore_missing=True, force_delete=False): """Delete a node. :param node: The value can be either the name or ID of a node or a - :class:`~openstack.clustering.v1.node.Node` instance. + :class:`~openstack.cluster.v1.node.Node` instance. :param bool ignore_missing: When set to ``False``, an exception :class:`~openstack.exceptions.ResourceNotFound` will be raised when the node could not be found. When set to ``True``, no exception will be raised when attempting to delete a non-existent node. + :param bool force_delete: When set to ``True``, the node deletion + will be forced immediately. :returns: The instance of the Node which was deleted. - :rtype: :class:`~openstack.clustering.v1.node.Node`. + :rtype: :class:`~openstack.cluster.v1.node.Node`. """ - return self._delete(_node.Node, node, ignore_missing=ignore_missing) + if force_delete: + server = self._get_resource(_node.Node, node) + return server.force_delete(self) + else: + return self._delete(_node.Node, node, + ignore_missing=ignore_missing) def find_node(self, name_or_id, ignore_missing=True): """Find a single node. diff --git a/openstack/clustering/v1/cluster.py b/openstack/clustering/v1/cluster.py index 7563d0a07..8b6561ba5 100644 --- a/openstack/clustering/v1/cluster.py +++ b/openstack/clustering/v1/cluster.py @@ -181,3 +181,11 @@ class Cluster(resource.Resource): resp = session.post(url, json={operation: params}) return resp.json() + + def force_delete(self, session): + """Force delete a cluster.""" + body = {'force': True} + url = utils.urljoin(self.base_path, self.id) + resp = session.delete(url, json=body) + self._translate_response(resp) + return self diff --git a/openstack/clustering/v1/node.py b/openstack/clustering/v1/node.py index 1e3208ad8..c0108df04 100644 --- a/openstack/clustering/v1/node.py +++ b/openstack/clustering/v1/node.py @@ -156,6 +156,14 @@ class Node(resource.Resource): self._translate_response(resp) return self + def force_delete(self, session): + """Force delete a node.""" + body = {'force': True} + url = utils.urljoin(self.base_path, self.id) + resp = session.delete(url, json=body) + self._translate_response(resp) + return self + class NodeDetail(Node): base_path = '/nodes/%(node_id)s?show_details=True' diff --git a/openstack/tests/unit/cluster/v1/test_cluster.py b/openstack/tests/unit/cluster/v1/test_cluster.py index 31f34cab7..4c4cf55b5 100644 --- a/openstack/tests/unit/cluster/v1/test_cluster.py +++ b/openstack/tests/unit/cluster/v1/test_cluster.py @@ -307,3 +307,19 @@ class TestCluster(testtools.TestCase): body = {'dance': {'style': 'tango'}} sess.post.assert_called_once_with(url, json=body) + + def test_force_delete(self): + sot = cluster.Cluster(**FAKE) + + resp = mock.Mock() + resp.headers = {} + resp.json = mock.Mock(return_value={"foo": "bar"}) + resp.status_code = 200 + sess = mock.Mock() + sess.delete = mock.Mock(return_value=resp) + + res = sot.force_delete(sess) + self.assertEqual(sot, res) + url = 'clusters/%s' % sot.id + body = {'force': True} + sess.delete.assert_called_once_with(url, json=body) diff --git a/openstack/tests/unit/cluster/v1/test_node.py b/openstack/tests/unit/cluster/v1/test_node.py index 3aa3b26ae..9e6cbf7aa 100644 --- a/openstack/tests/unit/cluster/v1/test_node.py +++ b/openstack/tests/unit/cluster/v1/test_node.py @@ -139,6 +139,22 @@ class TestNode(testtools.TestCase): sess.post.assert_called_once_with("nodes/adopt", json={"param": "value"}) + def test_force_delete(self): + sot = node.Node(**FAKE) + + resp = mock.Mock() + resp.headers = {} + resp.json = mock.Mock(return_value={"foo": "bar"}) + resp.status_code = 200 + sess = mock.Mock() + sess.delete = mock.Mock(return_value=resp) + + res = sot.force_delete(sess) + self.assertEqual(sot, res) + url = 'nodes/%s' % sot.id + body = {'force': True} + sess.delete.assert_called_once_with(url, json=body) + class TestNodeDetail(testtools.TestCase): diff --git a/openstack/tests/unit/cluster/v1/test_proxy.py b/openstack/tests/unit/cluster/v1/test_proxy.py index 905a46eae..592509b1f 100644 --- a/openstack/tests/unit/cluster/v1/test_proxy.py +++ b/openstack/tests/unit/cluster/v1/test_proxy.py @@ -94,6 +94,11 @@ class TestClusterProxy(test_proxy_base2.TestProxyBase): def test_cluster_delete_ignore(self): self.verify_delete(self.proxy.delete_cluster, cluster.Cluster, True) + def test_cluster_force_delete(self): + self._verify("openstack.clustering.v1.cluster.Cluster.force_delete", + self.proxy.delete_cluster, + method_args=["value", False, True]) + def test_cluster_find(self): self.verify_find(self.proxy.find_cluster, cluster.Cluster) @@ -349,6 +354,11 @@ class TestClusterProxy(test_proxy_base2.TestProxyBase): def test_node_delete_ignore(self): self.verify_delete(self.proxy.delete_node, node.Node, True) + def test_node_force_delete(self): + self._verify("openstack.clustering.v1.node.Node.force_delete", + self.proxy.delete_node, + method_args=["value", False, True]) + def test_node_find(self): self.verify_find(self.proxy.find_node, node.Node)