Adds new provider_networks module and reformats ml2_conf.ini

The ml2_conf.ini has been reformatted to work with the new data type
provided from the `provider_networks` module.

The new module parses and provides useful information from the
`provider_network` list as found within the base user config. The data
type has been documented within the defaults so that it can be used in
the role as stand alone, outside that of the OSAD project. The module
replaces functionality found in top of the ml2_conf.ini file that was
built using jinja2 syntax and flow control. The purpose is to allow
for more configuration possibilities while also being faster.

Closes-Bug: 1434942
Change-Id: If48267ba6f552eaf1535b8ecee6d26b2c6592b31
This commit is contained in:
Kevin Carter 2015-03-20 12:19:36 -05:00
parent caea202223
commit d31e0f69c2
4 changed files with 356 additions and 77 deletions

View File

@ -0,0 +1,280 @@
#!/usr/bin/python
# (c) 2014, Kevin Carter <kevin.carter@rackspace.com>
#
# Copyright 2014, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
DOCUMENTATION = """
---
module: provider_networks
version_added: "1.8.4"
short_description:
- Parse a list of networks and return data that Ansible can use
description:
- Parse a list of networks and return data that Ansible can use
options:
provider_networks:
description:
- List of networks to parse
required: true
is_metal:
description:
- Enable handling of on metal hosts
required: false
bind_prefix:
description:
- Add a prefix to all network interfaces.
required: false
author: Kevin Carter
"""
EXAMPLES = """
## This is what the provider_networks list should look like.
# provider_networks:
# - network:
# container_bridge: "br-mgmt"
# container_type: "veth"
# container_interface: "eth1"
# ip_from_q: "container"
# type: "raw"
# group_binds:
# - all_containers
# - hosts
# is_container_address: true
# is_ssh_address: true
# - network:
# container_bridge: "br-vxlan"
# container_type: "veth"
# container_interface: "eth10"
# ip_from_q: "tunnel"
# type: "vxlan"
# range: "1:1000"
# net_name: "vxlan"
# group_binds:
# - neutron_linuxbridge_agent
# - network:
# container_bridge: "br-vlan"
# container_type: "veth"
# container_interface: "eth12"
# host_bind_override: "eth12"
# type: "flat"
# net_name: "flat"
# group_binds:
# - neutron_linuxbridge_agent
# - network:
# container_bridge: "br-vlan"
# container_type: "veth"
# container_interface: "eth11"
# host_bind_override: "eth11"
# type: "vlan"
# range: "1:1, 101:101"
# net_name: "vlan"
# group_binds:
# - neutron_linuxbridge_agent
# - network:
# container_bridge: "br-storage"
# container_type: "veth"
# container_interface: "eth2"
# ip_from_q: "storage"
# type: "raw"
# group_binds:
# - glance_api
# - cinder_api
# - cinder_volume
# - nova_compute
# - swift_proxy
- name: Test provider networks
provider_networks:
provider_networks: "{{ provider_networks }}"
register: pndata1
- name: Test provider networks is metal
provider_networks:
provider_networks: "{{ provider_networks }}"
is_metal: true
register: pndata2
- name: Test provider networks with prfix
provider_networks:
provider_networks: "{{ provider_networks }}"
bind_prefix: "brx"
is_metal: true
register: pndata3
## Module output:
# {
# "network_flat_networks": "flat",
# "network_flat_networks_list": [
# "flat"
# ],
# "network_mappings": "flat:brx-eth12,vlan:brx-eth11",
# "network_mappings_list": [
# "flat:brx-eth12",
# "vlan:brx-eth11"
# ],
# "network_types": "vxlan,flat,vlan",
# "network_types_list": [
# "vxlan",
# "flat",
# "vlan"
# ],
# "network_vlan_ranges": "vlan:1:1,vlan:1024:1025",
# "network_vlan_ranges_list": [
# "vlan:1:1",
# "vlan:1024:1025"
# ],
# "network_vxlan_ranges": "1:1000",
# "network_vxlan_ranges_list": [
# "1:1000"
# ]
# }
"""
class ProviderNetworksParsing(object):
def __init__(self, module):
"""Generate an integer from a name.
:param module: Load the ansible module
:type module: ``object``
"""
self.module = module
self.network_vlan_ranges = list()
self.network_vxlan_ranges = list()
self.network_flat_networks = list()
self.network_mappings = list()
self.network_types = list()
def load_networks(self, provider_networks, is_metal=False,
bind_prefix=None):
"""Load the lists of network and network data types.
:param provider_networks: list of networks defined in user_config
:type provider_networks: ``list``
:param is_metal: Enable of disable handling of on metal nodes
:type is_metal: ``bol``
:param bind_prefix: Pre-interface prefix forced within the network map
:type bind_prefix: ``str``
"""
for net in provider_networks:
if net['network']['type'] == "vlan":
if "vlan" not in self.network_types:
self.network_types.append('vlan')
for vlan_range in net['network']['range'].split(','):
self.network_vlan_ranges.append(
'%s:%s' % (
net['network']['net_name'], vlan_range.strip()
)
)
elif net['network']['type'] == "vxlan":
if "vxlan" not in self.network_types:
self.network_types.append('vxlan')
self.network_vxlan_ranges.append(net['network']['range'])
elif net['network']['type'] == "flat":
if "flat" not in self.network_types:
self.network_types.append('flat')
self.network_flat_networks.append(
net['network']['net_name']
)
# Create the network mappings
if net['network']['type'] not in ['raw', 'vxlan']:
if 'net_name' in net['network']:
if is_metal:
if 'host_bind_override' in net['network']:
bind_device = net['network']['host_bind_override']
else:
bind_device = net['network']['container_bridge']
else:
bind_device = net['network']['container_interface']
if bind_prefix:
bind_device = '%s-%s' % (bind_prefix, bind_device)
self.network_mappings.append(
'%s:%s' % (
net['network']['net_name'],
bind_device
)
)
def main():
# Add in python True False
BOOLEANS.extend(['False', 'True'])
BOOLEANS_TRUE.append('True')
BOOLEANS_FALSE.append('False')
module = AnsibleModule(
argument_spec=dict(
provider_networks=dict(
type='list',
required=True
),
is_metal=dict(
choices=BOOLEANS,
default='false'
),
bind_prefix=dict(
type='str',
required=False,
default=None
)
),
supports_check_mode=False
)
try:
is_metal = module.params.get('is_metal')
if is_metal in BOOLEANS_TRUE:
module.params['is_metal'] = True
else:
module.params['is_metal'] = False
pnp = ProviderNetworksParsing(module=module)
pnp.load_networks(
provider_networks=module.params.get('provider_networks'),
is_metal=module.params.get('is_metal'),
bind_prefix=module.params.get('bind_prefix')
)
# Response dictionary, this adds commas to all list items in string
# format as well as preserves the list functionality for future data
# processing.
resp = {
'network_vlan_ranges': ','.join(pnp.network_vlan_ranges),
'network_vlan_ranges_list': pnp.network_vlan_ranges,
'network_vxlan_ranges': ','.join(pnp.network_vxlan_ranges),
'network_vxlan_ranges_list': pnp.network_vxlan_ranges,
'network_flat_networks': ','.join(pnp.network_flat_networks),
'network_flat_networks_list': pnp.network_flat_networks,
'network_mappings': ','.join(pnp.network_mappings),
'network_mappings_list': pnp.network_mappings,
'network_types': ','.join(pnp.network_types),
'network_types_list': pnp.network_types
}
module.exit_json(changed=True, **resp)
except Exception as exp:
resp = {'stderr': exp}
module.fail_json(msg='Failed Process', **resp)
# import module snippets
from ansible.module_utils.basic import *
if __name__ == '__main__':
main()

View File

@ -74,6 +74,22 @@
when: is_metal == true or is_metal == "True"
tags:
- neutron-logs
- name: Create the neutron provider networks facts
provider_networks:
provider_networks: "{{ provider_networks }}"
bind_prefix: "{{ bind_prefix }}"
is_metal: "{{ is_metal }}"
register: pndata
tags:
- neutron-provider-networks
- neutron-config
- name: Set provider network fact(s)
set_fact:
neutron_provider_networks: "{{ pndata }}"
neutron_overlay_network: "{{ container_networks.tunnel_address|default({}) }}"
tags:
- neutron-provider-networks
- neutron-config
roles:
- { role: "os_neutron", tags: [ "os-neutron" ] }
- { role: "openstack_openrc", tags: [ "openstack-openrc" ] }
@ -86,3 +102,4 @@
galera_address: "{{ internal_lb_vip_address }}"
ansible_hostname: "{{ container_name }}"
is_metal: "{{ properties.is_metal|default(false) }}"
bind_prefix: "{{ provider_network_bind_prefix|default('') }}"

View File

@ -54,6 +54,7 @@ neutron_driver_metering: neutron.services.metering.drivers.iptables.iptables_dri
neutron_driver_dhcp: neutron.agent.linux.dhcp.Dnsmasq
neutron_driver_notification: neutron.openstack.common.notifier.rpc_notifier
neutron_driver_quota: neutron.db.quota_db.DbQuotaDriver
neutron_driver_firewall: neutron.agent.linux.iptables_firewall.IptablesFirewallDriver
## General Neutron configuration
# If ``neutron_api_workers`` is unset the system will use half the number of available VCPUS to
@ -69,7 +70,6 @@ neutron_rpc_workers: 0
# neutron_metadata_workers: 16
neutron_metadata_backlog: 128
## Auth
neutron_service_tenant_name: service
neutron_service_role_name: admin
@ -115,6 +115,9 @@ neutron_service_metering_program_enabled: false
neutron_external_network_bridge: ""
neutron_gateway_external_network_id: ""
# Enable l2 population
neutron_l2_population: True
neutron_agent_mode: legacy
neutron_agent_down_time: 120
neutron_agent_polling_interval: 5
@ -145,6 +148,38 @@ neutron_dhcp_config:
dhcp-option-force: "26,1450"
log-facility: "/var/log/neutron/neutron-dnsmasq.log"
# Types of networks supported by the ml2 plugin
neutron_ml2_drivers_type: "flat,vlan,vxlan,local"
neutron_ml2_mechanism_drivers: "linuxbridge,l2population"
## Set this to configure overlay networks. The default is set as an empty hash.
# neutron_overlay_network:
# address: "172.29.241.248"
# bridge: "br-vxlan"
# interface: "eth10"
# netmask: "255.255.252.0"
# type: "veth"
neutron_overlay_network: {}
# Set the vxlan udp port. This is only used when neutron_tunnel_address is defined.
neutron_vxlan_udp_port: 4789
## The neutron multicast group address. This should be set as a host variable if used.
## This defaults to an empty string
# neutron_vxlan_group: 239.1.1.100
neutron_vxlan_group: ""
## Set this variable to configure the provider networks that will be available
## When setting up networking in things like the ml2_conf.ini file. Normally
## this will be defined as a host variable used within neutron as network configuration
## are likely to differ in between hosts.
# neutron_provider_networks:
# network_flat_networks: "flat"
# network_mappings: "flat:eth12,vlan:eth11"
# network_types: "vxlan,flat,vlan"
# network_vlan_ranges: "vlan:1:1,vlan:1024:1025"
# network_vxlan_ranges: "1:1000"
neutron_dhcp_domain: openstacklocal
neutron_dhcp_delete_namespaces: True
# Comma-separated list of DNS servers which will be used by dnsmasq as forwarders.

View File

@ -1,101 +1,46 @@
# {{ ansible_managed }}
{%- macro append(target_list, item) %}
{%- set _ = target_list.append(item) %}
{%- endmacro %}
{%- set network_vlan_ranges = [] %}
{%- set network_vxlan_ranges = [] %}
{%- set network_flat_networks = [] %}
{%- set network_mappings = [] %}
{%- set network_types = [] %}
{%- set used_interfaces = [] %}
{%- for net in provider_networks %}
{%- if net.network.type == "vlan" %}
{%- if "vlan" not in network_types %}
{{ append(network_types, "vlan") }}
{%- endif %}
{%- set vlan_pair = [] %}
{{ append(vlan_pair, net.network.net_name) }}
{{ append(vlan_pair, net.network.range) }}
{%- if vlan_pair|join(':') not in network_vlan_ranges%}
{{ append(network_vlan_ranges, vlan_pair|join(':')) }}
{%- endif %}
{%- elif net.network.type == "vxlan" %}
{%- if "vxlan" not in network_types %}
{{ append(network_types, "vxlan") }}
{%- endif %}
{%- if net.network.range not in network_vxlan_ranges %}
{{ append(network_vxlan_ranges, net.network.range) }}
{%- endif %}
{%- elif net.network.type == "flat" %}
{%- if "flat" not in network_types %}
{{ append(network_types, "flat") }}
{%- endif %}
{%- if net.network.net_name not in network_flat_networks %}
{{ append(network_flat_networks, net.network.net_name) }}
{%- endif %}
{%- endif %}
{% if net.network.type != 'raw' and net.network.type != 'vxlan' %}
{%- set map_pair = [] %}
{%- if 'net_name' in net.network %}
{{ append(map_pair, net.network.net_name) }}
{%- endif %}
{%- if is_metal == true or is_metal == "True" %}
{%- if net.network.host_bind_override is defined %}
{{ append(map_pair, net.network.host_bind_override) }}
{%- else %}
{{ append(map_pair, net.network.container_bridge) }}
{%- endif %}
{%- else %}
{{ append(map_pair, net.network.container_interface) }}
{%- endif %}
{%- if map_pair|join(':') not in network_mappings %}
{{ append(network_mappings, map_pair|join(':')) }}
{%- endif %}
{%- endif %}
{%- endfor %}
[ml2]
type_drivers = flat,vlan,vxlan,local
tenant_network_types = {{ network_types|join(',') }}
mechanism_drivers = linuxbridge,l2population
type_drivers = {{ neutron_ml2_drivers_type }}
tenant_network_types = {{ neutron_provider_networks.network_types }}
mechanism_drivers = {{ neutron_ml2_mechanism_drivers }}
{% if network_flat_networks %}
{% if neutron_provider_networks.network_flat_networks %}
[ml2_type_flat]
flat_networks = {{ network_flat_networks|join(',') }}
flat_networks = {{ neutron_provider_networks.network_flat_networks }}
{% endif %}
{% if network_vlan_ranges %}
{% if neutron_provider_networks.network_vlan_ranges %}
[ml2_type_vlan]
network_vlan_ranges = {{ network_vlan_ranges|join(',') }}
network_vlan_ranges = {{ neutron_provider_networks.network_vlan_ranges }}
[vlans]
tenant_network_type = vlan
network_vlan_ranges = {{ network_vlan_ranges|join(',') }}
network_vlan_ranges = {{ neutron_provider_networks.network_vlan_ranges }}
{% endif %}
{% if network_vxlan_ranges %}
{% if neutron_provider_networks.network_vxlan_ranges is defined %}
[ml2_type_vxlan]
vxlan_group = {{ neutron_vxlan_group|default('') }}
vni_ranges = {{ network_vxlan_ranges|join(',') }}
vni_ranges = {{ neutron_provider_networks.network_vxlan_ranges }}
{% endif %}
{% if container_networks.tunnel_address is defined %}
{% if neutron_overlay_network %}
[vxlan]
enable_vxlan = True
vxlan_group = {{ neutron_vxlan_group|default('') }}
{% if is_metal == true or is_metal == "True" %}
{% set on_metal_tunnel_bridge = 'ansible_' + container_networks.tunnel_address.bridge|replace('-', '_') %}
{% if (is_metal == true or is_metal == "True") and neutron_overlay_network.bridge is defined %}
{% set on_metal_tunnel_bridge = 'ansible_' + neutron_overlay_network.bridge|replace('-', '_') %}
local_ip = {{ hostvars[inventory_hostname][on_metal_tunnel_bridge]['ipv4']['address'] }}
{% else %}
local_ip = {{ container_networks.tunnel_address.address }}
local_ip = {{ neutron_overlay_network.address }}
{% endif %}
l2_population = True
{% endif %}
l2_population = {{ neutron_l2_population }}
{% endif %}
@ -105,19 +50,21 @@ tunnel_types = vxlan
# This is set for the vxlan port and while this
# is being set here it's ignored because
# the port is assigned by the kernel
vxlan_udp_port = 4789
vxlan_udp_port = {{ neutron_vxlan_udp_port }}
{% if network_mappings is defined %}
{% if neutron_provider_networks.network_mappings is defined %}
[linux_bridge]
physical_interface_mappings = {{ network_mappings|join(',') }}
physical_interface_mappings = {{ neutron_provider_networks.network_mappings }}
{% endif %}
[l2pop]
agent_boot_time = 180
[securitygroup]
enable_security_group = True
enable_ipset = True
firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver
firewall_driver = {{ neutron_driver_firewall }}