OpenStack Ansible Installation, Part 2

Networking on CentOS 7

Table of Contents

The OpenStack Ansible project includes examples for network configurations on Ubuntu, but not on CentOS. This is that journey.

Click here for this post’s git commit.

Preamble

I took the “Test” configuration examples, which use 3 nodes, and decided to build around that.

My first failed attempt was to use the nmcli Ansible module. At the time of writing, I encountered a number of issues with this module on CentOS 7 with kernel-3.10.0-862.el7.x86_64 and with NetworkManager-1.10.2-23.el7

The main problem is that it will not accept null values for variables that are not required.

In the interest of transparency, you can see my failed project here.

I used snippets of this code to help generate the ifcfg templates which I used in my actual solution.

Overview

Per OpenStack Ansible documentation, you need the following devices:

  • br-mgmt - For management, access to webUI
  • br-vxlan - For creating virtualized networks
  • br-vlan - For tagged and native traffic. MUST be assigned to physical device.
  • br-storage (optional) - for segregating storage traffic

It turned out USB3.0 Gigabit ethernet adapters that were confirmed to work under Linux were $14 apiece. I bought them so I could put br-mgmt on the native VLAN as well.

As it stands, br-mgmt (native) and br-storage (vlan) are on the internal NICs, and br-vlan (native) br-vxlan (vlan) are on the USB NICs.

osapreparenetwork
├── files
│   └── ifcfg-lo
├── tasks
│   └── main.yml
├── templates
│   ├── ifcfg-bridge.j2
│   ├── ifcfg-br-mgmt.j2
│   ├── ifcfg-netdev.j2
│   └── ifcfg-vlan.j2
└── vars
    └── main.yml

hostvars

I added a few hostvars for ease of use:

---
# infra.
netdev:
  - 'em1'
  - 'enp0s20u2'

# openstack-ansible
osa_deployhost: true
osa_host_id: 11

vars/main.yml

Since I began working on this before I got my adapters, I wanted to be able to quickly modify, and redeploy.

---
# Included for ease of testing
ifcfg_dir: /etc/sysconfig/network-scripts

# Load balancer IP, on infra br-mgmt iface
ext_vip_ip: 10.3.3.10

# Network block
osa_networks:
  - native: yes
    name: br-vlan
    device: "{{ netdev[1] }}"
    skip_network: true
  - native: yes
    name: br-mgmt
    device: "{{ netdev[0] }}"
    # network variable is the net prefix to be applied to hosts
    # actual network here is 10.3.2.0/23
    network: 10.3.3
    cidr_prefix: 23
    gw: 10.3.3.1
    dns:
      - 10.3.3.1
      - 172.98.193.42
  - vlan_id: 4
    name: br-vxlan
    device: "{{ netdev[1] }}"
    network: 10.3.4
    cidr_prefix: 24
    gw: 10.3.4.1
    dns:
      - 10.3.4.1
      - 172.98.193.42
  - vlan_id: 5
    name: br-storage
    device: "{{ netdev[0] }}"
    network: 10.3.5
    cidr_prefix: 24
    gw: 10.3.5.1
    dns:
      - 10.3.5.1
      - 172.98.193.42

tasks/main.yml

I’m leaving out the preamble, where I backup and delete the configs.

# easier than preserving the existing lo device
- name: install loopback device
  copy:
    src: ifcfg-lo
    dest: "{{ ifcfg_dir }}/ifcfg-lo"

- name: install netdevices file
  template:
    src: ifcfg-netdev.j2
    dest: "{{ ifcfg_dir }}/ifcfg-{{ item.device }}"
  with_items: "{{ osa_networks }}"
  when: item['native'] is defined

- name: install vlans
  template:
    src: "ifcfg-vlan.j2"
    dest: "{{ ifcfg_dir }}/ifcfg-{{ item.device }}.{{ item['vlan_id'] }}"
  with_items: "{{ osa_networks }}"
  when: item['vlan_id'] is defined

- name: install management bridge
  template:
    src: "ifcfg-br-mgmt.j2"
    dest: "{{ ifcfg_dir }}/ifcfg-br-mgmt"
  with_items: "{{ osa_networks }}"
  when: item['name'] == 'br-mgmt'

- name: other bridges
  template:
    src: "ifcfg-bridge.j2"
    dest: "{{ ifcfg_dir }}/ifcfg-{{ item.name }}"
  with_items: "{{ osa_networks }}"
  when: item['name'] != 'br-mgmt'

- name: disable NetworkManager
  systemd:
    name: NetworkManager
    state: stopped
    masked: yes
  ignore_errors: true

- name: restart network
  systemd:
    name: network
    state: restarted
    enabled: yes

templates/br-mgmt.j2

All of these look pretty similar. This is one of the more complex ones, and you can always check my project out.

NAME=br-mgmt
DEVICE=br-mgmt
UUID={{ inventory_hostname | password_hash('sha512') | to_uuid }}
TYPE=Bridge
STP=no
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=none
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
ONBOOT=yes
IPADDR={{ item.network }}.{{ osa_host_id }}
PREFIX={{ item.cidr_prefix }}
GATEWAY={{ item.gw }}
{% for object in item.dns %}
DNS{{loop.index}}={{ object }}
{% endfor %}
{% if osa_deployhost is defined %}
IPADDR2={{ ext_vip_ip }}
PREFIX2={{  item.cidr_prefix }}
{% endif %}

Conclusion

This worked pretty well. I did generate a single-NIC solution, and I was able to quickly and easily update the config when my NICs arrived.

Click here for this blog post’s git commit.