diff --git a/openstack_dashboard/dashboards/admin/floating_ips/tables.py b/openstack_dashboard/dashboards/admin/floating_ips/tables.py index 162277f5e2..e9007d61da 100644 --- a/openstack_dashboard/dashboards/admin/floating_ips/tables.py +++ b/openstack_dashboard/dashboards/admin/floating_ips/tables.py @@ -23,9 +23,9 @@ from horizon import messages from horizon import tables from openstack_dashboard import api +from openstack_dashboard.dashboards.project.floating_ips \ + import tables as project_tables from openstack_dashboard import policy -from openstack_dashboard.dashboards.project.access_and_security.\ - floating_ips import tables as project_tables from openstack_dashboard.utils import filters diff --git a/openstack_dashboard/dashboards/admin/floating_ips/views.py b/openstack_dashboard/dashboards/admin/floating_ips/views.py index e84ac7a2d6..ec1ab82cfc 100644 --- a/openstack_dashboard/dashboards/admin/floating_ips/views.py +++ b/openstack_dashboard/dashboards/admin/floating_ips/views.py @@ -32,8 +32,8 @@ from openstack_dashboard.dashboards.admin.floating_ips \ import forms as fip_forms from openstack_dashboard.dashboards.admin.floating_ips \ import tables as fip_tables -from openstack_dashboard.dashboards.project.access_and_security.\ - floating_ips import tables as project_tables +from openstack_dashboard.dashboards.project.floating_ips \ + import tables as project_tables def get_floatingip_pools(request): diff --git a/openstack_dashboard/dashboards/project/access_and_security/tabs.py b/openstack_dashboard/dashboards/project/access_and_security/tabs.py index c82ccfca79..aa1ac0ccfb 100644 --- a/openstack_dashboard/dashboards/project/access_and_security/tabs.py +++ b/openstack_dashboard/dashboards/project/access_and_security/tabs.py @@ -25,10 +25,6 @@ from horizon import tabs from neutronclient.common import exceptions as neutron_exc from openstack_dashboard.api import network -from openstack_dashboard.api import nova - -from openstack_dashboard.dashboards.project.access_and_security.\ - floating_ips.tables import FloatingIPsTable from openstack_dashboard.dashboards.project.access_and_security.\ security_groups.tables import SecurityGroupsTable @@ -53,60 +49,7 @@ class SecurityGroupsTab(tabs.TableTab): return sorted(security_groups, key=lambda group: group.name) -class FloatingIPsTab(tabs.TableTab): - table_classes = (FloatingIPsTable,) - name = _("Floating IPs") - slug = "floating_ips_tab" - template_name = "horizon/common/_detail_table.html" - permissions = ('openstack.services.compute',) - - def get_floating_ips_data(self): - try: - floating_ips = network.tenant_floating_ip_list(self.request) - except neutron_exc.ConnectionFailed: - floating_ips = [] - exceptions.handle(self.request) - except Exception: - floating_ips = [] - exceptions.handle(self.request, - _('Unable to retrieve floating IP addresses.')) - - try: - floating_ip_pools = network.floating_ip_pools_list(self.request) - except neutron_exc.ConnectionFailed: - floating_ip_pools = [] - exceptions.handle(self.request) - except Exception: - floating_ip_pools = [] - exceptions.handle(self.request, - _('Unable to retrieve floating IP pools.')) - pool_dict = dict([(obj.id, obj.name) for obj in floating_ip_pools]) - - attached_instance_ids = [ip.instance_id for ip in floating_ips - if ip.instance_id is not None] - if attached_instance_ids: - instances = [] - try: - # TODO(tsufiev): we should pass attached_instance_ids to - # nova.server_list as soon as Nova API allows for this - instances, has_more = nova.server_list(self.request) - except Exception: - exceptions.handle(self.request, - _('Unable to retrieve instance list.')) - - instances_dict = dict([(obj.id, obj.name) for obj in instances]) - - for ip in floating_ips: - ip.instance_name = instances_dict.get(ip.instance_id) - ip.pool_name = pool_dict.get(ip.pool, ip.pool) - - return floating_ips - - def allowed(self, request): - return network.floating_ip_supported(request) - - class AccessAndSecurityTabs(tabs.TabGroup): slug = "access_security_tabs" - tabs = (SecurityGroupsTab, FloatingIPsTab) + tabs = (SecurityGroupsTab,) sticky = True diff --git a/openstack_dashboard/dashboards/project/access_and_security/templates/access_and_security/floating_ips/allocate.html b/openstack_dashboard/dashboards/project/access_and_security/templates/access_and_security/floating_ips/allocate.html deleted file mode 100644 index 8679b9e8fe..0000000000 --- a/openstack_dashboard/dashboards/project/access_and_security/templates/access_and_security/floating_ips/allocate.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Allocate Floating IP" %}{% endblock %} - -{% block main %} - {% include 'project/access_and_security/floating_ips/_allocate.html' %} -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/access_and_security/tests.py b/openstack_dashboard/dashboards/project/access_and_security/tests.py index 60d4d69ee6..c525d160cf 100644 --- a/openstack_dashboard/dashboards/project/access_and_security/tests.py +++ b/openstack_dashboard/dashboards/project/access_and_security/tests.py @@ -23,7 +23,6 @@ from django import http from mox3.mox import IsA # noqa import six -from horizon.workflows import views from openstack_dashboard import api from openstack_dashboard.test import helpers as test from openstack_dashboard.usage import quotas @@ -35,32 +34,14 @@ class AccessAndSecurityTests(test.TestCase): def setUp(self): super(AccessAndSecurityTests, self).setUp() - @test.create_stubs({api.network: ('floating_ip_supported', - 'tenant_floating_ip_list', - 'floating_ip_pools_list', - 'security_group_list',), - api.nova: ('server_list',), + @test.create_stubs({api.network: ('security_group_list',), api.base: ('is_service_enabled',), quotas: ('tenant_quota_usages',)}) - def _test_index(self, instanceless_ips=False): + def _test_index(self): sec_groups = self.security_groups.list() - floating_ips = self.floating_ips.list() - floating_pools = self.pools.list() - if instanceless_ips: - for fip in floating_ips: - fip.instance_id = None quota_data = self.quota_usages.first() quota_data['security_groups']['available'] = 10 - api.network.floating_ip_supported(IsA(http.HttpRequest)) \ - .AndReturn(True) - if not instanceless_ips: - api.nova.server_list(IsA(http.HttpRequest)) \ - .AndReturn([self.servers.list(), False]) - api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \ - .AndReturn(floating_ips) - api.network.floating_ip_pools_list(IsA(http.HttpRequest)) \ - .AndReturn(floating_pools) api.network.security_group_list(IsA(http.HttpRequest)) \ .AndReturn(sec_groups) quotas.tenant_quota_usages(IsA(http.HttpRequest)).MultipleTimes() \ @@ -74,8 +55,6 @@ class AccessAndSecurityTests(test.TestCase): res = self.client.get(INDEX_URL) self.assertTemplateUsed(res, 'project/access_and_security/index.html') - self.assertItemsEqual(res.context['floating_ips_table'].data, - floating_ips) # Security groups sec_groups_from_ctx = res.context['security_groups_table'].data @@ -93,81 +72,22 @@ class AccessAndSecurityTests(test.TestCase): def test_index(self): self._test_index() - def test_index_with_instanceless_fips(self): - self._test_index(instanceless_ips=True) - - @test.create_stubs({api.network: ('floating_ip_target_list', - 'tenant_floating_ip_list',)}) - def test_association(self): - servers = [api.nova.Server(s, self.request) - for s in self.servers.list()] - # Add duplicate instance name to test instance name with [ID] - # Change id and private IP - server3 = api.nova.Server(self.servers.first(), self.request) - server3.id = 101 - server3.addresses = deepcopy(server3.addresses) - server3.addresses['private'][0]['addr'] = "10.0.0.5" - servers.append(server3) - - targets = [api.nova.FloatingIpTarget(s) for s in servers] - - api.network.tenant_floating_ip_list( - IsA(http.HttpRequest)) \ - .AndReturn(self.floating_ips.list()) - api.network.floating_ip_target_list( - IsA(http.HttpRequest)) \ - .AndReturn(targets) - - self.mox.ReplayAll() - - res = self.client.get(reverse("horizon:project:access_and_security:" - "floating_ips:associate")) - - self.assertTemplateUsed(res, views.WorkflowView.template_name) - self.assertContains(res, '') - self.assertContains(res, '') - self.assertContains(res, '') - - -class AccessAndSecurityNeutronProxyTests(AccessAndSecurityTests): - def setUp(self): - super(AccessAndSecurityNeutronProxyTests, self).setUp() - self.floating_ips = self.floating_ips_uuid - class SecurityGroupTabTests(test.TestCase): def setUp(self): super(SecurityGroupTabTests, self).setUp() - @test.create_stubs({api.network: ('floating_ip_supported', - 'tenant_floating_ip_list', - 'security_group_list', - 'floating_ip_pools_list',), - api.nova: ('server_list',), + @test.create_stubs({api.network: ('security_group_list',), quotas: ('tenant_quota_usages',), api.base: ('is_service_enabled',)}) def test_create_button_attributes(self): - floating_ips = self.floating_ips.list() - floating_pools = self.pools.list() sec_groups = self.security_groups.list() quota_data = self.quota_usages.first() quota_data['security_groups']['available'] = 10 - api.network.floating_ip_supported( - IsA(http.HttpRequest)) \ - .AndReturn(True) - api.network.tenant_floating_ip_list( - IsA(http.HttpRequest)) \ - .AndReturn(floating_ips) - api.network.floating_ip_pools_list( - IsA(http.HttpRequest)) \ - .AndReturn(floating_pools) api.network.security_group_list( IsA(http.HttpRequest)) \ .AndReturn(sec_groups) - api.nova.server_list( - IsA(http.HttpRequest)) \ - .AndReturn([self.servers.list(), False]) quotas.tenant_quota_usages( IsA(http.HttpRequest)).MultipleTimes() \ .AndReturn(quota_data) @@ -195,36 +115,18 @@ class SecurityGroupTabTests(test.TestCase): url = 'horizon:project:access_and_security:security_groups:create' self.assertEqual(url, create_action.url) - @test.create_stubs({api.network: ('floating_ip_supported', - 'tenant_floating_ip_list', - 'security_group_list', - 'floating_ip_pools_list',), - api.nova: ('server_list',), + @test.create_stubs({api.network: ('security_group_list',), quotas: ('tenant_quota_usages',), api.base: ('is_service_enabled',)}) def _test_create_button_disabled_when_quota_exceeded(self, network_enabled): - floating_ips = self.floating_ips.list() - floating_pools = self.pools.list() sec_groups = self.security_groups.list() quota_data = self.quota_usages.first() quota_data['security_groups']['available'] = 0 - api.network.floating_ip_supported( - IsA(http.HttpRequest)) \ - .AndReturn(True) - api.network.tenant_floating_ip_list( - IsA(http.HttpRequest)) \ - .AndReturn(floating_ips) - api.network.floating_ip_pools_list( - IsA(http.HttpRequest)) \ - .AndReturn(floating_pools) api.network.security_group_list( IsA(http.HttpRequest)) \ .AndReturn(sec_groups) - api.nova.server_list( - IsA(http.HttpRequest)) \ - .AndReturn([self.servers.list(), False]) quotas.tenant_quota_usages( IsA(http.HttpRequest)).MultipleTimes() \ .AndReturn(quota_data) diff --git a/openstack_dashboard/dashboards/project/access_and_security/urls.py b/openstack_dashboard/dashboards/project/access_and_security/urls.py index 76e3cc9d71..81f452fcd1 100644 --- a/openstack_dashboard/dashboards/project/access_and_security/urls.py +++ b/openstack_dashboard/dashboards/project/access_and_security/urls.py @@ -19,8 +19,6 @@ from django.conf.urls import include from django.conf.urls import url -from openstack_dashboard.dashboards.project.access_and_security.\ - floating_ips import urls as fip_urls from openstack_dashboard.dashboards.project.access_and_security.\ security_groups import urls as sec_group_urls from openstack_dashboard.dashboards.project.access_and_security import views @@ -28,7 +26,6 @@ from openstack_dashboard.dashboards.project.access_and_security import views urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index'), - url(r'floating_ips/', include(fip_urls, namespace='floating_ips')), url(r'security_groups/', include(sec_group_urls, namespace='security_groups')), ] diff --git a/openstack_dashboard/dashboards/project/access_and_security/floating_ips/__init__.py b/openstack_dashboard/dashboards/project/floating_ips/__init__.py similarity index 100% rename from openstack_dashboard/dashboards/project/access_and_security/floating_ips/__init__.py rename to openstack_dashboard/dashboards/project/floating_ips/__init__.py diff --git a/openstack_dashboard/dashboards/project/access_and_security/floating_ips/forms.py b/openstack_dashboard/dashboards/project/floating_ips/forms.py similarity index 100% rename from openstack_dashboard/dashboards/project/access_and_security/floating_ips/forms.py rename to openstack_dashboard/dashboards/project/floating_ips/forms.py diff --git a/openstack_dashboard/dashboards/project/floating_ips/panel.py b/openstack_dashboard/dashboards/project/floating_ips/panel.py new file mode 100644 index 0000000000..f8a241c35d --- /dev/null +++ b/openstack_dashboard/dashboards/project/floating_ips/panel.py @@ -0,0 +1,27 @@ +# Copyright 2017 Cisco Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from django.conf import settings +from django.utils.translation import ugettext_lazy as _ +import horizon + + +class FloatingIps(horizon.Panel): + name = _("Floating IPs") + slug = 'floating_ips' + + @staticmethod + def can_register(): + network_config = getattr(settings, 'OPENSTACK_NEUTRON_NETWORK', {}) + return network_config.get('enable_router', True) diff --git a/openstack_dashboard/dashboards/project/access_and_security/floating_ips/tables.py b/openstack_dashboard/dashboards/project/floating_ips/tables.py similarity index 96% rename from openstack_dashboard/dashboards/project/access_and_security/floating_ips/tables.py rename to openstack_dashboard/dashboards/project/floating_ips/tables.py index eec9f786c4..c894b8dd2b 100644 --- a/openstack_dashboard/dashboards/project/access_and_security/floating_ips/tables.py +++ b/openstack_dashboard/dashboards/project/floating_ips/tables.py @@ -41,10 +41,10 @@ class AllocateIP(tables.LinkAction): verbose_name = _("Allocate IP To Project") classes = ("ajax-modal",) icon = "link" - url = "horizon:project:access_and_security:floating_ips:allocate" + url = "horizon:project:floating_ips:allocate" def single(self, data_table, request, *args): - return shortcuts.redirect('horizon:project:access_and_security:index') + return shortcuts.redirect('horizon:project:floating_ips:index') def allowed(self, request, fip=None): usages = quotas.tenant_quota_usages(request) @@ -106,7 +106,7 @@ class ReleaseIPs(tables.BatchAction): class AssociateIP(tables.LinkAction): name = "associate" verbose_name = _("Associate") - url = "horizon:project:access_and_security:floating_ips:associate" + url = "horizon:project:floating_ips:associate" classes = ("ajax-modal",) icon = "link" @@ -152,7 +152,7 @@ class DisassociateIP(tables.Action): except Exception: exceptions.handle(request, _('Unable to disassociate floating IP.')) - return shortcuts.redirect('horizon:project:access_and_security:index') + return shortcuts.redirect('horizon:project:floating_ips:index') def get_instance_info(fip): diff --git a/openstack_dashboard/dashboards/project/access_and_security/templates/access_and_security/floating_ips/_allocate.html b/openstack_dashboard/dashboards/project/floating_ips/templates/floating_ips/_allocate.html similarity index 100% rename from openstack_dashboard/dashboards/project/access_and_security/templates/access_and_security/floating_ips/_allocate.html rename to openstack_dashboard/dashboards/project/floating_ips/templates/floating_ips/_allocate.html diff --git a/openstack_dashboard/dashboards/project/floating_ips/templates/floating_ips/allocate.html b/openstack_dashboard/dashboards/project/floating_ips/templates/floating_ips/allocate.html new file mode 100644 index 0000000000..17b7957d4c --- /dev/null +++ b/openstack_dashboard/dashboards/project/floating_ips/templates/floating_ips/allocate.html @@ -0,0 +1,6 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block main %} + {% include 'project/floating_ips/_allocate.html' %} +{% endblock %} diff --git a/openstack_dashboard/dashboards/project/access_and_security/floating_ips/tests.py b/openstack_dashboard/dashboards/project/floating_ips/tests.py similarity index 92% rename from openstack_dashboard/dashboards/project/access_and_security/floating_ips/tests.py rename to openstack_dashboard/dashboards/project/floating_ips/tests.py index ad2895aa7d..6e3882b6d3 100644 --- a/openstack_dashboard/dashboards/project/access_and_security/floating_ips/tests.py +++ b/openstack_dashboard/dashboards/project/floating_ips/tests.py @@ -31,8 +31,8 @@ from openstack_dashboard.usage import quotas from horizon.workflows import views -INDEX_URL = reverse('horizon:project:access_and_security:index') -NAMESPACE = "horizon:project:access_and_security:floating_ips" +INDEX_URL = reverse('horizon:project:floating_ips:index') +NAMESPACE = "horizon:project:floating_ips" class FloatingIpViewTests(test.TestCase): @@ -167,7 +167,6 @@ class FloatingIpViewTests(test.TestCase): @test.create_stubs({api.nova: ('server_list',), api.network: ('floating_ip_disassociate', - 'floating_ip_supported', 'tenant_floating_ip_get', 'tenant_floating_ip_list',), api.neutron: ('is_extension_supported',)}) @@ -176,8 +175,6 @@ class FloatingIpViewTests(test.TestCase): api.nova.server_list(IsA(http.HttpRequest)) \ .AndReturn([self.servers.list(), False]) - api.network.floating_ip_supported(IsA(http.HttpRequest)) \ - .AndReturn(True) api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \ .AndReturn(self.floating_ips.list()) api.neutron.is_extension_supported(IsA(http.HttpRequest), @@ -194,7 +191,6 @@ class FloatingIpViewTests(test.TestCase): @test.create_stubs({api.nova: ('server_list',), api.network: ('floating_ip_disassociate', - 'floating_ip_supported', 'tenant_floating_ip_get', 'tenant_floating_ip_list',), api.neutron: ('is_extension_supported',)}) @@ -203,8 +199,6 @@ class FloatingIpViewTests(test.TestCase): api.nova.server_list(IsA(http.HttpRequest)) \ .AndReturn([self.servers.list(), False]) - api.network.floating_ip_supported(IsA(http.HttpRequest)) \ - .AndReturn(True) api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \ .AndReturn(self.floating_ips.list()) api.neutron.is_extension_supported(IsA(http.HttpRequest), @@ -220,9 +214,7 @@ class FloatingIpViewTests(test.TestCase): res = self.client.post(INDEX_URL, {"action": action}) self.assertRedirectsNoFollow(res, INDEX_URL) - @test.create_stubs({api.network: ('floating_ip_supported', - 'tenant_floating_ip_list', - 'security_group_list', + @test.create_stubs({api.network: ('tenant_floating_ip_list', 'floating_ip_pools_list',), api.nova: ('server_list',), quotas: ('tenant_quota_usages',), @@ -232,17 +224,10 @@ class FloatingIpViewTests(test.TestCase): floating_pools = self.pools.list() quota_data = self.quota_usages.first() quota_data['floating_ips']['available'] = 10 - sec_groups = self.security_groups.list() - api.network.floating_ip_supported( - IsA(http.HttpRequest)) \ - .AndReturn(True) api.network.tenant_floating_ip_list( IsA(http.HttpRequest)) \ .AndReturn(floating_ips) - api.network.security_group_list( - IsA(http.HttpRequest)).MultipleTimes()\ - .AndReturn(sec_groups) api.network.floating_ip_pools_list( IsA(http.HttpRequest)) \ .AndReturn(floating_pools) @@ -252,7 +237,6 @@ class FloatingIpViewTests(test.TestCase): quotas.tenant_quota_usages( IsA(http.HttpRequest)).MultipleTimes() \ .AndReturn(quota_data) - api.base.is_service_enabled( IsA(http.HttpRequest), 'network').MultipleTimes() \ @@ -260,8 +244,7 @@ class FloatingIpViewTests(test.TestCase): self.mox.ReplayAll() - res = self.client.get(INDEX_URL + - "?tab=access_security_tabs__floating_ips_tab") + res = self.client.get(INDEX_URL) allocate_action = self.getAndAssertTableAction(res, 'floating_ips', 'allocate') @@ -270,12 +253,10 @@ class FloatingIpViewTests(test.TestCase): six.text_type(allocate_action.verbose_name)) self.assertIsNone(allocate_action.policy_rules) - url = 'horizon:project:access_and_security:floating_ips:allocate' + url = 'horizon:project:floating_ips:allocate' self.assertEqual(url, allocate_action.url) - @test.create_stubs({api.network: ('floating_ip_supported', - 'tenant_floating_ip_list', - 'security_group_list', + @test.create_stubs({api.network: ('tenant_floating_ip_list', 'floating_ip_pools_list',), api.nova: ('server_list',), quotas: ('tenant_quota_usages',), @@ -285,17 +266,10 @@ class FloatingIpViewTests(test.TestCase): floating_pools = self.pools.list() quota_data = self.quota_usages.first() quota_data['floating_ips']['available'] = 0 - sec_groups = self.security_groups.list() - api.network.floating_ip_supported( - IsA(http.HttpRequest)) \ - .AndReturn(True) api.network.tenant_floating_ip_list( IsA(http.HttpRequest)) \ .AndReturn(floating_ips) - api.network.security_group_list( - IsA(http.HttpRequest)).MultipleTimes()\ - .AndReturn(sec_groups) api.network.floating_ip_pools_list( IsA(http.HttpRequest)) \ .AndReturn(floating_pools) @@ -305,7 +279,6 @@ class FloatingIpViewTests(test.TestCase): quotas.tenant_quota_usages( IsA(http.HttpRequest)).MultipleTimes() \ .AndReturn(quota_data) - api.base.is_service_enabled( IsA(http.HttpRequest), 'network').MultipleTimes() \ @@ -313,8 +286,7 @@ class FloatingIpViewTests(test.TestCase): self.mox.ReplayAll() - res = self.client.get(INDEX_URL + - "?tab=access_security_tabs__floating_ips_tab") + res = self.client.get(INDEX_URL) allocate_action = self.getAndAssertTableAction(res, 'floating_ips', 'allocate') diff --git a/openstack_dashboard/dashboards/project/access_and_security/floating_ips/urls.py b/openstack_dashboard/dashboards/project/floating_ips/urls.py similarity index 88% rename from openstack_dashboard/dashboards/project/access_and_security/floating_ips/urls.py rename to openstack_dashboard/dashboards/project/floating_ips/urls.py index af3cef809a..5d7ca61826 100644 --- a/openstack_dashboard/dashboards/project/access_and_security/floating_ips/urls.py +++ b/openstack_dashboard/dashboards/project/floating_ips/urls.py @@ -18,11 +18,10 @@ from django.conf.urls import url -from openstack_dashboard.dashboards.project.access_and_security.\ - floating_ips import views - +from openstack_dashboard.dashboards.project.floating_ips import views urlpatterns = [ + url(r'^$', views.IndexView.as_view(), name='index'), url(r'^associate/$', views.AssociateView.as_view(), name='associate'), url(r'^allocate/$', views.AllocateView.as_view(), name='allocate'), ] diff --git a/openstack_dashboard/dashboards/project/access_and_security/floating_ips/views.py b/openstack_dashboard/dashboards/project/floating_ips/views.py similarity index 50% rename from openstack_dashboard/dashboards/project/access_and_security/floating_ips/views.py rename to openstack_dashboard/dashboards/project/floating_ips/views.py index 4c094e30ec..061aa8c601 100644 --- a/openstack_dashboard/dashboards/project/access_and_security/floating_ips/views.py +++ b/openstack_dashboard/dashboards/project/floating_ips/views.py @@ -28,15 +28,18 @@ from neutronclient.common import exceptions as neutron_exc from horizon import exceptions from horizon import forms +from horizon import tables from horizon import workflows from openstack_dashboard import api from openstack_dashboard.usage import quotas -from openstack_dashboard.dashboards.project.access_and_security.\ - floating_ips import forms as project_forms -from openstack_dashboard.dashboards.project.access_and_security.\ - floating_ips import workflows as project_workflows +from openstack_dashboard.dashboards.project.floating_ips \ + import forms as project_forms +from openstack_dashboard.dashboards.project.floating_ips \ + import tables as project_tables +from openstack_dashboard.dashboards.project.floating_ips \ + import workflows as project_workflows class AssociateView(workflows.WorkflowView): @@ -47,11 +50,10 @@ class AllocateView(forms.ModalFormView): form_class = project_forms.FloatingIpAllocate form_id = "associate_floating_ip_form" page_title = _("Allocate Floating IP") - template_name = 'project/access_and_security/floating_ips/allocate.html' + template_name = 'project/floating_ips/allocate.html' submit_label = _("Allocate IP") - submit_url = reverse_lazy( - "horizon:project:access_and_security:floating_ips:allocate") - success_url = reverse_lazy('horizon:project:access_and_security:index') + submit_url = reverse_lazy("horizon:project:floating_ips:allocate") + success_url = reverse_lazy('horizon:project:floating_ips:index') def get_object_display(self, obj): return obj.ip @@ -78,3 +80,51 @@ class AllocateView(forms.ModalFormView): if not pool_list: pool_list = [(None, _("No floating IP pools available"))] return {'pool_list': pool_list} + + +class IndexView(tables.DataTableView): + table_class = project_tables.FloatingIPsTable + page_title = _("Floating IPs") + + def get_data(self): + try: + floating_ips = api.network.tenant_floating_ip_list(self.request) + except neutron_exc.ConnectionFailed: + floating_ips = [] + exceptions.handle(self.request) + except Exception: + floating_ips = [] + exceptions.handle(self.request, + _('Unable to retrieve floating IP addresses.')) + + try: + floating_ip_pools = \ + api.network.floating_ip_pools_list(self.request) + except neutron_exc.ConnectionFailed: + floating_ip_pools = [] + exceptions.handle(self.request) + except Exception: + floating_ip_pools = [] + exceptions.handle(self.request, + _('Unable to retrieve floating IP pools.')) + pool_dict = dict([(obj.id, obj.name) for obj in floating_ip_pools]) + + attached_instance_ids = [ip.instance_id for ip in floating_ips + if ip.instance_id is not None] + if attached_instance_ids: + instances = [] + try: + # TODO(tsufiev): we should pass attached_instance_ids to + # nova.server_list as soon as Nova API allows for this + instances, has_more = api.nova.server_list(self.request) + except Exception: + exceptions.handle(self.request, + _('Unable to retrieve instance list.')) + + instances_dict = dict([(obj.id, obj.name) for obj in instances]) + + for ip in floating_ips: + ip.instance_name = instances_dict.get(ip.instance_id) + ip.pool_name = pool_dict.get(ip.pool, ip.pool) + + return floating_ips diff --git a/openstack_dashboard/dashboards/project/access_and_security/floating_ips/workflows.py b/openstack_dashboard/dashboards/project/floating_ips/workflows.py similarity index 95% rename from openstack_dashboard/dashboards/project/access_and_security/floating_ips/workflows.py rename to openstack_dashboard/dashboards/project/floating_ips/workflows.py index 7ee001f6a0..c62ae3eb24 100644 --- a/openstack_dashboard/dashboards/project/access_and_security/floating_ips/workflows.py +++ b/openstack_dashboard/dashboards/project/floating_ips/workflows.py @@ -26,7 +26,7 @@ from openstack_dashboard import api from openstack_dashboard.utils import filters -ALLOCATE_URL = "horizon:project:access_and_security:floating_ips:allocate" +ALLOCATE_URL = "horizon:project:floating_ips:allocate" class AssociateIPAction(workflows.Action): @@ -72,7 +72,7 @@ class AssociateIPAction(workflows.Action): def populate_ip_id_choices(self, request, context): ips = [] - redirect = reverse('horizon:project:access_and_security:index') + redirect = reverse('horizon:project:floating_ips:index') try: ips = api.network.tenant_floating_ip_list(self.request) except neutron_exc.ConnectionFailed: @@ -95,7 +95,7 @@ class AssociateIPAction(workflows.Action): try: targets = api.network.floating_ip_target_list(self.request) except Exception: - redirect = reverse('horizon:project:access_and_security:index') + redirect = reverse('horizon:project:floating_ips:index') exceptions.handle(self.request, _('Unable to retrieve instance list.'), redirect=redirect) @@ -146,7 +146,7 @@ class IPAssociationWorkflow(workflows.Workflow): finalize_button_name = _("Associate") success_message = _('IP address %s associated.') failure_message = _('Unable to associate IP address %s.') - success_url = "horizon:project:access_and_security:index" + success_url = "horizon:project:floating_ips:index" default_steps = (AssociateIP,) def format_status_message(self, message): diff --git a/openstack_dashboard/dashboards/project/instances/tables.py b/openstack_dashboard/dashboards/project/instances/tables.py index e3e56ee5a1..f01741e3c8 100644 --- a/openstack_dashboard/dashboards/project/instances/tables.py +++ b/openstack_dashboard/dashboards/project/instances/tables.py @@ -36,8 +36,7 @@ from horizon.templatetags import sizeformat from horizon.utils import filters from openstack_dashboard import api -from openstack_dashboard.dashboards.project.access_and_security.floating_ips \ - import workflows +from openstack_dashboard.dashboards.project.floating_ips import workflows from openstack_dashboard.dashboards.project.instances import tabs from openstack_dashboard.dashboards.project.instances.workflows \ import resize_instance @@ -617,7 +616,7 @@ class DecryptInstancePassword(tables.LinkAction): class AssociateIP(policy.PolicyTargetMixin, tables.LinkAction): name = "associate" verbose_name = _("Associate Floating IP") - url = "horizon:project:access_and_security:floating_ips:associate" + url = "horizon:project:floating_ips:associate" classes = ("ajax-modal",) icon = "link" policy_rules = (("compute", "network:associate_floating_ip"),) diff --git a/openstack_dashboard/enabled/_1490_project_floating_ips_panel.py b/openstack_dashboard/enabled/_1490_project_floating_ips_panel.py new file mode 100644 index 0000000000..872ead7b8c --- /dev/null +++ b/openstack_dashboard/enabled/_1490_project_floating_ips_panel.py @@ -0,0 +1,6 @@ +PANEL_DASHBOARD = 'project' +PANEL_GROUP = 'network' +PANEL = 'floating_ips' + +ADD_PANEL = \ + 'openstack_dashboard.dashboards.project.floating_ips.panel.FloatingIps'