Accepts UUID as an ID of Floating IP
Fixes bug 1052561. In Quanutm, Floating IPs are identified by UUID instead of integer ID. After quantum-nova integration for FLoating IP has been implemented, Horizon also needs to accept UUID style of ID for Floating IP. Change-Id: I6ed919cbbc818c97cecef2fe3a91c8e5a7ac76e0
This commit is contained in:
parent
8734ea4977
commit
7ab5ace768
|
@ -28,6 +28,8 @@ from horizon import tables
|
|||
|
||||
from openstack_dashboard import api
|
||||
|
||||
from .utils import get_int_or_uuid
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -83,7 +85,7 @@ class DisassociateIP(tables.Action):
|
|||
|
||||
def single(self, table, request, obj_id):
|
||||
try:
|
||||
fip = table.get_object_by_id(int(obj_id))
|
||||
fip = table.get_object_by_id(get_int_or_uuid(obj_id))
|
||||
api.server_remove_floating_ip(request, fip.instance_id, fip.id)
|
||||
LOG.info('Disassociating Floating IP "%s".' % obj_id)
|
||||
messages.success(request,
|
||||
|
@ -118,7 +120,7 @@ class FloatingIPsTable(tables.DataTable):
|
|||
empty_value="-")
|
||||
|
||||
def sanitize_id(self, obj_id):
|
||||
return int(obj_id)
|
||||
return get_int_or_uuid(obj_id)
|
||||
|
||||
def get_object_display(self, datum):
|
||||
return datum.ip
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import uuid
|
||||
|
||||
from django import http
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
|
@ -27,6 +29,8 @@ from mox import IsA
|
|||
from openstack_dashboard import api
|
||||
from openstack_dashboard.test import helpers as test
|
||||
|
||||
from .utils import get_int_or_uuid
|
||||
|
||||
|
||||
INDEX_URL = reverse('horizon:project:access_and_security:index')
|
||||
NAMESPACE = "horizon:project:access_and_security:floating_ips"
|
||||
|
@ -49,10 +53,10 @@ class FloatingIpViewTests(test.TestCase):
|
|||
workflow = res.context['workflow']
|
||||
choices = dict(workflow.steps[0].action.fields['ip_id'].choices)
|
||||
# Verify that our "associated" floating IP isn't in the choices list.
|
||||
self.assertTrue(self.floating_ips.get(id=1) not in choices)
|
||||
self.assertTrue(self.floating_ips.first() not in choices)
|
||||
|
||||
def test_associate_post(self):
|
||||
floating_ip = self.floating_ips.get(id=2)
|
||||
floating_ip = self.floating_ips.list()[1]
|
||||
server = self.servers.first()
|
||||
self.mox.StubOutWithMock(api.nova, 'server_add_floating_ip')
|
||||
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_list')
|
||||
|
@ -74,7 +78,7 @@ class FloatingIpViewTests(test.TestCase):
|
|||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def test_associate_post_with_redirect(self):
|
||||
floating_ip = self.floating_ips.get(id=2)
|
||||
floating_ip = self.floating_ips.list()[1]
|
||||
server = self.servers.first()
|
||||
self.mox.StubOutWithMock(api.nova, 'server_add_floating_ip')
|
||||
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_list')
|
||||
|
@ -97,7 +101,7 @@ class FloatingIpViewTests(test.TestCase):
|
|||
self.assertRedirectsNoFollow(res, next)
|
||||
|
||||
def test_associate_post_with_exception(self):
|
||||
floating_ip = self.floating_ips.get(id=2)
|
||||
floating_ip = self.floating_ips.list()[1]
|
||||
server = self.servers.first()
|
||||
self.mox.StubOutWithMock(api.nova, 'server_add_floating_ip')
|
||||
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_list')
|
||||
|
@ -175,3 +179,30 @@ class FloatingIpViewTests(test.TestCase):
|
|||
action = "floating_ips__disassociate__%s" % floating_ip.id
|
||||
res = self.client.post(INDEX_URL, {"action": action})
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
|
||||
class FloatingIpQuantumViewTests(FloatingIpViewTests):
|
||||
def setUp(self):
|
||||
super(FloatingIpViewTests, self).setUp()
|
||||
self.floating_ips = self.floating_ips_uuid
|
||||
|
||||
|
||||
class FloatingIpUtilsTests(test.TestCase):
|
||||
def test_accept_valid_integer(self):
|
||||
val = 100
|
||||
ret = get_int_or_uuid(val)
|
||||
self.assertEqual(val, ret)
|
||||
|
||||
def test_accept_valid_integer_string(self):
|
||||
val = '100'
|
||||
ret = get_int_or_uuid(val)
|
||||
self.assertEqual(int(val), ret)
|
||||
|
||||
def test_accept_valid_uuid(self):
|
||||
val = str(uuid.uuid4())
|
||||
ret = get_int_or_uuid(val)
|
||||
self.assertEqual(val, ret)
|
||||
|
||||
def test_reject_random_string(self):
|
||||
val = '55WbJTpJDf'
|
||||
self.assertRaises(ValueError, get_int_or_uuid, val)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 NEC Corporation All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import uuid
|
||||
|
||||
|
||||
def get_int_or_uuid(value):
|
||||
"""Check if a value is valid as UUID or an integer.
|
||||
|
||||
This method is mainly used to convert floating IP id to the
|
||||
appropriate type. For floating IP id, integer is used in Nova's
|
||||
original implementation, but UUID is used in Quantum based one.
|
||||
"""
|
||||
try:
|
||||
uuid.UUID(value)
|
||||
return value
|
||||
except (ValueError, AttributeError):
|
||||
return int(value)
|
|
@ -24,13 +24,15 @@ from horizon import forms
|
|||
|
||||
from openstack_dashboard import api
|
||||
|
||||
from .utils import get_int_or_uuid
|
||||
|
||||
|
||||
ALLOCATE_URL = "horizon:project:access_and_security:floating_ips:allocate"
|
||||
|
||||
|
||||
class AssociateIPAction(workflows.Action):
|
||||
ip_id = forms.DynamicTypedChoiceField(label=_("IP Address"),
|
||||
coerce=int,
|
||||
coerce=get_int_or_uuid,
|
||||
empty_value=None,
|
||||
add_item_link=ALLOCATE_URL)
|
||||
instance_id = forms.ChoiceField(label=_("Instance"))
|
||||
|
|
|
@ -86,3 +86,9 @@ class AccessAndSecurityTests(test.TestCase):
|
|||
self.assertContains(res,
|
||||
'<option value="101">server_1 (101)</option>')
|
||||
self.assertContains(res, '<option value="2">server_2 (2)</option>')
|
||||
|
||||
|
||||
class AccessAndSecurityQuantumTests(AccessAndSecurityTests):
|
||||
def setUp(self):
|
||||
super(AccessAndSecurityTests, self).setUp()
|
||||
self.floating_ips = self.floating_ips_uuid
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# under the License.
|
||||
|
||||
import json
|
||||
import uuid
|
||||
|
||||
from novaclient.v1_1 import (flavors, keypairs, servers, volumes,
|
||||
volume_types, quotas,
|
||||
|
@ -143,6 +144,7 @@ def data(TEST):
|
|||
TEST.quotas = TestDataContainer()
|
||||
TEST.quota_usages = TestDataContainer()
|
||||
TEST.floating_ips = TestDataContainer()
|
||||
TEST.floating_ips_uuid = TestDataContainer()
|
||||
TEST.usages = TestDataContainer()
|
||||
TEST.certs = TestDataContainer()
|
||||
TEST.volume_snapshots = TestDataContainer()
|
||||
|
@ -335,6 +337,19 @@ def data(TEST):
|
|||
'ip': '58.58.58.58'})
|
||||
TEST.floating_ips.add(fip_1, fip_2)
|
||||
|
||||
# Floating IP with UUID id (for Floating IP with Quantum)
|
||||
fip_3 = floating_ips.FloatingIP(floating_ips.FloatingIPManager(None),
|
||||
{'id': str(uuid.uuid4()),
|
||||
'fixed_ip': '10.0.0.4',
|
||||
'instance_id': server_1.id,
|
||||
'ip': '58.58.58.58'})
|
||||
fip_4 = floating_ips.FloatingIP(floating_ips.FloatingIPManager(None),
|
||||
{'id': str(uuid.uuid4()),
|
||||
'fixed_ip': None,
|
||||
'instance_id': None,
|
||||
'ip': '58.58.58.58'})
|
||||
TEST.floating_ips_uuid.add(fip_3, fip_4)
|
||||
|
||||
# Usage
|
||||
usage_vals = {"tenant_id": TEST.tenant.id,
|
||||
"instance_name": server_1.name,
|
||||
|
|
Loading…
Reference in New Issue