Fix NetworkInUse when deleting RS Cloud::Network
Adds retry logic to the deletion of Rackspace::Cloud::Network so that it doesn't throw NetworkInUse exceptions. Closes-Bug: 1402827 Change-Id: I5f1dc6d1c1cfc7d0b795fe43fdb677969372bd0b
This commit is contained in:
parent
f328ec3974
commit
9ffe53bac0
@ -23,6 +23,7 @@ from heat.engine import resource
|
|||||||
from heat.openstack.common import log as logging
|
from heat.openstack.common import log as logging
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
from pyrax.exceptions import NetworkInUse # noqa
|
||||||
from pyrax.exceptions import NotFound # noqa
|
from pyrax.exceptions import NotFound # noqa
|
||||||
PYRAX_INSTALLED = True
|
PYRAX_INSTALLED = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -31,13 +32,15 @@ except ImportError:
|
|||||||
class NotFound(Exception):
|
class NotFound(Exception):
|
||||||
"""Dummy pyrax exception - only used for testing."""
|
"""Dummy pyrax exception - only used for testing."""
|
||||||
|
|
||||||
|
class NetworkInUse(Exception):
|
||||||
|
"""Dummy pyrax exception - only used for testing."""
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class CloudNetwork(resource.Resource):
|
class CloudNetwork(resource.Resource):
|
||||||
"""
|
"""A resource for creating Rackspace Cloud Networks.
|
||||||
A resource for creating Rackspace Cloud Networks.
|
|
||||||
|
|
||||||
See http://www.rackspace.com/cloud/networks/ for service
|
See http://www.rackspace.com/cloud/networks/ for service
|
||||||
documentation.
|
documentation.
|
||||||
@ -106,20 +109,40 @@ class CloudNetwork(resource.Resource):
|
|||||||
self.cloud_networks().get(self.resource_id)
|
self.cloud_networks().get(self.resource_id)
|
||||||
|
|
||||||
def handle_delete(self):
|
def handle_delete(self):
|
||||||
net = self.network()
|
'''Delete cloud network.
|
||||||
if net:
|
|
||||||
net.delete()
|
Cloud Network doesn't have a status attribute, and there is a non-zero
|
||||||
return net
|
window between the deletion of a server and the acknowledgement from
|
||||||
|
the cloud network that it's no longer in use, so it needs some way to
|
||||||
|
keep track of when the delete call was successfully issued.
|
||||||
|
'''
|
||||||
|
network_info = {
|
||||||
|
'delete_issued': False,
|
||||||
|
'network': self.network(),
|
||||||
|
}
|
||||||
|
return network_info
|
||||||
|
|
||||||
|
def check_delete_complete(self, network_info):
|
||||||
|
network = network_info['network']
|
||||||
|
|
||||||
|
if not network:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not network_info['delete_issued']:
|
||||||
|
try:
|
||||||
|
network.delete()
|
||||||
|
except NetworkInUse:
|
||||||
|
LOG.warn("Network '%s' still in use." % network.id)
|
||||||
|
else:
|
||||||
|
network_info['delete_issued'] = True
|
||||||
|
return False
|
||||||
|
|
||||||
def check_delete_complete(self, network):
|
|
||||||
if network:
|
|
||||||
try:
|
try:
|
||||||
network.get()
|
network.get()
|
||||||
except NotFound:
|
except NotFound:
|
||||||
return True
|
return True
|
||||||
else:
|
|
||||||
return False
|
return False
|
||||||
return True
|
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
super(CloudNetwork, self).validate()
|
super(CloudNetwork, self).validate()
|
||||||
|
@ -26,7 +26,7 @@ from heat.tests import utils
|
|||||||
from ..resources import cloudnetworks # noqa
|
from ..resources import cloudnetworks # noqa
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from pyrax.exceptions import NotFound
|
from pyrax.exceptions import NotFound # noqa
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from ..resources.cloudnetworks import NotFound # noqa
|
from ..resources.cloudnetworks import NotFound # noqa
|
||||||
|
|
||||||
@ -144,10 +144,25 @@ class CloudNetworkTest(common.HeatTestCase):
|
|||||||
exc = self.assertRaises(NotFound, self.fake_cnw.get, res_id)
|
exc = self.assertRaises(NotFound, self.fake_cnw.get, res_id)
|
||||||
self.assertIn(res_id, six.text_type(exc))
|
self.assertIn(res_id, six.text_type(exc))
|
||||||
|
|
||||||
|
def test_delete_in_use(self, mock_client):
|
||||||
|
self._setup_stack(mock_client)
|
||||||
|
res = self.stack['cnw']
|
||||||
|
fake_network = res.network()
|
||||||
|
fake_network.delete = mock.Mock()
|
||||||
|
fake_network.delete.side_effect = [cloudnetworks.NetworkInUse(), True]
|
||||||
|
fake_network.get = mock.Mock(side_effect=cloudnetworks.NotFound())
|
||||||
|
|
||||||
|
scheduler.TaskRunner(res.delete)()
|
||||||
|
self.assertEqual((res.DELETE, res.COMPLETE), res.state)
|
||||||
|
|
||||||
def test_delete_not_complete(self, mock_client):
|
def test_delete_not_complete(self, mock_client):
|
||||||
self._setup_stack(mock_client)
|
self._setup_stack(mock_client)
|
||||||
res = self.stack['cnw']
|
res = self.stack['cnw']
|
||||||
self.assertFalse(res.check_delete_complete(res.network()))
|
fake_network = res.network()
|
||||||
|
fake_network.get = mock.Mock()
|
||||||
|
|
||||||
|
task = res.handle_delete()
|
||||||
|
self.assertFalse(res.check_delete_complete(task))
|
||||||
|
|
||||||
def test_delete_not_found(self, mock_client):
|
def test_delete_not_found(self, mock_client):
|
||||||
self._setup_stack(mock_client)
|
self._setup_stack(mock_client)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user