Merge "Option to send all portgroup data"
This commit is contained in:
commit
cc6e61f1dd
@ -10,6 +10,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
|
||||
from neutronclient.common import exceptions as neutron_exceptions
|
||||
from neutronclient.v2_0 import client as clientv20
|
||||
from oslo_log import log
|
||||
@ -203,6 +205,7 @@ def add_ports_to_network(task, network_uuid, security_groups=None):
|
||||
"""
|
||||
client = get_client(context=task.context)
|
||||
node = task.node
|
||||
add_all_ports = CONF.neutron.add_all_ports
|
||||
|
||||
# If Security Groups are specified, verify that they exist
|
||||
_verify_security_groups(security_groups, client)
|
||||
@ -211,6 +214,7 @@ def add_ports_to_network(task, network_uuid, security_groups=None):
|
||||
'%(network_uuid)s using %(net_iface)s network interface.',
|
||||
{'net_iface': task.driver.network.__class__.__name__,
|
||||
'node': node.uuid, 'network_uuid': network_uuid})
|
||||
|
||||
body = {
|
||||
'port': {
|
||||
'network_id': network_uuid,
|
||||
@ -231,21 +235,33 @@ def add_ports_to_network(task, network_uuid, security_groups=None):
|
||||
ports = {}
|
||||
failures = []
|
||||
portmap = get_node_portmap(task)
|
||||
pxe_enabled_ports = [p for p in task.ports if p.pxe_enabled]
|
||||
|
||||
if not add_all_ports:
|
||||
pxe_enabled_ports = [p for p in task.ports if p.pxe_enabled]
|
||||
else:
|
||||
pxe_enabled_ports = task.ports
|
||||
if not pxe_enabled_ports:
|
||||
raise exception.NetworkError(_(
|
||||
"No available PXE-enabled port on node %s.") % node.uuid)
|
||||
|
||||
for ironic_port in pxe_enabled_ports:
|
||||
# Start with a clean state for each port
|
||||
port_body = copy.deepcopy(body)
|
||||
# Skip ports that are missing required information for deploy.
|
||||
if not validate_port_info(node, ironic_port):
|
||||
failures.append(ironic_port.uuid)
|
||||
continue
|
||||
body['port']['mac_address'] = ironic_port.address
|
||||
port_body['port']['mac_address'] = ironic_port.address
|
||||
binding_profile = {'local_link_information':
|
||||
[portmap[ironic_port.uuid]]}
|
||||
body['port']['binding:profile'] = binding_profile
|
||||
port_body['port']['binding:profile'] = binding_profile
|
||||
|
||||
if add_all_ports and not ironic_port.pxe_enabled:
|
||||
LOG.debug("Adding port %(port)s to network %(net) for "
|
||||
"provisioning without an IP allocation.",
|
||||
{'port': ironic_port.uuid,
|
||||
'net': network_uuid})
|
||||
port_body['fixed_ips'] = []
|
||||
|
||||
is_smart_nic = is_smartnic_port(ironic_port)
|
||||
if is_smart_nic:
|
||||
@ -254,21 +270,22 @@ def add_ports_to_network(task, network_uuid, security_groups=None):
|
||||
'port %(port_id)s, hostname %(hostname)s',
|
||||
{'port_id': ironic_port.uuid,
|
||||
'hostname': link_info['hostname']})
|
||||
body['port']['binding:host_id'] = link_info['hostname']
|
||||
port_body['port']['binding:host_id'] = link_info['hostname']
|
||||
|
||||
# TODO(hamdyk): use portbindings.VNIC_SMARTNIC from neutron-lib
|
||||
body['port']['binding:vnic_type'] = VNIC_SMARTNIC
|
||||
port_body['port']['binding:vnic_type'] = VNIC_SMARTNIC
|
||||
client_id = ironic_port.extra.get('client-id')
|
||||
if client_id:
|
||||
client_id_opt = {'opt_name': DHCP_CLIENT_ID,
|
||||
'opt_value': client_id}
|
||||
extra_dhcp_opts = body['port'].get('extra_dhcp_opts', [])
|
||||
extra_dhcp_opts = port_body['port'].get('extra_dhcp_opts', [])
|
||||
extra_dhcp_opts.append(client_id_opt)
|
||||
body['port']['extra_dhcp_opts'] = extra_dhcp_opts
|
||||
port_body['port']['extra_dhcp_opts'] = extra_dhcp_opts
|
||||
try:
|
||||
if is_smart_nic:
|
||||
wait_for_host_agent(client, body['port']['binding:host_id'])
|
||||
port = client.create_port(body)
|
||||
wait_for_host_agent(client,
|
||||
port_body['port']['binding:host_id'])
|
||||
port = client.create_port(port_body)
|
||||
if is_smart_nic:
|
||||
wait_for_port_status(client, port['port']['id'], 'ACTIVE')
|
||||
except neutron_exceptions.NeutronClientException as e:
|
||||
@ -307,7 +324,11 @@ def remove_ports_from_network(task, network_uuid):
|
||||
:param network_uuid: UUID of a neutron network ports will be deleted from.
|
||||
:raises: NetworkError
|
||||
"""
|
||||
add_all_ports = CONF.neutron.add_all_ports
|
||||
if not add_all_ports:
|
||||
macs = [p.address for p in task.ports if p.pxe_enabled]
|
||||
else:
|
||||
macs = [p.address for p in task.ports]
|
||||
if macs:
|
||||
params = {
|
||||
'network_id': network_uuid,
|
||||
|
@ -83,7 +83,13 @@ opts = [
|
||||
'performs pre-commit validation prior returning to '
|
||||
'the API client which can take longer than normal '
|
||||
'client/server interactions.')),
|
||||
|
||||
cfg.BoolOpt('add_all_ports',
|
||||
default=False,
|
||||
help=_('Option to enable transmission of all ports '
|
||||
'to neutron when creating ports for provisioning, '
|
||||
'cleaning, or rescue. This is done without IP '
|
||||
'addresses assigned to the port, and may be useful '
|
||||
'in some bonded network configurations.')),
|
||||
]
|
||||
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
import time
|
||||
|
||||
from keystoneauth1 import loading as kaloading
|
||||
@ -171,16 +172,19 @@ class TestNeutronNetworkActions(db_base.DbTestCase):
|
||||
self.addCleanup(patcher.stop)
|
||||
|
||||
def _test_add_ports_to_network(self, is_client_id,
|
||||
security_groups=None):
|
||||
security_groups=None,
|
||||
add_all_ports=False):
|
||||
# Ports will be created only if pxe_enabled is True
|
||||
self.node.network_interface = 'neutron'
|
||||
self.node.save()
|
||||
object_utils.create_test_port(
|
||||
port2 = object_utils.create_test_port(
|
||||
self.context, node_id=self.node.id,
|
||||
uuid=uuidutils.generate_uuid(),
|
||||
address='52:54:00:cf:2d:22',
|
||||
address='54:00:00:cf:2d:22',
|
||||
pxe_enabled=False
|
||||
)
|
||||
if add_all_ports:
|
||||
self.config(add_all_ports=True, group="neutron")
|
||||
port = self.ports[0]
|
||||
if is_client_id:
|
||||
extra = port.extra
|
||||
@ -207,14 +211,34 @@ class TestNeutronNetworkActions(db_base.DbTestCase):
|
||||
if is_client_id:
|
||||
expected_body['port']['extra_dhcp_opts'] = (
|
||||
[{'opt_name': '61', 'opt_value': self._CLIENT_ID}])
|
||||
# Ensure we can create ports
|
||||
|
||||
if add_all_ports:
|
||||
expected_body2 = copy.deepcopy(expected_body)
|
||||
expected_body2['port']['mac_address'] = port2.address
|
||||
expected_body2['fixed_ips'] = []
|
||||
neutron_port2 = {'id': '132f871f-eaec-4fed-9475-0d54465e0f01',
|
||||
'mac_address': port2.address}
|
||||
self.client_mock.create_port.side_effect = [
|
||||
{'port': self.neutron_port},
|
||||
{'port': neutron_port2}
|
||||
]
|
||||
expected = {port.uuid: self.neutron_port['id'],
|
||||
port2.uuid: neutron_port2['id']}
|
||||
|
||||
else:
|
||||
self.client_mock.create_port.return_value = {
|
||||
'port': self.neutron_port}
|
||||
expected = {port.uuid: self.neutron_port['id']}
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
ports = neutron.add_ports_to_network(
|
||||
task, self.network_uuid, security_groups=security_groups)
|
||||
self.assertEqual(expected, ports)
|
||||
if add_all_ports:
|
||||
calls = [mock.call(expected_body),
|
||||
mock.call(expected_body2)]
|
||||
self.client_mock.create_port.assert_has_calls(calls)
|
||||
else:
|
||||
self.client_mock.create_port.assert_called_once_with(
|
||||
expected_body)
|
||||
|
||||
@ -222,6 +246,11 @@ class TestNeutronNetworkActions(db_base.DbTestCase):
|
||||
self._test_add_ports_to_network(is_client_id=False,
|
||||
security_groups=None)
|
||||
|
||||
def test_add_ports_to_network_all_ports(self):
|
||||
self._test_add_ports_to_network(is_client_id=False,
|
||||
security_groups=None,
|
||||
add_all_ports=True)
|
||||
|
||||
@mock.patch.object(neutron, '_verify_security_groups', autospec=True)
|
||||
def test_add_ports_to_network_with_sg(self, verify_mock):
|
||||
sg_ids = []
|
||||
@ -413,6 +442,25 @@ class TestNeutronNetworkActions(db_base.DbTestCase):
|
||||
'mac_address': [self.ports[0].address]}
|
||||
)
|
||||
|
||||
@mock.patch.object(neutron, 'remove_neutron_ports', autospec=True)
|
||||
def test_remove_ports_from_network_not_all_pxe_enabled_all_ports(
|
||||
self, remove_mock):
|
||||
self.config(add_all_ports=True, group="neutron")
|
||||
object_utils.create_test_port(
|
||||
self.context, node_id=self.node.id,
|
||||
uuid=uuidutils.generate_uuid(),
|
||||
address='52:54:55:cf:2d:32',
|
||||
pxe_enabled=False
|
||||
)
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
neutron.remove_ports_from_network(task, self.network_uuid)
|
||||
calls = [
|
||||
mock.call(task, {'network_id': self.network_uuid,
|
||||
'mac_address': [task.ports[0].address,
|
||||
task.ports[1].address]}),
|
||||
]
|
||||
remove_mock.assert_has_calls(calls)
|
||||
|
||||
def test_remove_neutron_ports(self):
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
self.client_mock.list_ports.return_value = {
|
||||
|
19
releasenotes/notes/transmit-all-ports-b570009d1a008067.yaml
Normal file
19
releasenotes/notes/transmit-all-ports-b570009d1a008067.yaml
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Provides an opt-in fix to change the default port attachment behavior
|
||||
for deployment and cleaning operations through a new configuration option,
|
||||
``[neutron]add_all_ports``. This option causes ironic to transmits all
|
||||
port information to neutron as opposed to only a single physical network
|
||||
port. This enables operators to successfully operate static Port Group
|
||||
configurations with Neutron ML2 drivers, where previously configuration
|
||||
of networking would fail.
|
||||
|
||||
When these ports are configured with ``pxe_enabled`` set to ``False``,
|
||||
neutron will be requested not to assign an IP address to the port. This
|
||||
is to prevent additional issues that may occur depending on physical
|
||||
switch configuration with static Port Group configurations.
|
||||
- |
|
||||
Fixes an issue during provisioning network attachment where
|
||||
neutron ports were being created with the same data structure
|
||||
being re-used.
|
Loading…
Reference in New Issue
Block a user