mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
nxos enable mode (#39355)
* nxos enable mode Signed-off-by: Trishna Guha <trishnaguha17@gmail.com> * fix prompt Signed-off-by: Trishna Guha <trishnaguha17@gmail.com> * Add authorize,auth_pass Signed-off-by: Trishna Guha <trishnaguha17@gmail.com> * remove byte string from exec_cli_command Signed-off-by: Trishna Guha <trishnaguha17@gmail.com> * Add on_become test Signed-off-by: Trishna Guha <trishnaguha17@gmail.com> * removed_in_version Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
This commit is contained in:
parent
83df7249fd
commit
f08332acb4
10 changed files with 162 additions and 1 deletions
|
@ -49,6 +49,9 @@ nxos_provider_spec = {
|
||||||
'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True),
|
'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True),
|
||||||
'ssh_keyfile': dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE'])),
|
'ssh_keyfile': dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE'])),
|
||||||
|
|
||||||
|
'authorize': dict(fallback=(env_fallback, ['ANSIBLE_NET_AUTHORIZE']), type='bool'),
|
||||||
|
'auth_pass': dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_AUTH_PASS'])),
|
||||||
|
|
||||||
'use_ssl': dict(type='bool'),
|
'use_ssl': dict(type='bool'),
|
||||||
'use_proxy': dict(default=True, type='bool'),
|
'use_proxy': dict(default=True, type='bool'),
|
||||||
'validate_certs': dict(type='bool'),
|
'validate_certs': dict(type='bool'),
|
||||||
|
@ -68,6 +71,9 @@ nxos_top_spec = {
|
||||||
'password': dict(removed_in_version=2.9, no_log=True),
|
'password': dict(removed_in_version=2.9, no_log=True),
|
||||||
'ssh_keyfile': dict(removed_in_version=2.9),
|
'ssh_keyfile': dict(removed_in_version=2.9),
|
||||||
|
|
||||||
|
'authorize': dict(fallback=(env_fallback, ['ANSIBLE_NET_AUTHORIZE']), type='bool'),
|
||||||
|
'auth_pass': dict(removed_in_version=2.9, no_log=True),
|
||||||
|
|
||||||
'use_ssl': dict(removed_in_version=2.9, type='bool'),
|
'use_ssl': dict(removed_in_version=2.9, type='bool'),
|
||||||
'validate_certs': dict(removed_in_version=2.9, type='bool'),
|
'validate_certs': dict(removed_in_version=2.9, type='bool'),
|
||||||
'timeout': dict(removed_in_version=2.9, type='int'),
|
'timeout': dict(removed_in_version=2.9, type='int'),
|
||||||
|
|
|
@ -63,6 +63,10 @@ class ActionModule(_ActionModule):
|
||||||
pc.password = provider['password'] or self._play_context.password
|
pc.password = provider['password'] or self._play_context.password
|
||||||
pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file
|
pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file
|
||||||
pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT)
|
pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT)
|
||||||
|
pc.become = provider['authorize'] or False
|
||||||
|
if pc.become:
|
||||||
|
pc.become_method = 'enable'
|
||||||
|
pc.become_pass = provider['auth_pass']
|
||||||
|
|
||||||
display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr)
|
display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr)
|
||||||
connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin)
|
connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin)
|
||||||
|
|
|
@ -20,9 +20,11 @@ from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
import json
|
||||||
|
|
||||||
from ansible.plugins.terminal import TerminalBase
|
from ansible.plugins.terminal import TerminalBase
|
||||||
from ansible.errors import AnsibleConnectionFailure
|
from ansible.errors import AnsibleConnectionFailure
|
||||||
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
|
||||||
|
|
||||||
class TerminalModule(TerminalBase):
|
class TerminalModule(TerminalBase):
|
||||||
|
@ -48,9 +50,50 @@ class TerminalModule(TerminalBase):
|
||||||
re.compile(br"invalid (.+?)at '\^' marker", re.I)
|
re.compile(br"invalid (.+?)at '\^' marker", re.I)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def on_become(self, passwd=None):
|
||||||
|
if self._get_prompt().endswith(b'enable#'):
|
||||||
|
return
|
||||||
|
|
||||||
|
out = self._exec_cli_command('show privilege')
|
||||||
|
out = to_text(out, errors='surrogate_then_replace').strip()
|
||||||
|
if 'Disabled' in out:
|
||||||
|
raise AnsibleConnectionFailure('Feature privilege is not enabled')
|
||||||
|
|
||||||
|
# if already at privilege level 15 return
|
||||||
|
if '15' in out:
|
||||||
|
return
|
||||||
|
|
||||||
|
cmd = {u'command': u'enable'}
|
||||||
|
if passwd:
|
||||||
|
cmd[u'prompt'] = to_text(r"(?i)[\r\n]?Password: $", errors='surrogate_or_strict')
|
||||||
|
cmd[u'answer'] = passwd
|
||||||
|
cmd[u'prompt_retry_check'] = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._exec_cli_command(to_bytes(json.dumps(cmd), errors='surrogate_or_strict'))
|
||||||
|
prompt = self._get_prompt()
|
||||||
|
if prompt is None or not prompt.strip().endswith(b'enable#'):
|
||||||
|
raise AnsibleConnectionFailure('failed to elevate privilege to enable mode still at prompt [%s]' % prompt)
|
||||||
|
except AnsibleConnectionFailure as e:
|
||||||
|
prompt = self._get_prompt()
|
||||||
|
raise AnsibleConnectionFailure('unable to elevate privilege to enable mode, at prompt [%s] with error: %s' % (prompt, e.message))
|
||||||
|
|
||||||
|
def on_unbecome(self):
|
||||||
|
prompt = self._get_prompt()
|
||||||
|
if prompt is None:
|
||||||
|
# if prompt is None most likely the terminal is hung up at a prompt
|
||||||
|
return
|
||||||
|
|
||||||
|
if b'(config' in prompt:
|
||||||
|
self._exec_cli_command('end')
|
||||||
|
self._exec_cli_command('exit')
|
||||||
|
|
||||||
|
elif prompt.endswith(b'enable#'):
|
||||||
|
self._exec_cli_command('exit')
|
||||||
|
|
||||||
def on_open_shell(self):
|
def on_open_shell(self):
|
||||||
try:
|
try:
|
||||||
for cmd in (b'terminal length 0', b'terminal width 511'):
|
for cmd in ('terminal length 0', 'terminal width 511'):
|
||||||
self._exec_cli_command(cmd)
|
self._exec_cli_command(cmd)
|
||||||
except AnsibleConnectionFailure:
|
except AnsibleConnectionFailure:
|
||||||
raise AnsibleConnectionFailure('unable to set terminal parameters')
|
raise AnsibleConnectionFailure('unable to set terminal parameters')
|
||||||
|
|
3
test/integration/targets/nxos_become/defaults/main.yaml
Normal file
3
test/integration/targets/nxos_become/defaults/main.yaml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
testcase: "*"
|
||||||
|
test_items: []
|
2
test/integration/targets/nxos_become/meta/main.yml
Normal file
2
test/integration/targets/nxos_become/meta/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
dependencies:
|
||||||
|
- prepare_nxos_tests
|
33
test/integration/targets/nxos_become/tasks/cli.yaml
Normal file
33
test/integration/targets/nxos_become/tasks/cli.yaml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
---
|
||||||
|
- name: collect common cli test cases
|
||||||
|
find:
|
||||||
|
paths: "{{ role_path }}/tests/common"
|
||||||
|
patterns: "{{ testcase }}.yaml"
|
||||||
|
connection: local
|
||||||
|
register: test_cases
|
||||||
|
|
||||||
|
- name: collect cli test cases
|
||||||
|
find:
|
||||||
|
paths: "{{ role_path }}/tests/cli"
|
||||||
|
patterns: "{{ testcase }}.yaml"
|
||||||
|
connection: local
|
||||||
|
register: cli_cases
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
test_cases:
|
||||||
|
files: "{{ test_cases.files }} + {{ cli_cases.files }}"
|
||||||
|
|
||||||
|
- name: set test_items
|
||||||
|
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
|
||||||
|
|
||||||
|
- name: run test cases (connection=network_cli)
|
||||||
|
include: "{{ test_case_to_run }} ansible_connection=network_cli connection={}"
|
||||||
|
with_items: "{{ test_items }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: test_case_to_run
|
||||||
|
|
||||||
|
- name: run test case (connection=local)
|
||||||
|
include: "{{ test_case_to_run }} ansible_connection=local connection={{ cli }}"
|
||||||
|
with_first_found: "{{ test_items }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: test_case_to_run
|
3
test/integration/targets/nxos_become/tasks/main.yaml
Normal file
3
test/integration/targets/nxos_become/tasks/main.yaml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
- { include: cli.yaml, tags: ['cli'] }
|
||||||
|
#- { include: nxapi.yaml, tags: ['nxapi'] }
|
27
test/integration/targets/nxos_become/tasks/nxapi.yaml
Normal file
27
test/integration/targets/nxos_become/tasks/nxapi.yaml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
- name: collect common nxapi test cases
|
||||||
|
find:
|
||||||
|
paths: "{{ role_path }}/tests/common"
|
||||||
|
patterns: "{{ testcase }}.yaml"
|
||||||
|
connection: local
|
||||||
|
register: test_cases
|
||||||
|
|
||||||
|
- name: collect nxapi test cases
|
||||||
|
find:
|
||||||
|
paths: "{{ role_path }}/tests/nxapi"
|
||||||
|
patterns: "{{ testcase }}.yaml"
|
||||||
|
connection: local
|
||||||
|
register: nxapi_cases
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
test_cases:
|
||||||
|
files: "{{ test_cases.files }} + {{ nxapi_cases.files }}"
|
||||||
|
|
||||||
|
- name: set test_items
|
||||||
|
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
|
||||||
|
|
||||||
|
- name: run test cases (connection=local)
|
||||||
|
include: "{{ test_case_to_run }} ansible_connection=local connection={{ nxapi }}"
|
||||||
|
with_items: "{{ test_items }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: test_case_to_run
|
39
test/integration/targets/nxos_become/tests/cli/sanity.yaml
Normal file
39
test/integration/targets/nxos_become/tests/cli/sanity.yaml
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
---
|
||||||
|
- debug: msg="START connection={{ ansible_connection }}/sanity.yaml"
|
||||||
|
- debug: msg="Using provider={{ connection.transport }}/sanity.yaml"
|
||||||
|
when: ansible_connection == "local"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: update role to priv-14
|
||||||
|
nxos_config:
|
||||||
|
lines:
|
||||||
|
- username admin role priv-14
|
||||||
|
- no username admin role priv-15
|
||||||
|
- enable secret 0 cisco
|
||||||
|
provider: "{{ cli }}"
|
||||||
|
|
||||||
|
- name: reset_connection
|
||||||
|
meta: reset_connection
|
||||||
|
|
||||||
|
- name: run commands with become
|
||||||
|
nxos_command:
|
||||||
|
commands: 'show privilege'
|
||||||
|
provider: "{{ cli }}"
|
||||||
|
become: yes
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "'Current privilege level: 15' in result['stdout'][0]"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: teardown
|
||||||
|
nxos_config:
|
||||||
|
lines:
|
||||||
|
- username admin role priv-15
|
||||||
|
- no username admin role priv-14
|
||||||
|
- no enable secret
|
||||||
|
provider: "{{ cli }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- debug: msg="END connection={{ ansible_connection }}/sanity.yaml"
|
|
@ -3,6 +3,7 @@
|
||||||
nxos_config:
|
nxos_config:
|
||||||
lines:
|
lines:
|
||||||
- feature nxapi
|
- feature nxapi
|
||||||
|
- feature privilege
|
||||||
connection: network_cli
|
connection: network_cli
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue