openstack-ansible-os_neutron/library/provider_networks
James Denton 98b3af136a Make VLAN ranges option when defining provider networks
The provider_network library expects VLAN ranges to be defined within
the provider network definition. In cases where this was not desired,
operators would set dummy ranges (i.e. 1:1) to work around this requirement.
The changes introduced in this patch make 'range' optional.

Change-Id: I0ab1720e5abd74dccf121e8bc075e55d9fbce6e1
2020-12-05 10:05:54 +00:00

381 lines
13 KiB
Python

#!/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.
# import module snippets
from ansible.module_utils.basic import AnsibleModule
DOCUMENTATION = """
---
module: provider_networks
version_added: "1.8.6"
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-vxlan"
# container_type: "veth"
# container_interface: "eth10"
# ip_from_q: "tunnel"
# type: "geneve"
# range: "1:1000"
# net_name: "geneve"
# group_binds:
# - neutron_ovn_northd
# - neutron_ovn_controller
# - 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"
# sriov_host_interfaces: "p1p1,p1p2"
# type: "vlan"
# range: "1:1, 101:101"
# net_name: "vlan"
# group_binds:
# - neutron_linuxbridge_agent
# - network:
# host_bind_override: "bond1"
# type: "vlan"
# net_name: "physnet1"
# group_binds:
# - neutron_linuxbridge_agent
# - network:
# container_bridge: "br-provider"
# container_type: "veth"
# container_interface: "eth11"
# network_interface: "bond1"
# type: "vlan"
# range: "1:1, 101:101"
# net_name: "physnet1"
# group_binds:
# - neutron_openvswitch_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_sriov_mappings": "physnet1:p1p1,physnet1:p1p2",
# "network_sriov_mappings_list": [
# "physnet1:p1p1"
# "physnet1:p1p2"
# ],
# "network_types": "vxlan,flat,vlan,geneve",
# "network_types_list": [
# "vxlan",
# "flat",
# "vlan",
# "geneve"
# ],
# "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"
# ]
# "network_geneve_ranges": "1:1000",
# "network_geneve_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_geneve_ranges = list()
self.network_flat_networks = list()
self.network_mappings = list()
self.network_types = list()
self.network_sriov_mappings = list()
self.network_interface_mappings = list()
def load_networks(self, provider_networks, is_metal=False,
bind_prefix=None, group_names=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``
:param group_names: list of groups associated with node
:type group_names: ``list``
"""
for net in provider_networks:
if net['network']['type'] == "vlan":
if (
set(
net["network"]["group_binds"]
).intersection(group_names)
or "neutron_server" in group_names # noqa W503
):
if "vlan" not in self.network_types:
self.network_types.append('vlan')
if "range" in net['network']:
for vlan_range in net['network']['range'].split(','):
self.network_vlan_ranges.append(
'%s:%s' % (
net['network']['net_name'],
vlan_range.strip()
)
)
else:
self.network_vlan_ranges.append(
net['network']['net_name']
)
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'] == "geneve":
if "geneve" not in self.network_types:
self.network_types.append('geneve')
self.network_geneve_ranges.append(net['network']['range'])
elif net['network']['type'] == "flat":
if (
set(
net["network"]["group_binds"]
).intersection(group_names)
or "neutron_server" in group_names # noqa W503
):
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', 'geneve']:
if (
set(
net["network"]["group_binds"]
).intersection(group_names)
):
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
)
)
# Builds a list of provider bridge to physical
# interface mappings and is used when adding OVS
# ports to bridges
if 'network_interface' in net['network']:
self.network_interface_mappings.append(
'%s:%s' % (
net['network']['container_bridge'],
net['network']['network_interface']
)
)
# SR-IOV interface mappings
if 'sriov_host_interfaces' in net['network']:
host_interfaces = \
net['network']['sriov_host_interfaces']
for interface in host_interfaces.split(','):
self.network_sriov_mappings.append(
'%s:%s' % (
net['network']['net_name'],
interface
)
)
def main():
module = AnsibleModule(
argument_spec=dict(
provider_networks=dict(
type='list',
required=True
),
is_metal=dict(
type='bool',
default='false'
),
bind_prefix=dict(
type='str',
required=False,
default=None
),
group_names=dict(
type='list',
required=False,
default=None
)
),
supports_check_mode=False
)
try:
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'),
group_names=module.params.get('group_names')
)
# 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_geneve_ranges': ','.join(pnp.network_geneve_ranges),
'network_geneve_ranges_list': pnp.network_geneve_ranges,
'network_flat_networks': ','.join(pnp.network_flat_networks),
'network_flat_networks_list': pnp.network_flat_networks,
'network_mappings': ','.join(list(set(pnp.network_mappings))),
'network_mappings_list': pnp.network_mappings,
'network_types': ','.join(pnp.network_types),
'network_sriov_mappings': ','.join(pnp.network_sriov_mappings),
'network_sriov_mappings_list': pnp.network_sriov_mappings,
'network_interface_mappings': ','.join(
pnp.network_interface_mappings
),
'network_interface_mappings_list': pnp.network_interface_mappings
}
module.exit_json(changed=True, **resp)
except Exception as exp:
resp = {'stderr': exp}
module.fail_json(msg='Failed Process', **resp)
if __name__ == '__main__':
main()