diff --git a/neutron/db/allowedaddresspairs_db.py b/neutron/db/allowedaddresspairs_db.py index bbc5bd7053c..1bc1bdf07c9 100644 --- a/neutron/db/allowedaddresspairs_db.py +++ b/neutron/db/allowedaddresspairs_db.py @@ -13,15 +13,16 @@ # under the License. # +from neutron_lib.api.definitions import allowedaddresspairs as addr_apidef from neutron_lib.api.definitions import port as port_def from neutron_lib.api import validators +from neutron_lib.exceptions import allowedaddresspairs as addr_exc from neutron_lib.objects import exceptions from neutron.common import utils from neutron.db import _resource_extend as resource_extend from neutron.db import _utils as db_utils from neutron.db import api as db_api -from neutron.extensions import allowedaddresspairs as addr_pair from neutron.objects.port.extensions import (allowedaddresspairs as obj_addr_pair) @@ -52,7 +53,7 @@ class AllowedAddressPairsMixin(object): ip_address=ip_address) pair_obj.create() except exceptions.NeutronDbObjectDuplicateEntry: - raise addr_pair.DuplicateAddressPairInRequest( + raise addr_exc.DuplicateAddressPairInRequest( mac_address=address_pair['mac_address'], ip_address=address_pair['ip_address']) @@ -74,7 +75,7 @@ class AllowedAddressPairsMixin(object): AllowedAddressPairsMixin._make_allowed_address_pairs_dict( address_pair) for address_pair in port_db.allowed_address_pairs] - port_res[addr_pair.ADDRESS_PAIRS] = allowed_address_pairs + port_res[addr_apidef.ADDRESS_PAIRS] = allowed_address_pairs return port_res def _delete_allowed_address_pairs(self, context, id): @@ -89,8 +90,8 @@ class AllowedAddressPairsMixin(object): return db_utils.resource_fields(res, fields) def _has_address_pairs(self, port): - return (validators.is_attr_set(port['port'][addr_pair.ADDRESS_PAIRS]) - and port['port'][addr_pair.ADDRESS_PAIRS] != []) + return (validators.is_attr_set(port['port'][addr_apidef.ADDRESS_PAIRS]) + and port['port'][addr_apidef.ADDRESS_PAIRS] != []) def _check_update_has_allowed_address_pairs(self, port): """Determine if request has an allowed address pair. @@ -98,7 +99,7 @@ class AllowedAddressPairsMixin(object): Return True if the port parameter has a non-empty 'allowed_address_pairs' attribute. Otherwise returns False. """ - return (addr_pair.ADDRESS_PAIRS in port['port'] and + return (addr_apidef.ADDRESS_PAIRS in port['port'] and self._has_address_pairs(port)) def _check_update_deletes_allowed_address_pairs(self, port): @@ -107,7 +108,7 @@ class AllowedAddressPairsMixin(object): Return True if port has an allowed address pair and its value is either [] or not is_attr_set, otherwise return False """ - return (addr_pair.ADDRESS_PAIRS in port['port'] and + return (addr_apidef.ADDRESS_PAIRS in port['port'] and not self._has_address_pairs(port)) def is_address_pairs_attribute_updated(self, port, update_attrs): @@ -118,10 +119,10 @@ class AllowedAddressPairsMixin(object): party controllers. """ - new_pairs = update_attrs.get(addr_pair.ADDRESS_PAIRS) + new_pairs = update_attrs.get(addr_apidef.ADDRESS_PAIRS) if new_pairs is None: return False - old_pairs = port.get(addr_pair.ADDRESS_PAIRS) + old_pairs = port.get(addr_apidef.ADDRESS_PAIRS) # Missing or unchanged address pairs in attributes mean no update return new_pairs != old_pairs @@ -135,11 +136,11 @@ class AllowedAddressPairsMixin(object): notification. This method is expected to be called within a transaction. """ - new_pairs = port['port'].get(addr_pair.ADDRESS_PAIRS) + new_pairs = port['port'].get(addr_apidef.ADDRESS_PAIRS) if self.is_address_pairs_attribute_updated(original_port, port['port']): - updated_port[addr_pair.ADDRESS_PAIRS] = new_pairs + updated_port[addr_apidef.ADDRESS_PAIRS] = new_pairs self._delete_allowed_address_pairs(context, port_id) self._process_create_allowed_address_pairs( context, updated_port, new_pairs) diff --git a/neutron/extensions/allowedaddresspairs.py b/neutron/extensions/allowedaddresspairs.py index e1f718dffdf..e0c2f003da5 100644 --- a/neutron/extensions/allowedaddresspairs.py +++ b/neutron/extensions/allowedaddresspairs.py @@ -12,123 +12,15 @@ # License for the specific language governing permissions and limitations # under the License. -from neutron_lib.api import converters +from neutron_lib.api.definitions import allowedaddresspairs as addr_apidef from neutron_lib.api import extensions -from neutron_lib.api import validators -from neutron_lib import constants -from neutron_lib import exceptions as nexception -from oslo_config import cfg -import webob.exc -from neutron._i18n import _ from neutron.conf.extensions import allowedaddresspairs as addr_pair + addr_pair.register_allowed_address_pair_opts() -class AllowedAddressPairsMissingIP(nexception.InvalidInput): - message = _("AllowedAddressPair must contain ip_address") - - -class AddressPairAndPortSecurityRequired(nexception.Conflict): - message = _("Port Security must be enabled in order to have allowed " - "address pairs on a port.") - - -class DuplicateAddressPairInRequest(nexception.InvalidInput): - message = _("Request contains duplicate address pair: " - "mac_address %(mac_address)s ip_address %(ip_address)s.") - - -class AllowedAddressPairExhausted(nexception.BadRequest): - message = _("The number of allowed address pair " - "exceeds the maximum %(quota)s.") - - -def _validate_allowed_address_pairs(address_pairs, valid_values=None): - unique_check = {} - if not isinstance(address_pairs, list): - raise webob.exc.HTTPBadRequest( - _("Allowed address pairs must be a list.")) - if len(address_pairs) > cfg.CONF.max_allowed_address_pair: - raise AllowedAddressPairExhausted( - quota=cfg.CONF.max_allowed_address_pair) - - for address_pair in address_pairs: - msg = validators.validate_dict(address_pair) - if msg: - return msg - # mac_address is optional, if not set we use the mac on the port - if 'mac_address' in address_pair: - msg = validators.validate_mac_address(address_pair['mac_address']) - if msg: - raise webob.exc.HTTPBadRequest(msg) - if 'ip_address' not in address_pair: - raise AllowedAddressPairsMissingIP() - - mac = address_pair.get('mac_address') - ip_address = address_pair['ip_address'] - if (mac, ip_address) not in unique_check: - unique_check[(mac, ip_address)] = None - else: - raise DuplicateAddressPairInRequest(mac_address=mac, - ip_address=ip_address) - - invalid_attrs = set(address_pair.keys()) - set(['mac_address', - 'ip_address']) - if invalid_attrs: - msg = (_("Unrecognized attribute(s) '%s'") % - ', '.join(set(address_pair.keys()) - - set(['mac_address', 'ip_address']))) - raise webob.exc.HTTPBadRequest(msg) - - if '/' in ip_address: - msg = validators.validate_subnet(ip_address) - else: - msg = validators.validate_ip_address(ip_address) - if msg: - raise webob.exc.HTTPBadRequest(msg) - -validators.add_validator('validate_allowed_address_pairs', - _validate_allowed_address_pairs) - -ADDRESS_PAIRS = 'allowed_address_pairs' -EXTENDED_ATTRIBUTES_2_0 = { - 'ports': { - ADDRESS_PAIRS: {'allow_post': True, 'allow_put': True, - 'convert_to': converters.convert_none_to_empty_list, - 'convert_list_to': - converters.convert_kvp_list_to_dict, - 'validate': {'type:validate_allowed_address_pairs': - None}, - 'enforce_policy': True, - 'default': constants.ATTR_NOT_SPECIFIED, - 'is_visible': True}, - } -} - - -class Allowedaddresspairs(extensions.ExtensionDescriptor): +class Allowedaddresspairs(extensions.APIExtensionDescriptor): """Extension class supporting allowed address pairs.""" - - @classmethod - def get_name(cls): - return "Allowed Address Pairs" - - @classmethod - def get_alias(cls): - return "allowed-address-pairs" - - @classmethod - def get_description(cls): - return "Provides allowed address pairs" - - @classmethod - def get_updated(cls): - return "2013-07-23T10:00:00-00:00" - - def get_extended_resources(self, version): - if version == "2.0": - return EXTENDED_ATTRIBUTES_2_0 - else: - return {} + api_definition = addr_apidef diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index 1eefb94a5fe..877441df2fa 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -14,6 +14,7 @@ # under the License. from eventlet import greenthread +from neutron_lib.api.definitions import allowedaddresspairs as addr_apidef from neutron_lib.api.definitions import availability_zone as az_def from neutron_lib.api.definitions import extra_dhcp_opt as edo_ext from neutron_lib.api.definitions import network as net_def @@ -29,6 +30,7 @@ from neutron_lib.callbacks import registry from neutron_lib.callbacks import resources from neutron_lib import constants as const from neutron_lib import exceptions as exc +from neutron_lib.exceptions import allowedaddresspairs as addr_exc from neutron_lib.exceptions import port_security as psec_exc from neutron_lib.plugins import constants as plugin_constants from neutron_lib.plugins import directory @@ -77,7 +79,6 @@ from neutron.db import securitygroups_rpc_base as sg_db_rpc from neutron.db import segments_db from neutron.db import subnet_service_type_db_models as service_type_db from neutron.db import vlantransparent_db -from neutron.extensions import allowedaddresspairs as addr_pair from neutron.extensions import netmtu_writable as mtu_ext from neutron.extensions import providernet as provider from neutron.extensions import vlantransparent @@ -1131,10 +1132,10 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, # allowed address pair checks if self._check_update_has_allowed_address_pairs(port): if not port_security: - raise addr_pair.AddressPairAndPortSecurityRequired() + raise addr_exc.AddressPairAndPortSecurityRequired() else: # remove ATTR_NOT_SPECIFIED - attrs[addr_pair.ADDRESS_PAIRS] = [] + attrs[addr_apidef.ADDRESS_PAIRS] = [] if port_security: self._ensure_default_security_group_on_port(context, port) @@ -1186,10 +1187,10 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, network, binding, None) self._process_port_binding(mech_context, attrs) - result[addr_pair.ADDRESS_PAIRS] = ( + result[addr_apidef.ADDRESS_PAIRS] = ( self._process_create_allowed_address_pairs( context, result, - attrs.get(addr_pair.ADDRESS_PAIRS))) + attrs.get(addr_apidef.ADDRESS_PAIRS))) self._process_port_create_extra_dhcp_opts(context, result, dhcp_opts) kwargs = {'context': context, 'port': result} @@ -1249,17 +1250,17 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, # check the address-pairs if self._check_update_has_allowed_address_pairs(port): # has address pairs in request - raise addr_pair.AddressPairAndPortSecurityRequired() + raise addr_exc.AddressPairAndPortSecurityRequired() elif (not self._check_update_deletes_allowed_address_pairs(port)): # not a request for deleting the address-pairs - updated_port[addr_pair.ADDRESS_PAIRS] = ( + updated_port[addr_apidef.ADDRESS_PAIRS] = ( self.get_allowed_address_pairs(context, id)) # check if address pairs has been in db, if address pairs could # be put in extension driver, we can refine here. - if updated_port[addr_pair.ADDRESS_PAIRS]: - raise addr_pair.AddressPairAndPortSecurityRequired() + if updated_port[addr_apidef.ADDRESS_PAIRS]: + raise addr_exc.AddressPairAndPortSecurityRequired() # checks if security groups were updated adding/modifying # security groups, port security is set @@ -1316,7 +1317,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, updated_port[qos_consts.QOS_POLICY_ID]): need_port_update_notify = True - if addr_pair.ADDRESS_PAIRS in attrs: + if addr_apidef.ADDRESS_PAIRS in attrs: need_port_update_notify |= ( self.update_address_pairs_on_port(context, id, port, original_port, diff --git a/neutron/tests/unit/agent/test_securitygroups_rpc.py b/neutron/tests/unit/agent/test_securitygroups_rpc.py index 31a059e8f67..9b445ebda03 100644 --- a/neutron/tests/unit/agent/test_securitygroups_rpc.py +++ b/neutron/tests/unit/agent/test_securitygroups_rpc.py @@ -18,6 +18,7 @@ import contextlib import mock import netaddr +from neutron_lib.api.definitions import allowedaddresspairs as addr_apidef from neutron_lib import constants as const from neutron_lib import context from neutron_lib.plugins import directory @@ -33,7 +34,6 @@ from neutron.agent import securitygroups_rpc as sg_rpc from neutron.api.rpc.handlers import securitygroups_rpc from neutron.common import rpc as n_rpc from neutron.db import securitygroups_rpc_base as sg_db_rpc -from neutron.extensions import allowedaddresspairs as addr_pair from neutron.extensions import securitygroup as ext_sg from neutron.tests import base from neutron.tests import tools @@ -303,7 +303,7 @@ class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase): res1 = self._create_port( self.fmt, n['network']['id'], security_groups=[sg1_id], - arg_list=(addr_pair.ADDRESS_PAIRS,), + arg_list=(addr_apidef.ADDRESS_PAIRS,), allowed_address_pairs=address_pairs) yield self.deserialize(self.fmt, res1) diff --git a/neutron/tests/unit/db/test_allowedaddresspairs_db.py b/neutron/tests/unit/db/test_allowedaddresspairs_db.py index 569af7e888d..381395cf3a8 100644 --- a/neutron/tests/unit/db/test_allowedaddresspairs_db.py +++ b/neutron/tests/unit/db/test_allowedaddresspairs_db.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from neutron_lib.api.definitions import allowedaddresspairs as addr_apidef from neutron_lib.api.definitions import port_security as psec from neutron_lib.api import validators from neutron_lib.plugins import directory @@ -22,7 +23,6 @@ from webob import exc as web_exc from neutron.db import allowedaddresspairs_db as addr_pair_db from neutron.db import db_base_plugin_v2 from neutron.db import portsecurity_db -from neutron.extensions import allowedaddresspairs as addr_pair from neutron.extensions import securitygroup as secgroup from neutron.tests.unit.db import test_db_base_plugin_v2 @@ -58,12 +58,12 @@ class AllowedAddressPairTestPlugin(portsecurity_db.PortSecurityDbMixin, neutron_db = super(AllowedAddressPairTestPlugin, self).create_port( context, port) p.update(neutron_db) - if validators.is_attr_set(p.get(addr_pair.ADDRESS_PAIRS)): + if validators.is_attr_set(p.get(addr_apidef.ADDRESS_PAIRS)): self._process_create_allowed_address_pairs( context, p, - p[addr_pair.ADDRESS_PAIRS]) + p[addr_apidef.ADDRESS_PAIRS]) else: - p[addr_pair.ADDRESS_PAIRS] = None + p[addr_apidef.ADDRESS_PAIRS] = None return port['port'] @@ -84,7 +84,7 @@ class AllowedAddressPairTestPlugin(portsecurity_db.PortSecurityDbMixin, self._delete_allowed_address_pairs(context, id) self._process_create_allowed_address_pairs( context, ret_port, - ret_port[addr_pair.ADDRESS_PAIRS]) + ret_port[addr_apidef.ADDRESS_PAIRS]) return ret_port @@ -106,7 +106,7 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): self._create_port( self.fmt, net['network']['id'], expected_res_status=web_exc.HTTPBadRequest.code, - arg_list=(addr_pair.ADDRESS_PAIRS,), + arg_list=(addr_apidef.ADDRESS_PAIRS,), allowed_address_pairs=value) def test_create_port_allowed_address_pairs(self): @@ -114,10 +114,10 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): address_pairs = [{'mac_address': '00:00:00:00:00:01', 'ip_address': '10.0.0.1'}] res = self._create_port(self.fmt, net['network']['id'], - arg_list=(addr_pair.ADDRESS_PAIRS,), + arg_list=(addr_apidef.ADDRESS_PAIRS,), allowed_address_pairs=address_pairs) port = self.deserialize(self.fmt, res) - self.assertEqual(port['port'][addr_pair.ADDRESS_PAIRS], + self.assertEqual(port['port'][addr_apidef.ADDRESS_PAIRS], address_pairs) self._delete('ports', port['port']['id']) @@ -130,12 +130,12 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): 'ip_address': '10.0.0.1'}] res = self._create_port(self.fmt, net['network']['id'], arg_list=('port_security_enabled', - addr_pair.ADDRESS_PAIRS,), + addr_apidef.ADDRESS_PAIRS,), port_security_enabled=True, allowed_address_pairs=address_pairs) port = self.deserialize(self.fmt, res) self.assertTrue(port['port'][psec.PORTSECURITY]) - self.assertEqual(port['port'][addr_pair.ADDRESS_PAIRS], + self.assertEqual(port['port'][addr_apidef.ADDRESS_PAIRS], address_pairs) self._delete('ports', port['port']['id']) @@ -148,7 +148,7 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): 'ip_address': '10.0.0.1'}] res = self._create_port(self.fmt, net['network']['id'], arg_list=('port_security_enabled', - addr_pair.ADDRESS_PAIRS,), + addr_apidef.ADDRESS_PAIRS,), port_security_enabled=False, allowed_address_pairs=address_pairs) self.deserialize(self.fmt, res) @@ -157,12 +157,12 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): address_pairs = [] res = self._create_port(self.fmt, net['network']['id'], arg_list=('port_security_enabled', - addr_pair.ADDRESS_PAIRS,), + addr_apidef.ADDRESS_PAIRS,), port_security_enabled=False, allowed_address_pairs=address_pairs) port = self.deserialize(self.fmt, res) self.assertFalse(port['port'][psec.PORTSECURITY]) - self.assertEqual(port['port'][addr_pair.ADDRESS_PAIRS], + self.assertEqual(port['port'][addr_apidef.ADDRESS_PAIRS], address_pairs) self._delete('ports', port['port']['id']) @@ -221,7 +221,7 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): fixed_ips = [{'subnet_id': subnet['subnet']['id'], 'ip_address': '10.0.0.2'}] res = self._create_port(self.fmt, network['network']['id'], - arg_list=(addr_pair.ADDRESS_PAIRS, + arg_list=(addr_apidef.ADDRESS_PAIRS, 'fixed_ips'), allowed_address_pairs=address_pairs, fixed_ips=fixed_ips) @@ -243,7 +243,7 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): def _create_port_with_address_pairs(self, address_pairs, ret_code): with self.network() as net: res = self._create_port(self.fmt, net['network']['id'], - arg_list=(addr_pair.ADDRESS_PAIRS,), + arg_list=(addr_apidef.ADDRESS_PAIRS,), allowed_address_pairs=address_pairs) port = self.deserialize(self.fmt, res) self.assertEqual(res.status_int, ret_code) @@ -257,7 +257,7 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): bad_values = [False, True, 1.1, 1, ['ip_address'], ['mac_address']] for value in bad_values: - update_port = {'port': {addr_pair.ADDRESS_PAIRS: value}} + update_port = {'port': {addr_apidef.ADDRESS_PAIRS: value}} req = self.new_update_request('ports', update_port, port['port']['id']) res = req.get_response(self.api) @@ -269,12 +269,12 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): port = self.deserialize(self.fmt, res) address_pairs = [{'mac_address': '00:00:00:00:00:01', 'ip_address': '10.0.0.1'}] - update_port = {'port': {addr_pair.ADDRESS_PAIRS: + update_port = {'port': {addr_apidef.ADDRESS_PAIRS: address_pairs}} req = self.new_update_request('ports', update_port, port['port']['id']) port = self.deserialize(self.fmt, req.get_response(self.api)) - self.assertEqual(port['port'][addr_pair.ADDRESS_PAIRS], + self.assertEqual(port['port'][addr_apidef.ADDRESS_PAIRS], address_pairs) self._delete('ports', port['port']['id']) @@ -284,7 +284,7 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): port = self.deserialize(self.fmt, res) address_pairs = {'mac_address': '00:00:00:00:00:01', 'ip_address': '10.0.0.1'} - update_port = {'port': {addr_pair.ADDRESS_PAIRS: + update_port = {'port': {addr_apidef.ADDRESS_PAIRS: address_pairs}} req = self.new_update_request('ports', update_port, port['port']['id']) @@ -296,10 +296,10 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): address_pairs = [{'ip_address': '23.23.23.23'}] res = self._create_port(self.fmt, net['network']['id'], arg_list=('port_security_enabled', - addr_pair.ADDRESS_PAIRS,), + addr_apidef.ADDRESS_PAIRS,), allowed_address_pairs=address_pairs) port = self.deserialize(self.fmt, res)['port'] - port_addr_mac = port[addr_pair.ADDRESS_PAIRS][0]['mac_address'] + port_addr_mac = port[addr_apidef.ADDRESS_PAIRS][0]['mac_address'] self.assertEqual(port_addr_mac, port['mac_address']) self._delete('ports', port['id']) @@ -314,7 +314,7 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): # The port should not have any security-groups associated to it with self.port(subnet=subnet, arg_list=(psec.PORTSECURITY, - addr_pair.ADDRESS_PAIRS, + addr_apidef.ADDRESS_PAIRS, secgroup.SECURITYGROUPS), port_security_enabled=True, allowed_address_pairs=address_pairs, @@ -334,7 +334,7 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): address_pairs = [{'ip_address': '10.0.0.1'}, {'mac_address': mac_address, 'ip_address': '10.0.0.1'}] - update_port = {'port': {addr_pair.ADDRESS_PAIRS: + update_port = {'port': {addr_apidef.ADDRESS_PAIRS: address_pairs}} req = self.new_update_request('ports', update_port, port['port']['id']) @@ -352,12 +352,12 @@ class TestAllowedAddressPairs(AllowedAddressPairDBTestCase): address_pairs = [{'mac_address': '00:00:00:00:00:01', 'ip_address': '10.0.0.1'}] res = self._create_port(self.fmt, net['network']['id'], - arg_list=(addr_pair.ADDRESS_PAIRS,), + arg_list=(addr_apidef.ADDRESS_PAIRS,), allowed_address_pairs=address_pairs) port = self.deserialize(self.fmt, res) - update_port = {'port': {addr_pair.ADDRESS_PAIRS: update_value}} + update_port = {'port': {addr_apidef.ADDRESS_PAIRS: update_value}} req = self.new_update_request('ports', update_port, port['port']['id']) port = self.deserialize(self.fmt, req.get_response(self.api)) - self.assertEqual([], port['port'][addr_pair.ADDRESS_PAIRS]) + self.assertEqual([], port['port'][addr_apidef.ADDRESS_PAIRS]) self._delete('ports', port['port']['id'])