Add support to regenerate port mac_address

- Adds converter to generate a valid mac address if the
  provided data is 'null' (None).
- Adds api extension definition for port using the new converter.

Related-Bug: #1768690
Change-Id: Ibfcf179c2051d2bf47d4d1e62e8146cbee29fd64
This commit is contained in:
Harald Jensås 2018-05-03 03:11:19 +02:00
parent 8664953c5a
commit 56033ba643
8 changed files with 120 additions and 7 deletions

View File

@ -96,6 +96,14 @@ define QoS policies and associate these to the ports by introducing the
``qos_policy_id`` attribute. The policies should be created before they are
associated to the ports.
Regenerate mac address extension
================================
The Port MAC address regenerate extension (``port-mac-address-regenerate``)
makes it possible to regenerate the mac address of a port. When passing
``'null'`` (``None``) as the ``mac_address`` on port update, a new mac address
will be generated and set on the port.
Resource timestamps
===================

View File

@ -11,6 +11,7 @@
# under the License.
import netaddr
from oslo_config import cfg
from oslo_utils import strutils
import six
@ -18,6 +19,7 @@ from neutron_lib._i18n import _
from neutron_lib.api import validators
from neutron_lib import constants
from neutron_lib import exceptions as n_exc
from neutron_lib.utils import net as net_utils
def convert_to_boolean(data):
@ -306,3 +308,15 @@ def convert_uppercase_ip(data):
the return value is data with the first two letter uppercased
"""
return convert_prefix_forced_case(data, "IP")
def convert_to_mac_if_none(data):
"""Convert to a random mac address if data is None
:param data: The data value
:return: Random mac address if data is None, else return data.
"""
if data is None:
return net_utils.get_random_mac(cfg.CONF.base_mac.split(':'))
return data

View File

@ -59,6 +59,7 @@ from neutron_lib.api.definitions import network_mtu
from neutron_lib.api.definitions import network_mtu_writable
from neutron_lib.api.definitions import pagination
from neutron_lib.api.definitions import port
from neutron_lib.api.definitions import port_mac_address_regenerate
from neutron_lib.api.definitions import port_security
from neutron_lib.api.definitions import portbindings
from neutron_lib.api.definitions import portbindings_extended
@ -141,6 +142,7 @@ _ALL_API_DEFINITIONS = {
network_mtu_writable,
pagination,
port,
port_mac_address_regenerate,
port_security,
portbindings,
portbindings_extended,

View File

@ -24,6 +24,8 @@ UPDATED_TIMESTAMP = "2012-01-01T10:00:00-00:00"
RESOURCE_NAME = 'port'
COLLECTION_NAME = 'ports'
PORT_MAC_ADDRESS = 'mac_address'
RESOURCE_ATTRIBUTE_MAP = {
COLLECTION_NAME: {
'id': {'allow_post': False, 'allow_put': False,
@ -50,13 +52,13 @@ RESOURCE_ATTRIBUTE_MAP = {
'is_filter': True,
'is_sort_key': True,
'is_visible': True},
'mac_address': {'allow_post': True, 'allow_put': True,
'default': constants.ATTR_NOT_SPECIFIED,
'validate': {'type:mac_address': None},
'enforce_policy': True,
'is_filter': True,
'is_sort_key': True,
'is_visible': True},
PORT_MAC_ADDRESS: {'allow_post': True, 'allow_put': True,
'default': constants.ATTR_NOT_SPECIFIED,
'validate': {'type:mac_address': None},
'enforce_policy': True,
'is_filter': True,
'is_sort_key': True,
'is_visible': True},
'fixed_ips': {'allow_post': True, 'allow_put': True,
'default': constants.ATTR_NOT_SPECIFIED,
'convert_list_to':

View File

@ -0,0 +1,42 @@
# 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_lib.api import converters
from neutron_lib.api.definitions import port as port_def
from neutron_lib import constants
NAME = 'Neutron Port MAC address regenerate'
ALIAS = 'port-mac-address-regenerate'
DESCRIPTION = "Network port MAC address regenerate"
UPDATED_TIMESTAMP = "2018-05-03T10:00:00-00:00"
RESOURCE_ATTRIBUTE_MAP = {
port_def.COLLECTION_NAME: {
port_def.PORT_MAC_ADDRESS: {
'allow_post': True, 'allow_put': True,
'default': constants.ATTR_NOT_SPECIFIED,
'convert_to': converters.convert_to_mac_if_none,
'validate': {'type:mac_address': None},
'enforce_policy': True,
'is_visible': True},
}
}
IS_SHIM_EXTENSION = False
IS_STANDARD_ATTR_EXTENSION = False
SUB_RESOURCE_ATTRIBUTE_MAP = {}
ACTION_MAP = {}
REQUIRED_EXTENSIONS = []
OPTIONAL_EXTENSIONS = []
ACTION_STATUS = {}

View File

@ -0,0 +1,20 @@
# 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_lib.api.definitions import port as port_def
from neutron_lib.api.definitions import port_mac_address_regenerate
from neutron_lib.tests.unit.api.definitions import base
class PortMacAddressRegenerateTestCase(base.DefinitionBaseTestCase):
extension_module = port_mac_address_regenerate
extension_attributes = (port_def.PORT_MAC_ADDRESS,)

View File

@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
import netaddr
import six
import testtools
@ -331,3 +333,17 @@ class TestConvertUppercasePrefix(base.BaseTestCase):
self.assertEqual('fo',
converters.convert_prefix_forced_case('fo',
'foo'))
class TestConvertPortMacAddress(base.BaseTestCase):
def test_mac_address_does_not_convert(self):
valid_mac = 'fa:16:3e:b6:78:1f'
self.assertEqual(valid_mac,
converters.convert_to_mac_if_none(valid_mac))
@mock.patch('oslo_config.cfg.CONF')
def test_convert_none_to_mac_address(self, CONF):
CONF.base_mac = 'fa:16:3e:00:00:00'
self.assertTrue(
netaddr.valid_mac(converters.convert_to_mac_if_none(None)))

View File

@ -0,0 +1,9 @@
---
features:
- |
Adds api extension ``port-mac-address-regenerate``. Also adds converter
``convert_to_mac_if_none`` used by api extenstion
``port-mac-address-regenerate``. When passing ``'null'`` (``None``) as the
``mac_address`` on port update the converter will generate a new mac
address that will be assigned to the port.
`RFE: #1768690 <https://bugs.launchpad.net/neutron/+bug/1768690>`_.