From 2949a9800f59b00c90a0eba23700a2adc5541ee3 Mon Sep 17 00:00:00 2001 From: Trygve Vea Date: Sat, 21 Oct 2017 11:36:29 +0000 Subject: [PATCH] Implement network availability zone column in network list If the 'network_availability_zone'-extension is enabled, this patch adds a column in the Networks-table named 'Availability Zones'. Change-Id: Iea2bac351b922a0d267c4a55e0d74f6c2639d967 Partial-Bug: #1725617 --- .../admin/networks/subnets/tests.py | 3 + .../dashboards/admin/networks/tables.py | 18 +++++ .../dashboards/admin/networks/tests.py | 33 +++++++++ .../dashboards/project/networks/tables.py | 25 +++++++ .../dashboards/project/networks/tests.py | 69 ++++++++++++++++--- 5 files changed, 138 insertions(+), 10 deletions(-) diff --git a/openstack_dashboard/dashboards/admin/networks/subnets/tests.py b/openstack_dashboard/dashboards/admin/networks/subnets/tests.py index 28b1816f08..14fc63fa5e 100644 --- a/openstack_dashboard/dashboards/admin/networks/subnets/tests.py +++ b/openstack_dashboard/dashboards/admin/networks/subnets/tests.py @@ -428,6 +428,9 @@ class NetworkSubnetTests(test.BaseAdminViewTests): api.neutron.is_extension_supported( IsA(http.HttpRequest), 'network-ip-availability').AndReturn(True) + api.neutron.is_extension_supported(IsA(http.HttpRequest), + 'network_availability_zone')\ + .MultipleTimes().AndReturn(True) api.neutron.is_extension_supported(IsA(http.HttpRequest), 'dhcp_agent_scheduler')\ .MultipleTimes().AndReturn(True) diff --git a/openstack_dashboard/dashboards/admin/networks/tables.py b/openstack_dashboard/dashboards/admin/networks/tables.py index 50f15051bd..d7c98ea81f 100644 --- a/openstack_dashboard/dashboards/admin/networks/tables.py +++ b/openstack_dashboard/dashboards/admin/networks/tables.py @@ -106,6 +106,13 @@ DISPLAY_CHOICES = ( ) +def get_availability_zones(network): + if 'availability_zones' in network and network.availability_zones: + return ', '.join(network.availability_zones) + else: + return _("-") + + class AdminNetworksFilterAction(project_tables.ProjectNetworksFilterAction): name = "filter_admin_networks" filter_choices = (('project', _("Project ="), True),) +\ @@ -131,6 +138,8 @@ class NetworksTable(tables.DataTable): admin_state = tables.Column("admin_state", verbose_name=_("Admin State"), display_choices=DISPLAY_CHOICES) + availability_zones = tables.Column(get_availability_zones, + verbose_name=_("Availability Zones")) def get_object_display(self, network): return network.name_or_id @@ -147,6 +156,15 @@ class NetworksTable(tables.DataTable): request, data=data, needs_form_wrapper=needs_form_wrapper, **kwargs) + try: + if not api.neutron.is_extension_supported( + request, "network_availability_zone"): + del self.columns["availability_zones"] + except Exception: + msg = _("Unable to check if network availability zone extension " + "is supported") + exceptions.handle(self.request, msg) + del self.columns['availability_zones'] try: if not api.neutron.is_extension_supported(request, 'dhcp_agent_scheduler'): diff --git a/openstack_dashboard/dashboards/admin/networks/tests.py b/openstack_dashboard/dashboards/admin/networks/tests.py index b147e72b6c..f3e4312a25 100644 --- a/openstack_dashboard/dashboards/admin/networks/tests.py +++ b/openstack_dashboard/dashboards/admin/networks/tests.py @@ -43,6 +43,9 @@ class NetworkTests(test.BaseAdminViewTests): .AndReturn(self.networks.list()) api.keystone.tenant_list(IsA(http.HttpRequest))\ .AndReturn([tenants, False]) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), + 'network_availability_zone').AndReturn(True) for network in self.networks.list(): usage.quotas.tenant_quota_usages( IsA(http.HttpRequest), tenant_id=network.tenant_id, @@ -70,6 +73,9 @@ class NetworkTests(test.BaseAdminViewTests): def test_index_network_list_exception(self): api.neutron.network_list(IsA(http.HttpRequest)) \ .AndRaise(self.exceptions.neutron) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), + 'network_availability_zone').AndReturn(True) api.neutron.is_extension_supported( IsA(http.HttpRequest), 'dhcp_agent_scheduler').AndReturn(True) @@ -117,6 +123,9 @@ class NetworkTests(test.BaseAdminViewTests): 'mac-learning') \ .AndReturn(mac_learning) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), + 'network_availability_zone').AndReturn(True) api.neutron.is_extension_supported( IsA(http.HttpRequest), 'dhcp_agent_scheduler').AndReturn(True) @@ -155,6 +164,9 @@ class NetworkTests(test.BaseAdminViewTests): api.neutron.is_extension_supported( IsA(http.HttpRequest), 'network-ip-availability').AndReturn(True) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), + 'network_availability_zone').AndReturn(True) api.neutron.is_extension_supported( IsA(http.HttpRequest), 'dhcp_agent_scheduler').AndReturn(True) @@ -192,6 +204,9 @@ class NetworkTests(test.BaseAdminViewTests): api.neutron.is_extension_supported(IsA(http.HttpRequest), 'mac-learning')\ .AndReturn(mac_learning) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), + 'network_availability_zone').AndReturn(True) api.neutron.is_extension_supported( IsA(http.HttpRequest), 'dhcp_agent_scheduler').AndReturn(True) @@ -232,6 +247,9 @@ class NetworkTests(test.BaseAdminViewTests): api.neutron.is_extension_supported( IsA(http.HttpRequest), 'dhcp_agent_scheduler').AndReturn(True) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), + 'network_availability_zone').AndReturn(True) api.neutron.is_extension_supported( IsA(http.HttpRequest), 'dhcp_agent_scheduler').AndReturn(True) @@ -333,6 +351,9 @@ class NetworkTests(test.BaseAdminViewTests): api.neutron.is_extension_supported( IsA(http.HttpRequest), 'dhcp_agent_scheduler').AndReturn(True) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), + 'network_availability_zone').AndReturn(True) api.neutron.is_extension_supported( IsA(http.HttpRequest), 'dhcp_agent_scheduler').AndReturn(True) @@ -389,6 +410,9 @@ class NetworkTests(test.BaseAdminViewTests): api.neutron.is_extension_supported( IsA(http.HttpRequest), 'network-ip-availability').AndReturn(True) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), + 'network_availability_zone').AndReturn(True) api.neutron.is_extension_supported(IsA(http.HttpRequest), 'dhcp_agent_scheduler')\ .AndReturn(True) @@ -772,6 +796,9 @@ class NetworkTests(test.BaseAdminViewTests): api.neutron.list_dhcp_agent_hosting_networks(IsA(http.HttpRequest), network.id).\ AndReturn(self.agents.list()) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), + 'network_availability_zone').AndReturn(True) api.neutron.is_extension_supported( IsA(http.HttpRequest), 'dhcp_agent_scheduler').AndReturn(True) @@ -802,6 +829,9 @@ class NetworkTests(test.BaseAdminViewTests): api.neutron.list_dhcp_agent_hosting_networks(IsA(http.HttpRequest), network.id).\ AndReturn(self.agents.list()) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), + 'network_availability_zone').AndReturn(True) api.neutron.is_extension_supported( IsA(http.HttpRequest), 'dhcp_agent_scheduler').AndReturn(True) @@ -825,6 +855,9 @@ class NetworkTests(test.BaseAdminViewTests): @test.create_stubs({api.neutron: ('is_extension_supported',)}) @test.update_settings(FILTER_DATA_FIRST={'admin.networks': True}) def test_networks_list_with_admin_filter_first(self): + api.neutron.is_extension_supported( + IsA(http.HttpRequest), + 'network_availability_zone').AndReturn(True) api.neutron.is_extension_supported( IsA(http.HttpRequest), 'dhcp_agent_scheduler').AndReturn(True) diff --git a/openstack_dashboard/dashboards/project/networks/tables.py b/openstack_dashboard/dashboards/project/networks/tables.py index b65926c997..dbae0127ab 100644 --- a/openstack_dashboard/dashboards/project/networks/tables.py +++ b/openstack_dashboard/dashboards/project/networks/tables.py @@ -150,6 +150,13 @@ STATUS_DISPLAY_CHOICES = ( ) +def get_availability_zones(network): + if 'availability_zones' in network and network.availability_zones: + return ', '.join(network.availability_zones) + else: + return _("-") + + class ProjectNetworksFilterAction(tables.FilterAction): name = "filter_project_networks" filter_type = "server" @@ -178,6 +185,24 @@ class NetworksTable(tables.DataTable): admin_state = tables.Column("admin_state", verbose_name=_("Admin State"), display_choices=DISPLAY_CHOICES) + availability_zones = tables.Column(get_availability_zones, + verbose_name=_("Availability Zones")) + + def __init__(self, request, data=None, needs_form_wrapper=None, **kwargs): + super(NetworksTable, self).__init__( + request, + data=data, + needs_form_wrapper=needs_form_wrapper, + **kwargs) + try: + if not api.neutron.is_extension_supported( + request, "network_availability_zone"): + del self.columns["availability_zones"] + except Exception: + msg = _("Unable to check if network availability zone extension " + "is supported") + exceptions.handle(self.request, msg) + del self.columns['availability_zones'] def get_object_display(self, network): return network.name_or_id diff --git a/openstack_dashboard/dashboards/project/networks/tests.py b/openstack_dashboard/dashboards/project/networks/tests.py index da05879dca..ac097fea6c 100644 --- a/openstack_dashboard/dashboards/project/networks/tests.py +++ b/openstack_dashboard/dashboards/project/networks/tests.py @@ -123,7 +123,8 @@ class NetworkStubMixin(object): class NetworkTests(test.TestCase, NetworkStubMixin): - @test.create_stubs({api.neutron: ('network_list',), + @test.create_stubs({api.neutron: ('network_list', + 'is_extension_supported'), quotas: ('tenant_quota_usages',)}) def test_index(self): quota_data = self.quota_usages.first() @@ -136,6 +137,9 @@ class NetworkTests(test.TestCase, NetworkStubMixin): quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('subnets', )) \ .MultipleTimes().AndReturn(quota_data) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), 'network_availability_zone')\ + .MultipleTimes().AndReturn(True) self.mox.ReplayAll() @@ -144,7 +148,8 @@ class NetworkTests(test.TestCase, NetworkStubMixin): networks = res.context['networks_table'].data self.assertItemsEqual(networks, self.networks.list()) - @test.create_stubs({api.neutron: ('network_list',), + @test.create_stubs({api.neutron: ('network_list', + 'is_extension_supported'), quotas: ('tenant_quota_usages',)}) def test_index_network_list_exception(self): quota_data = self.neutron_quota_usages.first() @@ -155,6 +160,9 @@ class NetworkTests(test.TestCase, NetworkStubMixin): quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('networks', )) \ .MultipleTimes().AndReturn(quota_data) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), 'network_availability_zone')\ + .MultipleTimes().AndReturn(True) self.mox.ReplayAll() res = self.client.get(INDEX_URL) @@ -194,6 +202,9 @@ class NetworkTests(test.TestCase, NetworkStubMixin): quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('subnets', )) \ .MultipleTimes().AndReturn(quota_data) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), 'network_availability_zone')\ + .MultipleTimes().AndReturn(True) self.mox.ReplayAll() url = urlunquote(reverse('horizon:project:networks:detail', @@ -219,6 +230,9 @@ class NetworkTests(test.TestCase, NetworkStubMixin): quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('subnets', )) \ .MultipleTimes().AndReturn(quota_data) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), 'network_availability_zone')\ + .MultipleTimes().AndReturn(True) self.mox.ReplayAll() url = urlunquote(reverse('horizon:project:networks:subnets_tab', @@ -290,6 +304,9 @@ class NetworkTests(test.TestCase, NetworkStubMixin): quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('subnets', )) \ .MultipleTimes().AndReturn(quota_data) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), 'network_availability_zone')\ + .MultipleTimes().AndReturn(True) self.mox.ReplayAll() url = urlunquote(reverse('horizon:project:networks:subnets_tab', @@ -330,6 +347,9 @@ class NetworkTests(test.TestCase, NetworkStubMixin): quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('subnets', )) \ .MultipleTimes().AndReturn(quota_data) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), 'network_availability_zone')\ + .MultipleTimes().AndReturn(True) self.mox.ReplayAll() url = urlunquote(reverse('horizon:project:networks:subnets_tab', @@ -911,7 +931,8 @@ class NetworkTests(test.TestCase, NetworkStubMixin): @test.create_stubs({api.neutron: ('network_get', 'network_list', - 'network_delete')}) + 'network_delete', + 'is_extension_supported')}) def test_delete_network_no_subnet(self): network = self.networks.first() network.subnets = [] @@ -919,6 +940,9 @@ class NetworkTests(test.TestCase, NetworkStubMixin): network.id, expand_subnet=False)\ .AndReturn(network) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), 'network_availability_zone')\ + .MultipleTimes().AndReturn(True) self._stub_net_list() api.neutron.network_delete(IsA(http.HttpRequest), network.id) @@ -931,7 +955,8 @@ class NetworkTests(test.TestCase, NetworkStubMixin): @test.create_stubs({api.neutron: ('network_get', 'network_list', 'network_delete', - 'subnet_delete')}) + 'subnet_delete', + 'is_extension_supported')}) def test_delete_network_with_subnet(self): network = self.networks.first() network.subnets = [subnet.id for subnet in network.subnets] @@ -941,6 +966,9 @@ class NetworkTests(test.TestCase, NetworkStubMixin): network.id, expand_subnet=False)\ .AndReturn(network) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), 'network_availability_zone')\ + .MultipleTimes().AndReturn(True) self._stub_net_list() api.neutron.subnet_delete(IsA(http.HttpRequest), subnet_id) api.neutron.subnet_delete(IsA(http.HttpRequest), subnetv6_id) @@ -956,7 +984,8 @@ class NetworkTests(test.TestCase, NetworkStubMixin): @test.create_stubs({api.neutron: ('network_get', 'network_list', 'network_delete', - 'subnet_delete')}) + 'subnet_delete', + 'is_extension_supported')}) def test_delete_network_exception(self): network = self.networks.first() network.subnets = [subnet.id for subnet in network.subnets] @@ -966,6 +995,9 @@ class NetworkTests(test.TestCase, NetworkStubMixin): network.id, expand_subnet=False)\ .AndReturn(network) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), 'network_availability_zone')\ + .MultipleTimes().AndReturn(True) self._stub_net_list() api.neutron.subnet_delete(IsA(http.HttpRequest), subnet_id) api.neutron.subnet_delete(IsA(http.HttpRequest), subnetv6_id) @@ -999,6 +1031,9 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin): quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('subnets', )) \ .MultipleTimes().AndReturn(quota_data) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), 'network_availability_zone')\ + .MultipleTimes().AndReturn(True) self.mox.ReplayAll() @@ -1028,6 +1063,9 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin): quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('subnets', )) \ .MultipleTimes().AndReturn(quota_data) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), 'network_availability_zone')\ + .MultipleTimes().AndReturn(True) self.mox.ReplayAll() @@ -1042,7 +1080,8 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin): "The create button should be disabled") return button - @test.create_stubs({api.neutron: ('network_list',), + @test.create_stubs({api.neutron: ('network_list', + 'is_extension_supported'), quotas: ('tenant_quota_usages',)}) def test_network_create_button_disabled_when_quota_exceeded_index(self): networks_tables.CreateNetwork() @@ -1052,7 +1091,8 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin): self._test_create_button_disabled_when_quota_exceeded(_find_net_button, network_quota=0) - @test.create_stubs({api.neutron: ('network_list',), + @test.create_stubs({api.neutron: ('network_list', + 'is_extension_supported'), quotas: ('tenant_quota_usages',)}) def test_subnet_create_button_disabled_when_quota_exceeded_index(self): network_id = self.networks.first().id @@ -1065,7 +1105,8 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin): self._test_create_button_disabled_when_quota_exceeded( _find_subnet_button, subnet_quota=0) - @test.create_stubs({api.neutron: ('network_list',), + @test.create_stubs({api.neutron: ('network_list', + 'is_extension_supported'), quotas: ('tenant_quota_usages',)}) def test_network_create_button_shown_when_quota_disabled_index(self): # if quota_data doesnt contain a networks["available"] key its disabled @@ -1074,7 +1115,8 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin): lambda res: self.getAndAssertTableAction(res, 'networks', 'create') ) - @test.create_stubs({api.neutron: ('network_list',), + @test.create_stubs({api.neutron: ('network_list', + 'is_extension_supported'), quotas: ('tenant_quota_usages',)}) def test_subnet_create_button_shown_when_quota_disabled_index(self): # if quota_data doesnt contain a subnets["available"] key, its disabled @@ -1106,6 +1148,9 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin): quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('subnets', )) \ .MultipleTimes().AndReturn(quota_data) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), 'network_availability_zone')\ + .MultipleTimes().AndReturn(True) self.mox.ReplayAll() @@ -1135,7 +1180,8 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin): self.assertNotIn('disabled', create_action.classes, 'The create button should be enabled') - @test.create_stubs({api.neutron: ('network_list',), + @test.create_stubs({api.neutron: ('network_list', + 'is_extension_supported'), quotas: ('tenant_quota_usages',)}) def test_create_button_attributes(self): create_action = self._test_create_button_shown_when_quota_disabled( @@ -1184,6 +1230,9 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin): quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('ports',)) \ .MultipleTimes().AndReturn(quota_data) + api.neutron.is_extension_supported( + IsA(http.HttpRequest), 'network_availability_zone')\ + .MultipleTimes().AndReturn(True) self.mox.ReplayAll()