Skip to content

Commit

Permalink
ios integration tests to network_cli (ansible#33920)
Browse files Browse the repository at this point in the history
* Preliminary steps

* Fix Python3 network_cli ios

* Add connection to debug strings

* Fix ios confirm prompt by way of optional newline

Also update ios_user delete tests
  • Loading branch information
Qalthos authored Dec 20, 2017
1 parent 8d5c8b2 commit cb1b705
Show file tree
Hide file tree
Showing 56 changed files with 358 additions and 102 deletions.
3 changes: 2 additions & 1 deletion lib/ansible/modules/network/ios/ios_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ def user_del_cmd(username):
return json.dumps({
'command': 'no username %s' % username,
'prompt': 'This operation will remove all username related configurations with same name',
'answer': 'y'
'answer': 'y',
'newline': False,
})


Expand Down
4 changes: 2 additions & 2 deletions lib/ansible/plugins/action/ios_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def run(self, tmp=None, task_vars=None):
try:
self._handle_template()
except ValueError as exc:
return dict(failed=True, msg=exc.message)
return dict(failed=True, msg=to_text(exc))

result = super(ActionModule, self).run(tmp, task_vars)

Expand All @@ -54,7 +54,7 @@ def run(self, tmp=None, task_vars=None):

# strip out any keys that have two leading and two trailing
# underscore characters
for key in result.keys():
for key in list(result.keys()):
if PRIVATE_KEYS_RE.match(key):
del result[key]

Expand Down
4 changes: 2 additions & 2 deletions lib/ansible/plugins/cliconf/ios.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ def get_config(self, source='running'):

@enable_mode
def edit_config(self, command):
for cmd in chain([b'configure terminal'], to_list(command), [b'end']):
self.send_command(cmd)
for cmd in chain(['configure terminal'], to_list(command), ['end']):
self.send_command(to_bytes(cmd))

def get(self, command, prompt=None, answer=None, sendonly=False):
return self.send_command(command, prompt=prompt, answer=answer, sendonly=sendonly)
Expand Down
20 changes: 12 additions & 8 deletions lib/ansible/plugins/connection/network_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,10 @@ def exec_command(self, cmd, in_data=None, sudoable=True):
try:
cmd = json.loads(to_text(cmd, errors='surrogate_or_strict'))
kwargs = {'command': to_bytes(cmd['command'], errors='surrogate_or_strict')}
for key in ('prompt', 'answer', 'sendonly'):
if cmd.get(key) is not None:
for key in ('prompt', 'answer', 'sendonly', 'newline'):
if cmd.get(key) is True or cmd.get(key) is False:
kwargs[key] = cmd[key]
elif cmd.get(key) is not None:
kwargs[key] = to_bytes(cmd[key], errors='surrogate_or_strict')
return self.send(**kwargs)
except ValueError:
Expand Down Expand Up @@ -257,7 +259,7 @@ def close(self):
self._connected = False
display.debug("ssh connection has been closed successfully")

def receive(self, command=None, prompts=None, answer=None):
def receive(self, command=None, prompts=None, answer=None, newline=True):
'''
Handles receiving of output from command
'''
Expand All @@ -279,14 +281,14 @@ def receive(self, command=None, prompts=None, answer=None):

window = self._strip(recv.read())
if prompts and not handled:
handled = self._handle_prompt(window, prompts, answer)
handled = self._handle_prompt(window, prompts, answer, newline)

if self._find_prompt(window):
self._last_response = recv.getvalue()
resp = self._strip(self._last_response)
return self._sanitize(resp, command)

def send(self, command, prompt=None, answer=None, sendonly=False):
def send(self, command, prompt=None, answer=None, newline=True, sendonly=False):
'''
Sends the command to the device in the opened shell
'''
Expand All @@ -295,7 +297,7 @@ def send(self, command, prompt=None, answer=None, sendonly=False):
self._ssh_shell.sendall(b'%s\r' % command)
if sendonly:
return
response = self.receive(command, prompt, answer)
response = self.receive(command, prompt, answer, newline)
return to_text(response, errors='surrogate_or_strict')
except (socket.timeout, AttributeError):
display.vvvv(traceback.format_exc(), host=self._play_context.remote_addr)
Expand All @@ -309,7 +311,7 @@ def _strip(self, data):
data = regex.sub(b'', data)
return data

def _handle_prompt(self, resp, prompts, answer):
def _handle_prompt(self, resp, prompts, answer, newline):
'''
Matches the command prompt and responds
Expand All @@ -325,7 +327,9 @@ def _handle_prompt(self, resp, prompts, answer):
for regex in prompts:
match = regex.search(resp)
if match:
self._ssh_shell.sendall(b'%s\r' % answer)
self._ssh_shell.sendall(b'%s' % answer)
if newline:
self._ssh_shell.sendall(b'\r')
return True
return False

Expand Down
11 changes: 9 additions & 2 deletions test/integration/targets/ios_banner/tasks/cli.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@
paths: "{{ role_path }}/tests/cli"
patterns: "{{ testcase }}.yaml"
register: test_cases
delegate_to: localhost

- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"

- name: run test case
include: "{{ test_case_to_run }}"
- name: run test cases (connection=network_cli)
include: "{{ test_case_to_run }} ansible_connection=network_cli"
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 ansible_become=no"
with_first_found: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
banner: login
state: absent
authorize: yes
become: yes

- name: Set login
ios_banner:
Expand All @@ -15,6 +16,7 @@
string
state: present
authorize: yes
become: yes
register: result

- debug:
Expand All @@ -34,6 +36,7 @@
string
state: present
authorize: yes
become: yes
register: result

- assert:
Expand Down
3 changes: 3 additions & 0 deletions test/integration/targets/ios_banner/tests/cli/basic-motd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
banner: motd
state: absent
authorize: yes
become: yes

- name: Set motd
ios_banner:
Expand All @@ -15,6 +16,7 @@
string
state: present
authorize: yes
become: yes
register: result

- debug:
Expand All @@ -34,6 +36,7 @@
string
state: present
authorize: yes
become: yes
register: result

- assert:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
over multiple lines
state: present
authorize: yes
become: yes

- name: remove login
ios_banner:
banner: login
state: absent
authorize: yes
become: yes
register: result

- debug:
Expand All @@ -28,6 +30,7 @@
banner: login
state: absent
authorize: yes
become: yes
register: result

- assert:
Expand Down
10 changes: 8 additions & 2 deletions test/integration/targets/ios_command/tasks/cli.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"

- name: run test case
include: "{{ test_case_to_run }}"
- name: run test cases (connection=network_cli)
include: "{{ test_case_to_run }} ansible_connection=network_cli"
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 ansible_become=no"
with_first_found: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
- debug: msg="START cli/bad_operator.yaml"
- debug: msg="START cli/bad_operator.yaml on connection={{ ansible_connection }}"

- name: test bad operator
ios_command:
Expand All @@ -9,6 +9,7 @@
authorize: yes
wait_for:
- "result[0] contains 'Description: Foo'"
become: yes
register: result
ignore_errors: yes

Expand All @@ -17,4 +18,4 @@
- "result.failed == true"
- "result.msg is defined"

- debug: msg="END cli/bad_operator.yaml"
- debug: msg="END cli/bad_operator.yaml on connection={{ ansible_connection }}"
5 changes: 3 additions & 2 deletions test/integration/targets/ios_command/tests/cli/contains.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
- debug: msg="START cli/contains.yaml"
- debug: msg="START cli/contains.yaml on connection={{ ansible_connection }}"

- name: test contains operator
ios_command:
Expand All @@ -10,11 +10,12 @@
wait_for:
- "result[0] contains Cisco"
- "result[1] contains Loopback888"
become: yes
register: result

- assert:
that:
- "result.changed == false"
- "result.stdout is defined"

- debug: msg="END cli/contains.yaml"
- debug: msg="END cli/contains.yaml on connection={{ ansible_connection }}"
6 changes: 4 additions & 2 deletions test/integration/targets/ios_command/tests/cli/invalid.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
---
- debug: msg="START cli/invalid.yaml"
- debug: msg="START cli/invalid.yaml on connection={{ ansible_connection }}"

- name: run invalid command
ios_command:
commands: show foo
authorize: yes
become: yes
register: result
ignore_errors: yes

Expand All @@ -18,11 +19,12 @@
- show version
- show foo
authorize: yes
become: yes
register: result
ignore_errors: yes

- assert:
that:
- "result.failed"

- debug: msg="END cli/invalid.yaml"
- debug: msg="END cli/invalid.yaml on connection={{ ansible_connection }}"
6 changes: 4 additions & 2 deletions test/integration/targets/ios_command/tests/cli/output.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
---
- debug: msg="START cli/output.yaml"
- debug: msg="START cli/output.yaml on connection={{ ansible_connection }}"

- name: get output for single command
ios_command:
commands:
- show version
authorize: yes
become: yes
register: result

- assert:
Expand All @@ -19,6 +20,7 @@
- show version
- show interfaces
authorize: yes
become: yes
register: result

- assert:
Expand All @@ -27,4 +29,4 @@
- "result.stdout is defined"
- "result.stdout | length == 2"

- debug: msg="END cli/output.yaml"
- debug: msg="END cli/output.yaml on connection={{ ansible_connection }}"
5 changes: 3 additions & 2 deletions test/integration/targets/ios_command/tests/cli/timeout.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
- debug: msg="START cli/timeout.yaml"
- debug: msg="START cli/timeout.yaml on connection={{ ansible_connection }}"

- name: test bad condition
ios_command:
Expand All @@ -8,6 +8,7 @@
authorize: yes
wait_for:
- "result[0] contains bad_value_string"
become: yes
register: result
ignore_errors: yes

Expand All @@ -16,4 +17,4 @@
- "result.failed == true"
- "result.msg is defined"

- debug: msg="END cli/timeout.yaml"
- debug: msg="END cli/timeout.yaml on connection={{ ansible_connection }}"
10 changes: 8 additions & 2 deletions test/integration/targets/ios_config/tasks/cli.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"

- name: run test case
include: "{{ test_case_to_run }}"
- name: run test cases (connection=network_cli)
include: "{{ test_case_to_run }} ansible_connection=network_cli"
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 ansible_become=no"
with_first_found: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run
10 changes: 6 additions & 4 deletions test/integration/targets/ios_config/tests/cli/backup.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
- debug: msg="START cli/backup.yaml"
- debug: msg="START cli/backup.yaml on connection={{ ansible_connection }}"

- name: setup
ios_config:
Expand All @@ -10,13 +10,14 @@
- interface Loopback999
match: none
authorize: yes
become: yes

- name: collect any backup files
find:
paths: "{{ role_path }}/backup"
pattern: "{{ inventory_hostname_short }}_config*"
register: backup_files
delegate_to: localhost
connection: local

- name: delete backup files
file:
Expand All @@ -29,6 +30,7 @@
src: basic/config.j2
backup: yes
authorize: yes
become: yes
register: result

- assert:
Expand All @@ -42,10 +44,10 @@
paths: "{{ role_path }}/backup"
pattern: "{{ inventory_hostname_short }}_config*"
register: backup_files
delegate_to: localhost
connection: local

- assert:
that:
- "backup_files.files is defined"

- debug: msg="END cli/backup.yaml"
- debug: msg="END cli/backup.yaml on connection={{ ansible_connection }}"
Loading

0 comments on commit cb1b705

Please sign in to comment.