Merge "Support names for {cleaning,provisioning}_network"

This commit is contained in:
Jenkins 2016-12-02 16:54:14 +00:00 committed by Gerrit Code Review
commit ff3a8f1d7f
15 changed files with 308 additions and 104 deletions

View File

@ -587,10 +587,7 @@ function configure_ironic_networks {
} }
function configure_ironic_cleaning_network { function configure_ironic_cleaning_network {
local cleaning_network_uuid iniset $IRONIC_CONF_FILE neutron cleaning_network $IRONIC_CLEAN_NET_NAME
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}
} }
function configure_ironic_provision_network { 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 sudo ip addr add dev $OVS_PHYSICAL_BRIDGE $ironic_provision_network_ip/$provision_net_prefix
fi 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 { 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 #. Define a provider network in neutron, which we shall refer to as the
"provisioning" network, and add it in under the neutron section in "provisioning" network, and add it in under the neutron section in
ironic-conductor configuration file. Using ``neutron`` network interface ironic-conductor configuration file. Using ``neutron`` network interface
requires that ``provisioning_network_uuid`` and ``cleaning_network_uuid`` requires that ``provisioning_network`` and ``cleaning_network``
configuration options are set to a valid neutron network UUIDs, otherwise configuration options are set to a valid neutron network UUIDs or names,
ironic-conductor will fail to start:: otherwise cleaning or provisioning will fail to start::
[neutron] [neutron]
... ...
cleaning_network_uuid=$CLEAN_UUID cleaning_network=$CLEAN_UUID_OR_NAME
provisioning_network_uuid=$PROVISION_UUID provisioning_network=$PROVISION_UUID_OR_NAME
Please refer to `Configure the Bare Metal service for cleaning`_ for more Please refer to `Configure the Bare Metal service for cleaning`_ for more
information about cleaning. information about cleaning.

View File

@ -1927,17 +1927,20 @@
# PEM encoded client certificate cert file (string value) # PEM encoded client certificate cert file (string value)
#certfile = <None> #certfile = <None>
# Neutron network UUID for the ramdisk to be booted into for # Neutron network UUID or name for the ramdisk to be booted
# cleaning nodes. Required for "neutron" network interface. It # into for cleaning nodes. Required for "neutron" network
# is also required if cleaning nodes when using "flat" network # interface. It is also required if cleaning nodes when using
# interface or "neutron" DHCP provider. (string value) # "flat" network interface or "neutron" DHCP provider. If a
#cleaning_network_uuid = <None> # 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 # List of Neutron Security Group UUIDs to be applied during
# cleaning of the nodes. Optional for the "neutron" network # cleaning of the nodes. Optional for the "neutron" network
# interface and not used for the "flat" or "noop" network # interface and not used for the "flat" or "noop" network
# interfaces. If not specified, default security # interfaces. If not specified, default security group is
# group is used. (list value) # used. (list value)
#cleaning_network_security_groups = #cleaning_network_security_groups =
# Optional domain ID to use with v3 and v2 parameters. It will # 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 # Neutron network UUID for the ramdisk to be booted into for
# provisioning nodes. Required for "neutron" network # provisioning nodes. Required for "neutron" network
# interface. (string value) # interface. If a name is provided, it must be unique among
#provisioning_network_uuid = <None> # 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 # List of Neutron Security Group UUIDs to be applied during
# provisioning of the nodes. Optional for the "neutron" # provisioning of the nodes. Optional for the "neutron"
# network interface and not used for the "flat" or "noop" # network interface and not used for the "flat" or "noop"
# network interfaces. If not specified, default # network interfaces. If not specified, default security group
# security group is used. (list value) # is used. (list value)
#provisioning_network_security_groups = #provisioning_network_security_groups =
# Client retries in the case of a failed request. (integer # 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`_ .. note:: If you configured the Bare Metal service to use `Node cleaning`_
(which is enabled by default), you will need to set the (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 .. _`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 $ 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 option in the Bare Metal service configuration file
(``/etc/ironic/ironic.conf``). In the following, replace ``NETWORK_UUID`` (``/etc/ironic/ironic.conf``). In the following, replace ``NETWORK_UUID``
with the UUID you noted in the previous step: with the UUID you noted in the previous step:
@ -24,7 +24,7 @@ Configure the Bare Metal service for cleaning
.. code-block:: ini .. code-block:: ini
[neutron] [neutron]
cleaning_network_uuid = NETWORK_UUID cleaning_network = NETWORK_UUID
#. Restart the Bare Metal service's ironic-conductor: #. Restart the Bare Metal service's ironic-conductor:

View File

@ -13,6 +13,7 @@
from neutronclient.common import exceptions as neutron_exceptions from neutronclient.common import exceptions as neutron_exceptions
from neutronclient.v2_0 import client as clientv20 from neutronclient.v2_0 import client as clientv20
from oslo_log import log from oslo_log import log
from oslo_utils import uuidutils
from ironic.common import exception from ironic.common import exception
from ironic.common.i18n import _, _LE, _LI, _LW 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 ' 'Failed to rollback port changes for node %(node)s '
'on network %(network)s'), {'node': task.node.uuid, 'on network %(network)s'), {'node': task.node.uuid,
'network': network_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 ' 'neutron. Running neutron in noauth mode (related to '
'but not affected by this setting) is insecure and ' 'but not affected by this setting) is insecure and '
'should only be used for testing.')), 'should only be used for testing.')),
cfg.StrOpt('cleaning_network_uuid', cfg.StrOpt('cleaning_network',
help=_('Neutron network UUID for the ramdisk to be booted ' help=_('Neutron network UUID or name for the ramdisk to be '
'into for cleaning nodes. Required for "neutron" ' 'booted into for cleaning nodes. Required for "neutron" '
'network interface. It is also required if cleaning ' 'network interface. It is also required if cleaning '
'nodes when using "flat" network interface or "neutron" ' 'nodes when using "flat" network interface or "neutron" '
'DHCP provider.')), 'DHCP provider. If a name is provided, it must be '
cfg.StrOpt('provisioning_network_uuid', '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 ' help=_('Neutron network UUID for the ramdisk to be booted '
'into for provisioning nodes. Required for "neutron" ' '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', cfg.ListOpt('provisioning_network_security_groups',
default=[], default=[],
help=_('List of Neutron Security Group UUIDs to be ' 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_config import cfg
from oslo_log import log 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.common import neutron
from ironic.drivers import base from ironic.drivers import base
@ -29,22 +27,32 @@ LOG = log.getLogger(__name__)
CONF = cfg.CONF CONF = cfg.CONF
class FlatNetwork(base.NetworkInterface): class FlatNetwork(neutron.NeutronNetworkInterfaceMixin, base.NetworkInterface):
"""Flat network interface.""" """Flat network interface."""
def __init__(self): def __init__(self):
cleaning_net = CONF.neutron.cleaning_network_uuid cleaning_net = CONF.neutron.cleaning_network
# TODO(vdrok): Switch to DriverLoadError in Ocata # TODO(vdrok): Switch to DriverLoadError in Ocata
if not uuidutils.is_uuid_like(cleaning_net): if not cleaning_net:
LOG.warning(_LW( LOG.warning(_LW(
'Please specify a valid UUID for ' 'Please specify a valid UUID or name for '
'[neutron]/cleaning_network_uuid configuration option so that ' '[neutron]/cleaning_network configuration option so that '
'this interface is able to perform cleaning. It will be ' 'this interface is able to perform cleaning. It will be '
'required starting with the Ocata release, and if not ' 'required starting with the Ocata release, and if not '
'specified then, the conductor service will fail to start if ' 'specified then, the conductor service will fail to start if '
'"flat" is in the list of values for ' '"flat" is in the list of values for '
'[DEFAULT]enabled_network_interfaces configuration option.')) '[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): def add_provisioning_network(self, task):
"""Add the provisioning network to a node. """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']} :returns: a dictionary in the form {port.uuid: neutron_port['id']}
:raises: NetworkError, InvalidParameterValue :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 # 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) LOG.info(_LI('Adding cleaning network to node %s'), task.node.uuid)
vifs = neutron.add_ports_to_network( 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: for port in task.ports:
if port.uuid in vifs: if port.uuid in vifs:
internal_info = port.internal_info internal_info = port.internal_info
@ -109,8 +113,8 @@ class FlatNetwork(base.NetworkInterface):
""" """
LOG.info(_LI('Removing ports from cleaning network for node %s'), LOG.info(_LI('Removing ports from cleaning network for node %s'),
task.node.uuid) task.node.uuid)
neutron.remove_ports_from_network( neutron.remove_ports_from_network(task,
task, CONF.neutron.cleaning_network_uuid) self.get_cleaning_network_uuid())
for port in task.ports: for port in task.ports:
if 'cleaning_vif_port_id' in port.internal_info: if 'cleaning_vif_port_id' in port.internal_info:
internal_info = port.internal_info internal_info = port.internal_info

View File

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

View File

@ -119,9 +119,9 @@ class TestCase(testtools.TestCase):
self.config(use_stderr=False, self.config(use_stderr=False,
fatal_exception_format_errors=True, fatal_exception_format_errors=True,
tempdir=tempfile.tempdir) tempdir=tempfile.tempdir)
self.config(cleaning_network_uuid=uuidutils.generate_uuid(), self.config(cleaning_network=uuidutils.generate_uuid(),
group='neutron') group='neutron')
self.config(provisioning_network_uuid=uuidutils.generate_uuid(), self.config(provisioning_network=uuidutils.generate_uuid(),
group='neutron') group='neutron')
self.config(enabled_drivers=['fake']) self.config(enabled_drivers=['fake'])
self.config(enabled_network_interfaces=['flat', 'noop', 'neutron'], 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: with task_manager.acquire(self.context, self.node.uuid) as task:
neutron.rollback_ports(task, self.network_uuid) neutron.rollback_ports(task, self.network_uuid)
self.assertTrue(log_mock.exception.called) 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, target_raid_config = {'logical_disks': [{'size_gb': 1,
'raid_level': '1'}]} 'raid_level': '1'}]}
node = obj_utils.create_test_node( 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, ret = self.service.validate_driver_interfaces(self.context,
node.uuid) node.uuid)
expected = {'console': {'result': True}, expected = {'console': {'result': True},
@ -2596,7 +2597,8 @@ class MiscTestCase(mgr_utils.ServiceSetUpMixin, mgr_utils.CommonMixIn,
@mock.patch.object(images, 'is_whole_disk_image') @mock.patch.object(images, 'is_whole_disk_image')
def test_validate_driver_interfaces_validation_fail(self, mock_iwdi): def test_validate_driver_interfaces_validation_fail(self, mock_iwdi):
mock_iwdi.return_value = False 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( with mock.patch(
'ironic.drivers.modules.fake.FakeDeploy.validate' 'ironic.drivers.modules.fake.FakeDeploy.validate'
) as deploy: ) as deploy:

View File

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

View File

@ -14,7 +14,6 @@ import mock
from oslo_config import cfg from oslo_config import cfg
from oslo_utils import uuidutils from oslo_utils import uuidutils
from ironic.common import exception
from ironic.common import neutron from ironic.common import neutron
from ironic.conductor import task_manager from ironic.conductor import task_manager
from ironic.drivers.modules.network import flat as flat_interface 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') @mock.patch.object(flat_interface, 'LOG')
def test_init_incorrect_cleaning_net(self, mock_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() flat_interface.FlatNetwork()
self.assertTrue(mock_log.warning.called) 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, 'add_ports_to_network')
@mock.patch.object(neutron, 'rollback_ports') @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'} add_mock.return_value = {self.port.uuid: 'vif-port-id'}
with task_manager.acquire(self.context, self.node.id) as task: with task_manager.acquire(self.context, self.node.id) as task:
self.interface.add_cleaning_network(task) self.interface.add_cleaning_network(task)
rollback_mock.assert_called_once_with( rollback_mock.assert_called_once_with(
task, CONF.neutron.cleaning_network_uuid) task, CONF.neutron.cleaning_network)
add_mock.assert_called_once_with( 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.port.refresh()
self.assertEqual('vif-port-id', self.assertEqual('vif-port-id',
self.port.internal_info['cleaning_vif_port_id']) self.port.internal_info['cleaning_vif_port_id'])
@mock.patch.object(neutron, 'add_ports_to_network') @mock.patch.object(neutron, 'validate_network',
@mock.patch.object(neutron, 'rollback_ports') side_effect=lambda n, t: n)
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, 'remove_ports_from_network') @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: with task_manager.acquire(self.context, self.node.id) as task:
self.interface.remove_cleaning_network(task) self.interface.remove_cleaning_network(task)
remove_mock.assert_called_once_with( 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.port.refresh()
self.assertNotIn('cleaning_vif_port_id', self.port.internal_info) 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'} 'mac_address': '52:54:00:cf:2d:32'}
def test_init_incorrect_provisioning_net(self): 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.assertRaises(exception.DriverLoadError, neutron.NeutronNetwork)
self.config(provisioning_network_uuid=uuidutils.generate_uuid(), self.config(provisioning_network=uuidutils.generate_uuid(),
group='neutron') group='neutron')
self.config(cleaning_network_uuid='asdf', group='neutron') self.config(cleaning_network=None, group='neutron')
self.assertRaises(exception.DriverLoadError, neutron.NeutronNetwork) 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, 'rollback_ports')
@mock.patch.object(neutron_common, 'add_ports_to_network') @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.internal_info = {'provisioning_vif_port_id': 'vif-port-id'}
self.port.save() self.port.save()
add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']} add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']}
with task_manager.acquire(self.context, self.node.id) as task: with task_manager.acquire(self.context, self.node.id) as task:
self.interface.add_provisioning_network(task) self.interface.add_provisioning_network(task)
rollback_mock.assert_called_once_with( rollback_mock.assert_called_once_with(
task, CONF.neutron.provisioning_network_uuid) task, CONF.neutron.provisioning_network)
add_ports_mock.assert_called_once_with( add_ports_mock.assert_called_once_with(
task, CONF.neutron.provisioning_network_uuid, task, CONF.neutron.provisioning_network,
security_groups=[]) security_groups=[])
validate_mock.assert_called_once_with(
CONF.neutron.provisioning_network,
'provisioning network')
self.port.refresh() self.port.refresh()
self.assertEqual(self.neutron_port['id'], self.assertEqual(self.neutron_port['id'],
self.port.internal_info['provisioning_vif_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, 'rollback_ports')
@mock.patch.object(neutron_common, 'add_ports_to_network') @mock.patch.object(neutron_common, 'add_ports_to_network')
def test_add_provisioning_network_with_sg(self, add_ports_mock, 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: with task_manager.acquire(self.context, self.node.id) as task:
self.interface.add_provisioning_network(task) self.interface.add_provisioning_network(task)
rollback_mock.assert_called_once_with( rollback_mock.assert_called_once_with(
task, CONF.neutron.provisioning_network_uuid) task, CONF.neutron.provisioning_network)
add_ports_mock.assert_called_once_with( add_ports_mock.assert_called_once_with(
task, CONF.neutron.provisioning_network_uuid, task, CONF.neutron.provisioning_network,
security_groups=( security_groups=(
CONF.neutron.provisioning_network_security_groups)) CONF.neutron.provisioning_network_security_groups))
self.port.refresh() self.port.refresh()
self.assertEqual(self.neutron_port['id'], self.assertEqual(self.neutron_port['id'],
self.port.internal_info['provisioning_vif_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') @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.internal_info = {'provisioning_vif_port_id': 'vif-port-id'}
self.port.save() self.port.save()
with task_manager.acquire(self.context, self.node.id) as task: with task_manager.acquire(self.context, self.node.id) as task:
self.interface.remove_provisioning_network(task) self.interface.remove_provisioning_network(task)
remove_ports_mock.assert_called_once_with( 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.port.refresh()
self.assertNotIn('provisioning_vif_port_id', self.port.internal_info) 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, 'rollback_ports')
@mock.patch.object(neutron_common, 'add_ports_to_network') @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']} add_ports_mock.return_value = {self.port.uuid: self.neutron_port['id']}
with task_manager.acquire(self.context, self.node.id) as task: with task_manager.acquire(self.context, self.node.id) as task:
res = self.interface.add_cleaning_network(task) res = self.interface.add_cleaning_network(task)
rollback_mock.assert_called_once_with( 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.assertEqual(res, add_ports_mock.return_value)
validate_mock.assert_called_once_with(
CONF.neutron.cleaning_network,
'cleaning network')
self.port.refresh() self.port.refresh()
self.assertEqual(self.neutron_port['id'], self.assertEqual(self.neutron_port['id'],
self.port.internal_info['cleaning_vif_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, 'rollback_ports')
@mock.patch.object(neutron_common, 'add_ports_to_network') @mock.patch.object(neutron_common, 'add_ports_to_network')
def test_add_cleaning_network_with_sg(self, add_ports_mock, rollback_mock): 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: with task_manager.acquire(self.context, self.node.id) as task:
res = self.interface.add_cleaning_network(task) res = self.interface.add_cleaning_network(task)
add_ports_mock.assert_called_once_with( 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) security_groups=CONF.neutron.cleaning_network_security_groups)
rollback_mock.assert_called_once_with( 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.assertEqual(res, add_ports_mock.return_value)
self.port.refresh() self.port.refresh()
self.assertEqual(self.neutron_port['id'], self.assertEqual(self.neutron_port['id'],
self.port.internal_info['cleaning_vif_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') @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.internal_info = {'cleaning_vif_port_id': 'vif-port-id'}
self.port.save() self.port.save()
with task_manager.acquire(self.context, self.node.id) as task: with task_manager.acquire(self.context, self.node.id) as task:
self.interface.remove_cleaning_network(task) self.interface.remove_cleaning_network(task)
remove_ports_mock.assert_called_once_with( 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.port.refresh()
self.assertNotIn('cleaning_vif_port_id', self.port.internal_info) 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".