diff options
author | Laura Moore <laura.moore@sap.com> | 2015-07-27 17:33:22 -0400 |
---|---|---|
committer | vsaienko <vsaienko@mirantis.com> | 2016-02-04 22:40:54 +0200 |
commit | e5c5ddbdc8b015221b2656270a2f3f21414a055f (patch) | |
tree | 3107a2e62e3a5c44cc8853763469720b94b66e44 /ironic/dhcp | |
parent | a603e3c12c62e29e12e45283d8602f9aa5acfc0f (diff) | |
download | ironic-e5c5ddbdc8b015221b2656270a2f3f21414a055f.tar.gz |
Add portgroups to support LAG interfaces - net
Ironic should be able to provide the requisite connectivity
information to the Neutron ML2 plugin to allow drivers to
provision the top-of-rack switch for the bare metal server.
The addition of portgroups in Ironic allows the concept of
link aggregation to be handled in Ironic in order to provide
support for cases where multiple interfaces on the bare metal
server connect to switch ports of a single LAG.
This commit includes changes to:
- the port vif mapping to also use portgroups
Partial-bug: #1526403
DocImpact
Co-Authored-By: Jenny Moorehead (jenny.moorehead@sap.com)
Co-Authored-By: Will Stevenson (will.stevenson@sap.com)
Co-Authored-By: Vasyl Saienko (vsaienko@mirantis.com)
Change-Id: I7f1cba65275078da750aa49ae83ba7345d6fd5e0
Diffstat (limited to 'ironic/dhcp')
-rw-r--r-- | ironic/dhcp/base.py | 22 | ||||
-rw-r--r-- | ironic/dhcp/neutron.py | 110 |
2 files changed, 86 insertions, 46 deletions
diff --git a/ironic/dhcp/base.py b/ironic/dhcp/base.py index ad1e4e042..9ebb20f5f 100644 --- a/ironic/dhcp/base.py +++ b/ironic/dhcp/base.py @@ -74,21 +74,27 @@ class BaseDHCP(object): {'opt_name': 'tftp-server', 'opt_value': '123.123.123.123'}] - :param vifs: a dict of Neutron port dicts to update DHCP options on. - The keys should be Ironic port UUIDs, and the values should be - Neutron port UUIDs - If the value is None, will get the list of ports from the Ironic - port objects. + :param vifs: A dict with keys 'ports' and 'portgroups' and + dicts as values. Each dict has key/value pairs of the form + <ironic UUID>:<neutron port UUID>. e.g. + :: + + {'ports': {'port.uuid': vif.id}, + 'portgroups': {'portgroup.uuid': vif.id}} + + If the value is None, will get the list of ports/portgroups + from the Ironic port/portgroup objects. :raises: FailedToUpdateDHCPOptOnPort """ @abc.abstractmethod def get_ip_addresses(self, task): - """Get IP addresses for all ports in `task`. + """Get IP addresses for all ports/portgroups in `task`. - :param task: a TaskManager instance. - :returns: List of IP addresses associated with task.ports + :param task: A TaskManager instance. + :returns: List of IP addresses associated with + task's ports and portgroups. """ def clean_dhcp_opts(self, task): diff --git a/ironic/dhcp/neutron.py b/ironic/dhcp/neutron.py index 167d7ecbb..60499dabf 100644 --- a/ironic/dhcp/neutron.py +++ b/ironic/dhcp/neutron.py @@ -30,6 +30,7 @@ from ironic.common import keystone from ironic.common import network from ironic.dhcp import base from ironic.drivers.modules import ssh +from ironic.objects.port import Port neutron_opts = [ @@ -152,37 +153,44 @@ class NeutronDHCPApi(base.BaseDHCP): 'opt_value': '123.123.123.456'}, {'opt_name': 'tftp-server', 'opt_value': '123.123.123.123'}] - :param vifs: a dict of Neutron port dicts to update DHCP options on. - The keys should be Ironic port UUIDs, and the values should be - Neutron port UUIDs - If the value is None, will get the list of ports from the Ironic - port objects. + :param vifs: a dict of Neutron port/portgroup dicts + to update DHCP options on. The port/portgroup dict key + should be Ironic port UUIDs, and the values should be + Neutron port UUIDs, e.g. + + :: + + {'ports': {'port.uuid': vif.id}, + 'portgroups': {'portgroup.uuid': vif.id}} + If the value is None, will get the list of ports/portgroups + from the Ironic port/portgroup objects. """ if vifs is None: vifs = network.get_node_vif_ids(task) - if not vifs: + if not (vifs['ports'] or vifs['portgroups']): raise exception.FailedToUpdateDHCPOptOnPort( _("No VIFs found for node %(node)s when attempting " "to update DHCP BOOT options.") % {'node': task.node.uuid}) failures = [] - for port_id, port_vif in vifs.items(): + vif_list = [vif for pdict in vifs.values() for vif in pdict.values()] + for vif in vif_list: try: - self.update_port_dhcp_opts(port_vif, options, + self.update_port_dhcp_opts(vif, options, token=task.context.auth_token) except exception.FailedToUpdateDHCPOptOnPort: - failures.append(port_id) + failures.append(vif) if failures: - if len(failures) == len(vifs): + if len(failures) == len(vif_list): raise exception.FailedToUpdateDHCPOptOnPort(_( "Failed to set DHCP BOOT options for any port on node %s.") % task.node.uuid) else: LOG.warning(_LW("Some errors were encountered when updating " "the DHCP BOOT options for node %(node)s on " - "the following ports: %(ports)s."), + "the following Neutron ports: %(ports)s."), {'node': task.node.uuid, 'ports': failures}) # TODO(adam_g): Hack to workaround bug 1334447 until we have a @@ -195,7 +203,7 @@ class NeutronDHCPApi(base.BaseDHCP): time.sleep(15) def _get_fixed_ip_address(self, port_uuid, client): - """Get a port's fixed ip address. + """Get a Neutron port's fixed ip address. :param port_uuid: Neutron port id. :param client: Neutron client instance. @@ -231,55 +239,81 @@ class NeutronDHCPApi(base.BaseDHCP): port_uuid) raise exception.FailedToGetIPAddressOnPort(port_id=port_uuid) - def _get_port_ip_address(self, task, port_uuid, client): - """Get ip address of ironic port assigned by neutron. + def _get_port_ip_address(self, task, p_obj, client): + """Get ip address of ironic port/portgroup assigned by Neutron. :param task: a TaskManager instance. - :param port_uuid: ironic Node's port UUID. + :param p_obj: Ironic port or portgroup object. :param client: Neutron client instance. - :returns: Neutron port ip address associated with Node's port. + :returns: List of Neutron vif ip address associated with + Node's port/portgroup. :raises: FailedToGetIPAddressOnPort :raises: InvalidIPv4Address """ - vifs = network.get_node_vif_ids(task) - if not vifs: + vif = p_obj.extra.get('vif_port_id') + if not vif: + obj_name = 'portgroup' + if isinstance(p_obj, Port): + obj_name = 'port' LOG.warning(_LW("No VIFs found for node %(node)s when attempting " - " to get port IP address."), - {'node': task.node.uuid}) - raise exception.FailedToGetIPAddressOnPort(port_id=port_uuid) - - port_vif = vifs[port_uuid] + "to get IP address for %(obj_name)s: %(obj_id)."), + {'node': task.node.uuid, 'obj_name': obj_name, + 'obj_id': p_obj.uuid}) + raise exception.FailedToGetIPAddressOnPort(port_id=p_obj.uuid) - port_ip_address = self._get_fixed_ip_address(port_vif, client) - return port_ip_address + vif_ip_address = self._get_fixed_ip_address(vif, client) + return vif_ip_address - def get_ip_addresses(self, task): - """Get IP addresses for all ports in `task`. + def _get_ip_addresses(self, task, pobj_list, client): + """Get IP addresses for all ports/portgroups. :param task: a TaskManager instance. - :returns: List of IP addresses associated with task.ports. + :param pobj_list: List of port or portgroup objects. + :param client: Neutron client instance. + :returns: List of IP addresses associated with + task's ports/portgroups. """ - client = _build_client(task.context.auth_token) failures = [] ip_addresses = [] - for port in task.ports: + for obj in pobj_list: try: - port_ip_address = self._get_port_ip_address(task, port.uuid, - client) - ip_addresses.append(port_ip_address) + vif_ip_address = self._get_port_ip_address(task, obj, + client) + ip_addresses.append(vif_ip_address) except (exception.FailedToGetIPAddressOnPort, exception.InvalidIPv4Address): - failures.append(port.uuid) + failures.append(obj.uuid) if failures: - LOG.warning(_LW("Some errors were encountered on node %(node)s" - " while retrieving IP address on the following" - " ports: %(ports)s."), - {'node': task.node.uuid, 'ports': failures}) + obj_name = 'portgroups' + if isinstance(pobj_list[0], Port): + obj_name = 'ports' + + LOG.warning(_LW( + "Some errors were encountered on node %(node)s " + "while retrieving IP addresses on the following " + "%(obj_name)s: %(failures)s."), + {'node': task.node.uuid, 'obj_name': obj_name, + 'failures': failures}) return ip_addresses + def get_ip_addresses(self, task): + """Get IP addresses for all ports/portgroups in `task`. + + :param task: a TaskManager instance. + :returns: List of IP addresses associated with + task's ports/portgroups. + """ + client = _build_client(task.context.auth_token) + + port_ip_addresses = self._get_ip_addresses(task, task.ports, client) + portgroup_ip_addresses = self._get_ip_addresses( + task, task.portgroups, client) + + return port_ip_addresses + portgroup_ip_addresses + def create_cleaning_ports(self, task): """Create neutron ports for each port on task.node to boot the ramdisk. |