From a6af204cee6415c4edc88c27c670ad3e885695bf Mon Sep 17 00:00:00 2001 From: Ganesh Nalawade Date: Thu, 31 Aug 2017 17:46:13 +0530 Subject: [PATCH] Fix junos_user purge option failures (#28867) * Fix junos_user pruge option failures Fixes #25989 Add seperate handling for purge option which fetches configured users on remote device and delete the one not present in aggregate list. * Minor changes --- lib/ansible/module_utils/junos.py | 8 ++- .../modules/network/junos/junos_user.py | 51 +++++++++++++------ .../junos_user/tests/netconf/basic.yaml | 23 +++++++++ 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/lib/ansible/module_utils/junos.py b/lib/ansible/module_utils/junos.py index 8ec0a8a0dfc..a7ea247e319 100644 --- a/lib/ansible/module_utils/junos.py +++ b/lib/ansible/module_utils/junos.py @@ -211,7 +211,13 @@ def load_config(module, candidate, warnings, action='merge', format='xml'): def get_param(module, key): - return module.params[key] or module.params['provider'].get(key) + if module.params.get(key): + value = module.params[key] + elif module.params.get('provider'): + value = module.params['provider'].get(key) + else: + value = None + return value def map_params_to_obj(module, param_to_xpath_map, param=None): diff --git a/lib/ansible/modules/network/junos/junos_user.py b/lib/ansible/modules/network/junos/junos_user.py index ca701e20787..ed1075ca1d6 100644 --- a/lib/ansible/modules/network/junos/junos_user.py +++ b/lib/ansible/modules/network/junos/junos_user.py @@ -57,7 +57,6 @@ options: remote system. User accounts can have more than one role configured. required: false - default: read-only choices: ['operator', 'read-only', 'super-user', 'unauthorized'] sshkey: description: @@ -71,7 +70,7 @@ options: - The C(purge) argument instructs the module to consider the users definition absolute. It will remove any previously configured users on the device with the exception of the current defined - set of users. + set of aggregate. required: false default: false state: @@ -113,7 +112,8 @@ EXAMPLES = """ - name: remove all user accounts except ansible junos_user: - name: ansible + aggregate: + - name: ansible purge: yes - name: Create list of users @@ -147,6 +147,7 @@ from copy import deepcopy from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.network_common import remove_default_spec +from ansible.module_utils.netconf import send_request from ansible.module_utils.junos import junos_argument_spec, check_args from ansible.module_utils.junos import commit_configuration, discard_changes from ansible.module_utils.junos import load_config, locked_config @@ -161,27 +162,47 @@ ROLES = ['operator', 'read-only', 'super-user', 'unauthorized'] USE_PERSISTENT_CONNECTION = True -def map_obj_to_ele(want): +def handle_purge(module, want): + want_users = [item['name'] for item in want] element = Element('system') - login = SubElement(element, 'login', {'replace': 'replace'}) + login = SubElement(element, 'login') + + reply = send_request(module, Element('get-configuration'), ignore_warning=False) + users = reply.xpath('configuration/system/login/user/name') + if users: + for item in users: + name = item.text + if name not in want_users and name != 'root': + user = SubElement(login, 'user', {'operation': 'delete'}) + SubElement(user, 'name').text = name + if element.xpath('/system/login/user/name'): + return element + + +def map_obj_to_ele(module, want): + element = Element('system') + login = SubElement(element, 'login') for item in want: if item['state'] != 'present': + if item['name'] == 'root': + module.fail_json(msg="cannot delete the 'root' account.") operation = 'delete' else: - operation = 'replace' + operation = 'merge' user = SubElement(login, 'user', {'operation': operation}) SubElement(user, 'name').text = item['name'] - if operation == 'replace': + if operation == 'merge': if item['active']: user.set('active', 'active') else: user.set('inactive', 'inactive') - SubElement(user, 'class').text = item['role'] + if item['role']: + SubElement(user, 'class').text = item['role'] if item.get('full_name'): SubElement(user, 'full-name').text = item['full_name'] @@ -262,7 +283,7 @@ def main(): element_spec = dict( name=dict(), full_name=dict(), - role=dict(choices=ROLES, default='unauthorized'), + role=dict(choices=ROLES), sshkey=dict(), state=dict(choices=['present', 'absent'], default='present'), active=dict(type='bool', default=True) @@ -294,16 +315,16 @@ def main(): result = {'changed': False, 'warnings': warnings} want = map_params_to_obj(module) - ele = map_obj_to_ele(want) + ele = map_obj_to_ele(module, want) - kwargs = {} + purge_request = None if module.params['purge']: - kwargs['action'] = 'replace' - else: - kwargs['action'] = 'merge' + purge_request = handle_purge(module, want) with locked_config(module): - diff = load_config(module, tostring(ele), warnings, **kwargs) + if purge_request: + load_config(module, tostring(purge_request), warnings, action='replace') + diff = load_config(module, tostring(ele), warnings, action='merge') commit = not module.check_mode if diff: diff --git a/test/integration/targets/junos_user/tests/netconf/basic.yaml b/test/integration/targets/junos_user/tests/netconf/basic.yaml index 0f8280f765d..192964b9263 100644 --- a/test/integration/targets/junos_user/tests/netconf/basic.yaml +++ b/test/integration/targets/junos_user/tests/netconf/basic.yaml @@ -168,3 +168,26 @@ - "result.changed == true" - "'test_user1' not in config.xml" - "'test_user2' not in config.xml" + +- name: Create list of users + junos_user: + aggregate: + - name: ansible + - {name: test_user1, full_name: test_user2, role: operator} + - {name: test_user2, full_name: test_user2, role: read-only} + provider: "{{ netconf }}" + register: result + +- name: Purge users except the users in aggregate + junos_user: + aggregate: + - name: ansible + purge: True + provider: "{{ netconf }}" + register: result + +- assert: + that: + - "result.changed == true" + - result.diff.prepared | search("\- *user test_user1") + - result.diff.prepared | search("\- *user test_user2")