Merge "Improve force delete"

This commit is contained in:
Zuul 2018-06-13 01:04:37 +00:00 committed by Gerrit Code Review
commit b7c90ff987
6 changed files with 40 additions and 39 deletions

View File

@ -0,0 +1,6 @@
---
features:
- The behavior of force deletion of clusters (APIv2) has changed.
Stack-abandon is no longer used. The response from the force-delete
API call now includes the name of the stack which had underlain
that deleted cluster.

View File

@ -84,5 +84,11 @@ def clusters_update(cluster_id, data):
def clusters_delete(cluster_id):
data = u.request_data()
force = data.get('force', False)
stack_name = api.get_cluster(cluster_id).get(
'extra', {}).get(
'heat_stack_name', None)
api.terminate_cluster(cluster_id, force=force)
return u.render()
if force:
return u.render({"stack_name": stack_name}, status=200)
else:
return u.render(res=None, status=204)

View File

@ -19,6 +19,7 @@ from oslo_log import log as logging
from sahara import conductor as c
from sahara import context
from sahara import exceptions as ex
from sahara.i18n import _
from sahara.service import engine as e
from sahara.service.heat import commons as heat_common
@ -194,7 +195,7 @@ class HeatEngine(e.Engine):
def shutdown_cluster(self, cluster, force=False):
"""Shutdown specified cluster and all related resources."""
if force:
heat_shutdown = heat.abandon_stack
heat_shutdown = heat.lazy_delete_stack
else:
heat_shutdown = heat.delete_stack
@ -202,11 +203,11 @@ class HeatEngine(e.Engine):
heat_shutdown(cluster)
except heat_exc.HTTPNotFound:
LOG.warning('Did not find stack for cluster.')
except heat_exc.BadRequest:
LOG.error("Can't force delete cluster.", exc_info=True)
finally:
self._clean_job_executions(cluster)
self._remove_db_objects(cluster)
except ex.HeatStackException:
raise
self._clean_job_executions(cluster)
self._remove_db_objects(cluster)
@cpo.event_wrapper(
True, step=_('Create Heat stack'), param=('cluster', 1))

View File

@ -127,42 +127,27 @@ class TestDeletion(base.SaharaTestCase):
@mock.patch('sahara.service.heat.heat_engine.LOG.error')
@mock.patch('sahara.utils.openstack.heat.delete_stack')
@mock.patch('sahara.utils.openstack.heat.abandon_stack')
@mock.patch('sahara.utils.openstack.heat.lazy_delete_stack')
@mock.patch('sahara.service.engine.Engine._remove_db_objects')
@mock.patch('sahara.service.engine.Engine._clean_job_executions')
def test_force_delete_calls(self, cj, rdb, abandon, delete, log_err):
def test_force_delete_calls(self, cj, rdb, lazy_delete, delete, log_err):
engine = heat_engine.HeatEngine()
# Force delete when Heat service support abandon
# Force delete (lazy_delete)
engine.shutdown_cluster(mock.Mock(), force=True)
self.assertEqual(delete.call_count, 0)
self.assertEqual(abandon.call_count, 1)
self.assertEqual(lazy_delete.call_count, 1)
self.assertEqual(cj.call_count, 1)
self.assertEqual(rdb.call_count, 1)
delete.reset_mock()
abandon.reset_mock()
lazy_delete.reset_mock()
rdb.reset_mock()
cj.reset_mock()
# Regular delete
engine.shutdown_cluster(mock.Mock(), force=False)
self.assertEqual(delete.call_count, 1)
self.assertEqual(abandon.call_count, 0)
self.assertEqual(lazy_delete.call_count, 0)
self.assertEqual(cj.call_count, 1)
self.assertEqual(rdb.call_count, 1)
delete.reset_mock()
abandon.reset_mock()
rdb.reset_mock()
cj.reset_mock()
# Force delete when stack abandon unavailable
abandon.side_effect = heat_exc.BadRequest()
engine.shutdown_cluster(mock.Mock(), force=True)
self.assertEqual(delete.call_count, 0)
self.assertEqual(abandon.call_count, 1)
self.assertEqual(cj.call_count, 1)
self.assertEqual(rdb.call_count, 1)
log_err.assert_called_once_with(
"Can't force delete cluster.", exc_info=True)

View File

@ -20,20 +20,26 @@ from sahara.utils.openstack import heat as heat_u
class HeatClientTest(testtools.TestCase):
@mock.patch('sahara.utils.openstack.heat.get_stack')
@mock.patch('heatclient.client.Client')
@mock.patch('sahara.utils.openstack.base.url_for')
@mock.patch('sahara.service.sessions.cache')
@mock.patch('sahara.context.ctx')
def test_abandon(self, ctx, cache, url_for, heat):
def test_deleting(self, ctx, cache, url_for, heat, get_stack):
class _FakeHeatStacks(object):
def delete(self, stack):
call_list.append("delete")
def abandon(self, stack):
call_list.append("abandon")
call_list = None
get_stack.return_value = None
get_stack.side_effect = lambda *args, **kwargs: call_list.append("get")
heat.return_value.stacks = _FakeHeatStacks()
call_list = []
heat_u.abandon_stack(mock.Mock())
self.assertEqual(call_list, ["delete", "abandon"])
heat_u.lazy_delete_stack(mock.Mock())
self.assertEqual(call_list, ["delete"])
call_list = []
heat_u.delete_stack(mock.Mock())
self.assertEqual(call_list, ["delete", "get"])

View File

@ -84,13 +84,10 @@ def delete_stack(cluster):
stack = get_stack(stack_name, raise_on_missing=False)
def abandon_stack(cluster):
'''Put stack in deleting state if not already, then abandon it.'''
heat_client = client()
def lazy_delete_stack(cluster):
'''Attempt to delete stack once, but do not await successful deletion'''
stack_name = cluster.stack_name
base.execute_with_retries(heat_client.stacks.delete, stack_name)
# TODO(jfreud): sleep between calls?
base.execute_with_retries(heat_client.stacks.abandon, stack_name)
base.execute_with_retries(client().stacks.delete, stack_name)
def get_stack_outputs(cluster):