kayobe/ansible/idrac-bootstrap.yml
Mark Goddard f639ad0b35 Use ansible_facts to reference facts
By default, Ansible injects a variable for every fact, prefixed with
ansible_. This can result in a large number of variables for each host,
which at scale can incur a performance penalty. Ansible provides a
configuration option [0] that can be set to False to prevent this
injection of facts. In this case, facts should be referenced via
ansible_facts.<fact>.

This change updates all references to Ansible facts within Kayobe
from using individual fact variables to using the items in the
ansible_facts dictionary. This allows users to disable fact variable
injection in their Ansible configuration, which may provide some
performance improvement.

This change disables fact variable injection in the ansible
configuration used in CI, to catch any attempts to use the injected
variables.

[0] https://docs.ansible.com/ansible/latest/reference_appendices/config.html#inject-facts-as-vars

Story: 2007993
Task: 42464
Depends-On: https://review.opendev.org/c/openstack/kolla-ansible/+/791276

Change-Id: I14db53ed6e57d37bbd28dd5819e432e3fe6628b2
2021-08-21 09:57:29 +02:00

232 lines
10 KiB
YAML

---
# This playbook is intended to bootstrap network configuration of the iDRACs on
# a set of Dell servers. By default, iDRACs have a known static IP address
# configured. Since all iDRACs have the same default IP address, we need a way
# to isolate a single iDRAC while we set its network configuration. We do this
# using a temporary VLAN accessible from one of the controllers.
#
# We use the following procedure:
# 1. Create a VLAN interface on the controller node with IP in the iDRAC
# default subnet.
# 2. Create the temporary bootstrap VLAN on the switch, accessible by the
# controller and trunked to all switches within the network.
# 3. For each iDRAC switch port in turn, flip to the temporary VLAN and
# configure the iDRAC's IP address, before returning the port to the iDRAC
# management VLAN.
# 4. Remove the temporary bootstrap VLAN from the switch.
# 5. Remove the VLAN interface on the controller node.
# Playbook variables:
#
# idrac_limit: Colon-separated list of names of idracs to limit bootstrappping
# to. These names should be present in the variable
# idrac_network_ips. If omitted all idracs will be bootstrapped.
- name: Ensure the iDRAC switches are supported
hosts: "{{ idrac_bootstrap_switch_group }}"
gather_facts: no
vars:
supported_switch_types:
- dellos6
tasks:
- name: Ensure switch type is supported
fail:
msg: >
The iDRAC bootstrap process currently only supports DellOS6 switches.
when: switch_type not in supported_switch_types
# 1. Create a VLAN interface on the controller node with IP in the iDRAC
# default subnet.
- name: Ensure the controller bootstrap network is configured
hosts: "{{ idrac_bootstrap_controller_group ~ '[0]' }}"
tasks:
# Install Dell server admin tools.
- block:
- name: Ensure wget is installed
package:
name: wget
state: present
cache_valid_time: "{{ apt_cache_valid_time if ansible_facts.os_family == 'Debian' else omit }}"
update_cache: "{{ True if ansible_facts.os_family == 'Debian' else omit }}"
- name: Ensure Dell srvadmin repository is installed
shell: "wget -q -O - http://linux.dell.com/repo/hardware/latest/bootstrap.cgi | bash"
- name: Ensure Dell srvadmin-idrac7 package is installed
package:
name: srvadmin-idrac7
state: present
# Configure access to the temporary network on a controller.
- block:
# Clear any previous state.
- name: Ensure iDRAC bootstrap network namespace is deleted from the controller
command: "ip netns delete {{ idrac_bootstrap_net_namespace }}"
args:
removes: "/var/run/netns/{{ idrac_bootstrap_net_namespace }}"
- name: Ensure iDRAC bootstrap network namespace exists on controller
command: "ip netns add {{ idrac_bootstrap_net_namespace }}"
- name: Ensure bootstrap VLAN interface exists on the controller
command: "ip link add link {{ idrac_bootstrap_controller_interface }} name {{ idrac_bootstrap_controller_vlan_interface }} type vlan id {{ idrac_bootstrap_vlan }}"
- name: Ensure bootstrap VLAN interface is in network namespace
command: "ip link set {{ idrac_bootstrap_controller_vlan_interface }} netns {{ idrac_bootstrap_net_namespace }}"
- name: Ensure the bootstrap VLAN interface is active
command: "ip netns exec {{ idrac_bootstrap_net_namespace }} ip link set {{ idrac_bootstrap_controller_vlan_interface }} up"
- name: Ensure the bootstrap VLAN interface IP address is configured
command: "ip netns exec {{ idrac_bootstrap_net_namespace }} ip address add {{ idrac_bootstrap_controller_ip }}/24 dev {{ idrac_bootstrap_controller_vlan_interface }}"
rescue:
- name: Rescue | Ensure the bootstrap network namespace is removed from the controller
command: "ip netns delete {{ idrac_bootstrap_net_namespace }}"
- name: Rescue | Fail playbook execution on error
fail:
msg: >
Failed to configure access to temporary iDRAC bootstrap
network on controller.
become: True
# 2. Create the temporary bootstrap VLAN on the switch, accessible by the
# controller and trunked to all switches within the network.
- name: Ensure the bootstrap VLAN is configured on switches
hosts: "{{ idrac_bootstrap_switch_group }}"
gather_facts: no
vars:
switch_interface_config_bootstrap_trunk:
config:
- "switchport trunk allowed vlan add {{ idrac_bootstrap_vlan }}"
# Initialise the switch interface configuration.
switch_interface_config_bootstrap: {}
pre_tasks:
- name: Update facts about switch trunk interfaces
set_fact:
switch_interface_config_bootstrap: >
{{ switch_interface_config_bootstrap | combine({item.key: switch_interface_config_bootstrap_trunk}) }}
with_dict: "{{ switch_interface_config }}"
when: >
{{ item.value.description | default == groups[idrac_bootstrap_controller_group][0] or
item.value.description | default | replace('-trunk', '') in groups[idrac_bootstrap_switch_group] }}
roles:
# Configure bootstrap VLAN on the switch and add controller and trunk
# interfaces to it.
- role: dell-switch
dell_switch_type: "{{ switch_type }}"
dell_switch_provider: "{{ switch_dellos_provider }}"
dell_switch_config:
- "vlan {{ idrac_bootstrap_vlan }}"
dell_switch_interface_config: "{{ switch_interface_config_bootstrap }}"
when: switch_interface_config_bootstrap != {}
# 3. For each iDRAC switch port in turn, flip to the temporary VLAN and
# configure the iDRAC's IP address, before returning the port to the iDRAC
# management VLAN.
- name: Ensure iDRACs are bootstrapped
hosts: "{{ idrac_bootstrap_switch_group }}"
gather_facts: no
vars:
# Set this to a colon-separated list of idrac hostnames to bootstrap.
# If unset, all idracs will be bootstrapped.
idrac_limit: ""
idrac_limit_list: "{{ idrac_limit.split(':') }}"
# This is a separate play so that we can apply the serial keyword.
serial: 1
tasks:
- name: Initialise facts containing successful, unchanged and failed iDRACs
set_fact:
idrac_bootstrap_success: []
idrac_bootstrap_unchanged: []
idrac_bootstrap_failed: []
# Iterate over each switch port with an iDRAC attached in turn.
- name: Ensure iDRACs are (sequentially) bootstrapped
include_tasks: idrac-bootstrap-one.yml
vars:
dell_switch_type: "{{ switch_type }}"
dell_switch_provider: "{{ switch_dellos_provider }}"
switch_interface_name: "{{ item.key }}"
idrac_port_description: "{{ item.value.description }}"
idrac_network_ip: "{{ idrac_network_ips[idrac_port_description] }}"
idrac_bootstrap_controller: "{{ hostvars[groups[idrac_bootstrap_controller_group][0]].ansible_host }}"
with_dict: "{{ switch_interface_config }}"
when: >
{{ item.value.description | default in idrac_network_ips and
(not idrac_limit or item.value.description | default in idrac_limit_list) }}
# 4. Remove the temporary bootstrap VLAN from the switch.
- name: Ensure the bootstrap VLAN is removed from switches
hosts: "{{ idrac_bootstrap_switch_group }}"
gather_facts: no
vars:
switch_interface_config_bootstrap_trunk:
config:
- "switchport trunk allowed vlan remove {{ idrac_bootstrap_vlan }}"
# Initialise the switch interface configuration.
switch_interface_config_bootstrap: {}
pre_tasks:
- name: Update facts about switch trunk interfaces
set_fact:
switch_interface_config_bootstrap: >
{{ switch_interface_config_bootstrap | combine({item.key: switch_interface_config_bootstrap_trunk}) }}
with_dict: "{{ switch_interface_config }}"
when: >
{{ item.value.description | default == groups[idrac_bootstrap_controller_group][0] or
item.value.description | default | replace('-trunk', '') in groups[idrac_bootstrap_switch_group] }}
roles:
# Remove bootstrap VLAN from the switch and remove controller and trunk
# interfaces from it.
- role: dell-switch
dell_switch_type: "{{ switch_type }}"
dell_switch_provider: "{{ switch_dellos_provider }}"
dell_switch_config:
- "no vlan {{ idrac_bootstrap_vlan }}"
dell_switch_interface_config: "{{ switch_interface_config_bootstrap }}"
when: switch_interface_config_bootstrap != {}
# 5. Remove the VLAN interface on the controller node.
- name: Ensure the controller bootstrap network is cleaned up
hosts: "{{ idrac_bootstrap_controller_group ~ '[0]' }}"
tasks:
# This should also delete the network interface within the namespace.
- name: Ensure the bootstrap network namespace is removed from the controller
command: "ip netns delete {{ idrac_bootstrap_net_namespace }}"
become: True
- name: Display the results of the iDRAC bootstrap procedure
hosts: "{{ idrac_bootstrap_switch_group }}"
gather_facts: no
tasks:
- name: Display a list of failed iDRACs
set_fact:
idrac_bootstrap_failed_port_descriptions: "{{ idrac_bootstrap_failed | map(attribute='port description') | list }}"
when: idrac_bootstrap_failed | length > 0
- name: Display a list of successfully bootstrapped iDRACs
debug:
var: idrac_bootstrap_success
- name: Display a list of iDRACs that did not require bootstrapping
debug:
var: idrac_bootstrap_unchanged
- name: Display a list of failed iDRACs
debug:
var: idrac_bootstrap_failed_port_descriptions
when: idrac_bootstrap_failed | length > 0
- name: Display a list of failed iDRACs with debug output for the failed tasks
debug:
var: idrac_bootstrap_failed
when: idrac_bootstrap_failed | length > 0
- name: Fail if there were any iDRAC bootstrapping failures
fail:
msg: >
One or more iDRACs failed to bootstrap, see the list above for
details.
when: idrac_bootstrap_failed | length > 0