Support names for {cleaning,provisioning}_network

Names are easier to use for humans, so let's allow them.
The actual name -> UUID convertion happens during validation and its
result is cached for each interface instance.

This change will allow recreating a network without changing Ironic
configuration or setting a network name in advance (e.g. by an installer).

Note that when names are used, an administrator is responsible for ensuring
that no other networks have the same name (names are not unique in Neutron).

Change-Id: I9905bdc3f778310ba191b2bed6eb11bad11a2846
Closes-Bug: #1614938
This commit is contained in:
Dmitry Tantsur 2016-08-19 18:01:31 +02:00
parent 257e5b78ab
commit b6a2919b61
15 changed files with 308 additions and 104 deletions

View File

@ -587,10 +587,7 @@ function configure_ironic_networks {
}
function configure_ironic_cleaning_network {
local cleaning_network_uuid
cleaning_network_uuid=$(openstack network show "$IRONIC_CLEAN_NET_NAME" -c id -f value)
die_if_not_set $LINENO cleaning_network_uuid "Failed to get ironic cleaning network id"
iniset $IRONIC_CONF_FILE neutron cleaning_network_uuid ${cleaning_network_uuid}
iniset $IRONIC_CONF_FILE neutron cleaning_network $IRONIC_CLEAN_NET_NAME
}
function configure_ironic_provision_network {
@ -639,7 +636,7 @@ function configure_ironic_provision_network {
sudo ip addr add dev $OVS_PHYSICAL_BRIDGE $ironic_provision_network_ip/$provision_net_prefix
fi
iniset $IRONIC_CONF_FILE neutron provisioning_network_uuid $net_id
iniset $IRONIC_CONF_FILE neutron provisioning_network $IRONIC_PROVISION_NETWORK_NAME
}
function cleanup_ironic_provision_network {

View File

@ -74,14 +74,14 @@ interface as stated above):
#. Define a provider network in neutron, which we shall refer to as the
"provisioning" network, and add it in under the neutron section in
ironic-conductor configuration file. Using ``neutron`` network interface
requires that ``provisioning_network_uuid`` and ``cleaning_network_uuid``
configuration options are set to a valid neutron network UUIDs, otherwise
ironic-conductor will fail to start::
requires that ``provisioning_network`` and ``cleaning_network``
configuration options are set to a valid neutron network UUIDs or names,
otherwise cleaning or provisioning will fail to start::
[neutron]
...
cleaning_network_uuid=$CLEAN_UUID
provisioning_network_uuid=$PROVISION_UUID
cleaning_network=$CLEAN_UUID_OR_NAME
provisioning_network=$PROVISION_UUID_OR_NAME
Please refer to `Configure the Bare Metal service for cleaning`_ for more
information about cleaning.

View File

@ -1927,17 +1927,20 @@
# PEM encoded client certificate cert file (string value)
#certfile = <None>
# Neutron network UUID for the ramdisk to be booted into for
# cleaning nodes. Required for "neutron" network interface. It
# is also required if cleaning nodes when using "flat" network
# interface or "neutron" DHCP provider. (string value)
#cleaning_network_uuid = <None>
# Neutron network UUID or name for the ramdisk to be booted
# into for cleaning nodes. Required for "neutron" network
# interface. It is also required if cleaning nodes when using
# "flat" network interface or "neutron" DHCP provider. If a
# name is provided, it must be unique among all networks or
# cleaning will fail. (string value)
# Deprecated group/name - [neutron]/cleaning_network_uuid
#cleaning_network = <None>
# List of Neutron Security Group UUIDs to be applied during
# cleaning of the nodes. Optional for the "neutron" network
# interface and not used for the "flat" or "noop" network
# interfaces. If not specified, default security
# group is used. (list value)
# interfaces. If not specified, default security group is
# used. (list value)
#cleaning_network_security_groups =
# Optional domain ID to use with v3 and v2 parameters. It will
@ -1986,14 +1989,16 @@
# Neutron network UUID for the ramdisk to be booted into for
# provisioning nodes. Required for "neutron" network
# interface. (string value)
#provisioning_network_uuid = <None>
# interface. If a name is provided, it must be unique among
# all networks or deploy will fail. (string value)
# Deprecated group/name - [neutron]/provisioning_network_uuid
#provisioning_network = <None>
# List of Neutron Security Group UUIDs to be applied during
# provisioning of the nodes. Optional for the "neutron"
# network interface and not used for the "flat" or "noop"
# network interfaces. If not specified, default
# security group is used. (list value)
# network interfaces. If not specified, default security group
# is used. (list value)
#provisioning_network_security_groups =
# Client retries in the case of a failed request. (integer

View File

@ -5,7 +5,7 @@ Configure the Bare Metal service for cleaning
.. note:: If you configured the Bare Metal service to use `Node cleaning`_
(which is enabled by default), you will need to set the
``cleaning_network_uuid`` configuration option.
``cleaning_network`` configuration option.
.. _`Node cleaning`: http://docs.openstack.org/developer/ironic/deploy/cleaning.html#node-cleaning
@ -16,7 +16,7 @@ Configure the Bare Metal service for cleaning
$ neutron net-list
#. Configure the cleaning network UUID via the ``cleaning_network_uuid``
#. Configure the cleaning network UUID via the ``cleaning_network``
option in the Bare Metal service configuration file
(``/etc/ironic/ironic.conf``). In the following, replace ``NETWORK_UUID``
with the UUID you noted in the previous step:
@ -24,7 +24,7 @@ Configure the Bare Metal service for cleaning
.. code-block:: ini
[neutron]
cleaning_network_uuid = NETWORK_UUID
cleaning_network = NETWORK_UUID
#. Restart the Bare Metal service's ironic-conductor:

View File

@ -13,6 +13,7 @@
from neutronclient.common import exceptions as neutron_exceptions
from neutronclient.v2_0 import client as clientv20
from oslo_log import log
from oslo_utils import uuidutils
from ironic.common import exception
from ironic.common.i18n import _, _LE, _LI, _LW
@ -286,3 +287,65 @@ def rollback_ports(task, network_uuid):
'Failed to rollback port changes for node %(node)s '
'on network %(network)s'), {'node': task.node.uuid,
'network': network_uuid})
def validate_network(uuid_or_name, net_type=_('network')):
"""Check that the given network is present.
:param uuid_or_name: network UUID or name
:param net_type: human-readable network type for error messages
:return: network UUID
:raises: MissingParameterValue if uuid_or_name is empty
:raises: NetworkError on failure to contact Neutron
:raises: InvalidParameterValue for missing or duplicated network
"""
if not uuid_or_name:
raise exception.MissingParameterValue(
_('UUID or name of %s is not set in configuration') % net_type)
if uuidutils.is_uuid_like(uuid_or_name):
filters = {'id': uuid_or_name}
else:
filters = {'name': uuid_or_name}
try:
client = get_client()
networks = client.list_networks(fields=['id'], **filters)
except neutron_exceptions.NeutronClientException as exc:
raise exception.NetworkError(_('Could not retrieve network list: %s') %
exc)
LOG.debug('Got list of networks matching %(cond)s: %(result)s',
{'cond': filters, 'result': networks})
networks = [n['id'] for n in networks.get('networks', [])]
if not networks:
raise exception.InvalidParameterValue(
_('%(type)s with name or UUID %(uuid_or_name)s was not found') %
{'type': net_type, 'uuid_or_name': uuid_or_name})
elif len(networks) > 1:
raise exception.InvalidParameterValue(
_('More than one %(type)s was found for name %(name)s: %(nets)s') %
{'name': uuid_or_name, 'nets': ', '.join(networks),
'type': net_type})
return networks[0]
class NeutronNetworkInterfaceMixin(object):
_cleaning_network_uuid = None
_provisioning_network_uuid = None
def get_cleaning_network_uuid(self):
if self._cleaning_network_uuid is None:
self._cleaning_network_uuid = validate_network(
CONF.neutron.cleaning_network,
_('cleaning network'))
return self._cleaning_network_uuid
def get_provisioning_network_uuid(self):
if self._provisioning_network_uuid is None:
self._provisioning_network_uuid = validate_network(
CONF.neutron.provisioning_network,
_('provisioning network'))
return self._provisioning_network_uuid

View File

@ -44,16 +44,20 @@ opts = [
'neutron. Running neutron in noauth mode (related to '
'but not affected by this setting) is insecure and '
'should only be used for testing.')),
cfg.StrOpt('cleaning_network_uuid',
help=_('Neutron network UUID for the ramdisk to be booted '
'into for cleaning nodes. Required for "neutron" '
cfg.StrOpt('cleaning_network',
help=_('Neutron network UUID or name for the ramdisk to be '
'booted into for cleaning nodes. Required for "neutron" '
'network interface. It is also required if cleaning '
'nodes when using "flat" network interface or "neutron" '
'DHCP provider.')),
cfg.StrOpt('provisioning_network_uuid',
'DHCP provider. If a name is provided, it must be '
'unique among all networks or cleaning will fail.'),
deprecated_name='cleaning_network_uuid'),
cfg.StrOpt('provisioning_network',
help=_('Neutron network UUID for the ramdisk to be booted '
'into for provisioning nodes. Required for "neutron" '
'network interface.')),
'network interface. If a name is provided, it must be '
'unique among all networks or deploy will fail.'),
deprecated_name='provisioning_network_uuid'),
cfg.ListOpt('provisioning_network_security_groups',
default=[],
help=_('List of Neutron Security Group UUIDs to be '

View File

@ -16,10 +16,8 @@ Flat network interface. Useful for shared, flat networks.
from oslo_config import cfg
from oslo_log import log
from oslo_utils import uuidutils
from ironic.common import exception
from ironic.common.i18n import _, _LI, _LW
from ironic.common.i18n import _LI, _LW
from ironic.common import neutron
from ironic.drivers import base
@ -29,22 +27,32 @@ LOG = log.getLogger(__name__)
CONF = cfg.CONF
class FlatNetwork(base.NetworkInterface):
class FlatNetwork(neutron.NeutronNetworkInterfaceMixin, base.NetworkInterface):
"""Flat network interface."""
def __init__(self):
cleaning_net = CONF.neutron.cleaning_network_uuid
cleaning_net = CONF.neutron.cleaning_network
# TODO(vdrok): Switch to DriverLoadError in Ocata
if not uuidutils.is_uuid_like(cleaning_net):
if not cleaning_net:
LOG.warning(_LW(
'Please specify a valid UUID for '
'[neutron]/cleaning_network_uuid configuration option so that '
'Please specify a valid UUID or name for '
'[neutron]/cleaning_network configuration option so that '
'this interface is able to perform cleaning. It will be '
'required starting with the Ocata release, and if not '
'specified then, the conductor service will fail to start if '
'"flat" is in the list of values for '
'[DEFAULT]enabled_network_interfaces configuration option.'))
def validate(self, task):
"""Validates the network interface.
:param task: a TaskManager instance.
:raises: InvalidParameterValue, if the network interface configuration
is invalid.
:raises: MissingParameterValue, if some parameters are missing.
"""
self.get_cleaning_network_uuid()
def add_provisioning_network(self, task):
"""Add the provisioning network to a node.
@ -84,15 +92,11 @@ class FlatNetwork(base.NetworkInterface):
:returns: a dictionary in the form {port.uuid: neutron_port['id']}
:raises: NetworkError, InvalidParameterValue
"""
if not uuidutils.is_uuid_like(CONF.neutron.cleaning_network_uuid):
raise exception.InvalidParameterValue(_(
'You must provide a valid cleaning network UUID in '
'[neutron]cleaning_network_uuid configuration option.'))
# If we have left over ports from a previous cleaning, remove them
neutron.rollback_ports(task, CONF.neutron.cleaning_network_uuid)
neutron.rollback_ports(task, self.get_cleaning_network_uuid())
LOG.info(_LI('Adding cleaning network to node %s'), task.node.uuid)
vifs = neutron.add_ports_to_network(
task, CONF.neutron.cleaning_network_uuid, is_flat=True)
task, self.get_cleaning_network_uuid(), is_flat=True)
for port in task.ports:
if port.uuid in vifs:
internal_info = port.internal_info
@ -109,8 +113,8 @@ class FlatNetwork(base.NetworkInterface):
"""
LOG.info(_LI('Removing ports from cleaning network for node %s'),
task.node.uuid)
neutron.remove_ports_from_network(
task, CONF.neutron.cleaning_network_uuid)
neutron.remove_ports_from_network(task,
self.get_cleaning_network_uuid())
for port in task.ports:
if 'cleaning_vif_port_id' in port.internal_info:
internal_info = port.internal_info

View File

@ -17,7 +17,6 @@
from neutronclient.common import exceptions as neutron_exceptions
from oslo_config import cfg
from oslo_log import log
from oslo_utils import uuidutils
from ironic.common import exception
from ironic.common.i18n import _, _LI
@ -30,25 +29,36 @@ LOG = log.getLogger(__name__)
CONF = cfg.CONF
class NeutronNetwork(base.NetworkInterface):
class NeutronNetwork(neutron.NeutronNetworkInterfaceMixin,
base.NetworkInterface):
"""Neutron v2 network interface"""
def __init__(self):
failures = []
cleaning_net = CONF.neutron.cleaning_network_uuid
if not uuidutils.is_uuid_like(cleaning_net):
failures.append('cleaning_network_uuid=%s' % cleaning_net)
cleaning_net = CONF.neutron.cleaning_network
if not cleaning_net:
failures.append('cleaning_network')
provisioning_net = CONF.neutron.provisioning_network_uuid
if not uuidutils.is_uuid_like(provisioning_net):
failures.append('provisioning_network_uuid=%s' % provisioning_net)
provisioning_net = CONF.neutron.provisioning_network
if not provisioning_net:
failures.append('provisioning_network')
if failures:
raise exception.DriverLoadError(
driver=self.__class__.__name__,
reason=(_('The following [neutron] group configuration '
'options are incorrect, they must be valid UUIDs: '
'%s') % ', '.join(failures)))
'options are missing: %s') % ', '.join(failures)))
def validate(self, task):
"""Validates the network interface.
:param task: a TaskManager instance.
:raises: InvalidParameterValue, if the network interface configuration
is invalid.
:raises: MissingParameterValue, if some parameters are missing.
"""
self.get_cleaning_network_uuid()
self.get_provisioning_network_uuid()
def add_provisioning_network(self, task):
"""Add the provisioning network to a node.
@ -58,11 +68,11 @@ class NeutronNetwork(base.NetworkInterface):
"""
# If we have left over ports from a previous provision attempt, remove
# them
neutron.rollback_ports(task, CONF.neutron.provisioning_network_uuid)
neutron.rollback_ports(task, self.get_provisioning_network_uuid())
LOG.info(_LI('Adding provisioning network to node %s'),
task.node.uuid)
vifs = neutron.add_ports_to_network(
task, CONF.neutron.provisioning_network_uuid,
task, self.get_provisioning_network_uuid(),
security_groups=CONF.neutron.provisioning_network_security_groups)
for port in task.ports:
if port.uuid in vifs:
@ -80,7 +90,7 @@ class NeutronNetwork(base.NetworkInterface):
LOG.info(_LI('Removing provisioning network from node %s'),
task.node.uuid)
neutron.remove_ports_from_network(
task, CONF.neutron.provisioning_network_uuid)
task, self.get_provisioning_network_uuid())
for port in task.ports:
if 'provisioning_vif_port_id' in port.internal_info:
internal_info = port.internal_info
@ -96,11 +106,11 @@ class NeutronNetwork(base.NetworkInterface):
:returns: a dictionary in the form {port.uuid: neutron_port['id']}
"""
# If we have left over ports from a previous cleaning, remove them
neutron.rollback_ports(task, CONF.neutron.cleaning_network_uuid)
neutron.rollback_ports(task, self.get_cleaning_network_uuid())
LOG.info(_LI('Adding cleaning network to node %s'), task.node.uuid)
security_groups = CONF.neutron.cleaning_network_security_groups
vifs = neutron.add_ports_to_network(task,
CONF.neutron.cleaning_network_uuid,
self.get_cleaning_network_uuid(),
security_groups=security_groups)
for port in task.ports:
if port.uuid in vifs:
@ -118,8 +128,8 @@ class NeutronNetwork(base.NetworkInterface):
"""
LOG.info(_LI('Removing cleaning network from node %s'),
task.node.uuid)
neutron.remove_ports_from_network(
task, CONF.neutron.cleaning_network_uuid)
neutron.remove_ports_from_network(task,
self.get_cleaning_network_uuid())
for port in task.ports:
if 'cleaning_vif_port_id' in port.internal_info:
internal_info = port.internal_info

View File

@ -119,9 +119,9 @@ class TestCase(testtools.TestCase):
self.config(use_stderr=False,
fatal_exception_format_errors=True,
tempdir=tempfile.tempdir)
self.config(cleaning_network_uuid=uuidutils.generate_uuid(),
self.config(cleaning_network=uuidutils.generate_uuid(),
group='neutron')
self.config(provisioning_network_uuid=uuidutils.generate_uuid(),
self.config(provisioning_network=uuidutils.generate_uuid(),
group='neutron')
self.config(enabled_drivers=['fake'])
self.config(enabled_network_interfaces=['flat', 'noop', 'neutron'],

View File

@ -447,3 +447,69 @@ class TestNeutronNetworkActions(db_base.DbTestCase):
with task_manager.acquire(self.context, self.node.uuid) as task:
neutron.rollback_ports(task, self.network_uuid)
self.assertTrue(log_mock.exception.called)
@mock.patch.object(neutron, 'get_client', autospec=True)
class TestValidateNetwork(base.TestCase):
def setUp(self):
super(TestValidateNetwork, self).setUp()
self.uuid = uuidutils.generate_uuid()
def test_by_uuid(self, client_mock):
net_mock = client_mock.return_value.list_networks
net_mock.return_value = {
'networks': [
{'id': self.uuid},
]
}
self.assertEqual(self.uuid, neutron.validate_network(self.uuid))
net_mock.assert_called_once_with(fields=['id'],
id=self.uuid)
def test_by_name(self, client_mock):
net_mock = client_mock.return_value.list_networks
net_mock.return_value = {
'networks': [
{'id': self.uuid},
]
}
self.assertEqual(self.uuid, neutron.validate_network('name'))
net_mock.assert_called_once_with(fields=['id'],
name='name')
def test_not_found(self, client_mock):
net_mock = client_mock.return_value.list_networks
net_mock.return_value = {
'networks': []
}
self.assertRaisesRegex(exception.InvalidParameterValue,
'was not found',
neutron.validate_network, self.uuid)
net_mock.assert_called_once_with(fields=['id'],
id=self.uuid)
def test_failure(self, client_mock):
net_mock = client_mock.return_value.list_networks
net_mock.side_effect = neutron_client_exc.NeutronClientException('foo')
self.assertRaisesRegex(exception.NetworkError, 'foo',
neutron.validate_network, 'name')
net_mock.assert_called_once_with(fields=['id'],
name='name')
def test_duplicate(self, client_mock):
net_mock = client_mock.return_value.list_networks
net_mock.return_value = {
'networks': [{'id': self.uuid},
{'id': 'uuid2'}]
}
self.assertRaisesRegex(exception.InvalidParameterValue,
'More than one network',
neutron.validate_network, 'name')
net_mock.assert_called_once_with(fields=['id'],
name='name')

View File

@ -2579,7 +2579,8 @@ class MiscTestCase(mgr_utils.ServiceSetUpMixin, mgr_utils.CommonMixIn,
target_raid_config = {'logical_disks': [{'size_gb': 1,
'raid_level': '1'}]}
node = obj_utils.create_test_node(
self.context, driver='fake', target_raid_config=target_raid_config)
self.context, driver='fake', target_raid_config=target_raid_config,
network_interface='noop')
ret = self.service.validate_driver_interfaces(self.context,
node.uuid)
expected = {'console': {'result': True},
@ -2596,7 +2597,8 @@ class MiscTestCase(mgr_utils.ServiceSetUpMixin, mgr_utils.CommonMixIn,
@mock.patch.object(images, 'is_whole_disk_image')
def test_validate_driver_interfaces_validation_fail(self, mock_iwdi):
mock_iwdi.return_value = False
node = obj_utils.create_test_node(self.context, driver='fake')
node = obj_utils.create_test_node(self.context, driver='fake',
network_interface='noop')
with mock.patch(
'ironic.drivers.modules.fake.FakeDeploy.validate'
) as deploy:

View File

@ -37,7 +37,7 @@ class TestNeutron(db_base.DbTestCase):
super(TestNeutron, self).setUp()
mgr_utils.mock_the_extension_manager(driver='fake')
self.config(
cleaning_network_uuid='00000000-0000-0000-0000-000000000000',
cleaning_network='00000000-0000-0000-0000-000000000000',
group='neutron')
self.config(enabled_drivers=['fake'])
self.config(dhcp_provider='neutron',

View File

@ -14,7 +14,6 @@ import mock
from oslo_config import cfg
from oslo_utils import uuidutils
from ironic.common import exception
from ironic.common import neutron
from ironic.conductor import task_manager
from ironic.drivers.modules.network import flat as flat_interface
@ -40,43 +39,48 @@ class TestFlatInterface(db_base.DbTestCase):
@mock.patch.object(flat_interface, 'LOG')
def test_init_incorrect_cleaning_net(self, mock_log):
self.config(cleaning_network_uuid=None, group='neutron')
self.config(cleaning_network=None, group='neutron')
flat_interface.FlatNetwork()
self.assertTrue(mock_log.warning.called)
@mock.patch.object(neutron, 'validate_network', autospec=True)
def test_validate(self, validate_mock):
with task_manager.acquire(self.context, self.node.id) as task:
self.interface.validate(task)
validate_mock.assert_called_once_with(CONF.neutron.cleaning_network,
'cleaning network')
@mock.patch.object(neutron, 'validate_network',
side_effect=lambda n, t: n)
@mock.patch.object(neutron, 'add_ports_to_network')
@mock.patch.object(neutron, 'rollback_ports')
def test_add_cleaning_network(self, rollback_mock, add_mock):
def test_add_cleaning_network(self, rollback_mock, add_mock,
validate_mock):
add_mock.return_value = {self.port.uuid: 'vif-port-id'}
with task_manager.acquire(self.context, self.node.id) as task:
self.interface.add_cleaning_network(task)
rollback_mock.assert_called_once_with(
task, CONF.neutron.cleaning_network_uuid)
task, CONF.neutron.cleaning_network)
add_mock.assert_called_once_with(
task, CONF.neutron.cleaning_network_uuid, is_flat=True)
task, CONF.neutron.cleaning_network, is_flat=True)
validate_mock.assert_called_once_with(
CONF.neutron.cleaning_network,
'cleaning network')
self.port.refresh()
self.assertEqual('vif-port-id',
self.port.internal_info['cleaning_vif_port_id'])
@mock.patch.object(neutron, 'add_ports_to_network')
@mock.patch.object(neutron, 'rollback_ports')
def test_add_cleaning_network_no_cleaning_net_uuid(self, rollback_mock,
add_mock):
with task_manager.acquire(self.context, self.node.id) as task:
# This has to go after acquire, or acquire will raise
# DriverLoadError.
self.config(cleaning_network_uuid='abc', group='neutron')
self.assertRaises(exception.InvalidParameterValue,
self.interface.add_cleaning_network, task)
self.assertFalse(rollback_mock.called)
self.assertFalse(add_mock.called)
@mock.patch.object(neutron, 'validate_network',
side_effect=lambda n, t: n)
@mock.patch.object(neutron, 'remove_ports_from_network')
def test_remove_cleaning_network(self, remove_mock):
def test_remove_cleaning_network(self, remove_mock, validate_mock):
with task_manager.acquire(self.context, self.node.id) as task:
self.interface.remove_cleaning_network(task)
remove_mock.assert_called_once_with(
task, CONF.neutron.cleaning_network_uuid)
task, CONF.neutron.cleaning_network)
validate_mock.assert_called_once_with(
CONF.neutron.cleaning_network,
'cleaning network')
self.port.refresh()
self.assertNotIn('cleaning_vif_port_id', self.port.internal_info)

View File

@ -47,30 +47,48 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
'mac_address': '52:54:00:cf:2d:32'}
def test_init_incorrect_provisioning_net(self):
self.config(provisioning_network_uuid=None, group='neutron')
self.config(provisioning_network=None, group='neutron')
self.assertRaises(exception.DriverLoadError, neutron.NeutronNetwork)
self.config(provisioning_network_uuid=uuidutils.generate_uuid(),
self.config(provisioning_network=uuidutils.generate_uuid(),
group='neutron')
self.config(cleaning_network_uuid='asdf', group='neutron')
self.config(cleaning_network=None, group='neutron')
self.assertRaises(exception.DriverLoadError, neutron.NeutronNetwork)
@mock.patch.object(neutron_common, 'validate_network', autospec=True)
def test_validate(self, validate_mock):
with task_manager.acquire(self.context, self.node.id) as task:
self.interface.validate(task)
self.assertEqual([mock.call(CONF.neutron.cleaning_network,
'cleaning network'),
mock.call(CONF.neutron.provisioning_network,
'provisioning network')],
validate_mock.call_args_list)
@mock.patch.object(neutron_common, 'validate_network',
side_effect=lambda n, t: n)
@mock.patch.object(neutron_common, 'rollback_ports')
@mock.patch.object(neutron_common, 'add_ports_to_network')
def test_add_provisioning_network(self, add_ports_mock, rollback_mock):
def test_add_provisioning_network(self, add_ports_mock, rollback_mock,
validate_mock):
self.port.internal_info = {'provisioning_vif_port_id': 'vif-port-id'}
self.port.save()
add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']}
with task_manager.acquire(self.context, self.node.id) as task:
self.interface.add_provisioning_network(task)
rollback_mock.assert_called_once_with(
task, CONF.neutron.provisioning_network_uuid)
task, CONF.neutron.provisioning_network)
add_ports_mock.assert_called_once_with(
task, CONF.neutron.provisioning_network_uuid,
task, CONF.neutron.provisioning_network,
security_groups=[])
validate_mock.assert_called_once_with(
CONF.neutron.provisioning_network,
'provisioning network')
self.port.refresh()
self.assertEqual(self.neutron_port['id'],
self.port.internal_info['provisioning_vif_port_id'])
@mock.patch.object(neutron_common, 'validate_network',
lambda n, t: n)
@mock.patch.object(neutron_common, 'rollback_ports')
@mock.patch.object(neutron_common, 'add_ports_to_network')
def test_add_provisioning_network_with_sg(self, add_ports_mock,
@ -85,39 +103,53 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
with task_manager.acquire(self.context, self.node.id) as task:
self.interface.add_provisioning_network(task)
rollback_mock.assert_called_once_with(
task, CONF.neutron.provisioning_network_uuid)
task, CONF.neutron.provisioning_network)
add_ports_mock.assert_called_once_with(
task, CONF.neutron.provisioning_network_uuid,
task, CONF.neutron.provisioning_network,
security_groups=(
CONF.neutron.provisioning_network_security_groups))
self.port.refresh()
self.assertEqual(self.neutron_port['id'],
self.port.internal_info['provisioning_vif_port_id'])
@mock.patch.object(neutron_common, 'validate_network',
side_effect=lambda n, t: n)
@mock.patch.object(neutron_common, 'remove_ports_from_network')
def test_remove_provisioning_network(self, remove_ports_mock):
def test_remove_provisioning_network(self, remove_ports_mock,
validate_mock):
self.port.internal_info = {'provisioning_vif_port_id': 'vif-port-id'}
self.port.save()
with task_manager.acquire(self.context, self.node.id) as task:
self.interface.remove_provisioning_network(task)
remove_ports_mock.assert_called_once_with(
task, CONF.neutron.provisioning_network_uuid)
task, CONF.neutron.provisioning_network)
validate_mock.assert_called_once_with(
CONF.neutron.provisioning_network,
'provisioning network')
self.port.refresh()
self.assertNotIn('provisioning_vif_port_id', self.port.internal_info)
@mock.patch.object(neutron_common, 'validate_network',
side_effect=lambda n, t: n)
@mock.patch.object(neutron_common, 'rollback_ports')
@mock.patch.object(neutron_common, 'add_ports_to_network')
def test_add_cleaning_network(self, add_ports_mock, rollback_mock):
def test_add_cleaning_network(self, add_ports_mock, rollback_mock,
validate_mock):
add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']}
with task_manager.acquire(self.context, self.node.id) as task:
res = self.interface.add_cleaning_network(task)
rollback_mock.assert_called_once_with(
task, CONF.neutron.cleaning_network_uuid)
task, CONF.neutron.cleaning_network)
self.assertEqual(res, add_ports_mock.return_value)
validate_mock.assert_called_once_with(
CONF.neutron.cleaning_network,
'cleaning network')
self.port.refresh()
self.assertEqual(self.neutron_port['id'],
self.port.internal_info['cleaning_vif_port_id'])
@mock.patch.object(neutron_common, 'validate_network',
lambda n, t: n)
@mock.patch.object(neutron_common, 'rollback_ports')
@mock.patch.object(neutron_common, 'add_ports_to_network')
def test_add_cleaning_network_with_sg(self, add_ports_mock, rollback_mock):
@ -129,23 +161,29 @@ class NeutronInterfaceTestCase(db_base.DbTestCase):
with task_manager.acquire(self.context, self.node.id) as task:
res = self.interface.add_cleaning_network(task)
add_ports_mock.assert_called_once_with(
task, CONF.neutron.cleaning_network_uuid,
task, CONF.neutron.cleaning_network,
security_groups=CONF.neutron.cleaning_network_security_groups)
rollback_mock.assert_called_once_with(
task, CONF.neutron.cleaning_network_uuid)
task, CONF.neutron.cleaning_network)
self.assertEqual(res, add_ports_mock.return_value)
self.port.refresh()
self.assertEqual(self.neutron_port['id'],
self.port.internal_info['cleaning_vif_port_id'])
@mock.patch.object(neutron_common, 'validate_network',
side_effect=lambda n, t: n)
@mock.patch.object(neutron_common, 'remove_ports_from_network')
def test_remove_cleaning_network(self, remove_ports_mock):
def test_remove_cleaning_network(self, remove_ports_mock,
validate_mock):
self.port.internal_info = {'cleaning_vif_port_id': 'vif-port-id'}
self.port.save()
with task_manager.acquire(self.context, self.node.id) as task:
self.interface.remove_cleaning_network(task)
remove_ports_mock.assert_called_once_with(
task, CONF.neutron.cleaning_network_uuid)
task, CONF.neutron.cleaning_network)
validate_mock.assert_called_once_with(
CONF.neutron.cleaning_network,
'cleaning network')
self.port.refresh()
self.assertNotIn('cleaning_vif_port_id', self.port.internal_info)

View File

@ -0,0 +1,11 @@
---
features:
- Names can now be used instead of UUIDs for "cleaning_network" and
"provisioning_network" options (former "cleaning_network_uuid" and
"provisioning_network_uuid"). Care has to be taken to ensure that the
names are unique among all networks in this case. Note that mapping between
a name and a UUID is cached for the lifetime of the conductor.
deprecations:
- Configuration options "[neutron]cleaning_network_uuid" and
"[neutron]provisioning_network_uuid" were deprecated in favor of new
"[neutron]cleaning_network" and "[neutron]provisioning_network".