Add Ironic enrolment Ansible role
This commit is contained in:
parent
8e9e91ac79
commit
81f1696263
@ -51,6 +51,8 @@ class ActionModule(ActionBase):
|
||||
for typ, cnt in six.iteritems(task_vars['specs']):
|
||||
for _ in six.moves.range(cnt):
|
||||
node = deepcopy(task_vars['node_types'][typ])
|
||||
# Set the type, for future reference.
|
||||
node['type'] = typ
|
||||
# Sequentially number the node and volume names.
|
||||
node['name'] = "%s%d" % (task_vars['node_name_prefix'], idx)
|
||||
for vol_idx, vol in enumerate(node['volumes']):
|
||||
|
@ -89,3 +89,27 @@
|
||||
loop_control:
|
||||
loop_var: domain
|
||||
index_var: port_offset
|
||||
|
||||
- hosts: localhost
|
||||
tasks:
|
||||
- name: Check that OpenStack credentials exist in the environment
|
||||
fail:
|
||||
msg: >
|
||||
$OS_USERNAME was not found in the environment. Ensure the OpenStack
|
||||
credentials exist in your environment, perhaps by sourcing your RC file.
|
||||
when: not lookup('env', 'OS_USERNAME')
|
||||
|
||||
- name: Perform Ironic enrolment for each hypervisor's nodes
|
||||
include_role:
|
||||
name: ironic-enrolment
|
||||
vars:
|
||||
ironic_deploy_kernel_uuid: "{{ deploy_kernel_uuid }}"
|
||||
ironic_deploy_ramdisk_uuid: "{{ deploy_ramdisk_uuid }}"
|
||||
ironic_nodes: "{{ alloc.1 }}"
|
||||
ironic_hypervisor: "{{ alloc.0 }}"
|
||||
ironic_virtualenv_path: "{{ virtualenv_path }}"
|
||||
ironic_python_upper_constraints_url: >-
|
||||
{{ python_upper_constraints_url }}
|
||||
loop: "{{ allocations.result.iteritems() | list }}"
|
||||
loop_control:
|
||||
loop_var: alloc
|
||||
|
@ -111,7 +111,7 @@ def ovs_link_name(context, node, physnet):
|
||||
def source_to_ovs_link_name(context, source):
|
||||
"""Get the corresponding OVS link name for a source link name.
|
||||
"""
|
||||
base = source[:len(_get_hostvar(context, 'veth_node_source_suffix'))]
|
||||
base = source[:-len(_get_hostvar(context, 'veth_node_source_suffix'))]
|
||||
return base + _get_hostvar(context, 'veth_node_ovs_suffix')
|
||||
|
||||
|
||||
|
@ -32,3 +32,8 @@ node_types: {}
|
||||
# # 'type0'.
|
||||
# type0: 4
|
||||
specs: {}
|
||||
|
||||
# The Glance UUID of the image to use for the deployment kernel.
|
||||
deploy_kernel_uuid:
|
||||
# The Glance UUID of the image to use for the deployment ramdisk.
|
||||
deploy_ramdisk_uuid:
|
||||
|
30
ansible/roles/ironic-enrolment/README.md
Normal file
30
ansible/roles/ironic-enrolment/README.md
Normal file
@ -0,0 +1,30 @@
|
||||
Ironic Enrolment
|
||||
================
|
||||
|
||||
This role enrols nodes with OpenStack Ironic, creates Ironic ports for each of
|
||||
the nodes' NICs, and sets relevant attributes on created resources.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
- *OS_\** environment variables for the OpenStack cloud in question present in
|
||||
the shell environment. These can be sourced from an OpenStack RC file, for
|
||||
example.
|
||||
|
||||
- The `virsh` command-line tool present at `/bin/virsh`.
|
||||
|
||||
Role Variables
|
||||
--------------
|
||||
|
||||
- `ironic_nodes`: A list of dicts of details for nodes that are to be enroled
|
||||
in Ironic.
|
||||
- `ironic_hypervisor`: The hostname of the hypervisor on which `ironic_nodes`
|
||||
exist.
|
||||
- `ironic_deploy_kernel_uuid`: The Glance UUID of the image to use for the
|
||||
deployment kernel.
|
||||
- `ironic_deploy_ramdisk_uuid`: The Glance UUID of the image to use for the
|
||||
deployment ramdisk.
|
||||
- `ironic_virtualenv_path`: The path to the virtualenv in which to install the
|
||||
OpenStack clients.
|
||||
- `ironic_python_upper_constraints_url`: The URL of the upper constraints file
|
||||
to pass to pip when installing Python packages.
|
14
ansible/roles/ironic-enrolment/defaults/main.yml
Normal file
14
ansible/roles/ironic-enrolment/defaults/main.yml
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
# A list of dicts of details for nodes that are to be enroled in Ironic.
|
||||
ironic_nodes: []
|
||||
# The hostname of the hypervisor where these nodes exist.
|
||||
ironic_hypervisor:
|
||||
# The Glance UUID of the image to use for the deployment kernel.
|
||||
ironic_deploy_kernel_uuid:
|
||||
# The Glance UUID of the image to use for the deployment ramdisk.
|
||||
ironic_deploy_ramdisk_uuid:
|
||||
# The path to the virtualenv in which to install the OpenStack clients.
|
||||
ironic_virtualenv_path:
|
||||
# The URL of the upper constraints file to pass to pip when installing Python
|
||||
# packages.
|
||||
ironic_python_upper_constraints_url:
|
6
ansible/roles/ironic-enrolment/files/requirements.txt
Normal file
6
ansible/roles/ironic-enrolment/files/requirements.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# This file contains the Python packages that are needed in the Tenks virtual
|
||||
# env.
|
||||
|
||||
openstacksdk>=0.17.2 # Apache
|
||||
python-ironicclient>=2.5.0 # Apache
|
||||
python-openstackclient>=3.16.0 # Apache
|
18
ansible/roles/ironic-enrolment/tasks/main.yml
Normal file
18
ansible/roles/ironic-enrolment/tasks/main.yml
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
- name: Ensure Python requirements are installed
|
||||
pip:
|
||||
requirements: "{{ '/'.join([role_path, 'files', 'requirements.txt']) }}"
|
||||
extra_args: >-
|
||||
-c {{ ironic_python_upper_constraints_url }}
|
||||
virtualenv: "{{ ironic_virtualenv_path }}"
|
||||
|
||||
- name: Enrol the Ironic nodes
|
||||
include_tasks: node.yml
|
||||
vars:
|
||||
node: "{{ ironic_node }}"
|
||||
ipmi_port: >-
|
||||
{{ hostvars[ironic_hypervisor].ipmi_port_range_start + port_offset }}
|
||||
loop: "{{ ironic_nodes | sort(attribute='name') }}"
|
||||
loop_control:
|
||||
loop_var: ironic_node
|
||||
index_var: port_offset
|
90
ansible/roles/ironic-enrolment/tasks/node.yml
Normal file
90
ansible/roles/ironic-enrolment/tasks/node.yml
Normal file
@ -0,0 +1,90 @@
|
||||
---
|
||||
- name: Get vNIC MAC addresses
|
||||
# The output format of this command gives two lines of header, followed by
|
||||
# (for each vNIC):
|
||||
# <name> <type> <source interface> <model> <MAC>
|
||||
# The VMs will have been created with the virt module, using become: true.
|
||||
# This targets /bin/virsh rather than /usr/bin/virsh.
|
||||
command: /bin/virsh domiflist '{{ node.name }}'
|
||||
register: iflist_res
|
||||
changed_when: false
|
||||
become: true
|
||||
delegate_to: "{{ ironic_hypervisor }}"
|
||||
run_once: true
|
||||
|
||||
# We need to do this for each run to ensure other nodes' NICs don't carry over
|
||||
# to this run.
|
||||
- name: Reset list of NICs
|
||||
set_fact:
|
||||
nics: []
|
||||
|
||||
- name: Collect MAC addresses into NIC list
|
||||
set_fact:
|
||||
nics: "{{ nics | union([{'mac': item.split()[4]}]) }}"
|
||||
loop: "{{ iflist_res.stdout_lines[2:] }}"
|
||||
|
||||
- name: Create node in Ironic
|
||||
os_ironic:
|
||||
auth_type: password
|
||||
driver: ipmi
|
||||
driver_info:
|
||||
power:
|
||||
ipmi_address: "{{ hostvars[ironic_hypervisor].ipmi_address }}"
|
||||
# This is passed in from main.yml.
|
||||
ipmi_port: "{{ ipmi_port }}"
|
||||
ipmi_username: "{{ hostvars[ironic_hypervisor].ipmi_username }}"
|
||||
ipmi_password: "{{ hostvars[ironic_hypervisor].ipmi_password }}"
|
||||
deploy:
|
||||
deploy_kernel: "{{ ironic_deploy_kernel_uuid | default(omit, true) }}"
|
||||
deploy_ramdisk: "{{ ironic_deploy_ramdisk_uuid | default(omit, true) }}"
|
||||
name: "{{ node.name }}"
|
||||
nics: "{{ nics }}"
|
||||
properties:
|
||||
ram: "{{ node.memory_mb }}"
|
||||
# FIXME(w-miller): Instead of assuming the first volume is the primary
|
||||
# volume, make this configurable?
|
||||
disk_size: >-
|
||||
{{ (node.volumes.0.capacity | default('1')) | size_string_to_gb }}
|
||||
cpus: "{{ node.vcpus }}"
|
||||
vars:
|
||||
# This module requires the openstacksdk package, which is installed within
|
||||
# our virtualenv.
|
||||
ansible_python_interpreter: >-
|
||||
{{ '/'.join([ironic_virtualenv_path, 'bin', 'python']) }}
|
||||
register: created_node
|
||||
|
||||
# The os_ironic module automatically brings the node from 'enrol' to
|
||||
# 'available' state, but we still need to set more port and node attributes.
|
||||
# Use maintenance mode to do this.
|
||||
- name: Put Ironic node into maintenance mode
|
||||
command: >-
|
||||
'{{ ironic_virtualenv_path }}/bin/openstack' baremetal node maintenance set
|
||||
'{{ created_node.uuid }}'
|
||||
|
||||
# FIXME(w-miller): Make interfaces/driver configurable, for example to allow
|
||||
# use of Redfish instead of IPMI.
|
||||
- name: Set Ironic node resource class
|
||||
command: >-
|
||||
'{{ ironic_virtualenv_path }}/bin/openstack' baremetal node set
|
||||
'{{ created_node.uuid }}'
|
||||
--resource-class {{ node.type }}
|
||||
# --boot-interface pxe
|
||||
# --deploy-interface iscsi
|
||||
# --management-interface ipmitool
|
||||
# --network-interface neutron
|
||||
# --power-interface ipmitool
|
||||
|
||||
- name: Set additional Ironic port attributes
|
||||
include_tasks: port.yml
|
||||
vars:
|
||||
source_interface: "{{ vnic.split()[2] }}"
|
||||
mac: "{{ vnic.split()[4] }}"
|
||||
# Loop over each NIC.
|
||||
loop: "{{ iflist_res.stdout_lines[2:] }}"
|
||||
loop_control:
|
||||
loop_var: vnic
|
||||
|
||||
- name: Bring Ironic node out of maintenance mode
|
||||
command: >-
|
||||
'{{ ironic_virtualenv_path }}/bin/openstack' baremetal node maintenance
|
||||
unset '{{ created_node.uuid }}'
|
29
ansible/roles/ironic-enrolment/tasks/port.yml
Normal file
29
ansible/roles/ironic-enrolment/tasks/port.yml
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
- name: Get Ironic port UUID
|
||||
command: >-
|
||||
'{{ ironic_virtualenv_path }}/bin/openstack' baremetal port list
|
||||
--format value
|
||||
--column UUID
|
||||
--address {{ mac }}
|
||||
register: uuid
|
||||
changed_when: false
|
||||
|
||||
- name: Get physical network name
|
||||
set_fact:
|
||||
physnet: "{{ source_interface | source_link_to_physnet_name }}"
|
||||
|
||||
- name: Get bridge name
|
||||
set_fact:
|
||||
bridge: "{{ physnet | bridge_name }}"
|
||||
|
||||
- name: Set Ironic port attributes
|
||||
command: >-
|
||||
'{{ ironic_virtualenv_path }}/bin/openstack' baremetal port set
|
||||
{{ uuid.stdout }}
|
||||
--physical-network '{{ physnet }}'
|
||||
--local-link-connection switch_id='{{ hostvars[ironic_hypervisor][
|
||||
'ansible_' + bridge
|
||||
].macaddress }}'
|
||||
--local-link-connection switch_info='{{ bridge }}'
|
||||
--local-link-connection port_id='{{ source_interface
|
||||
| source_to_ovs_link_name }}'
|
Loading…
x
Reference in New Issue
Block a user