--- # Some Dell switch OSs (including Dell Network OS 9.10(0.1)) do not support # sending interface port description TLVs correctly. Instead of sending the # interface description, they send the interface name (e.g. TenGigabitEthernet # 1/1/1). This breaks the discovery process which relies on Ironic node # introspection data containing the node's name in the interface port # description. We work around this here by creating an introspection rule for # each ironic node that matches against the switch system and the relevant # interface name, then sets the node's name appropriately. # # Note that some Dell switches running Dell Networking OS version 9.11(2.0P1) # and newer do *not* need this workaround. The interface description can be # sent using the following configuration: # # (conf-if-interface)#protocol lldp # (conf-if-interface-lldp)#advertise interface-port-desc description - name: Check whether Ironic is enabled hosts: controllers tags: - introspection-rules - introspection-rules-dell-lldp-workaround tasks: - name: Create controllers group with ironic enabled group_by: key: "controllers_for_introspection_rules_dell_lldp_workaround_{{ kolla_enable_ironic | bool }}" - name: Group controller hosts in systems requiring the workaround hosts: controllers_for_introspection_rules_dell_lldp_workaround_True gather_facts: False tags: - introspection-rules - introspection-rules-dell-lldp-workaround tasks: - name: Group controller hosts in systems requiring the Dell switch LLDP workaround group_by: key: "controllers_require_workaround_{{ groups[inspector_dell_switch_lldp_workaround_group] | default([]) | length > 0 }}" - name: Ensure introspection rules for Dell switch LLDP workarounds are registered in Ironic Inspector # Only required to run on a single host. hosts: controllers_require_workaround_True[0] gather_facts: False tags: - introspection-rules - introspection-rules-dell-lldp-workaround vars: all_switch_interfaces: [] ironic_inspector_rules: [] # This rule template is used in a with_subelements loop. inspector_interface_mapping_rule: description: "Set {{ item.1.1.description }} node name from {{ inspector_rule_var_lldp_switch_port_interface }} LLDP switch port description" conditions: - field: "data://all_interfaces.{{ inspector_rule_var_lldp_switch_port_interface }}" op: "is-empty" invert: True - field: "data://all_interfaces.{{ inspector_rule_var_lldp_switch_port_interface }}.lldp_processed" op: "is-empty" invert: True - field: "data://all_interfaces.{{ inspector_rule_var_lldp_switch_port_interface }}.lldp_processed.switch_port_description" op: "is-empty" invert: True - field: "data://all_interfaces.{{ inspector_rule_var_lldp_switch_port_interface }}.lldp_processed.switch_system_name" op: "is-empty" invert: True # Match against the interface name. - field: "data://all_interfaces.{{ inspector_rule_var_lldp_switch_port_interface }}.lldp_processed.switch_port_description" op: "eq" # Our interface names may be of a shortened form e.g. Te1/1/1, but # the port description will contain the full interface name. Use a # regex to expand to the full form. value: "{{ item.1.0 | regex_replace('^Te([a-zA-z ]*)([0-9/]+)$', 'TenGigabitEthernet \\2') }}" # Match against the switch system name. - field: "data://all_interfaces.{{ inspector_rule_var_lldp_switch_port_interface }}.lldp_processed.switch_system_name" op: "eq" value: "{{ item.0.host }}" actions: - action: "set-attribute" path: "name" value: "{{ item.1.1.description }}" inspector_rule_var_lldp_switch_port_interface: "{{ inspector_lldp_switch_port_interface_map.get(item.1.1.description, inspector_lldp_switch_port_interface_default) }}" pre_tasks: - name: Validate OpenStack password authentication parameters fail: msg: > Required OpenStack authentication parameter {{ item }} is {% if item in openstack_auth %}empty{% else %}not present{% endif %} in openstack_auth. Have you sourced the environment file? when: - openstack_auth_type == 'password' - item not in openstack_auth or not openstack_auth[item] with_items: "{{ openstack_auth_password_required_params }}" tags: - config-validation # We build up the rules using a 2-step process. First we build a list of # relevant switch hosts and their interface configuration (in list form). # This allows us to use with_subelements in the next task to iterate over # the interfaces for each switch. - name: Update a fact containing switch interface configuration set_fact: all_switch_interfaces: > {{ all_switch_interfaces + [{'host': item.key, 'interface_config': item.value.switch_interface_config.items()}] }} with_dict: "{{ hostvars }}" when: item.key in groups[inspector_dell_switch_lldp_workaround_group] - name: Update a fact containing Ironic Inspector rules set_fact: ironic_inspector_rules: > {{ ironic_inspector_rules + [inspector_interface_mapping_rule] }} with_subelements: - "{{ all_switch_interfaces }}" - interface_config when: - item.1.1.description is defined # Ignore VLAN interfaces. - "'vlan' not in item.1.0" # Ignore trunk links. - "'-trunk' not in item.1.1.description" roles: - role: ironic-inspector-rules os_openstacksdk_install_epel: "{{ dnf_install_epel }}" os_openstacksdk_state: latest ironic_inspector_venv: "{{ virtualenv_path }}/openstacksdk" ironic_inspector_upper_constraints_file: "{{ pip_upper_constraints_file }}" ironic_inspector_auth_type: "{{ openstack_auth_type }}" ironic_inspector_auth: "{{ openstack_auth }}" ironic_inspector_cacert: "{{ openstack_cacert }}" ironic_inspector_interface: "{{ openstack_interface }}"