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'