Use poll_for_events for "openstack stack delete"

Change-Id: Ie918e095e7d67c94991f1a7e4b0ede9127134936
Blueprint: heat-support-python-openstackclient
This commit is contained in:
Mark Vanderwiel
2016-02-29 14:18:04 -06:00
parent 0eb686e5b3
commit a3c32990a8
4 changed files with 40 additions and 65 deletions

View File

@@ -17,7 +17,6 @@ import base64
import logging
import os
import textwrap
import time
import uuid
from oslo_serialization import jsonutils
@@ -116,30 +115,6 @@ def event_log_formatter(events):
return "\n".join(event_log)
def wait_for_delete(status_f,
res_id,
status_field='status',
sleep_time=5,
timeout=300):
"""Wait for resource deletion."""
total_time = 0
while total_time < timeout:
try:
res = status_f(res_id)
except exc.HTTPNotFound:
return True
status = res.get(status_field, '').lower()
if 'failed' in status:
return False
time.sleep(sleep_time)
total_time += sleep_time
return False
def print_update_list(lst, fields, formatters=None):
"""Print the stack-update --dry-run output as a table.

View File

@@ -631,25 +631,39 @@ class DeleteStack(command.Command):
failure_count = 0
stacks_waiting = []
for sid in parsed_args.stack:
marker = None
if parsed_args.wait:
try:
# find the last event to use as the marker
events = event_utils.get_events(heat_client,
stack_id=sid,
event_args={
'sort_dir': 'desc',
'limit': 1})
if events:
marker = events[0].id
except heat_exc.CommandError as ex:
failure_count += 1
print(ex)
continue
try:
heat_client.stacks.delete(sid)
stacks_waiting.append(sid)
stacks_waiting.append((sid, marker))
except heat_exc.HTTPNotFound:
failure_count += 1
print(_('Stack not found: %s') % sid)
if parsed_args.wait:
for sid in stacks_waiting:
def status_f(id):
return heat_client.stacks.get(id).to_dict()
# TODO(jonesbr): switch to use openstack client wait_for_delete
# when version 2.1.0 is adopted.
if not heat_utils.wait_for_delete(status_f,
sid,
status_field='stack_status'):
for sid, marker in stacks_waiting:
try:
stack_status, msg = event_utils.poll_for_events(
heat_client, sid, action='DELETE', marker=marker)
except heat_exc.CommandError:
continue
if stack_status == 'DELETE_FAILED':
failure_count += 1
print(_('Stack failed to delete: %s') % sid)
print(msg)
if failure_count:
msg = (_('Unable to delete %(count)d of the %(total)d stacks.') %

View File

@@ -581,38 +581,35 @@ class TestStackDelete(TestStack):
self.stack_client.delete.assert_any_call('stack2')
self.assertEqual('Unable to delete 1 of the 2 stacks.', str(error))
def test_stack_delete_wait(self):
@mock.patch('heatclient.common.event_utils.poll_for_events',
return_value=('DELETE_COMPLETE',
'Stack my_stack DELETE_COMPLETE'))
@mock.patch('heatclient.common.event_utils.get_events', return_value=[])
def test_stack_delete_wait(self, mock_get_event, mock_poll, ):
arglist = ['stack1', 'stack2', 'stack3', '--wait']
parsed_args = self.check_parser(self.cmd, arglist, [])
self.cmd.take_action(parsed_args)
self.stack_client.delete.assert_any_call('stack1')
self.stack_client.get.assert_any_call('stack1')
self.stack_client.delete.assert_any_call('stack2')
self.stack_client.get.assert_any_call('stack2')
self.stack_client.delete.assert_any_call('stack3')
self.stack_client.get.assert_any_call('stack3')
def test_stack_delete_wait_one_pass_one_fail(self):
@mock.patch('heatclient.common.event_utils.poll_for_events')
@mock.patch('heatclient.common.event_utils.get_events', return_value=[])
def test_stack_delete_wait_fail(self, mock_get_event, mock_poll):
mock_poll.side_effect = [['DELETE_COMPLETE',
'Stack my_stack DELETE_COMPLETE'],
['DELETE_FAILED',
'Stack my_stack DELETE_FAILED'],
['DELETE_COMPLETE',
'Stack my_stack DELETE_COMPLETE']]
arglist = ['stack1', 'stack2', 'stack3', '--wait']
self.stack_client.get.side_effect = [
stacks.Stack(None, {'stack_status': 'DELETE_FAILED'}),
heat_exc.HTTPNotFound,
stacks.Stack(None, {'stack_status': 'DELETE_FAILED'}),
]
parsed_args = self.check_parser(self.cmd, arglist, [])
error = self.assertRaises(exc.CommandError,
self.cmd.take_action, parsed_args)
self.stack_client.delete.assert_any_call('stack1')
self.stack_client.get.assert_any_call('stack1')
self.stack_client.delete.assert_any_call('stack2')
self.stack_client.get.assert_any_call('stack2')
self.stack_client.delete.assert_any_call('stack3')
self.stack_client.get.assert_any_call('stack3')
self.assertEqual('Unable to delete 2 of the 3 stacks.', str(error))
self.assertEqual('Unable to delete 1 of the 3 stacks.', str(error))
@mock.patch('sys.stdin', spec=six.StringIO)
def test_stack_delete_prompt(self, mock_stdin):

View File

@@ -188,17 +188,6 @@ class ShellTest(testtools.TestCase):
self.assertEqual(expected, utils.event_log_formatter(events_list))
self.assertEqual('', utils.event_log_formatter([]))
def test_wait_for_delete(self):
def status_f(id):
raise exc.HTTPNotFound
def bad_status_f(id):
return {'status': 'failed'}
self.assertTrue(utils.wait_for_delete(status_f, 123))
self.assertFalse(utils.wait_for_delete(status_f, 123, timeout=0))
self.assertFalse(utils.wait_for_delete(bad_status_f, 123))
class ShellTestParameterFiles(testtools.TestCase):