Add initial host setup

Set up the basic Ansible directory structure, and add the logic to
connect up the physical networks.
This commit is contained in:
Will Miller 2018-08-17 16:58:28 +00:00
parent 80ff2d9c88
commit 72a17aabd1
7 changed files with 229 additions and 0 deletions

5
.gitignore vendored
View File

@ -1,3 +1,8 @@
# All dot-files
.*
# Ansible retry files
*.retry
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

41
ansible/group_vars/all Normal file
View File

@ -0,0 +1,41 @@
---
# Map physical network names to their source device. This can be either an
# existing interface or an existing bridge.
physnet_mappings: {}
virtualisation_provider: libvirt
system_requirements:
- python-pip
- python-virtualenv
# Path to virtualenv used to install Python requirements. If a virtualenv does
# not exist at this location, one will be created.
virtualenv_path: ~/tenks-venv
python_requirements:
- virtualbmc
# Naming scheme for bridges created by tenks for physical networks is
# {{ bridge_prefix + i }}, where `i` is the index of the physical network in
# physnet_mappings (sorted alphabetically by key).
bridge_prefix: brtenks
# Naming scheme for veth pairs connected to the Tenks OVS bridge.
veth_prefix: p-
# Used for the port on the Tenks OVS bridge.
veth_tenks_suffix: "-ovs"
# Used for the port on the existing bridge.
veth_source_suffix: "-phy"
libvirt_pool_name: tenks
libvirt_pool_path: /var/lib/libvirt/tenks_pool/
libvirt_pool_type: dir
# Capacity is irrelevant for directory-based pools.
libvirt_pool_capacity:
libvirt_pool_mode: 755
libvirt_pool_owner: "{ remote_user }}"
libvirt_pool_group: "{ remote_user }}"
# By default, allow QEMU without hardware virtualisation since this is a
# development tool.
libvirt_require_vt: false

View File

@ -0,0 +1,13 @@
---
libvirt_pool_name: tenks
libvirt_pool_path: /var/lib/libvirt/tenks_pool/
libvirt_pool_type: dir
# Capacity is irrelevant for directory-based pools.
libvirt_pool_capacity:
libvirt_pool_mode: 755
libvirt_pool_owner: "{{ ansible_user_id }}"
libvirt_pool_group: "{{ ansible_user_id }}"
# By default, allow QEMU without hardware virtualisation since this is a
# development tool.
libvirt_require_vt: false

44
ansible/host_setup.yml Normal file
View File

@ -0,0 +1,44 @@
---
- name: Ensure general system requirements are installed
yum:
name: "{{ system_requirements }}"
become: true
- name: Check if ovs-vsctl command is present
shell: ovs-vsctl --version
register: ovs_vsctl_check
failed_when: false
changed_when: false
- block:
- name: Ensure Open vSwitch package is installed
yum:
name: openvswitch
become: true
- name: Ensure Open vSwitch is started and enabled
service:
name: openvswitch
state: running
enabled: true
become: true
# Return code 127 means the command does not exist. Do this check to avoid
# installing Open vSwitch system-wide if the command already exists as a link
# to a containerised version of OVS.
when: ovs_vsctl_check.rc == 127
- name: Configure physical network
include_tasks: physical_network.yml
vars:
network_name: "{{ item.0 }}"
tenks_bridge: "{{ bridge_prefix ~ idx }}"
source_interface: "{{ item.1 }}"
# Sort to ensure we always enumerate in the same order.
loop: "{{ physnet_mappings | dictsort }}"
loop_control:
index_var: idx
- name: Ensure Python requirements are installed
pip:
name: "{{ python_requirements }}"
virtualenv: "{{ virtualenv_path }}"

20
ansible/main.yml Normal file
View File

@ -0,0 +1,20 @@
---
- hosts: all
tasks:
- include_tasks: host_setup.yml
- hosts: libvirt
tasks:
- name: Configure host as a Libvirt/QEMU/KVM hypervisor
include_role:
name: stackhpc.libvirt-host
vars:
libvirt_host_pools:
- name: "{{ libvirt_pool_name }}"
type: "{{ libvirt_pool_type }}"
capacity: "{{ libvirt_pool_capacity }}"
path: "{{ libvirt_pool_path }}"
mode: "{{ libvirt_pool_mode }}"
owner: "{{ libvirt_pool_owner }}"
group: "{{ libvirt_pool_group }}"
libvirt_host_require_vt: "{{ libvirt_require_vt }}"

View File

@ -0,0 +1,103 @@
---
- name: Fail if source interface does not exist
fail:
msg: >
The interface {{ source_interface }} specified for the physical network
{{ network_name }} does not exist.
when: source_interface not in ansible_interfaces
### Firstly, some fact gathering.
# Start off by assuming the source interface is direct, unless proven
# otherwise.
- set_fact:
source_type: 'direct'
- name: Get source interface details
command: ip -details link show {{ source_interface }}
register: if_details
changed_when: false
- name: Register source interface as a Linux bridge
set_fact:
source_type: linux_bridge
when: if_details.stdout_lines[-1].split()[0] == 'bridge'
- block:
- name: Get list of OVS bridges
command: ovs-vsctl list-br
register: ovs_bridges
changed_when: false
- name: Register source interface as an Open vSwitch bridge
set_fact:
source_type: ovs_bridge
when: source_interface in ovs_bridges.stdout_lines
when: if_details.stdout_lines[-1].split()[0] == 'openvswitch'
### Actual configuration starts here.
- name: Ensure Open vSwitch bridge exists
openvswitch_bridge:
bridge: "{{ tenks_bridge }}"
- name: Connect to existing Linux bridge
when: source_type == 'linux_bridge'
block:
- name: Create veth pair
command: >
ip link add dev {{ veth_prefix + tenks_bridge + veth_tenks_suffix }}
type veth
peer name {{ veth_prefix + tenks_bridge + veth_source_suffix }}
register: res
changed_when: res.rc == 0
# Return code 2 means the veth pair already exists
failed_when: res.rc not in [0, 2]
become: true
- name: Plug veth into Tenks bridge
openvswitch_port:
bridge: "{{ tenks_bridge }}"
port: "{{ veth_prefix + tenks_bridge + veth_tenks_suffix }}"
- name: Plug veth into source interface
command: >
brctl addif {{ source_interface }}
{{ veth_prefix + tenks_bridge + veth_source_suffix }}
register: res
failed_when:
- res.rc != 0
- "'already a member of a bridge' not in res.stderr"
changed_when: "'already a member of a bridge' not in res.stderr"
become: true
- name: Connect to existing Open vSwitch bridge
when: source_type == 'ovs_bridge'
block:
- name: Create patch port on Tenks bridge
openvswitch_port:
bridge: "{{ tenks_bridge }}"
port: "{{ veth_prefix + tenks_bridge + veth_tenks_suffix }}"
# Despite the module documentation, `set` will happily take multiple
# properties.
set: >
Interface {{ veth_prefix + tenks_bridge + veth_tenks_suffix }}
type=patch
options:peer={{ veth_prefix + tenks_bridge + veth_source_suffix }}
- name: Create patch port on source bridge
openvswitch_port:
bridge: "{{ source_interface }}"
port: "{{ veth_prefix + tenks_bridge + veth_source_suffix }}"
set: >
Interface {{ veth_prefix + tenks_bridge + veth_source_suffix }}
type=patch
options:peer={{ veth_prefix + tenks_bridge + veth_tenks_suffix }}
when: if_details.stdout_lines[-1].split()[0] == 'openvswitch'
- name: Plug source interface into Tenks bridge
when: source_type == 'direct'
openvswitch_port:
bridge: "{{ tenks_bridge }}"
port: "{{ source_interface }}"

3
requirements.yml Normal file
View File

@ -0,0 +1,3 @@
---
src: stackhpc.libvirt-host
src: stackhpc.libvirt-vm