Add DNS parameters to Floating IP panels

This adds support for the "DNS Domain" and "DNS Name" options to the
panels for listing and allocation Floating IPs.

These options are available as a Neutron extension, so we need to
make them conditional based on the availability of that extension.

Change-Id: Ife8e19aac44dccbdf11a6a6d4bb50cd3b7ed8d8e
This commit is contained in:
Jens Harbott 2018-04-13 10:20:16 +00:00 committed by Akihiro Motoki
parent 94aea2fedd
commit 9e703aec2f
8 changed files with 105 additions and 11 deletions

View File

@ -492,7 +492,7 @@ class SecurityGroupManager(object):
class FloatingIp(base.APIDictWrapper):
_attrs = ['id', 'ip', 'fixed_ip', 'port_id', 'instance_id',
'instance_type', 'pool']
'instance_type', 'pool', 'dns_domain', 'dns_name']
def __init__(self, fip):
fip['ip'] = fip['floating_ip_address']
@ -631,6 +631,10 @@ class FloatingIpManager(object):
create_dict['floating_ip_address'] = params['floating_ip_address']
if 'description' in params:
create_dict['description'] = params['description']
if 'dns_domain' in params:
create_dict['dns_domain'] = params['dns_domain']
if 'dns_name' in params:
create_dict['dns_name'] = params['dns_name']
fip = self.client.create_floatingip(
{'floatingip': create_dict}).get('floatingip')
self._set_instance_info(fip)

View File

@ -61,7 +61,13 @@ class FloatingIP(generic.View):
:return: JSON representation of the new floating IP address
"""
pool = request.DATA['pool_id']
result = api.neutron.tenant_floating_ip_allocate(request, pool)
params = {}
if 'dns_domain' in request.DATA:
params['dns_domain'] = request.DATA['dns_domain']
if 'dns_name' in request.DATA:
params['dns_name'] = request.DATA['dns_name']
result = api.neutron.tenant_floating_ip_allocate(request, pool,
None, params)
return result.to_dict()
@rest_utils.ajax(data_required=True)

View File

@ -27,7 +27,9 @@ class AdminFloatingIpViewTest(test.BaseAdminViewTests):
@test.create_mocks({
api.nova: ['server_list'],
api.keystone: ['tenant_list'],
api.neutron: ['network_list', 'tenant_floating_ip_list']})
api.neutron: ['network_list',
'is_extension_supported',
'tenant_floating_ip_list']})
def test_index(self):
# Use neutron test data
fips = self.floating_ips.list()
@ -37,6 +39,7 @@ class AdminFloatingIpViewTest(test.BaseAdminViewTests):
self.mock_server_list.return_value = [servers, False]
self.mock_tenant_list.return_value = [tenants, False]
self.mock_network_list.return_value = self.networks.list()
self.mock_is_extension_supported.return_value = True
res = self.client.get(INDEX_URL)
self.assertTemplateUsed(res, INDEX_TEMPLATE)
@ -60,14 +63,19 @@ class AdminFloatingIpViewTest(test.BaseAdminViewTests):
params = {"router:external": True}
self.mock_network_list.assert_called_once_with(
test.IsHttpRequest(), **params)
self.mock_is_extension_supported.assert_called_once_with(
test.IsHttpRequest(), 'dns-integration')
@test.create_mocks({
api.neutron: ['tenant_floating_ip_get', 'network_get']})
api.neutron: ['network_get',
'is_extension_supported',
'tenant_floating_ip_get']})
def test_floating_ip_detail_get(self):
fip = self.floating_ips.first()
network = self.networks.first()
self.mock_tenant_floating_ip_get.return_value = fip
self.mock_network_get.return_value = network
self.mock_is_extension_supported.return_value = True
res = self.client.get(reverse('horizon:admin:floating_ips:detail',
args=[fip.id]))
@ -78,6 +86,8 @@ class AdminFloatingIpViewTest(test.BaseAdminViewTests):
test.IsHttpRequest(), fip.id)
self.mock_network_get.assert_called_once_with(
test.IsHttpRequest(), fip.pool)
self.mock_is_extension_supported.assert_called_once_with(
test.IsHttpRequest(), 'dns-integration')
@test.create_mocks({api.neutron: ['tenant_floating_ip_get']})
def test_floating_ip_detail_exception(self):
@ -92,23 +102,31 @@ class AdminFloatingIpViewTest(test.BaseAdminViewTests):
self.mock_tenant_floating_ip_get.assert_called_once_with(
test.IsHttpRequest(), fip.id)
@test.create_mocks({api.neutron: ['tenant_floating_ip_list']})
@test.create_mocks({api.neutron: ['tenant_floating_ip_list',
'is_extension_supported']})
def test_index_no_floating_ips(self):
self.mock_tenant_floating_ip_list.return_value = []
self.mock_is_extension_supported.return_value = True
res = self.client.get(INDEX_URL)
self.assertTemplateUsed(res, INDEX_TEMPLATE)
self.mock_tenant_floating_ip_list.assert_called_once_with(
test.IsHttpRequest(), all_tenants=True)
self.mock_is_extension_supported.assert_called_once_with(
test.IsHttpRequest(), 'dns-integration')
@test.create_mocks({api.neutron: ['tenant_floating_ip_list']})
@test.create_mocks({api.neutron: ['tenant_floating_ip_list',
'is_extension_supported']})
def test_index_error(self):
self.mock_tenant_floating_ip_list.side_effect = self.exceptions.neutron
self.mock_is_extension_supported.return_value = True
res = self.client.get(INDEX_URL)
self.assertTemplateUsed(res, INDEX_TEMPLATE)
self.mock_tenant_floating_ip_list.assert_called_once_with(
test.IsHttpRequest(), all_tenants=True)
self.mock_is_extension_supported.assert_called_once_with(
test.IsHttpRequest(), 'dns-integration')
@test.create_mocks({
api.neutron: ['network_list'],
@ -193,6 +211,7 @@ class AdminFloatingIpViewTest(test.BaseAdminViewTests):
@test.create_mocks({
api.neutron: ['tenant_floating_ip_list',
'floating_ip_disassociate',
'is_extension_supported',
'network_list'],
api.nova: ['server_list'],
api.keystone: ['tenant_list']})
@ -207,6 +226,7 @@ class AdminFloatingIpViewTest(test.BaseAdminViewTests):
self.mock_tenant_list.return_value = [tenants, False]
self.mock_network_list.return_value = self.networks.list()
self.mock_floating_ip_disassociate.return_value = None
self.mock_is_extension_supported.return_value = True
form_data = {
"action":
@ -226,9 +246,12 @@ class AdminFloatingIpViewTest(test.BaseAdminViewTests):
test.IsHttpRequest(), **params)
self.mock_floating_ip_disassociate.assert_called_once_with(
test.IsHttpRequest(), floating_ip.id)
self.mock_is_extension_supported.assert_called_once_with(
test.IsHttpRequest(), 'dns-integration')
@test.create_mocks({
api.neutron: ['tenant_floating_ip_list',
'is_extension_supported',
'network_list'],
api.nova: ['server_list'],
api.keystone: ['tenant_list']})
@ -242,6 +265,7 @@ class AdminFloatingIpViewTest(test.BaseAdminViewTests):
self.mock_server_list.return_value = [servers, False]
self.mock_tenant_list.return_value = [tenants, False]
self.mock_network_list.return_value = self.networks.list()
self.mock_is_extension_supported.return_value = True
form_data = {
"action":
@ -259,9 +283,12 @@ class AdminFloatingIpViewTest(test.BaseAdminViewTests):
params = {"router:external": True}
self.mock_network_list.assert_called_once_with(
test.IsHttpRequest(), **params)
self.mock_is_extension_supported.assert_called_once_with(
test.IsHttpRequest(), 'dns-integration')
@test.create_mocks({
api.neutron: ['tenant_floating_ip_list',
'is_extension_supported',
'network_list'],
api.nova: ['server_list'],
api.keystone: ['tenant_list']})
@ -274,6 +301,7 @@ class AdminFloatingIpViewTest(test.BaseAdminViewTests):
self.mock_server_list.return_value = [servers, False]
self.mock_tenant_list.return_value = [tenants, False]
self.mock_network_list.return_value = self.networks.list()
self.mock_is_extension_supported.return_value = True
res = self.client.get(INDEX_URL)
self.assertTemplateUsed(res, INDEX_TEMPLATE)
@ -297,3 +325,5 @@ class AdminFloatingIpViewTest(test.BaseAdminViewTests):
params = {"router:external": True}
self.mock_network_list.assert_called_once_with(
test.IsHttpRequest(), **params)
self.mock_is_extension_supported.assert_called_once_with(
test.IsHttpRequest(), 'dns-integration')

View File

@ -32,12 +32,25 @@ class FloatingIpAllocate(forms.SelfHandlingForm):
description = forms.CharField(max_length=255,
label=_("Description"),
required=False)
dns_domain = forms.CharField(max_length=255,
label=_("DNS Domain"),
required=False)
dns_name = forms.CharField(max_length=255,
label=_("DNS Name"),
required=False)
def __init__(self, *args, **kwargs):
super(FloatingIpAllocate, self).__init__(*args, **kwargs)
def __init__(self, request, *args, **kwargs):
super(FloatingIpAllocate, self).__init__(request, *args, **kwargs)
floating_pool_list = kwargs.get('initial', {}).get('pool_list', [])
self.fields['pool'].choices = floating_pool_list
dns_supported = api.neutron.is_extension_supported(
request,
"dns-integration")
if not dns_supported:
del self.fields["dns_name"]
del self.fields["dns_domain"]
def handle(self, request, data):
try:
# Prevent allocating more IP than the quota allows
@ -52,6 +65,10 @@ class FloatingIpAllocate(forms.SelfHandlingForm):
param = {}
if data['description']:
param['description'] = data['description']
if 'dns_domain' in data and data['dns_domain']:
param['dns_domain'] = data['dns_domain']
if 'dns_name' in data and data['dns_name']:
param['dns_name'] = data['dns_name']
fip = api.neutron.tenant_floating_ip_allocate(
request,
pool=data['pool'],

View File

@ -189,6 +189,10 @@ class FloatingIPsTable(tables.DataTable):
attrs={'data-type': "ip"})
description = tables.Column("description",
verbose_name=_("Description"))
dns_name = tables.Column("dns_name",
verbose_name=_("DNS Name"))
dns_domain = tables.Column("dns_domain",
verbose_name=_("DNS Domain"))
fixed_ip = tables.Column(get_instance_info,
link=get_instance_link,
verbose_name=_("Mapped Fixed IP Address"))
@ -204,6 +208,12 @@ class FloatingIPsTable(tables.DataTable):
super(FloatingIPsTable, self).__init__(
request, data=data, needs_form_wrapper=needs_form_wrapper,
**kwargs)
dns_supported = api.neutron.is_extension_supported(
request,
"dns-integration")
if not dns_supported:
del self.columns["dns_name"]
del self.columns["dns_domain"]
def sanitize_id(self, obj_id):
return filters.get_int_or_uuid(obj_id)

View File

@ -214,10 +214,12 @@ class FloatingIpViewTests(test.TestCase):
@test.create_mocks({api.nova: ('server_list',),
api.neutron: ('floating_ip_disassociate',
'floating_ip_pools_list',
'is_extension_supported',
'tenant_floating_ip_list')})
def test_disassociate_post(self):
floating_ip = self.floating_ips.first()
self.mock_is_extension_supported.return_value = False
self.mock_server_list.return_value = [self.servers.list(), False]
self.mock_tenant_floating_ip_list.return_value = \
self.floating_ips.list()
@ -237,14 +239,18 @@ class FloatingIpViewTests(test.TestCase):
test.IsHttpRequest())
self.mock_floating_ip_disassociate.assert_called_once_with(
test.IsHttpRequest(), floating_ip.id)
self.mock_is_extension_supported.assert_called_once_with(
test.IsHttpRequest(), 'dns-integration')
@test.create_mocks({api.nova: ('server_list',),
api.neutron: ('floating_ip_disassociate',
'floating_ip_pools_list',
'is_extension_supported',
'tenant_floating_ip_list')})
def test_disassociate_post_with_exception(self):
floating_ip = self.floating_ips.first()
self.mock_is_extension_supported.return_value = False
self.mock_server_list.return_value = [self.servers.list(), False]
self.mock_tenant_floating_ip_list.return_value = \
self.floating_ips.list()
@ -263,8 +269,11 @@ class FloatingIpViewTests(test.TestCase):
test.IsHttpRequest())
self.mock_floating_ip_disassociate.assert_called_once_with(
test.IsHttpRequest(), floating_ip.id)
self.mock_is_extension_supported.assert_called_once_with(
test.IsHttpRequest(), 'dns-integration')
@test.create_mocks({api.neutron: ('tenant_floating_ip_list',
'is_extension_supported',
'floating_ip_pools_list'),
api.nova: ('server_list',),
quotas: ('tenant_quota_usages',)})
@ -273,6 +282,7 @@ class FloatingIpViewTests(test.TestCase):
floating_pools = self.pools.list()
quota_data = self.neutron_quota_usages.first()
self.mock_is_extension_supported.return_value = False
self.mock_tenant_floating_ip_list.return_value = floating_ips
self.mock_floating_ip_pools_list.return_value = floating_pools
self.mock_server_list.return_value = [self.servers.list(), False]
@ -299,8 +309,12 @@ class FloatingIpViewTests(test.TestCase):
self.assert_mock_multiple_calls_with_same_arguments(
self.mock_tenant_quota_usages, 3,
mock.call(test.IsHttpRequest(), targets=('floatingip', )))
self.mock_is_extension_supported.assert_called_once_with(
test.IsHttpRequest(), 'dns-integration',
)
@test.create_mocks({api.neutron: ('tenant_floating_ip_list',
'is_extension_supported',
'floating_ip_pools_list'),
api.nova: ('server_list',),
quotas: ('tenant_quota_usages',)})
@ -310,6 +324,7 @@ class FloatingIpViewTests(test.TestCase):
quota_data = self.neutron_quota_usages.first()
quota_data['floatingip']['available'] = 0
self.mock_is_extension_supported.return_value = False
self.mock_tenant_floating_ip_list.return_value = floating_ips
self.mock_floating_ip_pools_list.return_value = floating_pools
self.mock_server_list.return_value = [self.servers.list(), False]
@ -333,6 +348,9 @@ class FloatingIpViewTests(test.TestCase):
self.assert_mock_multiple_calls_with_same_arguments(
self.mock_tenant_quota_usages, 3,
mock.call(test.IsHttpRequest(), targets=('floatingip', )))
self.mock_is_extension_supported.assert_called_once_with(
test.IsHttpRequest(), 'dns-integration',
)
@test.create_mocks({api.neutron: ('floating_ip_pools_list',
'tenant_floating_ip_list',
@ -343,7 +361,7 @@ class FloatingIpViewTests(test.TestCase):
@test.update_settings(OPENSTACK_NEUTRON_NETWORK={'enable_quotas': True})
def test_correct_quotas_displayed(self):
self.mock_is_service_enabled.return_value = True
self.mock_is_extension_supported.side_effect = [True, False]
self.mock_is_extension_supported.side_effect = [False, True, False]
self.mock_is_router_enabled.return_value = True
self.mock_tenant_quota_get.return_value = self.neutron_quotas.first()
self.mock_tenant_floating_ip_list.return_value = \
@ -357,8 +375,9 @@ class FloatingIpViewTests(test.TestCase):
self.mock_is_service_enabled.assert_called_once_with(
test.IsHttpRequest(), 'network')
self.assertEqual(2, self.mock_is_extension_supported.call_count)
self.assertEqual(3, self.mock_is_extension_supported.call_count)
self.mock_is_extension_supported.assert_has_calls([
mock.call(test.IsHttpRequest(), 'dns-integration'),
mock.call(test.IsHttpRequest(), 'quotas'),
mock.call(test.IsHttpRequest(), 'quota_details'),
])

View File

@ -75,7 +75,9 @@ class RestNetworkApiFloatingIpTests(test.TestCase):
self.assertStatusCode(response, 200)
self.assertEqual(response.json, fip.to_dict())
self.mock_tenant_floating_ip_allocate.assert_called_once_with(request,
'pool')
'pool',
None,
{})
@test.create_mocks({api.neutron: ['floating_ip_associate']})
def test_associate_floating_ip(self):

View File

@ -0,0 +1,6 @@
---
features:
- |
Support has been added to set and display DNS attributes for Floating IPs
(DNS Name and DNS Domain). These attributes are only available if Neutron
has the `dns-integration` extension enabled.