Merge "Extension to tell when deferred binding is in effect"
This commit is contained in:
56
neutron/extensions/ip_allocation.py
Normal file
56
neutron/extensions/ip_allocation.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Copyright (c) 2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||||
|
#
|
||||||
|
# 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 neutron.api import extensions
|
||||||
|
from neutron.api.v2 import attributes
|
||||||
|
|
||||||
|
IP_ALLOCATION = 'ip_allocation'
|
||||||
|
IP_ALLOCATION_IMMEDIATE = 'immediate'
|
||||||
|
IP_ALLOCATION_DEFERRED = 'deferred'
|
||||||
|
IP_ALLOCATION_NONE = 'none'
|
||||||
|
|
||||||
|
# Attribute Map
|
||||||
|
RESOURCE_ATTRIBUTE_MAP = {
|
||||||
|
attributes.PORTS: {
|
||||||
|
IP_ALLOCATION: {'allow_post': False,
|
||||||
|
'allow_put': False,
|
||||||
|
'is_visible': True, },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Ip_allocation(extensions.ExtensionDescriptor):
|
||||||
|
"""Extension indicates when ports use deferred or no IP allocation."""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_name(cls):
|
||||||
|
return "IP Allocation"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_alias(cls):
|
||||||
|
return "ip_allocation"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_description(cls):
|
||||||
|
return "IP allocation extension."
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_updated(cls):
|
||||||
|
return "2016-06-10T23:00:00-00:00"
|
||||||
|
|
||||||
|
def get_extended_resources(self, version):
|
||||||
|
if version == "2.0":
|
||||||
|
return RESOURCE_ATTRIBUTE_MAP
|
||||||
|
else:
|
||||||
|
return {}
|
@@ -17,7 +17,9 @@
|
|||||||
|
|
||||||
from neutron.api.v2 import attributes
|
from neutron.api.v2 import attributes
|
||||||
from neutron.db import common_db_mixin
|
from neutron.db import common_db_mixin
|
||||||
|
from neutron.extensions import ip_allocation
|
||||||
from neutron.extensions import segment
|
from neutron.extensions import segment
|
||||||
|
from neutron import manager
|
||||||
from neutron.services.segments import db
|
from neutron.services.segments import db
|
||||||
|
|
||||||
|
|
||||||
@@ -25,15 +27,28 @@ def _extend_subnet_dict_binding(plugin, subnet_res, subnet_db):
|
|||||||
subnet_res['segment_id'] = subnet_db.get('segment_id')
|
subnet_res['segment_id'] = subnet_db.get('segment_id')
|
||||||
|
|
||||||
|
|
||||||
|
def _extend_port_dict_binding(plugin, port_res, port_db):
|
||||||
|
if not manager.NeutronManager.get_service_plugins().get('segments'):
|
||||||
|
return
|
||||||
|
|
||||||
|
if port_res.get('fixed_ips'):
|
||||||
|
value = ip_allocation.IP_ALLOCATION_IMMEDIATE
|
||||||
|
else:
|
||||||
|
value = ip_allocation.IP_ALLOCATION_DEFERRED
|
||||||
|
port_res[ip_allocation.IP_ALLOCATION] = value
|
||||||
|
|
||||||
|
|
||||||
class Plugin(db.SegmentDbMixin, segment.SegmentPluginBase):
|
class Plugin(db.SegmentDbMixin, segment.SegmentPluginBase):
|
||||||
|
|
||||||
_instance = None
|
_instance = None
|
||||||
|
|
||||||
supported_extension_aliases = ["segment"]
|
supported_extension_aliases = ["segment", "ip_allocation"]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
common_db_mixin.CommonDbMixin.register_dict_extend_funcs(
|
common_db_mixin.CommonDbMixin.register_dict_extend_funcs(
|
||||||
attributes.SUBNETS, [_extend_subnet_dict_binding])
|
attributes.SUBNETS, [_extend_subnet_dict_binding])
|
||||||
|
common_db_mixin.CommonDbMixin.register_dict_extend_funcs(
|
||||||
|
attributes.PORTS, [_extend_port_dict_binding])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_instance(cls):
|
def get_instance(cls):
|
||||||
|
@@ -25,6 +25,7 @@ from neutron.db import agentschedulers_db
|
|||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import portbindings_db
|
from neutron.db import portbindings_db
|
||||||
from neutron.db import segments_db
|
from neutron.db import segments_db
|
||||||
|
from neutron.extensions import ip_allocation
|
||||||
from neutron.extensions import portbindings
|
from neutron.extensions import portbindings
|
||||||
from neutron.extensions import segment as ext_segment
|
from neutron.extensions import segment as ext_segment
|
||||||
from neutron.plugins.common import constants as p_constants
|
from neutron.plugins.common import constants as p_constants
|
||||||
@@ -109,7 +110,7 @@ class SegmentTestPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
__native_pagination_support = True
|
__native_pagination_support = True
|
||||||
__native_sorting_support = True
|
__native_sorting_support = True
|
||||||
|
|
||||||
supported_extension_aliases = ["segment", "binding"]
|
supported_extension_aliases = ["segment", "binding", "ip_allocation"]
|
||||||
|
|
||||||
def get_plugin_description(self):
|
def get_plugin_description(self):
|
||||||
return "Network Segments"
|
return "Network Segments"
|
||||||
@@ -643,6 +644,8 @@ class TestSegmentAwareIpam(SegmentTestCase):
|
|||||||
tenant_id=network['network']['tenant_id'],
|
tenant_id=network['network']['tenant_id'],
|
||||||
arg_list=(portbindings.HOST_ID,),
|
arg_list=(portbindings.HOST_ID,),
|
||||||
**{portbindings.HOST_ID: 'fakehost'})
|
**{portbindings.HOST_ID: 'fakehost'})
|
||||||
|
res = self.deserialize(self.fmt, response)
|
||||||
|
self._validate_immediate_ip_allocation(res['port']['id'])
|
||||||
|
|
||||||
# Since host mapped to middle segment, IP must come from middle subnet
|
# Since host mapped to middle segment, IP must come from middle subnet
|
||||||
self._assert_one_ip_in_subnet(response, subnets[1]['subnet']['cidr'])
|
self._assert_one_ip_in_subnet(response, subnets[1]['subnet']['cidr'])
|
||||||
@@ -686,6 +689,9 @@ class TestSegmentAwareIpam(SegmentTestCase):
|
|||||||
arg_list=(portbindings.HOST_ID,),
|
arg_list=(portbindings.HOST_ID,),
|
||||||
**{portbindings.HOST_ID: 'fakehost'})
|
**{portbindings.HOST_ID: 'fakehost'})
|
||||||
|
|
||||||
|
res = self.deserialize(self.fmt, response)
|
||||||
|
self._validate_immediate_ip_allocation(res['port']['id'])
|
||||||
|
|
||||||
# Since the subnet is not on a segment, fall back to it
|
# Since the subnet is not on a segment, fall back to it
|
||||||
self._assert_one_ip_in_subnet(response, subnet['subnet']['cidr'])
|
self._assert_one_ip_in_subnet(response, subnet['subnet']['cidr'])
|
||||||
|
|
||||||
@@ -775,6 +781,7 @@ class TestSegmentAwareIpam(SegmentTestCase):
|
|||||||
arg_list=(portbindings.HOST_ID,),
|
arg_list=(portbindings.HOST_ID,),
|
||||||
**{portbindings.HOST_ID: 'fakehost'})
|
**{portbindings.HOST_ID: 'fakehost'})
|
||||||
port = self.deserialize(self.fmt, response)
|
port = self.deserialize(self.fmt, response)
|
||||||
|
self._validate_deferred_ip_allocation(port['port']['id'])
|
||||||
|
|
||||||
# Create the subnet and try to update the port to get an IP
|
# Create the subnet and try to update the port to get an IP
|
||||||
with self.subnet(network=network,
|
with self.subnet(network=network,
|
||||||
@@ -790,6 +797,24 @@ class TestSegmentAwareIpam(SegmentTestCase):
|
|||||||
self.assertEqual(webob.exc.HTTPOk.code, response.status_int)
|
self.assertEqual(webob.exc.HTTPOk.code, response.status_int)
|
||||||
self._assert_one_ip_in_subnet(response, subnet['subnet']['cidr'])
|
self._assert_one_ip_in_subnet(response, subnet['subnet']['cidr'])
|
||||||
|
|
||||||
|
def _validate_deferred_ip_allocation(self, port_id):
|
||||||
|
request = self.new_show_request('ports', port_id)
|
||||||
|
response = self.deserialize(self.fmt, request.get_response(self.api))
|
||||||
|
|
||||||
|
self.assertEqual(ip_allocation.IP_ALLOCATION_DEFERRED,
|
||||||
|
response['port'][ip_allocation.IP_ALLOCATION])
|
||||||
|
ips = response['port']['fixed_ips']
|
||||||
|
self.assertEqual(0, len(ips))
|
||||||
|
|
||||||
|
def _validate_immediate_ip_allocation(self, port_id):
|
||||||
|
request = self.new_show_request('ports', port_id)
|
||||||
|
response = self.deserialize(self.fmt, request.get_response(self.api))
|
||||||
|
|
||||||
|
self.assertEqual(ip_allocation.IP_ALLOCATION_IMMEDIATE,
|
||||||
|
response['port'][ip_allocation.IP_ALLOCATION])
|
||||||
|
ips = response['port']['fixed_ips']
|
||||||
|
self.assertNotEqual(0, len(ips))
|
||||||
|
|
||||||
def _create_deferred_ip_port(self, network):
|
def _create_deferred_ip_port(self, network):
|
||||||
response = self._create_port(self.fmt,
|
response = self._create_port(self.fmt,
|
||||||
net_id=network['network']['id'],
|
net_id=network['network']['id'],
|
||||||
@@ -797,6 +822,9 @@ class TestSegmentAwareIpam(SegmentTestCase):
|
|||||||
port = self.deserialize(self.fmt, response)
|
port = self.deserialize(self.fmt, response)
|
||||||
ips = port['port']['fixed_ips']
|
ips = port['port']['fixed_ips']
|
||||||
self.assertEqual(0, len(ips))
|
self.assertEqual(0, len(ips))
|
||||||
|
|
||||||
|
self._validate_deferred_ip_allocation(port['port']['id'])
|
||||||
|
|
||||||
return port
|
return port
|
||||||
|
|
||||||
def test_port_update_deferred_allocation(self):
|
def test_port_update_deferred_allocation(self):
|
||||||
|
Reference in New Issue
Block a user