Better error on deleting non-empty Swift container
Swift client method delete_container() does not allow to delete non-empty containers, in which case user gets a confusing 409 error exessively truncated by Swift with no actual reason information. This patch catches 409 errors from Swift client on container delete, checks for objects in the container and raises a suitable error if container is not empty, so that the DELETE_FAILED reason is clearly seen. Change-Id: Ibca3851d11b509413b739a693b1ddd244479d37b Closes-Bug: #1406263
This commit is contained in:
parent
d5de387c86
commit
ae0ccc4b51
|
@ -14,6 +14,7 @@ import six
|
|||
|
||||
from six.moves.urllib import parse as urlparse
|
||||
|
||||
from heat.common import exception
|
||||
from heat.common.i18n import _
|
||||
from heat.common.i18n import _LW
|
||||
from heat.engine import attributes
|
||||
|
@ -150,6 +151,13 @@ class SwiftContainer(resource.Resource):
|
|||
try:
|
||||
self.swift().delete_container(self.resource_id)
|
||||
except Exception as ex:
|
||||
if self.client_plugin().is_conflict(ex):
|
||||
container, objects = self.swift().get_container(
|
||||
self.resource_id)
|
||||
if objects:
|
||||
msg = _("Deleting non-empty container (%s)"
|
||||
) % self.resource_id
|
||||
raise exception.NotSupported(feature=msg)
|
||||
self.client_plugin().ignore_not_found(ex)
|
||||
|
||||
def handle_check(self):
|
||||
|
|
|
@ -72,6 +72,7 @@ class swiftTest(common.HeatTestCase):
|
|||
self.m.CreateMock(sc.Connection)
|
||||
self.m.StubOutWithMock(sc.Connection, 'post_account')
|
||||
self.m.StubOutWithMock(sc.Connection, 'put_container')
|
||||
self.m.StubOutWithMock(sc.Connection, 'get_container')
|
||||
self.m.StubOutWithMock(sc.Connection, 'delete_container')
|
||||
self.m.StubOutWithMock(sc.Connection, 'head_container')
|
||||
self.m.StubOutWithMock(sc.Connection, 'get_auth')
|
||||
|
@ -255,6 +256,50 @@ class swiftTest(common.HeatTestCase):
|
|||
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_delete_conflict_non_empty(self):
|
||||
container_name = utils.PhysName('test_stack', 'test_resource')
|
||||
sc.Connection.put_container(
|
||||
container_name,
|
||||
{}).AndReturn(None)
|
||||
sc.Connection.delete_container(container_name).AndRaise(
|
||||
sc.ClientException('Conflict',
|
||||
http_status=409))
|
||||
sc.Connection.get_container(
|
||||
container_name).AndReturn(({'name': container_name},
|
||||
[{'name': 'test'}]))
|
||||
|
||||
self.m.ReplayAll()
|
||||
t = template_format.parse(swift_template)
|
||||
stack = utils.parse_stack(t)
|
||||
rsrc = self.create_resource(t, stack, 'SwiftContainer')
|
||||
deleter = scheduler.TaskRunner(rsrc.delete)
|
||||
ex = self.assertRaises(exception.ResourceFailure, deleter)
|
||||
self.assertIn('NotSupported: Deleting non-empty container',
|
||||
six.text_type(ex))
|
||||
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_delete_conflict_other(self):
|
||||
container_name = utils.PhysName('test_stack', 'test_resource')
|
||||
sc.Connection.put_container(
|
||||
container_name,
|
||||
{}).AndReturn(None)
|
||||
sc.Connection.delete_container(container_name).AndRaise(
|
||||
sc.ClientException('Conflict',
|
||||
http_status=409))
|
||||
sc.Connection.get_container(
|
||||
container_name).AndReturn(({'name': container_name}, []))
|
||||
|
||||
self.m.ReplayAll()
|
||||
t = template_format.parse(swift_template)
|
||||
stack = utils.parse_stack(t)
|
||||
rsrc = self.create_resource(t, stack, 'SwiftContainer')
|
||||
deleter = scheduler.TaskRunner(rsrc.delete)
|
||||
ex = self.assertRaises(exception.ResourceFailure, deleter)
|
||||
self.assertIn('Conflict', six.text_type(ex))
|
||||
|
||||
self.m.VerifyAll()
|
||||
|
||||
def _get_check_resource(self):
|
||||
t = template_format.parse(swift_template)
|
||||
stack = utils.parse_stack(t)
|
||||
|
|
Loading…
Reference in New Issue