diff --git a/playbooks/library/provider_networks b/playbooks/library/provider_networks new file mode 100644 index 0000000000..f55c9ec292 --- /dev/null +++ b/playbooks/library/provider_networks @@ -0,0 +1,280 @@ +#!/usr/bin/python +# (c) 2014, Kevin Carter +# +# 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() diff --git a/playbooks/os-neutron-install.yml b/playbooks/os-neutron-install.yml index b842837e46..a6350ed24a 100644 --- a/playbooks/os-neutron-install.yml +++ b/playbooks/os-neutron-install.yml @@ -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('') }}" diff --git a/playbooks/roles/os_neutron/defaults/main.yml b/playbooks/roles/os_neutron/defaults/main.yml index 01d86dc896..2240c2c27c 100644 --- a/playbooks/roles/os_neutron/defaults/main.yml +++ b/playbooks/roles/os_neutron/defaults/main.yml @@ -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. diff --git a/playbooks/roles/os_neutron/templates/plugins/ml2/ml2_conf.ini.j2 b/playbooks/roles/os_neutron/templates/plugins/ml2/ml2_conf.ini.j2 index d5dfd34a2a..0acb5fcc64 100644 --- a/playbooks/roles/os_neutron/templates/plugins/ml2/ml2_conf.ini.j2 +++ b/playbooks/roles/os_neutron/templates/plugins/ml2/ml2_conf.ini.j2 @@ -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 }} +