Add ansible playbook for configuring octavia

This patch adds ansible for creating resources required for octavia load
balancers in the overcloud and updating the octavia configuration. While
this can be used directly from the command line, it is intended to be
driven from heat via mistral workflow.

Change-Id: Ia4916e431bf241b92194773a4d55300c7230ebf9
This commit is contained in:
Or Idgar 2017-07-26 14:41:20 +00:00
parent 49d881a097
commit c7c66b9e93
23 changed files with 475 additions and 0 deletions

3
.gitignore vendored
View File

@ -54,3 +54,6 @@ ChangeLog
# Files created by releasenotes build
releasenotes/build
# Playbook retry files
*.retry

View File

@ -0,0 +1,82 @@
---
- hosts: undercloud[0]
remote_user: stack
gather_facts: False
environment:
OS_USERNAME: "{{ os_username }}"
OS_USER_DOMAIN_NAME: "Default"
OS_PROJECT_DOMAIN_NAME: "Default"
NOVA_VERSION: "1.1"
OS_PROJECT_NAME: "{{ os_project_name }}"
OS_PASSWORD: "{{ os_password }}"
COMPUTE_API_VERSION: "1.1"
OS_CLOUDNAME: "overcloud"
OS_AUTH_URL: "{{ os_auth_url }}"
OS_IDENTITY_API_VERSION: "{{ os_identity_api_version }}"
OS_IMAGE_API_VERSION: "2"
OS_AUTH_TYPE: "{{ os_auth_type }}"
roles:
- octavia-undercloud
- hosts: octavia_nodes[0]
gather_facts: True
vars:
generate_certs: "{{ generate_certs }}"
octavia_confd_prefix: "/var/lib/config-data/puppet-generated/octavia"
openssl_temp_dir: "/tmp/octavia-ssl"
ca_cert_path: "{{ ca_cert_path }}"
ca_private_key_path: "{{ ca_private_key_path }}"
ca_passphrase: "{{ ca_passphrase }}"
client_cert_path: "{{ client_cert_path }}"
environment:
OS_USERNAME: "{{ os_username }}"
OS_USER_DOMAIN_NAME: "Default"
OS_PROJECT_DOMAIN_NAME: "Default"
NOVA_VERSION: "1.1"
OS_PROJECT_NAME: "{{ os_project_name }}"
OS_PASSWORD: "{{ os_password }}"
COMPUTE_API_VERSION: "1.1"
OS_CLOUDNAME: "overcloud"
OS_AUTH_URL: "{{ os_auth_url }}"
OS_IDENTITY_API_VERSION: "{{ os_identity_api_version }}"
OS_IMAGE_API_VERSION: "2"
OS_AUTH_TYPE: "{{ os_auth_type }}"
roles:
- octavia-overcloud-config
- hosts: octavia_nodes
gather_facts: True
vars:
octavia_confd_prefix: "/var/lib/config-data/puppet-generated/octavia"
lb_mgmt_net_id: "{{ hostvars[groups['octavia_nodes'][0]]['lb_mgmt_net_id'] }}"
lb_mgmt_secgroup_id: "{{ hostvars[groups['octavia_nodes'][0]]['lb_mgmt_secgroup_id'] }}"
private_key_content: "{{ hostvars[groups['octavia_nodes'][0]]['private_key_content'] }}"
ca_cert_content: "{{ hostvars[groups['octavia_nodes'][0]]['ca_cert_content'] }}"
service_pem_content: "{{ hostvars[groups['octavia_nodes'][0]]['service_pem_content'] }}"
generate_certs: "{{ generate_certs }}"
ca_cert_path: "{{ ca_cert_path }}"
ca_private_key_path: "{{ ca_private_key_path }}"
ca_passphrase: "{{ ca_passphrase }}"
client_cert_path: "{{ client_cert_path }}"
environment:
OS_USERNAME: "{{ os_username }}"
OS_USER_DOMAIN_NAME: "Default"
OS_PROJECT_DOMAIN_NAME: "Default"
NOVA_VERSION: "1.1"
OS_PROJECT_NAME: "{{ os_project_name }}"
OS_PASSWORD: "{{ os_password }}"
COMPUTE_API_VERSION: "1.1"
OS_CLOUDNAME: "overcloud"
OS_AUTH_URL: "{{ os_auth_url }}"
OS_IDENTITY_API_VERSION: "{{ os_identity_api_version }}"
OS_IMAGE_API_VERSION: "2"
OS_AUTH_TYPE: "{{ os_auth_type }}"
roles:
- octavia-controller-config
- hosts: octavia_nodes
gather_facts: True
vars:
octavia_confd_prefix: "/var/lib/config-data/puppet-generated/octavia"
roles:
- octavia-controller-post-config

View File

@ -0,0 +1,13 @@
---
amp_image_name: "octavia-amphora"
amp_image_filename: "/usr/share/openstack-octavia-amphora-images/amphora-x64-haproxy.qcow2"
amp_image_tag: "amphora-image"
lb_mgmt_net_name: "lb-mgmt-net"
lb_mgmt_subnet_name: "lb-mgmt-subnet"
lb_mgmt_subnet_cidr: "192.168.199.0/24"
lb_mgmt_subnet_gateway: "192.168.199.1"
lb_mgmt_subnet_pool_start: "192.168.199.50"
lb_mgmt_subnet_pool_end: "192.168.199.200"
lb_mgmt_sec_grp_name: "lb-mgmt-sec-grp"
lb_health_mgr_sec_grp_name: "lb-health-mgr-sec-grp"
mgmt_port_dev: "o-hm0"

View File

@ -0,0 +1,5 @@
---
- name: octavia config updated
set_fact:
octavia_config_updated: true

View File

@ -0,0 +1,2 @@
dependencies:
- common

View File

@ -0,0 +1,15 @@
---
- name: making sure octavia worker configuration directory exists
file: path="{{ octavia_confd_prefix }}{{ ca_private_key_path | dirname }}" state=directory
become: true
- name: Copying ca private key to octavia
become: true
copy: content="{{ private_key_content }}" dest="{{ octavia_confd_prefix }}{{ ca_private_key_path }}"
- name: copying ca certificate to octavia
become: true
copy: content="{{ ca_cert_content }}" dest="{{ octavia_confd_prefix }}{{ ca_cert_path }}"
- name: Create pem file with service private key & public certificate
become: true
copy: content="{{ service_pem_content }}" dest="{{ octavia_confd_prefix }}{{ client_cert_path }}"
notify:
- octavia config updated

View File

@ -0,0 +1,15 @@
---
- name: gathering controller host name
command: "hostname -f"
register: hostname
changed_when: False
- set_fact:
node_hostname: "{{ hostname.stdout }}"
- include_tasks: certificate.yml
when: generate_certs
- include_tasks: netport.yml
- include_tasks: netinterface.yml
- include_tasks: octavia.yml
- name: making sure octavia common configuration directory exists
file: path="{{ octavia_confd_prefix }}/etc/octavia/conf.d/common" state=directory
become: true

View File

@ -0,0 +1,20 @@
---
- name: create br-int interface file
become: true
become_user: root
template:
dest: "/etc/sysconfig/network-scripts/ifcfg-br-int"
src: "ifcfg-br-int.j2"
force: no
- name: create octavia management interface
become: true
become_user: root
template:
dest: "/etc/sysconfig/network-scripts/ifcfg-{{ mgmt_port_dev }}"
src: "ifcfg.j2"
- name: Bring the management port interface up
become: true
become_user: root
command: "ifup {{ mgmt_port_dev }}"
notify:
- octavia config updated

View File

@ -0,0 +1,57 @@
---
- name: create management port
shell: |
port_id=$(openstack port show octavia-health-manager-{{ node_hostname }}-listen-port -f value -c id 2> /dev/null)
if [[ $port_id == "" ]]; then
neutron port-create {{ lb_mgmt_net_name }} --binding:host_id={{ node_hostname }} --no-security-groups --port-security-enabled=False --device-owner Octavia:health-mgr \
--name octavia-health-manager-{{ node_hostname }}-listen-port -f value -c id
fi
register: out_mgmt_port
changed_when: "out_mgmt_port.stdout != ''"
notify:
- octavia config updated
- name: getting management port
shell: |
openstack port show octavia-health-manager-{{ node_hostname }}-listen-port -f value -c id
register: out_mgmt_port_id
changed_when: False
- name: setting fact for management network controller port ID
set_fact:
mgmt_port_id: "{{ out_mgmt_port_id.stdout }}"
- name: get management port mac
shell: |
openstack port show {{ mgmt_port_id }} -f value -c mac_address
register: out_mgmt_port_mac
changed_when: False
- name: setting fact for management network controller port MAC
set_fact:
mgmt_port_mac: "{{ out_mgmt_port_mac.stdout }}"
- name: get management port ip
shell: |
openstack port show {{ mgmt_port_id }} -f value -c fixed_ips | cut -f1 -d, | cut -f2 -d= | tr -d "'"
register: out_mgmt_port_ip
changed_when: False
- name: setting fact for management network controller port IP
set_fact:
mgmt_port_ip: "{{ out_mgmt_port_ip.stdout }}"
- name: get management port net mask
shell: |
subnet_id=$(openstack port show {{ mgmt_port_id }} -f value -c fixed_ips | cut -f2 -d, | cut -f2 -d= | tr -d "'" 2> /dev/null)
openstack subnet show $subnet_id -f value -c cidr 2> /dev/null
register: out_mgmt_subnet_cidr
- name: setting fact for management subnet cidr
set_fact:
mgmt_subnet_cidr: "{{ out_mgmt_subnet_cidr.stdout }}"
- name: setting fact for management network netmask
set_fact:
mgmt_port_netmask: "{{ mgmt_subnet_cidr | ipaddr('netmask') }}"
- name: get MTU for managment port
shell: |
openstack network show {{ lb_mgmt_net_name }} -f value -c mtu
register: out_mgmt_port_mtu
- name: setting fact for management port MTU
set_fact:
mgmt_port_mtu: "{{ out_mgmt_port_mtu.stdout }}"
- name: creating fact for management network health manager controller IP
set_fact:
o_hm_ip: "{{ mgmt_port_ip }}:5555"

View File

@ -0,0 +1,19 @@
---
- name: making sure octavia worker configuration directory exists
file: path="{{ octavia_confd_prefix }}/etc/octavia/conf.d/octavia-worker" state=directory
become: true
- name: create octavia worker post deploy configuration file
become: true
become_user: root
template:
dest: "{{ octavia_confd_prefix }}/etc/octavia/conf.d/octavia-worker/worker-post-deploy.conf"
src: "worker-post-deploy.conf.j2"
- name: making sure octavia worker configuration directory exists
file: path="{{octavia_confd_prefix}}/etc/octavia/conf.d/octavia-health-manager" state=directory
become: true
- name: create octavia health manager configuration file
become: true
become_user: root
template:
dest: "{{octavia_confd_prefix}}/etc/octavia/conf.d/octavia-health-manager/manager-post-deploy.conf"
src: "manager-post-deploy.conf.j2"

View File

@ -0,0 +1,6 @@
DEVICETYPE=ovs
TYPE=OVSBridge
BOOTPROTO=none
DEVICE=br-int
NM_CONTROLLED=no
ONBOOT=yes

View File

@ -0,0 +1,19 @@
TYPE=OVSIntPort
OVS_BRIDGE=br-int
DEVICETYPE=ovs
BOOTPROTO=static
IPV6_AUTOCONF=no
DEVICE={{ mgmt_port_dev }}
IPADDR={{ mgmt_port_ip }}
NETMASK={{ mgmt_port_netmask }}
NM_CONTROLLED=no
MACADDR={{ mgmt_port_mac }}
MTU={{ mgmt_port_mtu }}
OVS_EXTRA="-- set Interface {{ mgmt_port_dev }} external-ids:iface-status=active \
-- set Interface {{ mgmt_port_dev }} external-ids:attached-mac={{ mgmt_port_mac }} \
-- set Interface {{ mgmt_port_dev }} external-ids:iface-id={{mgmt_port_id }} \
-- set Interface {{ mgmt_port_dev }} external-ids:skip_cleanup=true \
-- set Interface {{ mgmt_port_dev }} mac=\"{{ mgmt_port_mac }}\" \
-- set Interface {{ mgmt_port_dev }} other-config:hwaddr={{ mgmt_port_mac }}"
ONBOOT=yes

View File

@ -0,0 +1,2 @@
[health_manager]
bind_ip = {{ mgmt_port_ip }}

View File

@ -0,0 +1,4 @@
[controller_worker]
amp_boot_network_list = {{ lb_mgmt_net_id }}
amp_secgroup_list = {{ lb_mgmt_secgroup_id }}

View File

@ -0,0 +1 @@
octavia_config_updated: no

View File

@ -0,0 +1,2 @@
dependencies:
- common

View File

@ -0,0 +1,44 @@
- debug:
msg: "Octavia services will be restarted because of updated configuration"
when: octavia_config_updated
- name: create ip list
set_fact:
o_hm_ip_list: "{% for octavia_node in groups['octavia_nodes'] %}{{ hostvars[octavia_node].o_hm_ip }}, {%endfor%}"
- set_fact:
o_hm_ip_list: "{{ o_hm_ip_list[:-2] }}" #remove the last two characters
- name: read the current IP list
become: true
become_user: root
shell: |
crudini --get "{{octavia_confd_prefix}}/etc/octavia/conf.d/octavia-health-manager/manager-post-deploy.conf" health_manager controller_ip_port_list
register: config_contents
failed_when: config_contents.rc != 0 and 'Parameter not found' not in config_contents.stderr
changed_when: false
ignore_errors: true
- name: retrieve current ip list
set_fact:
current_ip_list: "{{config_contents.stdout}}"
# This isn't perfect as they execution order will make them not match, but we can avoid a restart
# if things have stayed the same.
- name: check if ip list needs updating
set_fact:
octavia_config_updated: true
when: current_ip_list != o_hm_ip_list
- name: update octavia health manager config file
become: true
become_user: root
ini_file:
section: "health_manager"
option: "controller_ip_port_list"
value: "{{ o_hm_ip_list }}"
path: "{{octavia_confd_prefix}}/etc/octavia/conf.d/octavia-health-manager/manager-post-deploy.conf"
when: octavia_config_updated
- name: restart octavia containers
become: true
become_user: root
shell: "docker restart $(sudo docker ps -f name=octavia -q)"
when: octavia_config_updated

View File

@ -0,0 +1,2 @@
dependencies:
- common

View File

@ -0,0 +1,72 @@
---
- name: delete temporary ssl directory
become: true
file: path={{ openssl_temp_dir }} state=absent
- name: create temporary ssl directories
become: true
file: path={{ openssl_temp_dir }}/private recurse=yes
- name: create temporary ssl newcerts directory
become: true
file: path={{ openssl_temp_dir }}/newcerts recurse=yes
- name: create index.txt
become: true
copy: content="" dest={{ openssl_temp_dir }}/index.txt force=no
- name: create serial file
become: true
copy: content="01" dest={{ openssl_temp_dir }}/serial
- name: create openssl configuration file from template
become: true
copy: src="/etc/pki/tls/openssl.cnf" dest="{{ openssl_temp_dir }}/openssl.cnf" remote_src=yes
- name: update openssl directory entry in the configuration file
become: true
ini_file: path="{{ openssl_temp_dir }}/openssl.cnf" section=" CA_default " option="dir" value="{{ openssl_temp_dir }}"
- name: update openssl ca certificate file in the configuration file
become: true
replace: path="{{ openssl_temp_dir }}/openssl.cnf" regexp="cacert.pem" replace="ca_01.pem"
- name: Generating certificate authority private key
become: true
shell: |
openssl genrsa -passout pass:{{ ca_passphrase }} -des3 -out {{ openssl_temp_dir }}/private/cakey.pem 2048
- name: Reading private key
become: true
shell: cat {{ openssl_temp_dir }}/private/cakey.pem
register: private_key_data
- name: Setting private key fact
set_fact:
private_key_content: "{{ private_key_data.stdout }}"
- name: Generating certificate authority certificate
become: true
shell: |
openssl req -x509 -passin pass:{{ ca_passphrase }} -new -nodes -key {{ openssl_temp_dir }}/private/cakey.pem \
-subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" \
-days 365 -config {{ openssl_temp_dir }}/openssl.cnf \
-out {{ openssl_temp_dir }}/ca_01.pem
- name: Reading CA certificate
become: true
shell: cat {{ openssl_temp_dir }}/ca_01.pem
register: ca_cert_data
- name: Setting CA certificate fact
set_fact:
ca_cert_content: "{{ ca_cert_data.stdout }}"
- name: Generating service private key & certificate request
become: true
shell: |
openssl req -newkey rsa:2048 -nodes -config {{ openssl_temp_dir }}/openssl.cnf -keyout {{ openssl_temp_dir }}/client.key \
-subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" \
-out {{ openssl_temp_dir }}/client.csr
- name: Signing service certificate request
become: true
shell: |
openssl ca -config {{ openssl_temp_dir }}/openssl.cnf -passin pass:{{ ca_passphrase }} -in {{ openssl_temp_dir }}/client.csr \
-days 365 -out {{ openssl_temp_dir }}/client-.pem -batch
- name: Read service private key and public certifcate
become: true
shell: |
cat {{ openssl_temp_dir }}/client-.pem {{ openssl_temp_dir }}/client.key
register: service_key_data
- name: Set service key fact
set_fact:
service_pem_content: "{{ service_key_data.stdout }}"

View File

@ -0,0 +1,5 @@
---
# Previously was a stack in the overcloud
- include_tasks: network.yml
- include_tasks: certs_gen.yml
when: generate_certs

View File

@ -0,0 +1,70 @@
---
- name: create management network for load balancers
shell: |
if [[ $(openstack network show {{ lb_mgmt_net_name }} > /dev/null; echo $?) -eq 1 ]]; then
openstack network create -f value -c id {{ lb_mgmt_net_name }}
fi
register: out_lb_mgmt_net
changed_when: "out_lb_mgmt_net.stdout != ''"
- name: getting management network ID
shell: |
openstack network show {{ lb_mgmt_net_name }} -f value -c id
register: out_lb_mgmt_net_id
changed_when: False
- name: setting management network ID fact
set_fact:
lb_mgmt_net_id: "{{ out_lb_mgmt_net_id.stdout }}"
- name: create subnet
shell: |
if [[ $(openstack subnet show {{ lb_mgmt_subnet_name }} > /dev/null; echo $?) -eq 1 ]]; then
openstack subnet create {{ lb_mgmt_subnet_name }} \
--allocation-pool=start={{ lb_mgmt_subnet_pool_start }},end={{ lb_mgmt_subnet_pool_end }} \
--gateway={{ lb_mgmt_subnet_gateway }} \
--network {{ lb_mgmt_net_id }} \
--subnet-range {{ lb_mgmt_subnet_cidr }}
fi
register: lb_mgmt_subnet_result
changed_when: "lb_mgmt_subnet_result.stdout != ''"
- name: create security group #get the security group id
shell: |
if [[ $(openstack security group show {{ lb_mgmt_sec_grp_name }} > /dev/null; echo $?) -eq 1 ]]; then
openstack security group create --project service --project-domain Default {{ lb_mgmt_sec_grp_name }} -f value -c id
else
openstack security group show {{ lb_mgmt_sec_grp_name }} -f value -c id
fi
register: lb_mgmt_secgroup_result
changed_when: "lb_mgmt_secgroup_result.stdout != ''"
- name: setting fact for management network security group
set_fact:
lb_mgmt_secgroup_id: "{{ lb_mgmt_secgroup_result.stdout }}"
- name: create security group rule to open amphora management ssh port
shell: |
if [[ $(openstack security group rule list {{ lb_mgmt_sec_grp_name }} --protocol tcp --ingress -f value 2>&1 | grep "0.0.0.0/0 22:22") == "" ]]; then
openstack security group rule create --protocol tcp --dst-port 22 {{ lb_mgmt_sec_grp_name }}
fi
register: sec_group_rule_one
changed_when: "sec_group_rule_one.stdout != ''"
- name: create security group rule to open amphora management API port
shell: |
if [[ $(openstack security group rule list {{ lb_mgmt_sec_grp_name }} --protocol tcp --ingress -f value 2>&1 | grep "0.0.0.0/0 9443:9443") == "" ]]; then
openstack security group rule create --protocol tcp --dst-port 9443 {{ lb_mgmt_sec_grp_name }}
fi
register: sec_group_rule_two
changed_when: "sec_group_rule_two.stdout != ''"
- name: create security group for health manager
shell: |
if [[ $(openstack security group show {{ lb_health_mgr_sec_grp_name }} > /dev/null; echo $?) -eq 1 ]]; then
openstack security group create --project service --project-domain Default {{ lb_health_mgr_sec_grp_name }} -f value -c id
else
openstack security group show {{ lb_health_mgr_sec_grp_name }} -f value -c id
fi
register: lb_health_manager_sec_grp_result
changed_when: "lb_health_manager_sec_grp_result.stdout != ''"
- name: create security group rule for health manager
shell: |
if [[ $(openstack security group rule list {{ lb_health_mgr_sec_grp_name }} --protocol udp --ingress -f value 2>&1 | grep "0.0.0.0/0 5555:5555") == "" ]]; then
openstack security group rule create --protocol udp --dst-port 5555 {{ lb_health_mgr_sec_grp_name }}
fi
register: health_mgr_sec_grp_rule
changed_when: "health_mgr_sec_grp_rule.stdout != ''"

View File

@ -0,0 +1,2 @@
dependencies:
- common

View File

@ -0,0 +1,15 @@
---
- name: check if amphora image file exists
stat:
path: "{{ amp_image_filename }}"
register: amp_image_file_result
- name: upload image to glance
shell: |
if [[ $(openstack image show {{ amp_image_name }} > /dev/null; echo $?) -eq 1 ]]; then
glance image-create --name {{ amp_image_name }} --disk-format qcow2 \
--container-format bare --tags {{ amp_image_tag }} --file {{ amp_image_filename }}
fi
register: image_result
changed_when: "image_result.stdout != ''"
when: amp_image_file_result.stat.exists == True