mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
436 lines
18 KiB
Python
436 lines
18 KiB
Python
|
#!/usr/bin/python
|
||
|
#
|
||
|
# Copyright: Ansible Project
|
||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||
|
|
||
|
from __future__ import absolute_import, division, print_function
|
||
|
__metaclass__ = type
|
||
|
|
||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||
|
'status': ['preview'],
|
||
|
'supported_by': 'community'}
|
||
|
|
||
|
DOCUMENTATION = '''
|
||
|
---
|
||
|
module: onyx_igmp_vlan
|
||
|
author: Anas Badaha (@anasbadaha)
|
||
|
short_description: Configures IGMP Vlan parameters
|
||
|
description:
|
||
|
- This module provides declarative management of IGMP vlan configuration on Mellanox ONYX network devices.
|
||
|
notes:
|
||
|
- Tested on ONYX 3.7.0932-01
|
||
|
options:
|
||
|
vlan_id:
|
||
|
description:
|
||
|
- VLAN ID, vlan should exist.
|
||
|
required: true
|
||
|
state:
|
||
|
description:
|
||
|
- IGMP state.
|
||
|
choices: ['enabled', 'disabled']
|
||
|
default: enabled
|
||
|
mrouter:
|
||
|
description:
|
||
|
- Configure ip igmp snooping mrouter port on vlan
|
||
|
suboptions:
|
||
|
state:
|
||
|
description:
|
||
|
- Enable IGMP snooping mrouter on vlan interface.
|
||
|
choices: ['enabled', 'disabled']
|
||
|
default: enabled
|
||
|
name:
|
||
|
description:
|
||
|
- Configure mrouter interface
|
||
|
required: true
|
||
|
querier:
|
||
|
description:
|
||
|
- Configure the IGMP querier parameters
|
||
|
suboptions:
|
||
|
state:
|
||
|
description:
|
||
|
- Enable IGMP snooping querier on vlan in the switch.
|
||
|
choices: ['enabled', 'disabled']
|
||
|
default: enabled
|
||
|
interval:
|
||
|
description:
|
||
|
- Update time interval between querier queries, range 60-600
|
||
|
address:
|
||
|
description:
|
||
|
- Update IP address for the querier
|
||
|
static_groups:
|
||
|
description:
|
||
|
- List of IGMP static groups.
|
||
|
suboptions:
|
||
|
multicast_ip_address:
|
||
|
description:
|
||
|
- Configure static IP multicast group, range 224.0.1.0-239.255.255.25.
|
||
|
required: true
|
||
|
name:
|
||
|
description:
|
||
|
- interface name to configure static groups on it.
|
||
|
sources:
|
||
|
description:
|
||
|
- List of IP sources to be configured
|
||
|
version:
|
||
|
description:
|
||
|
- IGMP snooping operation version on this vlan
|
||
|
choices: ['V2','V3']
|
||
|
'''
|
||
|
|
||
|
EXAMPLES = """
|
||
|
- name: configure igmp vlan
|
||
|
onyx_igmp_vlan:
|
||
|
state: enabled
|
||
|
vlan_id: 10
|
||
|
version:
|
||
|
V2
|
||
|
querier:
|
||
|
state: enabled
|
||
|
interval: 70
|
||
|
address: 10.11.121.13
|
||
|
mrouter:
|
||
|
state: disabled
|
||
|
name: Eth1/2
|
||
|
static_groups:
|
||
|
- multicast_ip_address: 224.5.5.8
|
||
|
name: Eth1/1
|
||
|
sources:
|
||
|
- 1.1.1.1
|
||
|
- 1.1.1.2
|
||
|
"""
|
||
|
|
||
|
RETURN = """
|
||
|
commands:
|
||
|
description: The list of configuration mode commands to send to the device.
|
||
|
returned: always
|
||
|
type: list
|
||
|
sample:
|
||
|
- vlan 10 ip igmp snooping
|
||
|
- vlan 10 ip igmp snooping static-group 224.5.5.5 interface ethernet 1/1
|
||
|
"""
|
||
|
import socket
|
||
|
import struct
|
||
|
|
||
|
from ansible.module_utils.basic import AnsibleModule
|
||
|
from ansible_collections.community.general.plugins.module_utils.network.onyx.onyx import show_cmd
|
||
|
from ansible_collections.community.general.plugins.module_utils.network.onyx.onyx import BaseOnyxModule
|
||
|
|
||
|
|
||
|
def _ip_to_int(addr):
|
||
|
return struct.unpack("!I", socket.inet_aton(addr))[0]
|
||
|
|
||
|
|
||
|
class OnyxIgmpVlanModule(BaseOnyxModule):
|
||
|
MIN_MULTICAST_IP = _ip_to_int("224.0.1.0")
|
||
|
MAX_MULTICAST_IP = _ip_to_int("239.255.255.255")
|
||
|
|
||
|
def init_module(self):
|
||
|
""" initialize module
|
||
|
"""
|
||
|
mrouter_spec = dict(name=dict(required=True),
|
||
|
state=dict(choices=['enabled', 'disabled'], default='enabled'))
|
||
|
querier_spec = dict(state=dict(choices=['enabled', 'disabled'], default='enabled'),
|
||
|
interval=dict(type='int'), address=dict())
|
||
|
static_groups_spec = dict(multicast_ip_address=dict(required=True),
|
||
|
name=dict(required=True), sources=dict(type='list'))
|
||
|
element_spec = dict(vlan_id=dict(type='int', required=True),
|
||
|
state=dict(choices=['enabled', 'disabled'], default='enabled'),
|
||
|
querier=dict(type='dict', options=querier_spec),
|
||
|
static_groups=dict(type='list', elements='dict', options=static_groups_spec),
|
||
|
mrouter=dict(type='dict', options=mrouter_spec),
|
||
|
version=dict(choices=['V2', 'V3']))
|
||
|
argument_spec = dict()
|
||
|
argument_spec.update(element_spec)
|
||
|
self._module = AnsibleModule(
|
||
|
argument_spec=argument_spec,
|
||
|
supports_check_mode=True)
|
||
|
|
||
|
def get_required_config(self):
|
||
|
module_params = self._module.params
|
||
|
self._required_config = dict(module_params)
|
||
|
self.validate_param_values(self._required_config)
|
||
|
|
||
|
def _validate_attr_is_not_none(self, attr_name, attr_value):
|
||
|
if attr_name == 'vlan_id' or attr_name == 'state':
|
||
|
pass
|
||
|
elif attr_value is not None:
|
||
|
self._module.fail_json(msg='Can not set %s value on switch while state is disabled' % attr_name)
|
||
|
|
||
|
def validate_param_values(self, obj, param=None):
|
||
|
if obj['state'] == 'disabled':
|
||
|
for attr_name in obj:
|
||
|
self._validate_attr_is_not_none(attr_name, obj[attr_name])
|
||
|
super(OnyxIgmpVlanModule, self).validate_param_values(obj, param)
|
||
|
|
||
|
def validate_querier(self, value):
|
||
|
interval = value.get('interval')
|
||
|
if interval and not 60 <= int(interval) <= 600:
|
||
|
self._module.fail_json(msg='query-interval value must be between 60 and 600')
|
||
|
|
||
|
def validate_static_groups(self, value):
|
||
|
multicast_ip = value.get('multicast_ip_address')
|
||
|
multicast_ip = _ip_to_int(multicast_ip)
|
||
|
|
||
|
if multicast_ip < self.MIN_MULTICAST_IP or multicast_ip > self.MAX_MULTICAST_IP:
|
||
|
self._module.fail_json(msg='multicast IP address must be in range 224.0.1.0 - 239.255.255.255')
|
||
|
|
||
|
@staticmethod
|
||
|
def _get_curr_mrouter_config(mrouter_port):
|
||
|
if mrouter_port == "none":
|
||
|
return {'state': 'disabled'}
|
||
|
else:
|
||
|
return {'state': 'enabled',
|
||
|
'name': mrouter_port}
|
||
|
|
||
|
def _get_curr_querier_config(self, querier_config):
|
||
|
if "Non-Querier" in querier_config:
|
||
|
return {'state': 'disabled'}
|
||
|
elif "Querier" in querier_config:
|
||
|
igmp_querier_config = self._show_igmp_querier_config()[0]
|
||
|
snooping_querier_info = igmp_querier_config["Snooping querier information for VLAN %d" % (
|
||
|
self._required_config['vlan_id'])]
|
||
|
snooping_querier_info = snooping_querier_info[1]
|
||
|
interval = int(snooping_querier_info["Query interval"])
|
||
|
address = snooping_querier_info["Configured querier IP address"]
|
||
|
return {'state': 'enabled',
|
||
|
'interval': interval,
|
||
|
'address': address}
|
||
|
|
||
|
@staticmethod
|
||
|
def _get_curr_version(version):
|
||
|
if "V3" in version:
|
||
|
return "V3"
|
||
|
elif "V2" in version:
|
||
|
return "V2"
|
||
|
|
||
|
def _get_curr_static_group_config(self, multicast_ip_address):
|
||
|
sources = None
|
||
|
names = None
|
||
|
igmp_snooping_groups_config = self._show_igmp_snooping_groups_config(multicast_ip_address)
|
||
|
if igmp_snooping_groups_config is not None:
|
||
|
igmp_snooping_groups_config = igmp_snooping_groups_config[0]
|
||
|
snooping_group_information = igmp_snooping_groups_config.get('Snooping group '
|
||
|
'information for VLAN %d and group '
|
||
|
'%s' % (self._required_config['vlan_id'],
|
||
|
multicast_ip_address))
|
||
|
if snooping_group_information is not None:
|
||
|
if len(snooping_group_information) == 1:
|
||
|
names = snooping_group_information[0].get('V1/V2 Receiver Ports')
|
||
|
elif len(snooping_group_information) == 2:
|
||
|
sources_dict = dict()
|
||
|
v3_receiver_ports = snooping_group_information[1].get('V3 Receiver Ports')
|
||
|
ports_number = v3_receiver_ports[0].get('Port Number')
|
||
|
sources = v3_receiver_ports[0].get('Include sources')
|
||
|
if isinstance(ports_number, list):
|
||
|
i = 0
|
||
|
for port_number in ports_number:
|
||
|
sources_dict[port_number] = sources[i]
|
||
|
i += 1
|
||
|
else:
|
||
|
sources_dict[ports_number] = sources
|
||
|
names = snooping_group_information[0].get('V1/V2 Receiver Ports')
|
||
|
sources = sources_dict
|
||
|
|
||
|
return {'sources': sources,
|
||
|
'names': names}
|
||
|
else:
|
||
|
return None
|
||
|
else:
|
||
|
return None
|
||
|
|
||
|
def _set_igmp_config(self, igmp_vlan_config):
|
||
|
igmp_vlan_config = igmp_vlan_config[0]
|
||
|
if not igmp_vlan_config:
|
||
|
return
|
||
|
|
||
|
self._current_config['state'] = igmp_vlan_config.get('message 1')
|
||
|
if "enabled" in self._current_config['state']:
|
||
|
self._current_config['state'] = "enabled"
|
||
|
elif "disabled" in self._current_config['state']:
|
||
|
self._current_config['state'] = "disabled"
|
||
|
|
||
|
mrouter_port = igmp_vlan_config.get('mrouter static port list')
|
||
|
self._current_config['mrouter'] = dict(self._get_curr_mrouter_config(mrouter_port))
|
||
|
|
||
|
querier_config = igmp_vlan_config.get('message 3')
|
||
|
self._current_config['querier'] = dict(self._get_curr_querier_config(querier_config))
|
||
|
|
||
|
version = igmp_vlan_config.get('message 2')
|
||
|
self._current_config['version'] = self._get_curr_version(version)
|
||
|
|
||
|
req_static_groups = self._required_config.get('static_groups')
|
||
|
if req_static_groups is not None:
|
||
|
static_groups = self._current_config['static_groups'] = dict()
|
||
|
for static_group in req_static_groups:
|
||
|
static_group_config = self._get_curr_static_group_config(static_group['multicast_ip_address'])
|
||
|
static_groups[static_group['multicast_ip_address']] = static_group_config
|
||
|
|
||
|
def _show_igmp_vlan(self):
|
||
|
cmd = ("show ip igmp snooping vlan %d" % self._required_config['vlan_id'])
|
||
|
return show_cmd(self._module, cmd, json_fmt=True, fail_on_error=False)
|
||
|
|
||
|
def _show_igmp_querier_config(self):
|
||
|
cmd = ("show ip igmp snooping querier vlan %d " % self._required_config['vlan_id'])
|
||
|
return show_cmd(self._module, cmd, json_fmt=True, fail_on_error=False)
|
||
|
|
||
|
def _show_igmp_snooping_groups_config(self, multicast_ip_address):
|
||
|
cmd = ("show ip igmp snooping groups vlan %d group %s" % (self._required_config['vlan_id'],
|
||
|
multicast_ip_address))
|
||
|
return show_cmd(self._module, cmd, json_fmt=True, fail_on_error=False)
|
||
|
|
||
|
def load_current_config(self):
|
||
|
self._current_config = dict()
|
||
|
igmp_vlan_config = self._show_igmp_vlan()
|
||
|
if igmp_vlan_config:
|
||
|
self._set_igmp_config(igmp_vlan_config)
|
||
|
|
||
|
def generate_commands(self):
|
||
|
req_state = self._required_config.get('state', 'enabled')
|
||
|
self._generate_igmp_vlan_cmds(req_state)
|
||
|
|
||
|
_mrouter = self._required_config.get('mrouter')
|
||
|
if _mrouter is not None:
|
||
|
self._generate_igmp_mrouter_cmds(_mrouter)
|
||
|
|
||
|
_querier = self._required_config.get('querier')
|
||
|
if _querier is not None:
|
||
|
req_querier_state = _querier.get('state', 'enabled')
|
||
|
self._generate_igmp_querier_cmds(req_querier_state)
|
||
|
|
||
|
req_querier_interval = _querier.get('interval')
|
||
|
if req_querier_interval is not None:
|
||
|
self._gen_querier_attr_commands("interval", req_querier_interval, "query-interval")
|
||
|
|
||
|
req_querier_address = _querier.get('address')
|
||
|
if req_querier_address is not None:
|
||
|
self._gen_querier_attr_commands("address", req_querier_address, "address")
|
||
|
|
||
|
_version = self._required_config.get('version')
|
||
|
if _version is not None:
|
||
|
self._generate_igmp_version_cmds(_version)
|
||
|
|
||
|
_static_groups = self._required_config.get('static_groups')
|
||
|
if _static_groups is not None:
|
||
|
for static_group in _static_groups:
|
||
|
self._generate_igmp_static_groups_cmd(static_group)
|
||
|
|
||
|
def _add_igmp_vlan_commands(self, req_state):
|
||
|
if req_state == 'enabled':
|
||
|
igmp_vlan_cmd = 'vlan %d ip igmp snooping' % self._required_config['vlan_id']
|
||
|
else:
|
||
|
igmp_vlan_cmd = 'vlan %d no ip igmp snooping' % self._required_config['vlan_id']
|
||
|
|
||
|
self._commands.append(igmp_vlan_cmd)
|
||
|
|
||
|
def _generate_igmp_vlan_cmds(self, req_state):
|
||
|
curr_state = self._current_config.get('state')
|
||
|
if curr_state != req_state:
|
||
|
self._add_igmp_vlan_commands(req_state)
|
||
|
|
||
|
def _gen_querier_attr_commands(self, attr_name, req_attr_value, attr_cmd_name):
|
||
|
_curr_querier = self._current_config.get('querier')
|
||
|
curr_querier_val = _curr_querier.get(attr_name)
|
||
|
if req_attr_value != curr_querier_val:
|
||
|
self._commands.append('vlan %d ip igmp snooping querier %s %s' % (self._required_config['vlan_id'],
|
||
|
attr_cmd_name, req_attr_value))
|
||
|
|
||
|
def _add_querier_commands(self, req_querier_state):
|
||
|
if req_querier_state == 'enabled':
|
||
|
self._commands.append('vlan %d ip igmp snooping querier' % self._required_config['vlan_id'])
|
||
|
elif req_querier_state == 'disabled':
|
||
|
self._commands.append('vlan %d no ip igmp snooping querier' % (
|
||
|
self._required_config['vlan_id']))
|
||
|
|
||
|
def _generate_igmp_querier_cmds(self, req_querier_state):
|
||
|
_curr_querier = self._current_config.get('querier')
|
||
|
curr_querier_state = _curr_querier.get('state')
|
||
|
if req_querier_state != curr_querier_state:
|
||
|
self._add_querier_commands(req_querier_state)
|
||
|
|
||
|
def _generate_igmp_version_cmds(self, version):
|
||
|
_curr_version = self._current_config.get('version')
|
||
|
if version != _curr_version:
|
||
|
self._commands.append('vlan %d ip igmp snooping version %s' % (
|
||
|
self._required_config['vlan_id'], version[1]))
|
||
|
|
||
|
def _add_mrouter_commands(self, req_mrouter, curr_mrouter):
|
||
|
curr_state = curr_mrouter.get('state')
|
||
|
curr_interface = curr_mrouter.get('name')
|
||
|
req_state = req_mrouter.get('state')
|
||
|
req_interface = req_mrouter.get('name')
|
||
|
mrouter_interface = req_interface.replace("Eth", "ethernet ")
|
||
|
if curr_state == 'enabled' and req_state == 'disabled':
|
||
|
self._commands.append('vlan %d no ip igmp snooping mrouter interface '
|
||
|
'%s' % (self._required_config['vlan_id'], mrouter_interface))
|
||
|
elif curr_state == 'disabled' and req_state == 'enabled':
|
||
|
self._commands.append('vlan %d ip igmp snooping mrouter interface '
|
||
|
'%s' % (self._required_config['vlan_id'], mrouter_interface))
|
||
|
elif req_state == 'enabled' and curr_state == 'enabled' and req_interface != curr_interface:
|
||
|
self._commands.append('vlan %d ip igmp snooping mrouter interface '
|
||
|
'%s' % (self._required_config['vlan_id'], mrouter_interface))
|
||
|
|
||
|
def _generate_igmp_mrouter_cmds(self, req_mrouter):
|
||
|
curr_mrouter = self._current_config.get('mrouter')
|
||
|
if curr_mrouter != req_mrouter:
|
||
|
self._add_mrouter_commands(req_mrouter, curr_mrouter)
|
||
|
|
||
|
def _add_igmp_static_groups_cmd(self, req_name, req_multicast_ip_address, curr_names):
|
||
|
if curr_names is None:
|
||
|
self._commands.append('vlan %d ip igmp snooping static-group %s interface %s' % (
|
||
|
self._required_config['vlan_id'], req_multicast_ip_address, req_name.replace('Eth', 'ethernet ')))
|
||
|
elif req_name.replace('E', 'e') not in curr_names:
|
||
|
self._commands.append('vlan %d ip igmp snooping static-group %s interface %s' % (
|
||
|
self._required_config['vlan_id'], req_multicast_ip_address, req_name.replace('Eth', 'ethernet ')))
|
||
|
|
||
|
def _add_igmp_static_groups_sources_cmd(self, req_sources, req_name, req_multicast_ip_address, curr_sources):
|
||
|
if curr_sources is None:
|
||
|
for source in req_sources:
|
||
|
self._commands.append('vlan %d ip igmp snooping static-group %s interface %s source %s' % (
|
||
|
self._required_config['vlan_id'], req_multicast_ip_address, req_name.replace('Eth', 'ethernet '),
|
||
|
source))
|
||
|
else:
|
||
|
curr_sources = curr_sources.get(req_name.replace('E', 'e'))
|
||
|
if curr_sources is None:
|
||
|
curr_sources = set([])
|
||
|
else:
|
||
|
curr_sources = set(x.strip() for x in curr_sources.split(','))
|
||
|
sources_to_add = set(req_sources) - set(curr_sources)
|
||
|
sources_to_remove = set(curr_sources) - set(req_sources)
|
||
|
if len(sources_to_add) != 0:
|
||
|
for source in sources_to_add:
|
||
|
self._commands.append('vlan %d ip igmp snooping static-group %s interface %s source %s' % (
|
||
|
self._required_config['vlan_id'], req_multicast_ip_address,
|
||
|
req_name.replace('Eth', 'ethernet '), source))
|
||
|
if len(sources_to_remove) != 0:
|
||
|
for source in sources_to_remove:
|
||
|
self._commands.append('vlan %d no ip igmp snooping static-group %s interface %s source %s' % (
|
||
|
self._required_config['vlan_id'], req_multicast_ip_address,
|
||
|
req_name.replace('Eth', 'ethernet '),
|
||
|
source))
|
||
|
|
||
|
def _generate_igmp_static_groups_cmd(self, static_group):
|
||
|
req_multicast_ip_address = static_group.get('multicast_ip_address')
|
||
|
req_name = static_group.get('name')
|
||
|
req_sources = static_group.get('sources')
|
||
|
curr_static_groups = self._current_config.get('static_groups')
|
||
|
curr_static_group = curr_static_groups.get(req_multicast_ip_address)
|
||
|
curr_names = None
|
||
|
curr_sources = None
|
||
|
if curr_static_group is not None:
|
||
|
curr_names = curr_static_group.get('names')
|
||
|
curr_sources = curr_static_group.get('sources')
|
||
|
|
||
|
self._add_igmp_static_groups_cmd(req_name, req_multicast_ip_address, curr_names)
|
||
|
if req_sources is not None:
|
||
|
self._add_igmp_static_groups_sources_cmd(req_sources, req_name, req_multicast_ip_address, curr_sources)
|
||
|
|
||
|
|
||
|
def main():
|
||
|
""" main entry point for module execution
|
||
|
"""
|
||
|
OnyxIgmpVlanModule.main()
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|