#!/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. # 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()