1#!/usr/bin/python 2# 3# This file is part of Ansible 4# 5# Ansible is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# Ansible is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with Ansible. If not, see <http://www.gnu.org/licenses/>. 17# 18 19ANSIBLE_METADATA = {'metadata_version': '1.1', 20 'status': ['preview'], 21 'supported_by': 'network'} 22 23 24DOCUMENTATION = ''' 25--- 26module: nxos_pim_rp_address 27extends_documentation_fragment: nxos 28version_added: "2.2" 29short_description: Manages configuration of an PIM static RP address instance. 30description: 31 - Manages configuration of an Protocol Independent Multicast (PIM) static 32 rendezvous point (RP) address instance. 33author: Gabriele Gerbino (@GGabriele) 34notes: 35 - Tested against NXOSv 7.3.(0)D1(1) on VIRL 36 - C(state=absent) is currently not supported on all platforms. 37options: 38 rp_address: 39 description: 40 - Configures a Protocol Independent Multicast (PIM) static 41 rendezvous point (RP) address. Valid values are 42 unicast addresses. 43 required: true 44 group_list: 45 description: 46 - Group range for static RP. Valid values are multicast addresses. 47 prefix_list: 48 description: 49 - Prefix list policy for static RP. Valid values are prefix-list 50 policy names. 51 route_map: 52 description: 53 - Route map policy for static RP. Valid values are route-map 54 policy names. 55 bidir: 56 description: 57 - Group range is treated in PIM bidirectional mode. 58 type: bool 59 state: 60 description: 61 - Specify desired state of the resource. 62 required: true 63 default: present 64 choices: ['present','absent','default'] 65''' 66EXAMPLES = ''' 67- nxos_pim_rp_address: 68 rp_address: "10.1.1.20" 69 state: present 70''' 71 72RETURN = ''' 73commands: 74 description: commands sent to the device 75 returned: always 76 type: list 77 sample: ["router bgp 65535", "vrf test", "router-id 192.0.2.1"] 78''' 79 80 81import re 82 83from ansible.module_utils.network.nxos.nxos import get_config, load_config 84from ansible.module_utils.network.nxos.nxos import nxos_argument_spec, check_args 85from ansible.module_utils.basic import AnsibleModule 86from ansible.module_utils.network.common.config import CustomNetworkConfig 87 88 89def get_existing(module, args, gl): 90 existing = {} 91 config = str(get_config(module)) 92 address = module.params['rp_address'] 93 94 pim_address_re = r'ip pim rp-address (?P<value>.*)$' 95 for line in re.findall(pim_address_re, config, re.M): 96 97 values = line.split() 98 if values[0] != address: 99 continue 100 if gl and 'group-list' not in line: 101 continue 102 elif not gl and 'group-list' in line: 103 if '224.0.0.0/4' not in line: # ignore default group-list 104 continue 105 106 existing['bidir'] = existing.get('bidir') or 'bidir' in line 107 if len(values) > 2: 108 value = values[2] 109 if values[1] == 'route-map': 110 existing['route_map'] = value 111 elif values[1] == 'prefix-list': 112 existing['prefix_list'] = value 113 elif values[1] == 'group-list': 114 if value != '224.0.0.0/4': # ignore default group-list 115 existing['group_list'] = value 116 117 return existing 118 119 120def state_present(module, existing, proposed, candidate): 121 address = module.params['rp_address'] 122 command = 'ip pim rp-address {0}'.format(address) 123 if module.params['group_list'] and not proposed.get('group_list'): 124 command += ' group-list ' + module.params['group_list'] 125 if module.params['prefix_list']: 126 if not proposed.get('prefix_list'): 127 command += ' prefix-list ' + module.params['prefix_list'] 128 if module.params['route_map']: 129 if not proposed.get('route_map'): 130 command += ' route-map ' + module.params['route_map'] 131 commands = build_command(proposed, command) 132 if commands: 133 candidate.add(commands, parents=[]) 134 135 136def build_command(param_dict, command): 137 for param in ['group_list', 'prefix_list', 'route_map']: 138 if param_dict.get(param): 139 command += ' {0} {1}'.format( 140 param.replace('_', '-'), param_dict.get(param)) 141 if param_dict.get('bidir'): 142 command += ' bidir' 143 return [command] 144 145 146def state_absent(module, existing, candidate): 147 address = module.params['rp_address'] 148 149 commands = [] 150 command = 'no ip pim rp-address {0}'.format(address) 151 if module.params['group_list'] == existing.get('group_list'): 152 commands = build_command(existing, command) 153 elif not module.params['group_list']: 154 commands = [command] 155 156 if commands: 157 candidate.add(commands, parents=[]) 158 159 160def get_proposed(pargs, existing): 161 proposed = {} 162 163 for key, value in pargs.items(): 164 if key != 'rp_address': 165 if str(value).lower() == 'true': 166 value = True 167 elif str(value).lower() == 'false': 168 value = False 169 170 if existing.get(key) != value: 171 proposed[key] = value 172 173 return proposed 174 175 176def main(): 177 argument_spec = dict( 178 rp_address=dict(required=True, type='str'), 179 group_list=dict(required=False, type='str'), 180 prefix_list=dict(required=False, type='str'), 181 route_map=dict(required=False, type='str'), 182 bidir=dict(required=False, type='bool'), 183 state=dict(choices=['present', 'absent'], default='present', required=False), 184 ) 185 argument_spec.update(nxos_argument_spec) 186 187 module = AnsibleModule(argument_spec=argument_spec, 188 mutually_exclusive=[['group_list', 'route_map'], 189 ['group_list', 'prefix_list'], 190 ['route_map', 'prefix_list']], 191 supports_check_mode=True) 192 193 warnings = list() 194 check_args(module, warnings) 195 result = {'changed': False, 'commands': [], 'warnings': warnings} 196 197 state = module.params['state'] 198 199 args = [ 200 'rp_address', 201 'group_list', 202 'prefix_list', 203 'route_map', 204 'bidir' 205 ] 206 207 proposed_args = dict((k, v) for k, v in module.params.items() 208 if v is not None and k in args) 209 210 if module.params['group_list']: 211 existing = get_existing(module, args, True) 212 proposed = get_proposed(proposed_args, existing) 213 214 else: 215 existing = get_existing(module, args, False) 216 proposed = get_proposed(proposed_args, existing) 217 218 candidate = CustomNetworkConfig(indent=3) 219 if state == 'present' and (proposed or not existing): 220 state_present(module, existing, proposed, candidate) 221 elif state == 'absent' and existing: 222 state_absent(module, existing, candidate) 223 224 if candidate: 225 candidate = candidate.items_text() 226 result['commands'] = candidate 227 result['changed'] = True 228 msgs = load_config(module, candidate, True) 229 if msgs: 230 for item in msgs: 231 if item: 232 if isinstance(item, dict): 233 err_str = item['clierror'] 234 else: 235 err_str = item 236 if 'No policy was configured' in err_str: 237 if state == 'absent': 238 addr = module.params['rp_address'] 239 new_cmd = 'no ip pim rp-address {0}'.format(addr) 240 load_config(module, new_cmd) 241 242 module.exit_json(**result) 243 244 245if __name__ == '__main__': 246 main() 247