Merge "Improve exception message in network related Batch/DeleteAction"

This commit is contained in:
Zuul
2018-01-25 11:49:14 +00:00
committed by Gerrit Code Review
6 changed files with 74 additions and 176 deletions

View File

@@ -17,7 +17,6 @@ import logging
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext_lazy
from horizon import exceptions from horizon import exceptions
from horizon import tables from horizon import tables
@@ -33,38 +32,6 @@ from openstack_dashboard.usage import quotas
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class DeleteSubnet(proj_tables.SubnetPolicyTargetMixin, tables.DeleteAction):
@staticmethod
def action_present(count):
return ungettext_lazy(
u"Delete Subnet",
u"Delete Subnets",
count
)
@staticmethod
def action_past(count):
return ungettext_lazy(
u"Deleted Subnet",
u"Deleted Subnets",
count
)
policy_rules = (("network", "delete_subnet"),)
def delete(self, request, obj_id):
try:
api.neutron.subnet_delete(request, obj_id)
except Exception as e:
LOG.info('Failed to delete subnet %(id)s: %(exc)s',
{'id': obj_id, 'exc': e})
msg = _('Failed to delete subnet %s') % obj_id
network_id = self.table.kwargs['network_id']
redirect = reverse('horizon:admin:networks:detail',
args=[network_id])
exceptions.handle(request, msg, redirect=redirect)
class CreateSubnet(proj_tables.SubnetPolicyTargetMixin, tables.LinkAction): class CreateSubnet(proj_tables.SubnetPolicyTargetMixin, tables.LinkAction):
name = "create" name = "create"
verbose_name = _("Create Subnet") verbose_name = _("Create Subnet")
@@ -149,8 +116,9 @@ class SubnetsTable(tables.DataTable):
class Meta(object): class Meta(object):
name = "subnets" name = "subnets"
verbose_name = _("Subnets") verbose_name = _("Subnets")
table_actions = (CreateSubnet, DeleteSubnet, tables.FilterAction,) table_actions = (CreateSubnet, proj_tables.DeleteSubnet,
row_actions = (UpdateSubnet, DeleteSubnet,) tables.FilterAction,)
row_actions = (UpdateSubnet, proj_tables.DeleteSubnet,)
hidden_title = False hidden_title = False
def __init__(self, request, data=None, needs_form_wrapper=None, **kwargs): def __init__(self, request, data=None, needs_form_wrapper=None, **kwargs):

View File

@@ -14,11 +14,9 @@
import logging import logging
from django.core.urlresolvers import reverse
from django.template import defaultfilters as filters from django.template import defaultfilters as filters
from django.utils.translation import pgettext_lazy from django.utils.translation import pgettext_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext_lazy
from horizon import exceptions from horizon import exceptions
from horizon import tables from horizon import tables
@@ -32,36 +30,6 @@ from openstack_dashboard.usage import quotas
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class DeleteNetwork(policy.PolicyTargetMixin, tables.DeleteAction):
@staticmethod
def action_present(count):
return ungettext_lazy(
u"Delete Network",
u"Delete Networks",
count
)
@staticmethod
def action_past(count):
return ungettext_lazy(
u"Deleted Network",
u"Deleted Networks",
count
)
policy_rules = (("network", "delete_network"),)
def delete(self, request, obj_id):
try:
api.neutron.network_delete(request, obj_id)
except Exception as e:
LOG.info('Failed to delete network %(id)s: %(exc)s',
{'id': obj_id, 'exc': e})
msg = _('Failed to delete network %s') % obj_id
redirect = reverse('horizon:admin:networks:index')
exceptions.handle(request, msg, redirect=redirect)
class CreateNetwork(tables.LinkAction): class CreateNetwork(tables.LinkAction):
name = "create" name = "create"
verbose_name = _("Create Network") verbose_name = _("Create Network")
@@ -147,9 +115,9 @@ class NetworksTable(tables.DataTable):
class Meta(object): class Meta(object):
name = "networks" name = "networks"
verbose_name = _("Networks") verbose_name = _("Networks")
table_actions = (CreateNetwork, DeleteNetwork, table_actions = (CreateNetwork, project_tables.DeleteNetwork,
AdminNetworksFilterAction) AdminNetworksFilterAction)
row_actions = (EditNetwork, CreateSubnet, DeleteNetwork) row_actions = (EditNetwork, CreateSubnet, project_tables.DeleteNetwork)
def __init__(self, request, data=None, needs_form_wrapper=None, **kwargs): def __init__(self, request, data=None, needs_form_wrapper=None, **kwargs):
super(NetworksTable, self).__init__( super(NetworksTable, self).__init__(

View File

@@ -14,6 +14,8 @@
import logging import logging
from neutronclient.common import exceptions as neutron_exceptions
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@@ -21,6 +23,7 @@ from django.utils.translation import ungettext_lazy
from horizon import exceptions from horizon import exceptions
from horizon import tables from horizon import tables
from horizon.tables import actions
from horizon.utils import memoized from horizon.utils import memoized
from openstack_dashboard import api from openstack_dashboard import api
@@ -73,17 +76,20 @@ class DeleteSubnet(SubnetPolicyTargetMixin, tables.DeleteAction):
policy_rules = (("network", "delete_subnet"),) policy_rules = (("network", "delete_subnet"),)
@actions.handle_exception_with_detail_message(
# normal_log_message
'Failed to delete subnet %(id)s: %(exc)s',
# target_exception
neutron_exceptions.Conflict,
# target_log_message
'Unable to delete subnet %(id)s with 409 Conflict: %(exc)s',
# target_user_message
_('Unable to delete subnet %(name)s. Most possible reason is because '
'one or more ports have an IP allocation from this subnet.'),
# logger_name
__name__)
def delete(self, request, obj_id): def delete(self, request, obj_id):
try: api.neutron.subnet_delete(request, obj_id)
api.neutron.subnet_delete(request, obj_id)
except Exception as e:
LOG.info('Failed to delete subnet %(id)s: %(exc)s',
{'id': obj_id, 'exc': e})
msg = _('Failed to delete subnet %s') % obj_id
network_id = self.table.kwargs['network_id']
redirect = reverse('horizon:project:networks:detail',
args=[network_id])
exceptions.handle(request, msg, redirect=redirect)
class CreateSubnet(SubnetPolicyTargetMixin, tables.LinkAction): class CreateSubnet(SubnetPolicyTargetMixin, tables.LinkAction):

View File

@@ -13,7 +13,6 @@
# under the License. # under the License.
import logging import logging
from django.core.urlresolvers import reverse_lazy
from django import template from django import template
from django.template import defaultfilters as filters from django.template import defaultfilters as filters
from django.utils.translation import pgettext_lazy from django.utils.translation import pgettext_lazy
@@ -23,6 +22,7 @@ from neutronclient.common import exceptions as neutron_exceptions
from horizon import exceptions from horizon import exceptions
from horizon import tables from horizon import tables
from horizon.tables import actions
from openstack_dashboard import api from openstack_dashboard import api
from openstack_dashboard.dashboards.project.networks.subnets import tables \ from openstack_dashboard.dashboards.project.networks.subnets import tables \
@@ -53,34 +53,24 @@ class DeleteNetwork(policy.PolicyTargetMixin, tables.DeleteAction):
policy_rules = (("network", "delete_network"),) policy_rules = (("network", "delete_network"),)
@actions.handle_exception_with_detail_message(
# normal_log_message
'Failed to delete network %(id)s: %(exc)s',
# target_exception
neutron_exceptions.Conflict,
# target_log_message
'Unable to delete network %(id)s with 409 Conflict: %(exc)s',
# target_user_message
_('Unable to delete network %(name)s. Most possible reason is because '
'one or more ports still exist on the requested network.'),
# logger_name
__name__)
def delete(self, request, network_id): def delete(self, request, network_id):
network_name = network_id network = self.table.get_object_by_id(network_id)
redirect_url = reverse_lazy("horizon:project:networks:index") LOG.debug('Network %(network_id)s has subnets: %(subnets)s',
try: {'network_id': network_id, 'subnets': network.subnets})
# Retrieve the network list. api.neutron.network_delete(request, network_id)
network = api.neutron.network_get(request, network_id, LOG.debug('Deleted network %s successfully', network_id)
expand_subnet=False)
network_name = network.name
LOG.debug('Network %(network_id)s has subnets: %(subnets)s',
{'network_id': network_id, 'subnets': network.subnets})
for subnet_id in network.subnets:
api.neutron.subnet_delete(request, subnet_id)
LOG.debug('Deleted subnet %s', subnet_id)
api.neutron.network_delete(request, network_id)
LOG.debug('Deleted network %s successfully', network_id)
except neutron_exceptions.Conflict as e:
LOG.info('Failed to delete network %(id)s with 409 Conflict: '
'%(exc)s', {'id': network_id, 'exc': e})
msg = (_('Failed to delete network %(network_name)s. '
'Most possible case is that one or more ports still '
'exist on the requested network.') %
{"network_name": network_name, "subnet_id": subnet_id})
exceptions.handle(request, msg, redirect=redirect_url)
except Exception as e:
LOG.info('Failed to delete network %(id)s: %(exc)s',
{'id': network_id, 'exc': e})
msg = _('Failed to delete network %s') % network_name
exceptions.handle(request, msg, redirect=redirect_url)
class CreateNetwork(tables.LinkAction): class CreateNetwork(tables.LinkAction):

View File

@@ -1011,10 +1011,6 @@ class NetworkTests(test.TestCase, NetworkStubMixin):
def test_delete_network_no_subnet(self): def test_delete_network_no_subnet(self):
network = self.networks.first() network = self.networks.first()
network.subnets = [] network.subnets = []
api.neutron.network_get(IsA(http.HttpRequest),
network.id,
expand_subnet=False)\
.AndReturn(network)
api.neutron.is_extension_supported( api.neutron.is_extension_supported(
IsA(http.HttpRequest), 'network_availability_zone')\ IsA(http.HttpRequest), 'network_availability_zone')\
.MultipleTimes().AndReturn(True) .MultipleTimes().AndReturn(True)
@@ -1030,23 +1026,13 @@ class NetworkTests(test.TestCase, NetworkStubMixin):
@test.create_stubs({api.neutron: ('network_get', @test.create_stubs({api.neutron: ('network_get',
'network_list', 'network_list',
'network_delete', 'network_delete',
'subnet_delete',
'is_extension_supported')}) 'is_extension_supported')})
def test_delete_network_with_subnet(self): def test_delete_network_with_subnet(self):
network = self.networks.first() network = self.networks.first()
network.subnets = [subnet.id for subnet in network.subnets]
subnet_id = network.subnets[0]
subnetv6_id = network.subnets[1]
api.neutron.network_get(IsA(http.HttpRequest),
network.id,
expand_subnet=False)\
.AndReturn(network)
api.neutron.is_extension_supported( api.neutron.is_extension_supported(
IsA(http.HttpRequest), 'network_availability_zone')\ IsA(http.HttpRequest), 'network_availability_zone')\
.MultipleTimes().AndReturn(True) .MultipleTimes().AndReturn(True)
self._stub_net_list() self._stub_net_list()
api.neutron.subnet_delete(IsA(http.HttpRequest), subnet_id)
api.neutron.subnet_delete(IsA(http.HttpRequest), subnetv6_id)
api.neutron.network_delete(IsA(http.HttpRequest), network.id) api.neutron.network_delete(IsA(http.HttpRequest), network.id)
self.mox.ReplayAll() self.mox.ReplayAll()
@@ -1059,23 +1045,13 @@ class NetworkTests(test.TestCase, NetworkStubMixin):
@test.create_stubs({api.neutron: ('network_get', @test.create_stubs({api.neutron: ('network_get',
'network_list', 'network_list',
'network_delete', 'network_delete',
'subnet_delete',
'is_extension_supported')}) 'is_extension_supported')})
def test_delete_network_exception(self): def test_delete_network_exception(self):
network = self.networks.first() network = self.networks.first()
network.subnets = [subnet.id for subnet in network.subnets]
subnet_id = network.subnets[0]
subnetv6_id = network.subnets[1]
api.neutron.network_get(IsA(http.HttpRequest),
network.id,
expand_subnet=False)\
.AndReturn(network)
api.neutron.is_extension_supported( api.neutron.is_extension_supported(
IsA(http.HttpRequest), 'network_availability_zone')\ IsA(http.HttpRequest), 'network_availability_zone')\
.MultipleTimes().AndReturn(True) .MultipleTimes().AndReturn(True)
self._stub_net_list() self._stub_net_list()
api.neutron.subnet_delete(IsA(http.HttpRequest), subnet_id)
api.neutron.subnet_delete(IsA(http.HttpRequest), subnetv6_id)
api.neutron.network_delete(IsA(http.HttpRequest), network.id)\ api.neutron.network_delete(IsA(http.HttpRequest), network.id)\
.AndRaise(self.exceptions.neutron) .AndRaise(self.exceptions.neutron)

View File

@@ -19,11 +19,11 @@ from django.template import defaultfilters as filters
from django.utils.translation import pgettext_lazy from django.utils.translation import pgettext_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext_lazy from django.utils.translation import ungettext_lazy
from neutronclient.common import exceptions as q_ext from neutronclient.common import exceptions as neutron_exceptions
from horizon import exceptions from horizon import exceptions
from horizon import messages
from horizon import tables from horizon import tables
from horizon.tables import actions
from openstack_dashboard import api from openstack_dashboard import api
from openstack_dashboard import policy from openstack_dashboard import policy
@@ -53,38 +53,26 @@ class DeleteRouter(policy.PolicyTargetMixin, tables.DeleteAction):
redirect_url = "horizon:project:routers:index" redirect_url = "horizon:project:routers:index"
policy_rules = (("network", "delete_router"),) policy_rules = (("network", "delete_router"),)
@actions.handle_exception_with_detail_message(
# normal_log_message
'Failed to delete router %(id)s: %(exc)s',
# target_exception
neutron_exceptions.NeutronClientException,
# target_log_message
'Unable to delete router %(id)s: %(exc)s',
# target_user_message
_('Unable to delete router %(name)s: %(exc)s'),
# logger_name
__name__)
def delete(self, request, obj_id): def delete(self, request, obj_id):
try: # detach all interfaces before attempting to delete the router
# detach all interfaces before attempting to delete the router search_opts = {'device_owner': 'network:router_interface',
search_opts = {'device_owner': 'network:router_interface', 'device_id': obj_id}
'device_id': obj_id} ports = api.neutron.port_list(request, **search_opts)
ports = api.neutron.port_list(request, **search_opts) for port in ports:
for port in ports: api.neutron.router_remove_interface(request, obj_id,
api.neutron.router_remove_interface(request, obj_id, port_id=port.id)
port_id=port.id) api.neutron.router_delete(request, obj_id)
api.neutron.router_delete(request, obj_id)
except q_ext.NeutronClientException as e:
# TODO(amotoki): Revisit why Http302 needs to be raised.
# We have this pattern ONLY HERE.
# Can't we merge two except clauses?
LOG.info('Unable to delete router %(id)s: %(exc)s',
{'id': obj_id, 'exc': e})
obj = self.table.get_object_by_id(obj_id)
name = self.table.get_object_display(obj)
msg = _('Unable to delete router "%s"') % name
messages.error(request, msg)
redirect = reverse(self.redirect_url)
raise exceptions.Http302(redirect, message=msg)
except Exception as e:
LOG.info('Unable to delete router %(id)s: %(exc)s',
{'id': obj_id, 'exc': e})
obj = self.table.get_object_by_id(obj_id)
name = self.table.get_object_display(obj)
msg = _('Unable to delete router "%s"') % name
exceptions.handle(request, msg)
def allowed(self, request, router=None):
return True
class CreateRouter(tables.LinkAction): class CreateRouter(tables.LinkAction):
@@ -159,19 +147,21 @@ class ClearGateway(policy.PolicyTargetMixin, tables.BatchAction):
policy_rules = (("network", "update_router"),) policy_rules = (("network", "update_router"),)
action_type = "danger" action_type = "danger"
@actions.handle_exception_with_detail_message(
# normal_log_message
'Unable to clear gateway for router %(id)s: %(exc)s',
# target_exception
neutron_exceptions.Conflict,
# target_log_message
'Unable to clear gateway for router %(id)s: %(exc)s',
# target_user_message
_('Unable to clear gateway for router %(name)s. '
'Most possible reason is because the gateway is required '
'by one or more floating IPs'),
# logger_name
__name__)
def action(self, request, obj_id): def action(self, request, obj_id):
obj = self.table.get_object_by_id(obj_id) api.neutron.router_remove_gateway(request, obj_id)
name = self.table.get_object_display(obj)
try:
api.neutron.router_remove_gateway(request, obj_id)
except Exception as e:
LOG.info('Unable to clear gateway for router %(id)s: %(exc)s',
{'id': obj_id, 'exc': e})
msg = (_('Unable to clear gateway for router '
'"%(name)s": "%(msg)s"')
% {"name": name, "msg": e})
redirect = reverse(self.redirect_url)
exceptions.handle(request, msg, redirect=redirect)
def get_success_url(self, request): def get_success_url(self, request):
return reverse(self.redirect_url) return reverse(self.redirect_url)