1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00
community.general/plugins/modules/network/icx/icx_system.py
Ansible Core Team aebc1b03fd Initial commit
2020-03-09 09:11:07 +00:00

470 lines
16 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: icx_system
author: "Ruckus Wireless (@Commscope)"
short_description: Manage the system attributes on Ruckus ICX 7000 series switches
description:
- This module provides declarative management of node system attributes
on Ruckus ICX 7000 series switches. It provides an option to configure host system
parameters or remove those parameters from the device active
configuration.
notes:
- Tested against ICX 10.1.
- For information on using ICX platform, see L(the ICX OS Platform Options guide,../network/user_guide/platform_icx.html).
options:
hostname:
description:
- Configure the device hostname parameter. This option takes an ASCII string value.
type: str
domain_name:
description:
- Configure the IP domain name on the remote device to the provided value.
Value should be in the dotted name form and
will be appended to the hostname to create a fully-qualified domain name.
type: list
domain_search:
description:
- Provides the list of domain names to
append to the hostname for the purpose of doing name resolution.
This argument accepts a list of names and will be reconciled
with the current active configuration on the running node.
type: list
name_servers:
description:
- List of DNS name servers by IP address to use to perform name resolution
lookups.
type: list
aaa_servers:
description:
- Configures radius/tacacs server
type: list
suboptions:
type:
description:
- specify the type of the server
type: str
choices: ['radius','tacacs']
hostname:
description:
- Configures the host name of the RADIUS server
type: str
auth_port_type:
description:
- specifies the type of the authentication port
type: str
choices: ['auth-port']
auth_port_num:
description:
- Configures the authentication UDP port. The default value is 1812.
type: str
acct_port_num:
description:
- Configures the accounting UDP port. The default value is 1813.
type: str
acct_type:
description:
- Usage of the accounting port.
type: str
choices: ['accounting-only', 'authentication-only','authorization-only', default]
auth_key:
description:
- Configure the key for the server
type: str
auth_key_type:
description:
- List of authentication level specified in the choices
type: list
choices: ['dot1x','mac-auth','web-auth']
state:
description:
- State of the configuration
values in the device's current active configuration. When set
to I(present), the values should be configured in the device active
configuration and when set to I(absent) the values should not be
in the device active configuration
type: str
default: present
choices: ['present', 'absent']
check_running_config:
description:
- Check running configuration. This can be set as environment variable.
Module will use environment variable value(default:True), unless it is overridden, by specifying it as module parameter.
type: bool
default: yes
'''
EXAMPLES = """
- name: configure hostname and domain name
icx_system:
hostname: icx
domain_search:
- ansible.com
- redhat.com
- ruckus.com
- name: configure radius server of type auth-port
icx_system:
aaa_servers:
- type: radius
hostname: radius-server
auth_port_type: auth-port
auth_port_num: 1821
acct_port_num: 1321
acct_type: accounting-only
auth_key: abc
auth_key_type:
- dot1x
- mac-auth
- name: configure tacacs server
icx_system:
aaa_servers:
- type: tacacs
hostname: tacacs-server
auth_port_type: auth-port
auth_port_num: 1821
acct_port_num: 1321
acct_type: accounting-only
auth_key: xyz
- name: configure name servers
icx_system:
name_servers:
- 8.8.8.8
- 8.8.4.4
"""
RETURN = """
commands:
description: The list of configuration mode commands to send to the device
returned: always
type: list
sample:
- hostname icx
- ip domain name test.example.com
- radius-server host 172.16.10.12 auth-port 2083 acct-port 1850 default key abc dot1x mac-auth
- tacacs-server host 10.2.3.4 auth-port 4058 authorization-only key xyz
"""
import re
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible_collections.community.general.plugins.module_utils.network.icx.icx import get_config, load_config
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ComplexList, validate_ip_v6_address
from ansible.module_utils.connection import Connection, ConnectionError, exec_command
def diff_list(want, have):
adds = [w for w in want if w not in have]
removes = [h for h in have if h not in want]
return (adds, removes)
def map_obj_to_commands(want, have, module):
commands = list()
state = module.params['state']
def needs_update(x):
return want.get(x) is not None and (want.get(x) != have.get(x))
if state == 'absent':
if have['name_servers'] == [] and have['aaa_servers'] == [] and have['domain_search'] == [] and have['hostname'] is None:
if want['hostname']:
commands.append('no hostname')
if want['domain_search']:
for item in want['domain_search']:
commands.append('no ip dns domain-list %s' % item)
if want['name_servers']:
for item in want['name_servers']:
commands.append('no ip dns server-address %s' % item)
if want['aaa_servers']:
want_servers = []
want_server = want['aaa_servers']
if want_server:
want_list = deepcopy(want_server)
for items in want_list:
items['auth_key'] = None
want_servers.append(items)
for item in want_servers:
ipv6addr = validate_ip_v6_address(item['hostname'])
if ipv6addr:
commands.append('no ' + item['type'] + '-server host ipv6 ' + item['hostname'])
else:
commands.append('no ' + item['type'] + '-server host ' + item['hostname'])
if want['hostname']:
if have['hostname'] == want['hostname']:
commands.append('no hostname')
if want['domain_search']:
for item in want['domain_search']:
if item in have['domain_search']:
commands.append('no ip dns domain-list %s' % item)
if want['name_servers']:
for item in want['name_servers']:
if item in have['name_servers']:
commands.append('no ip dns server-address %s' % item)
if want['aaa_servers']:
want_servers = []
want_server = want['aaa_servers']
have_server = have['aaa_servers']
if want_server:
want_list = deepcopy(want_server)
for items in want_list:
items['auth_key'] = None
want_servers.append(items)
for item in want_servers:
if item in have_server:
ipv6addr = validate_ip_v6_address(item['hostname'])
if ipv6addr:
commands.append('no ' + item['type'] + '-server host ipv6 ' + item['hostname'])
else:
commands.append('no ' + item['type'] + '-server host ' + item['hostname'])
elif state == 'present':
if needs_update('hostname'):
commands.append('hostname %s' % want['hostname'])
if want['domain_search']:
adds, removes = diff_list(want['domain_search'], have['domain_search'])
for item in removes:
commands.append('no ip dns domain-list %s' % item)
for item in adds:
commands.append('ip dns domain-list %s' % item)
if want['name_servers']:
adds, removes = diff_list(want['name_servers'], have['name_servers'])
for item in removes:
commands.append('no ip dns server-address %s' % item)
for item in adds:
commands.append('ip dns server-address %s' % item)
if want['aaa_servers']:
want_servers = []
want_server = want['aaa_servers']
have_server = have['aaa_servers']
want_list = deepcopy(want_server)
for items in want_list:
items['auth_key'] = None
want_servers.append(items)
adds, removes = diff_list(want_servers, have_server)
for item in removes:
ip6addr = validate_ip_v6_address(item['hostname'])
if ip6addr:
cmd = 'no ' + item['type'] + '-server host ipv6 ' + item['hostname']
else:
cmd = 'no ' + item['type'] + '-server host ' + item['hostname']
commands.append(cmd)
for w_item in adds:
for item in want_server:
if item['hostname'] == w_item['hostname'] and item['type'] == w_item['type']:
auth_key = item['auth_key']
ip6addr = validate_ip_v6_address(w_item['hostname'])
if ip6addr:
cmd = w_item['type'] + '-server host ipv6 ' + w_item['hostname']
else:
cmd = w_item['type'] + '-server host ' + w_item['hostname']
if w_item['auth_port_type']:
cmd += ' ' + w_item['auth_port_type'] + ' ' + w_item['auth_port_num']
if w_item['acct_port_num'] and w_item['type'] == 'radius':
cmd += ' acct-port ' + w_item['acct_port_num']
if w_item['type'] == 'tacacs':
if any((w_item['acct_port_num'], w_item['auth_key_type'])):
module.fail_json(msg='acct_port and auth_key_type is not applicable for tacacs server')
if w_item['acct_type']:
cmd += ' ' + w_item['acct_type']
if auth_key is not None:
cmd += ' key ' + auth_key
if w_item['auth_key_type'] and w_item['type'] == 'radius':
val = ''
for y in w_item['auth_key_type']:
val = val + ' ' + y
cmd += val
commands.append(cmd)
return commands
def parse_hostname(config):
match = re.search(r'^hostname (\S+)', config, re.M)
if match:
return match.group(1)
def parse_domain_search(config):
match = re.findall(r'^ip dns domain[- ]list (\S+)', config, re.M)
matches = list()
for name in match:
matches.append(name)
return matches
def parse_name_servers(config):
matches = list()
values = list()
lines = config.split('\n')
for line in lines:
if 'ip dns server-address' in line:
values = line.split(' ')
for val in values:
match = re.search(r'([0-9.]+)', val)
if match:
matches.append(match.group())
return matches
def parse_aaa_servers(config):
configlines = config.split('\n')
obj = []
for line in configlines:
auth_key_type = []
if 'radius-server' in line or 'tacacs-server' in line:
aaa_type = 'radius' if 'radius-server' in line else 'tacacs'
match = re.search(r'(host ipv6 (\S+))|(host (\S+))', line)
if match:
hostname = match.group(2) if match.group(2) is not None else match.group(4)
match = re.search(r'auth-port ([0-9]+)', line)
if match:
auth_port_num = match.group(1)
else:
auth_port_num = None
match = re.search(r'acct-port ([0-9]+)', line)
if match:
acct_port_num = match.group(1)
else:
acct_port_num = None
match = re.search(r'acct-port [0-9]+ (\S+)', line)
if match:
acct_type = match.group(1)
else:
acct_type = None
if aaa_type == 'tacacs':
match = re.search(r'auth-port [0-9]+ (\S+)', line)
if match:
acct_type = match.group(1)
else:
acct_type = None
match = re.search(r'(dot1x)', line)
if match:
auth_key_type.append('dot1x')
match = re.search(r'(mac-auth)', line)
if match:
auth_key_type.append('mac-auth')
match = re.search(r'(web-auth)', line)
if match:
auth_key_type.append('web-auth')
obj.append({
'type': aaa_type,
'hostname': hostname,
'auth_port_type': 'auth-port',
'auth_port_num': auth_port_num,
'acct_port_num': acct_port_num,
'acct_type': acct_type,
'auth_key': None,
'auth_key_type': set(auth_key_type) if len(auth_key_type) > 0 else None
})
return obj
def map_config_to_obj(module):
compare = module.params['check_running_config']
config = get_config(module, None, compare=compare)
return {
'hostname': parse_hostname(config),
'domain_search': parse_domain_search(config),
'name_servers': parse_name_servers(config),
'aaa_servers': parse_aaa_servers(config)
}
def map_params_to_obj(module):
if module.params['aaa_servers']:
for item in module.params['aaa_servers']:
if item['auth_key_type']:
item['auth_key_type'] = set(item['auth_key_type'])
obj = {
'hostname': module.params['hostname'],
'domain_name': module.params['domain_name'],
'domain_search': module.params['domain_search'],
'name_servers': module.params['name_servers'],
'state': module.params['state'],
'aaa_servers': module.params['aaa_servers']
}
return obj
def main():
""" Main entry point for Ansible module execution
"""
server_spec = dict(
type=dict(choices=['radius', 'tacacs']),
hostname=dict(),
auth_port_type=dict(choices=['auth-port']),
auth_port_num=dict(),
acct_port_num=dict(),
acct_type=dict(choices=['accounting-only', 'authentication-only', 'authorization-only', 'default']),
auth_key=dict(),
auth_key_type=dict(type='list', choices=['dot1x', 'mac-auth', 'web-auth'])
)
argument_spec = dict(
hostname=dict(),
domain_name=dict(type='list'),
domain_search=dict(type='list'),
name_servers=dict(type='list'),
aaa_servers=dict(type='list', elements='dict', options=server_spec),
state=dict(choices=['present', 'absent'], default='present'),
check_running_config=dict(default=True, type='bool', fallback=(env_fallback, ['ANSIBLE_CHECK_ICX_RUNNING_CONFIG']))
)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
result = {'changed': False}
warnings = list()
result['warnings'] = warnings
exec_command(module, 'skip')
want = map_params_to_obj(module)
have = map_config_to_obj(module)
commands = map_obj_to_commands(want, have, module)
result['commands'] = commands
if commands:
if not module.check_mode:
load_config(module, commands)
result['changed'] = True
module.exit_json(**result)
if __name__ == "__main__":
main()