Automatically remove interfaces on router delete
This change removes all attached interfaces from a router when it is deleted from the project dashboard. This was only being done when the router was deleted from the admin dashboard. Change-Id: Ic0b639bfad7451bb5acbf486c39e349c938723db Closes-Bug: 1384400
This commit is contained in:
parent
c88e944b97
commit
b37fa64bdd
@ -21,19 +21,6 @@ from openstack_dashboard.dashboards.project.routers import tables as r_tables
|
||||
|
||||
class DeleteRouter(r_tables.DeleteRouter):
|
||||
redirect_url = "horizon:admin:routers:index"
|
||||
policy_rules = (("network", "delete_router"),)
|
||||
|
||||
def delete(self, request, obj_id):
|
||||
search_opts = {'device_owner': 'network:router_interface',
|
||||
'device_id': obj_id}
|
||||
ports = api.neutron.port_list(request, **search_opts)
|
||||
for port in ports:
|
||||
api.neutron.router_remove_interface(request, obj_id,
|
||||
port_id=port.id)
|
||||
super(DeleteRouter, self).delete(request, obj_id)
|
||||
|
||||
def allowed(self, request, router=None):
|
||||
return True
|
||||
|
||||
|
||||
class EditRouter(r_tables.EditRouter):
|
||||
|
@ -15,6 +15,7 @@
|
||||
from django.core.urlresolvers import reverse
|
||||
from django import http
|
||||
|
||||
from mox import IgnoreArg # noqa
|
||||
from mox import IsA # noqa
|
||||
|
||||
from openstack_dashboard import api
|
||||
@ -80,3 +81,84 @@ class RouterTests(test.BaseAdminViewTests, r_test.RouterTests):
|
||||
table_data[0]['external_gateway_info']['network'])
|
||||
self.assertTemplateUsed(res, '%s/routers/index.html' % self.DASHBOARD)
|
||||
self.assertMessageCount(res, error=1)
|
||||
|
||||
@test.create_stubs({api.neutron: ('router_list', 'network_list',
|
||||
'port_list', 'router_delete',),
|
||||
api.keystone: ('tenant_list',)})
|
||||
def test_router_delete(self):
|
||||
router = self.routers.first()
|
||||
tenants = self.tenants.list()
|
||||
api.neutron.router_list(
|
||||
IsA(http.HttpRequest),
|
||||
search_opts=None).AndReturn(self.routers.list())
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||
.AndReturn([tenants, False])
|
||||
self._mock_external_network_list()
|
||||
api.neutron.router_list(
|
||||
IsA(http.HttpRequest),
|
||||
search_opts=None).AndReturn(self.routers.list())
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||
.AndReturn([tenants, False])
|
||||
self._mock_external_network_list()
|
||||
api.neutron.port_list(IsA(http.HttpRequest),
|
||||
device_id=router.id, device_owner=IgnoreArg())\
|
||||
.AndReturn([])
|
||||
api.neutron.router_delete(IsA(http.HttpRequest), router.id)
|
||||
api.neutron.router_list(
|
||||
IsA(http.HttpRequest),
|
||||
search_opts=None).AndReturn(self.routers.list())
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||
.AndReturn([tenants, False])
|
||||
self._mock_external_network_list()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(self.INDEX_URL)
|
||||
|
||||
formData = {'action': 'Routers__delete__' + router.id}
|
||||
res = self.client.post(self.INDEX_URL, formData, follow=True)
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertMessageCount(response=res, success=1)
|
||||
self.assertIn('Deleted Router: ' + router.name, res.content)
|
||||
|
||||
@test.create_stubs({api.neutron: ('router_list', 'network_list',
|
||||
'port_list', 'router_remove_interface',
|
||||
'router_delete',),
|
||||
api.keystone: ('tenant_list',)})
|
||||
def test_router_with_interface_delete(self):
|
||||
router = self.routers.first()
|
||||
ports = self.ports.list()
|
||||
tenants = self.tenants.list()
|
||||
api.neutron.router_list(
|
||||
IsA(http.HttpRequest),
|
||||
search_opts=None).AndReturn(self.routers.list())
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||
.AndReturn([tenants, False])
|
||||
self._mock_external_network_list()
|
||||
api.neutron.router_list(
|
||||
IsA(http.HttpRequest),
|
||||
search_opts=None).AndReturn(self.routers.list())
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||
.AndReturn([tenants, False])
|
||||
self._mock_external_network_list()
|
||||
api.neutron.port_list(IsA(http.HttpRequest),
|
||||
device_id=router.id, device_owner=IgnoreArg())\
|
||||
.AndReturn(ports)
|
||||
for port in ports:
|
||||
api.neutron.router_remove_interface(IsA(http.HttpRequest),
|
||||
router.id, port_id=port.id)
|
||||
api.neutron.router_delete(IsA(http.HttpRequest), router.id)
|
||||
api.neutron.router_list(
|
||||
IsA(http.HttpRequest),
|
||||
search_opts=None).AndReturn(self.routers.list())
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||
.AndReturn([tenants, False])
|
||||
self._mock_external_network_list()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(self.INDEX_URL)
|
||||
|
||||
formData = {'action': 'Routers__delete__' + router.id}
|
||||
res = self.client.post(self.INDEX_URL, formData, follow=True)
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertMessageCount(response=res, success=1)
|
||||
self.assertIn('Deleted Router: ' + router.name, res.content)
|
||||
|
@ -53,9 +53,14 @@ class DeleteRouter(policy.PolicyTargetMixin, tables.DeleteAction):
|
||||
policy_rules = (("network", "delete_router"),)
|
||||
|
||||
def delete(self, request, obj_id):
|
||||
obj = self.table.get_object_by_id(obj_id)
|
||||
name = self.table.get_object_display(obj)
|
||||
try:
|
||||
# detach all interfaces before attempting to delete the router
|
||||
search_opts = {'device_owner': 'network:router_interface',
|
||||
'device_id': obj_id}
|
||||
ports = api.neutron.port_list(request, **search_opts)
|
||||
for port in ports:
|
||||
api.neutron.router_remove_interface(request, obj_id,
|
||||
port_id=port.id)
|
||||
api.neutron.router_delete(request, obj_id)
|
||||
except q_ext.NeutronClientException as e:
|
||||
msg = _('Unable to delete router "%s"') % e
|
||||
@ -64,6 +69,8 @@ class DeleteRouter(policy.PolicyTargetMixin, tables.DeleteAction):
|
||||
redirect = reverse(self.redirect_url)
|
||||
raise exceptions.Http302(redirect, message=msg)
|
||||
except Exception:
|
||||
obj = self.table.get_object_by_id(obj_id)
|
||||
name = self.table.get_object_display(obj)
|
||||
msg = _('Unable to delete router "%s"') % name
|
||||
LOG.info(msg)
|
||||
exceptions.handle(request, msg)
|
||||
|
@ -16,6 +16,7 @@ import copy
|
||||
from django.core.urlresolvers import reverse
|
||||
from django import http
|
||||
|
||||
from mox import IgnoreArg # noqa
|
||||
from mox import IsA # noqa
|
||||
|
||||
from openstack_dashboard import api
|
||||
@ -146,6 +147,89 @@ class RouterTests(test.TestCase):
|
||||
args=[router.id]))
|
||||
self.assertRedirectsNoFollow(res, self.INDEX_URL)
|
||||
|
||||
@test.create_stubs({api.neutron: ('router_list', 'network_list',
|
||||
'port_list', 'router_delete',),
|
||||
quotas: ('tenant_quota_usages',)})
|
||||
def test_router_delete(self):
|
||||
router = self.routers.first()
|
||||
quota_data = self.quota_usages.first()
|
||||
quota_data['routers']['available'] = 5
|
||||
api.neutron.router_list(
|
||||
IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
search_opts=None).AndReturn(self.routers.list())
|
||||
quotas.tenant_quota_usages(
|
||||
IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(quota_data)
|
||||
self._mock_external_network_list()
|
||||
api.neutron.router_list(
|
||||
IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
search_opts=None).AndReturn(self.routers.list())
|
||||
self._mock_external_network_list()
|
||||
api.neutron.router_list(
|
||||
IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
search_opts=None).AndReturn(self.routers.list())
|
||||
self._mock_external_network_list()
|
||||
api.neutron.port_list(IsA(http.HttpRequest),
|
||||
device_id=router.id, device_owner=IgnoreArg())\
|
||||
.AndReturn([])
|
||||
api.neutron.router_delete(IsA(http.HttpRequest), router.id)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(self.INDEX_URL)
|
||||
|
||||
formData = {'action': 'Routers__delete__' + router.id}
|
||||
res = self.client.post(self.INDEX_URL, formData, follow=True)
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertMessageCount(response=res, success=1)
|
||||
self.assertIn('Deleted Router: ' + router.name, res.content)
|
||||
|
||||
@test.create_stubs({api.neutron: ('router_list', 'network_list',
|
||||
'port_list', 'router_remove_interface',
|
||||
'router_delete',),
|
||||
quotas: ('tenant_quota_usages',)})
|
||||
def test_router_with_interface_delete(self):
|
||||
router = self.routers.first()
|
||||
ports = self.ports.list()
|
||||
quota_data = self.quota_usages.first()
|
||||
quota_data['routers']['available'] = 5
|
||||
api.neutron.router_list(
|
||||
IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
search_opts=None).AndReturn(self.routers.list())
|
||||
quotas.tenant_quota_usages(
|
||||
IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(quota_data)
|
||||
self._mock_external_network_list()
|
||||
api.neutron.router_list(
|
||||
IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
search_opts=None).AndReturn(self.routers.list())
|
||||
self._mock_external_network_list()
|
||||
api.neutron.router_list(
|
||||
IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
search_opts=None).AndReturn(self.routers.list())
|
||||
self._mock_external_network_list()
|
||||
api.neutron.port_list(IsA(http.HttpRequest),
|
||||
device_id=router.id, device_owner=IgnoreArg())\
|
||||
.AndReturn(ports)
|
||||
for port in ports:
|
||||
api.neutron.router_remove_interface(IsA(http.HttpRequest),
|
||||
router.id, port_id=port.id)
|
||||
api.neutron.router_delete(IsA(http.HttpRequest), router.id)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(self.INDEX_URL)
|
||||
|
||||
formData = {'action': 'Routers__delete__' + router.id}
|
||||
res = self.client.post(self.INDEX_URL, formData, follow=True)
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertMessageCount(response=res, success=1)
|
||||
self.assertIn('Deleted Router: ' + router.name, res.content)
|
||||
|
||||
|
||||
class RouterActionTests(test.TestCase):
|
||||
DASHBOARD = 'project'
|
||||
|
Loading…
x
Reference in New Issue
Block a user