From d0d8fca3346dcad1b3bfbc7e78d3a35c21630097 Mon Sep 17 00:00:00 2001 From: Sara-Touqan <55439434+Sara-Touqan@users.noreply.github.com> Date: Tue, 17 Dec 2019 08:20:58 +0200 Subject: [PATCH] Supporting SNMP Users Configurations in Ansible (#63778) --- .../modules/network/onyx/onyx_snmp_users.py | 278 ++++++++++++++++++ .../onyx/fixtures/onyx_show_snmp_users.cfg | 22 ++ .../network/onyx/test_onyx_snmp_users.py | 95 ++++++ 3 files changed, 395 insertions(+) create mode 100644 lib/ansible/modules/network/onyx/onyx_snmp_users.py create mode 100644 test/units/modules/network/onyx/fixtures/onyx_show_snmp_users.cfg create mode 100644 test/units/modules/network/onyx/test_onyx_snmp_users.py diff --git a/lib/ansible/modules/network/onyx/onyx_snmp_users.py b/lib/ansible/modules/network/onyx/onyx_snmp_users.py new file mode 100644 index 00000000000..aa68b61291e --- /dev/null +++ b/lib/ansible/modules/network/onyx/onyx_snmp_users.py @@ -0,0 +1,278 @@ +#!/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_snmp_users +version_added: "2.10" +author: "Sara Touqan (@sarato)" +short_description: Configures SNMP User parameters +description: + - This module provides declarative management of SNMP Users protocol params + on Mellanox ONYX network devices. +options: + users: + type: list + description: + - List of snmp users + suboptions: + name: + description: + - Specifies the name of the user. + required: true + type: str + enabled: + description: + - Enables/Disables SNMP v3 access for the user. + type: bool + set_access_enabled: + description: + - Enables/Disables SNMP SET requests for the user. + type: bool + require_privacy: + description: + - Enables/Disables the Require privacy (encryption) for requests from this user + type: bool + auth_type: + description: + - Configures the hash type used to configure SNMP v3 security parameters. + choices: ['md5', 'sha', 'sha224', 'sha256', 'sha384', 'sha512'] + type: str + auth_password: + description: + - The password needed to configure the hash type. + type: str + capability_level: + description: + - Sets capability level for SET requests. + choices: ['admin','monitor','unpriv','v_admin'] + type: str +""" + +EXAMPLES = """ +- name: enables snmp user + onyx_snmp_users: + users: + - name: sara + enabled: true + +- name: enables snmp set requests + onyx_snmp_users: + users: + - name: sara + set_access_enabled: yes + +- name: enables user require privacy + onyx_snmp_users: + users: + - name: sara + require_privacy: true + +- name: configures user hash type + onyx_snmp_users: + users: + - auth_type: md5 + auth_password: 1297sara1234sara + +- name: configures user capability_level + onyx_snmp_users: + users: + - name: sara + capability_level: admin +""" + +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device. + returned: always + type: list + sample: + - snmp-server user v3 enable + - no snmp-server user v3 enable + - snmp-server user v3 enable sets + - no snmp-server user v3 enable sets + - snmp-server user v3 require-privacy + - no snmp-server user v3 require-privacy + - snmp-server user v3 capability + - snmp-server user v3 auth +""" + +import re + +from ansible.module_utils.basic import AnsibleModule + +from ansible.module_utils.network.onyx.onyx import show_cmd +from ansible.module_utils.network.onyx.onyx import BaseOnyxModule + + +class OnyxSNMPUsersModule(BaseOnyxModule): + + def init_module(self): + """ initialize module + """ + user_spec = dict(name=dict(required=True), + enabled=dict(type='bool'), + set_access_enabled=dict(type='bool'), + require_privacy=dict(type='bool'), + auth_type=dict(type='str', choices=['md5', 'sha', 'sha224', 'sha256', 'sha384', 'sha512']), + auth_password=dict(type='str'), + capability_level=dict(type='str', choices=['admin', 'monitor', 'unpriv', 'v_admin']), + ) + element_spec = dict( + users=dict(type='list', elements='dict', options=user_spec), + ) + 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 _set_snmp_config(self, users_config): + if users_config[0]: + if users_config[0].get('Lines'): + return + current_users = [] + count = 0 + enabled = True + set_access_enabled = True + require_privacy = True + auth_type = '' + capability_level = '' + name = '' + all_users_names = [] + for user in users_config: + user_dict = {} + entry_dict = {} + for entry in user: + name = entry.split()[2] + if user.get(entry): + if user.get(entry)[0]: + enabled = user.get(entry)[0].get('Enabled overall') + if enabled == 'no': + enabled = False + else: + enabled = True + set_access_enabled = user.get(entry)[1].get('SET access')[0].get('Enabled') + if set_access_enabled == 'no': + set_access_enabled = False + else: + set_access_enabled = True + require_privacy = user.get(entry)[0].get('Require privacy') + if require_privacy == 'yes': + require_privacy = True + else: + require_privacy = False + capability_level = user.get(entry)[1].get('SET access')[0].get('Capability level') + auth_type = user.get(entry)[0].get('Authentication type') + user_dict['enabled'] = enabled + user_dict['set_access_enabled'] = set_access_enabled + user_dict['auth_type'] = auth_type + user_dict['capability_level'] = capability_level + user_dict['require_privacy'] = require_privacy + entry_dict[name] = user_dict + all_users_names.append(name) + current_users.append(entry_dict) + self._current_config['users'] = current_users + self._current_config['current_names'] = all_users_names + + def _show_users(self): + cmd = "show snmp user" + return show_cmd(self._module, cmd, json_fmt=True, fail_on_error=False) + + def load_current_config(self): + self._current_config = dict() + users_config = self._show_users() + if users_config: + self._set_snmp_config(users_config) + + def generate_commands(self): + req_uers = self._required_config.get("users") + current_users = self._current_config.get("users") + current_names = self._current_config.get("current_names") + if req_uers: + for user in req_uers: + user_id = user.get('name') + if user_id: + if current_names and (user_id in current_names): + for user_entry in current_users: + for user_name in user_entry: + if user_name == user_id: + user_state = user.get("enabled") + user_entry_name = user_entry.get(user_name) + if user_state is not None: + if user_state != user_entry_name.get("enabled"): + if user_state is True: + self._commands.append('snmp-server user {0} v3 enable' .format(user_id)) + else: + self._commands.append('no snmp-server user {0} v3 enable' .format(user_id)) + set_state = user.get("set_access_enabled") + if set_state is not None: + if set_state != user_entry_name.get("set_access_enabled"): + if set_state is True: + self._commands.append('snmp-server user {0} v3 enable sets' .format(user_id)) + else: + self._commands.append('no snmp-server user {0} v3 enable sets' .format(user_id)) + auth_type = user.get("auth_type") + if auth_type is not None: + if user.get("auth_password") is not None: + if auth_type != user_entry_name.get("auth_type"): + self._commands.append('snmp-server user {0} v3 auth {1} {2}' + .format(user_id, user.get('auth_type'), user.get('auth_password'))) + cap_level = user.get("capability_level") + if cap_level is not None: + if cap_level != user_entry_name.get("capability_level"): + self._commands.append('snmp-server user {0} v3 capability {1}' + .format(user_id, user.get('capability_level'))) + req_priv = user.get("require_privacy") + if req_priv is not None: + if req_priv != user_entry_name.get("require_privacy"): + if req_priv is True: + self._commands.append('snmp-server user {0} v3 require-privacy' .format(user_id)) + else: + self._commands.append('no snmp-server user {0} v3 require-privacy' .format(user_id)) + + else: + user_state = user.get("enabled") + if user_state is not None: + if user_state is True: + self._commands.append('snmp-server user {0} v3 enable' .format(user_id)) + else: + self._commands.append('no snmp-server user {0} v3 enable' .format(user_id)) + set_state = user.get("set_access_enabled") + if set_state is not None: + if set_state is True: + self._commands.append('snmp-server user {0} v3 enable sets' .format(user_id)) + else: + self._commands.append('no snmp-server user {0} v3 enable sets' .format(user_id)) + if user.get("capability_level") is not None: + self._commands.append('snmp-server user {0} v3 capability {1}' .format(user_id, user.get('capability_level'))) + req_priv = user.get("require_privacy") + if req_priv is not None: + if req_priv is True: + self._commands.append('snmp-server user {0} v3 require-privacy' .format(user_id)) + else: + self._commands.append('no snmp-server user {0} v3 require-privacy' .format(user_id)) + + +def main(): + """ main entry point for module execution + """ + OnyxSNMPUsersModule.main() + + +if __name__ == '__main__': + main() diff --git a/test/units/modules/network/onyx/fixtures/onyx_show_snmp_users.cfg b/test/units/modules/network/onyx/fixtures/onyx_show_snmp_users.cfg new file mode 100644 index 00000000000..6c957ff0e52 --- /dev/null +++ b/test/units/modules/network/onyx/fixtures/onyx_show_snmp_users.cfg @@ -0,0 +1,22 @@ +[ + { + "User name sara": [ + { + "Privacy password": "(NOT SET; user disabled)", + "Enabled overall": "yes", + "Authentication password": "(NOT SET; user disabled)", + "Authentication type": "sha", + "Require privacy": "no", + "Privacy type": "aes-128" + }, + { + "SET access": [ + { + "Capability level": "admin", + "Enabled": "yes" + } + ] + } + ] + } +] diff --git a/test/units/modules/network/onyx/test_onyx_snmp_users.py b/test/units/modules/network/onyx/test_onyx_snmp_users.py new file mode 100644 index 00000000000..cc4176cd491 --- /dev/null +++ b/test/units/modules/network/onyx/test_onyx_snmp_users.py @@ -0,0 +1,95 @@ +# +# Copyright: Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from units.compat.mock import patch +from ansible.modules.network.onyx import onyx_snmp_users +from units.modules.utils import set_module_args +from .onyx_module import TestOnyxModule, load_fixture + + +class TestOnyxSNMPUsersModule(TestOnyxModule): + + module = onyx_snmp_users + + def setUp(self): + self.enabled = False + super(TestOnyxSNMPUsersModule, self).setUp() + self.mock_get_config = patch.object( + onyx_snmp_users.OnyxSNMPUsersModule, "_show_users") + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + 'ansible.module_utils.network.onyx.onyx.load_config') + self.load_config = self.mock_load_config.start() + + def tearDown(self): + super(TestOnyxSNMPUsersModule, self).tearDown() + self.mock_get_config.stop() + self.mock_load_config.stop() + + def load_fixtures(self, commands=None, transport='cli'): + config_file = 'onyx_show_snmp_users.cfg' + self.get_config.return_value = load_fixture(config_file) + self.load_config.return_value = None + + def test_snmp_user_state_no_change(self): + set_module_args(dict(users=[dict(name='sara', + enabled='true')])) + self.execute_module(changed=False) + + def test_snmp_user_state_with_change(self): + set_module_args(dict(users=[dict(name='sara', + enabled='false')])) + commands = ['no snmp-server user sara v3 enable'] + self.execute_module(changed=True, commands=commands) + + def test_snmp_user_set_access_state_no_change(self): + set_module_args(dict(users=[dict(name='sara', + set_access_enabled='true')])) + self.execute_module(changed=False) + + def test_snmp_user_set_access_state_with_change(self): + set_module_args(dict(users=[dict(name='sara', + set_access_enabled='false')])) + commands = ['no snmp-server user sara v3 enable sets'] + self.execute_module(changed=True, commands=commands) + + def test_snmp_user_require_privacy_state_no_change(self): + set_module_args(dict(users=[dict(name='sara', + require_privacy='false')])) + self.execute_module(changed=False) + + def test_snmp_user_require_privacy_state_with_change(self): + set_module_args(dict(users=[dict(name='sara', + require_privacy='yes')])) + commands = ['snmp-server user sara v3 require-privacy'] + self.execute_module(changed=True, commands=commands) + + def test_snmp_user_auth_type_no_change(self): + set_module_args(dict(users=[dict(name='sara', + auth_type='sha', + auth_password='12sara123456')])) + self.execute_module(changed=False) + + def test_snmp_user_auth_type_with_change(self): + set_module_args(dict(users=[dict(name='sara', + auth_type='md5', + auth_password='12sara123456')])) + commands = ['snmp-server user sara v3 auth md5 12sara123456'] + self.execute_module(changed=True, commands=commands) + + def test_snmp_user_capability_level_no_change(self): + set_module_args(dict(users=[dict(name='sara', + capability_level='admin')])) + self.execute_module(changed=False) + + def test_snmp_user_capability_level_with_change(self): + set_module_args(dict(users=[dict(name='sara', + capability_level='monitor')])) + commands = ['snmp-server user sara v3 capability monitor'] + self.execute_module(changed=True, commands=commands)