From 69dd03d4726f3e927f65707a055ef30e4f581bae Mon Sep 17 00:00:00 2001 From: Nilashish Chakraborty Date: Mon, 28 Jan 2019 13:44:15 +0530 Subject: [PATCH] ios_user: Add support for multiple sshkeys (#51173) * Add support for multiple sshkeys Signed-off-by: NilashishC * Fix CI Signed-off-by: NilashishC * Add the keys at on go Signed-off-by: NilashishC * Update tests Signed-off-by: NilashishC --- lib/ansible/modules/network/ios/ios_user.py | 54 ++++++++++++------- .../modules/network/ios/test_ios_user.py | 13 +++++ 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/lib/ansible/modules/network/ios/ios_user.py b/lib/ansible/modules/network/ios/ios_user.py index 9969dc56525..d3aeb833322 100644 --- a/lib/ansible/modules/network/ios/ios_user.py +++ b/lib/ansible/modules/network/ios/ios_user.py @@ -102,8 +102,9 @@ options: aliases: ['role'] sshkey: description: - - Specifies the SSH public key to configure - for the given username. This argument accepts a valid SSH key value. + - Specifies one or more SSH public key(s) to configure + for the given username. + - This argument accepts a valid SSH key value. version_added: "2.7" nopassword: description: @@ -139,6 +140,14 @@ EXAMPLES = """ sshkey: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" state: present +- name: create a new user with multiple keys + ios_user: + name: ansible + sshkey: + - "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" + - "{{ lookup('file', '~/path/to/public_key') }}" + state: present + - name: remove all users except admin ios_user: purge: yes @@ -210,19 +219,17 @@ commands: - username ansible secret password - username admin secret admin """ -from copy import deepcopy - -import re import base64 import hashlib - +import re +from copy import deepcopy from functools import partial from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.network.common.utils import remove_default_spec from ansible.module_utils.network.ios.ios import get_config, load_config -from ansible.module_utils.six import iteritems from ansible.module_utils.network.ios.ios import ios_argument_spec, check_args +from ansible.module_utils.six import iteritems def validate_privilege(value, module): @@ -275,7 +282,8 @@ def map_obj_to_commands(updates, module): command.append('ip ssh pubkey-chain') if x: command.append('username %s' % want['name']) - command.append('key-hash %s' % x) + for item in x: + command.append('key-hash %s' % item) command.append('exit') else: command.append('no username %s' % want['name']) @@ -324,10 +332,15 @@ def parse_view(data): return match.group(1) -def parse_sshkey(data): - match = re.search(r'key-hash (\S+ \S+(?: .+)?)$', data, re.M) - if match: - return match.group(1) +def parse_sshkey(data, user): + sshregex = r'username %s(\n\s+key-hash .+$)+' % user + sshcfg = re.search(sshregex, data, re.M) + key_list = [] + if sshcfg: + match = re.findall(r'key-hash (\S+ \S+(?: .+)?)$', sshcfg.group(), re.M) + if match: + key_list = match + return key_list def parse_privilege(data): @@ -356,9 +369,6 @@ def map_config_to_obj(module): regex = r'username %s .+$' % user cfg = re.findall(regex, data, re.M) cfg = '\n'.join(cfg) - sshregex = r'username %s\n\s+key-hash .+$' % user - sshcfg = re.findall(sshregex, data, re.M) - sshcfg = '\n'.join(sshcfg) obj = { 'name': user, 'state': 'present', @@ -366,7 +376,7 @@ def map_config_to_obj(module): 'configured_password': None, 'hashed_password': None, 'password_type': parse_password_type(cfg), - 'sshkey': parse_sshkey(sshcfg), + 'sshkey': parse_sshkey(data, user), 'privilege': parse_privilege(cfg), 'view': parse_view(cfg) } @@ -423,13 +433,21 @@ def map_params_to_obj(module): item['nopassword'] = get_value('nopassword') item['privilege'] = get_value('privilege') item['view'] = get_value('view') - item['sshkey'] = sshkey_fingerprint(get_value('sshkey')) + item['sshkey'] = render_key_list(get_value('sshkey')) item['state'] = get_value('state') objects.append(item) return objects +def render_key_list(ssh_keys): + key_list = [] + if ssh_keys: + for item in ssh_keys: + key_list.append(sshkey_fingerprint(item)) + return key_list + + def update_objects(want, have): updates = list() for entry in want: @@ -463,7 +481,7 @@ def main(): privilege=dict(type='int'), view=dict(aliases=['role']), - sshkey=dict(), + sshkey=dict(type='list'), state=dict(default='present', choices=['present', 'absent']) ) diff --git a/test/units/modules/network/ios/test_ios_user.py b/test/units/modules/network/ios/test_ios_user.py index 43b3ce70b67..e81eddef67f 100644 --- a/test/units/modules/network/ios/test_ios_user.py +++ b/test/units/modules/network/ios/test_ios_user.py @@ -128,3 +128,16 @@ class TestIosUserModule(TestIosModule): ] result = self.execute_module(changed=True, commands=commands) self.assertEqual(result['commands'], commands) + + def test_ios_user_set_sshkey_multiple(self): + set_module_args(dict(name='ansible', sshkey=['dGVzdA==', 'eHWacB2=='])) + commands = [ + 'ip ssh pubkey-chain', + 'username ansible', + 'key-hash ssh-rsa 098F6BCD4621D373CADE4E832627B4F6', + 'key-hash ssh-rsa A019918340A1E9183388D9A675603036', + 'exit', + 'exit' + ] + result = self.execute_module(changed=True, commands=commands) + self.assertEqual(result['commands'], commands)