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:
parent
257e5b78ab
commit
b6a2919b61
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 '
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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'],
|
||||
|
@ -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')
|
||||
|
@ -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:
|
||||
|
@ -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',
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
11
releasenotes/notes/net-names-b8a36aa30659ce2f.yaml
Normal file
11
releasenotes/notes/net-names-b8a36aa30659ce2f.yaml
Normal 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".
|
Loading…
Reference in New Issue
Block a user