]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Allow to specify IP address of floating ip
authorfujioka yuuichi <fujioka-yuuichi@zx.mxh.nes.nec.co.jp>
Fri, 31 Jan 2014 01:54:34 +0000 (10:54 +0900)
committerYuuichi Fujioka <fujioka.yuuichi@gmail.com>
Fri, 26 Dec 2014 02:25:00 +0000 (02:25 +0000)
IP address of floating ip will be automatically allocated.
There are cases where users need to specify a floating IP address.
This patch addresses the problem.

The feature is limited by "create_floatingip:floating_ip_address" in
"policy.json".
By default, it needs an admin role.

DocImpact
APIImpact

Implements: blueprint allow-specific-floating-ip-address

Change-Id: Iba64a0f0a38ca5eb39c605e121a12c956637b96c

etc/policy.json
neutron/db/l3_db.py
neutron/extensions/l3.py
neutron/tests/unit/test_l3_plugin.py

index 1664c8d7afd67cf4d2014aa199492f66ac7fe221..f8414e14bcb35657070fa143527e77d884920752 100644 (file)
     "get_loadbalancer-pools": "rule:admin_only",
 
     "create_floatingip": "rule:regular_user",
+    "create_floatingip:floating_ip_address": "rule:admin_only",
     "update_floatingip": "rule:admin_or_owner",
     "delete_floatingip": "rule:admin_or_owner",
     "get_floatingip": "rule:admin_or_owner",
index bdef81933285c6e4c5948ce771823d857d8affe5..679f4c534d3e1d0cf96efc9ad3ac9927f146e864 100644 (file)
@@ -773,16 +773,23 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase):
             # This external port is never exposed to the tenant.
             # it is used purely for internal system and admin use when
             # managing floating IPs.
-            external_port = self._core_plugin.create_port(context.elevated(), {
-                'port':
-                {'tenant_id': '',  # tenant intentionally not set
-                 'network_id': f_net_id,
-                 'mac_address': attributes.ATTR_NOT_SPECIFIED,
-                 'fixed_ips': attributes.ATTR_NOT_SPECIFIED,
-                 'admin_state_up': True,
-                 'device_id': fip_id,
-                 'device_owner': DEVICE_OWNER_FLOATINGIP,
-                 'name': ''}})
+
+            port = {'tenant_id': '',  # tenant intentionally not set
+                    'network_id': f_net_id,
+                    'mac_address': attributes.ATTR_NOT_SPECIFIED,
+                    'fixed_ips': attributes.ATTR_NOT_SPECIFIED,
+                    'admin_state_up': True,
+                    'device_id': fip_id,
+                    'device_owner': DEVICE_OWNER_FLOATINGIP,
+                    'name': ''}
+
+            if fip.get('floating_ip_address'):
+                port['fixed_ips'] = [
+                    {'ip_address': fip['floating_ip_address']}]
+
+            external_port = self._core_plugin.create_port(context.elevated(),
+                                                          {'port': port})
+
             # Ensure IP addresses are allocated on external port
             if not external_port['fixed_ips']:
                 raise n_exc.ExternalIpAddressExhausted(net_id=f_net_id)
index 1497d9fb45c06ccd0548982949562bfadcbd061f..e1106cda0115c830a358af68bbcffe67cf323e6a 100644 (file)
@@ -120,9 +120,10 @@ RESOURCE_ATTRIBUTE_MAP = {
                'validate': {'type:uuid': None},
                'is_visible': True,
                'primary_key': True},
-        'floating_ip_address': {'allow_post': False, 'allow_put': False,
+        'floating_ip_address': {'allow_post': True, 'allow_put': False,
                                 'validate': {'type:ip_address_or_none': None},
-                                'is_visible': True},
+                                'is_visible': True, 'default': None,
+                                'enforce_policy': True},
         'floating_network_id': {'allow_post': True, 'allow_put': False,
                                 'validate': {'type:uuid': None},
                                 'is_visible': True},
index f97111d245c9e151d96893dad91f6e4bdc63fa6f..8b86e02e0a09138986250ac2fa747222f3a46934 100644 (file)
@@ -415,13 +415,18 @@ class L3NatTestCaseMixin(object):
                      {'network': {external_net.EXTERNAL: True}})
 
     def _create_floatingip(self, fmt, network_id, port_id=None,
-                           fixed_ip=None, set_context=False):
+                           fixed_ip=None, set_context=False,
+                           floating_ip=None):
         data = {'floatingip': {'floating_network_id': network_id,
                                'tenant_id': self._tenant_id}}
         if port_id:
             data['floatingip']['port_id'] = port_id
             if fixed_ip:
                 data['floatingip']['fixed_ip_address'] = fixed_ip
+
+        if floating_ip:
+            data['floatingip']['floating_ip_address'] = floating_ip
+
         floatingip_req = self.new_create_request('floatingips', data, fmt)
         if set_context and self._tenant_id:
             # create a specific auth context for this request
@@ -430,10 +435,11 @@ class L3NatTestCaseMixin(object):
         return floatingip_req.get_response(self.ext_api)
 
     def _make_floatingip(self, fmt, network_id, port_id=None,
-                         fixed_ip=None, set_context=False):
+                         fixed_ip=None, set_context=False, floating_ip=None,
+                         http_status=exc.HTTPCreated.code):
         res = self._create_floatingip(fmt, network_id, port_id,
-                                      fixed_ip, set_context)
-        self.assertEqual(res.status_int, exc.HTTPCreated.code)
+                                      fixed_ip, set_context, floating_ip)
+        self.assertEqual(res.status_int, http_status)
         return self.deserialize(fmt, res)
 
     def _validate_floating_ip(self, fip):
@@ -1795,6 +1801,68 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
             with self.subnet(network=net):
                 self._make_floatingip(self.fmt, net_id)
 
+    def test_create_floatingip_with_specific_ip(self):
+        with self.subnet(cidr='10.0.0.0/24') as s:
+            network_id = s['subnet']['network_id']
+            self._set_net_external(network_id)
+            fp = self._make_floatingip(self.fmt, network_id,
+                                       floating_ip='10.0.0.10')
+            try:
+                self.assertEqual(fp['floatingip']['floating_ip_address'],
+                                 '10.0.0.10')
+            finally:
+                self._delete('floatingips', fp['floatingip']['id'])
+
+    def test_create_floatingip_with_specific_ip_out_of_allocation(self):
+        with self.subnet(cidr='10.0.0.0/24',
+                         allocation_pools=[
+                             {'start': '10.0.0.10', 'end': '10.0.0.20'}]
+                         ) as s:
+            network_id = s['subnet']['network_id']
+            self._set_net_external(network_id)
+            fp = self._make_floatingip(self.fmt, network_id,
+                                       floating_ip='10.0.0.30')
+            try:
+                self.assertEqual(fp['floatingip']['floating_ip_address'],
+                                 '10.0.0.30')
+            finally:
+                self._delete('floatingips', fp['floatingip']['id'])
+
+    def test_create_floatingip_with_specific_ip_non_admin(self):
+        ctx = context.Context('user_id', 'tenant_id')
+
+        with self.subnet(cidr='10.0.0.0/24') as s:
+            network_id = s['subnet']['network_id']
+            self._set_net_external(network_id)
+            self._make_floatingip(self.fmt, network_id,
+                                  set_context=ctx,
+                                  floating_ip='10.0.0.10',
+                                  http_status=exc.HTTPForbidden.code)
+
+    def test_create_floatingip_with_specific_ip_out_of_subnet(self):
+
+        with self.subnet(cidr='10.0.0.0/24') as s:
+            network_id = s['subnet']['network_id']
+            self._set_net_external(network_id)
+            self._make_floatingip(self.fmt, network_id,
+                                  floating_ip='10.0.1.10',
+                                  http_status=exc.HTTPBadRequest.code)
+
+    def test_create_floatingip_with_duplicated_specific_ip(self):
+
+        with self.subnet(cidr='10.0.0.0/24') as s:
+            network_id = s['subnet']['network_id']
+            self._set_net_external(network_id)
+            fp1 = self._make_floatingip(self.fmt, network_id,
+                                        floating_ip='10.0.0.10')
+
+            try:
+                self._make_floatingip(self.fmt, network_id,
+                                      floating_ip='10.0.0.10',
+                                      http_status=exc.HTTPConflict.code)
+            finally:
+                self._delete('floatingips', fp1['floatingip']['id'])
+
 
 class L3AgentDbTestCaseBase(L3NatTestCaseMixin):