Skip to content

Commit

Permalink
Use poll_for_events for "openstack stack delete"
Browse files Browse the repository at this point in the history
Change-Id: Ie918e095e7d67c94991f1a7e4b0ede9127134936
Blueprint: heat-support-python-openstackclient
  • Loading branch information
kramvan1 committed Mar 1, 2016
1 parent 0eb686e commit a3c3299
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 65 deletions.
25 changes: 0 additions & 25 deletions heatclient/common/utils.py
Expand Up @@ -17,7 +17,6 @@
import logging
import os
import textwrap
import time
import uuid

from oslo_serialization import jsonutils
Expand Down Expand Up @@ -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.
Expand Down
36 changes: 25 additions & 11 deletions heatclient/osc/v1/stack.py
Expand Up @@ -631,25 +631,39 @@ def take_action(self, parsed_args):
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.') %
Expand Down
33 changes: 15 additions & 18 deletions heatclient/tests/unit/osc/v1/test_stack.py
Expand Up @@ -581,38 +581,35 @@ def test_stack_delete_one_found_one_not_found(self):
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):
Expand Down
11 changes: 0 additions & 11 deletions heatclient/tests/unit/test_utils.py
Expand Up @@ -188,17 +188,6 @@ def test_event_log_formatter(self):
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):

Expand Down

0 comments on commit a3c3299

Please sign in to comment.