Skip to content

Commit 02572cb

Browse files
mikewiebeabadger
authored andcommitted
Rewrite nxos_file_copy as an action plugin (ansible#60643)
* Initial nxos_file_copy action plugin work * Remove code from nxos_file_copy module * Add file_push and file_pull support * Additional refactoring and shipable updates * Simplify outcomes and update doc header * Add more error data information for easier debugging * Reorder outcomes and add additional tests * Capture more data for permission denied outcome
1 parent 2215a62 commit 02572cb

File tree

9 files changed

+793
-355
lines changed

9 files changed

+793
-355
lines changed

lib/ansible/modules/network/nxos/nxos_file_copy.py

+40-306
Large diffs are not rendered by default.

lib/ansible/plugins/action/nxos_file_copy.py

+475
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
dependencies:
2-
- prepare_nxos_tests
2+
# prepare_nxos_tests is not needed for this test and simply adds overhead.
3+
# This can be uncommented in the future if needed.
4+
#
5+
# - prepare_nxos_tests

test/integration/targets/nxos_file_copy/tasks/cli.yaml

-6
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,3 @@
2525
with_items: "{{ test_items }}"
2626
loop_control:
2727
loop_var: test_case_to_run
28-
29-
- name: run test cases (connection=local)
30-
include: "{{ test_case_to_run }} ansible_connection=local"
31-
with_items: "{{ test_items }}"
32-
loop_control:
33-
loop_var: test_case_to_run
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
- debug: msg="START nxos_file_copy input_validation test"
3+
4+
- name: "Input Validation - param should be type <str>"
5+
nxos_file_copy:
6+
remote_file: 500
7+
register: result
8+
ignore_errors: true
9+
10+
- assert:
11+
that:
12+
- result is search('Playbook parameter <remote_file> value should be of type <str>')
13+
14+
- name: "Input Validation - param should be type <int>"
15+
nxos_file_copy:
16+
file_pull_timeout: 'foobar'
17+
register: result
18+
ignore_errors: true
19+
20+
- assert:
21+
that:
22+
- result is search('Playbook parameter <file_pull_timeout> value should be of type <int>')
23+
24+
- name: "Input Validation - param should be type <bool>"
25+
nxos_file_copy:
26+
file_pull: 'foobar'
27+
register: result
28+
ignore_errors: true
29+
30+
- assert:
31+
that:
32+
- result is search('Playbook parameter <file_pull> value should be of type <bool>')
33+
34+
- name: "Input Validation - param <file_pull> <remote_file> dependency"
35+
nxos_file_copy:
36+
file_pull: True
37+
register: result
38+
ignore_errors: true
39+
40+
- assert:
41+
that:
42+
- result is search('Playbook parameter <remote_file> required when <file_pull> is True')
43+
44+
- name: "Input Validation - param <file_pull> <remote_scp_server> dependency"
45+
nxos_file_copy:
46+
file_pull: True
47+
remote_file: "/network-integration.cfg"
48+
register: result
49+
ignore_errors: true
50+
51+
- assert:
52+
that:
53+
- result is search('Playbook parameter <remote_scp_server> required when <file_pull> is True')
54+
55+
- name: "Input Validation - remote_scp_server params together"
56+
nxos_file_copy:
57+
remote_scp_server: "{{ inventory_hostname_short }}"
58+
register: result
59+
ignore_errors: true
60+
61+
- assert:
62+
that:
63+
- result is search('Playbook parameters <remote_scp_server>, <remote_scp_server_user>, ,remote_scp_server_password> must all be set together')
64+
65+
- debug: msg="END nxos_file_copy input_validation test"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
---
2+
- debug: msg="START nxos_file_copy negative test"
3+
4+
# This test uses a file that is committed to the Ansible core repository.
5+
# The file name and relative path is test/integration/targets/network-integration.cfg
6+
- set_fact: test_source_file="network-integration.cfg"
7+
- set_fact: test_destination_file="test_destination_file"
8+
9+
# -------------------------
10+
# Tests for file_pull False
11+
# -------------------------
12+
- name: "Attempt to copy file to invalid file_system"
13+
nxos_file_copy:
14+
file_pull: False
15+
local_file: "./{{ test_source_file }}"
16+
file_system: "invalid_media_type:"
17+
connect_ssh_port: "{{ ansible_ssh_port }}"
18+
register: result
19+
ignore_errors: true
20+
21+
- assert:
22+
that:
23+
- result is search('Invalid nxos filesystem invalid_media_type:')
24+
25+
- name: "Attempt to copy source file that does not exist on Ansible controller"
26+
nxos_file_copy:
27+
file_pull: False
28+
local_file: "./{{ test_source_file }}_does_not_exist"
29+
file_system: "bootflash:"
30+
connect_ssh_port: "{{ ansible_ssh_port }}"
31+
register: result
32+
ignore_errors: true
33+
34+
- assert:
35+
that:
36+
- result is search('Local file ./network-integration.cfg_does_not_exist not found')
37+
38+
# -------------------------
39+
# Tests for file_pull True
40+
# -------------------------
41+
- name: "Try and copy file using an invalid remote scp server name"
42+
nxos_file_copy:
43+
file_pull: True
44+
file_pull_timeout: 10
45+
remote_file: "/{{ test_destination_file }}"
46+
local_file: "{{ test_destination_file }}_copy"
47+
local_file_directory: "dir1/dir2/dir3"
48+
remote_scp_server: "scp_server_gone.example.com"
49+
remote_scp_server_user: "{{ ansible_ssh_user }}"
50+
remote_scp_server_password: "{{ ansible_ssh_pass }}"
51+
register: result
52+
ignore_errors: true
53+
54+
- assert:
55+
that:
56+
- "result.changed == false"
57+
- "'copy scp:' in result.copy_cmd"
58+
- "'bootflash:' in result.file_system"
59+
- "'No Transfer' in result.transfer_status"
60+
61+
- assert:
62+
that:
63+
- result.error_data is search("ERROR Could not resolve hostname|Copying to.*from this server name is not permitted")
64+
65+
- name: "Try and copy file using an invalid remote scp server ip address"
66+
nxos_file_copy:
67+
file_pull: True
68+
file_pull_timeout: 300
69+
remote_file: "/{{ test_destination_file }}"
70+
local_file: "{{ test_destination_file }}_copy"
71+
local_file_directory: "dir1/dir2/dir3"
72+
remote_scp_server: "192.168.55.55"
73+
remote_scp_server_user: "{{ ansible_ssh_user }}"
74+
remote_scp_server_password: "{{ ansible_ssh_pass }}"
75+
register: result
76+
ignore_errors: true
77+
78+
- assert:
79+
that:
80+
- "result.changed == false"
81+
- "'copy scp:' in result.copy_cmd"
82+
- "'timed out' in result.error_data"
83+
- "'bootflash:' in result.file_system"
84+
- "'No Transfer' in result.transfer_status"
85+
86+
# Sometimes the previous negative test needs a few seconds after the timeout
87+
# failure before the next negative test is executed.
88+
- pause:
89+
seconds: 10
90+
91+
- name: "Try and copy file using an invalid username"
92+
nxos_file_copy:
93+
file_pull: True
94+
file_pull_timeout: 10
95+
remote_file: "/{{ test_destination_file }}"
96+
local_file: "{{ test_destination_file }}_copy"
97+
local_file_directory: "dir1/dir2/dir3"
98+
remote_scp_server: "{{ inventory_hostname_short }}"
99+
remote_scp_server_user: "invalid_user_name"
100+
remote_scp_server_password: "{{ ansible_ssh_pass }}"
101+
register: result
102+
ignore_errors: true
103+
104+
- assert:
105+
that:
106+
- "result.changed == false"
107+
- "'copy scp:' in result.copy_cmd"
108+
- "'Too many authentication failures' in result.error_data"
109+
- "'bootflash:' in result.file_system"
110+
- "'No Transfer' in result.transfer_status"
111+
112+
- name: "Try and copy file using an invalid password"
113+
nxos_file_copy:
114+
file_pull: True
115+
file_pull_timeout: 10
116+
remote_file: "/{{ test_destination_file }}"
117+
local_file: "{{ test_destination_file }}_copy"
118+
local_file_directory: "dir1/dir2/dir3"
119+
remote_scp_server: "{{ inventory_hostname_short }}"
120+
remote_scp_server_user: "{{ ansible_ssh_user }}"
121+
remote_scp_server_password: "invalid_password"
122+
register: result
123+
ignore_errors: true
124+
125+
- assert:
126+
that:
127+
- "result.changed == false"
128+
- "'copy scp:' in result.copy_cmd"
129+
- "'Too many authentication failures' in result.error_data"
130+
- "'bootflash:' in result.file_system"
131+
- "'No Transfer' in result.transfer_status"
132+
133+
- debug: msg="END nxos_file_copy negative test"

test/integration/targets/nxos_file_copy/tests/cli/sanity.yaml

+75-35
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,45 @@
11
---
22
- debug: msg="START connection={{ ansible_connection }} nxos_file_copy sanity test"
33

4+
# This test uses a file that is committed to the Ansible core repository.
5+
# The file name and relative path is test/integration/targets/network-integration.cfg
6+
- set_fact: test_source_file="network-integration.cfg"
7+
- set_fact: test_destination_file="test_destination_file"
8+
49
- name: "Setup - Remove existing file"
510
nxos_command: &remove_file
611
commands:
712
- terminal dont-ask
8-
- delete network-integration.cfg
9-
- delete bootflash:/dir1/dir2/dir3/network-integration_copy.cfg
13+
- "delete {{ test_source_file }}"
14+
- "delete {{ test_destination_file }}"
15+
- "delete bootflash:/dir1/dir2/dir3/*"
1016
- rmdir dir1/dir2/dir3
1117
- rmdir dir1/dir2
1218
- rmdir dir1
1319
ignore_errors: yes
1420

1521
- name: "Setup - Turn on feature scp-server"
16-
nxos_feature:
22+
nxos_feature:
1723
feature: scp-server
1824
state: enabled
1925

2026
- block:
21-
- name: "Copy network-integration.cfg to bootflash"
27+
- name: "Copy {{ test_source_file }} file from Ansible controller to bootflash"
2228
nxos_file_copy: &copy_file_same_name
23-
local_file: "./network-integration.cfg"
29+
local_file: "./{{ test_source_file }}"
2430
file_system: "bootflash:"
2531
connect_ssh_port: "{{ ansible_ssh_port }}"
2632
register: result
2733

28-
- assert: &true
34+
- assert:
2935
that:
3036
- "result.changed == true"
37+
- "'bootflash:' in result.file_system"
38+
- "'./{{ test_source_file }}' in result.local_file"
39+
- "'network-integration.cfg' in result.remote_file"
40+
- "'Sent: File copied to remote device.' in result.transfer_status"
3141

32-
- name: "Check Idempotence - Copy network-integration.cfg to bootflash"
42+
- name: "Idempotence - Copy {{ test_source_file }} file from Ansible controller to bootflash"
3343
nxos_file_copy: *copy_file_same_name
3444
register: result
3545

@@ -41,47 +51,77 @@
4151
nxos_command: *remove_file
4252
register: result
4353

44-
- name: "Copy inventory.networking.template to bootflash as another name"
54+
- name: "Copy {{ test_source_file }} file from Ansible controller to bootflash renamed as {{ test_destination_file }}"
4555
nxos_file_copy: &copy_file_different_name
46-
local_file: "./inventory.networking.template"
47-
remote_file: "network-integration.cfg"
56+
local_file: "./{{ test_source_file }}"
57+
remote_file: "{{ test_destination_file }}"
4858
file_system: "bootflash:"
4959
connect_ssh_port: "{{ ansible_ssh_port }}"
5060
register: result
5161

52-
- assert: *true
62+
- assert:
63+
that:
64+
- "result.changed == true"
65+
- "'bootflash:' in result.file_system"
66+
- "'./{{ test_source_file }}' in result.local_file"
67+
- "'{{ test_destination_file }}' in result.remote_file"
68+
- "'Sent: File copied to remote device.' in result.transfer_status"
5369

54-
- name: "Check Idempotence - Copy inventory.networking.template to bootflash as another name"
70+
- name: "Idempotence - Copy {{ test_source_file }} file from Ansible controller to bootflash renamed as {{ test_destination_file }}"
5571
nxos_file_copy: *copy_file_different_name
5672
register: result
5773

74+
- name: "Verify file_pull true options have no impact when file_true is false"
75+
nxos_file_copy:
76+
file_pull: False
77+
file_pull_timeout: 1200
78+
file_pull_compact: True
79+
file_pull_kstack: True
80+
local_file_directory: "dir1/dir2/dir3"
81+
remote_scp_server: "{{ inventory_hostname_short }}"
82+
remote_scp_server_user: "{{ ansible_ssh_user }}"
83+
remote_scp_server_password: "{{ ansible_ssh_pass }}"
84+
# Parameters above are only used when file_pull is True
85+
local_file: "./{{ test_source_file }}"
86+
remote_file: "{{ test_destination_file }}"
87+
file_system: "bootflash:"
88+
connect_ssh_port: "{{ ansible_ssh_port }}"
89+
register: result
90+
5891
- assert: *false
5992

60-
- block:
61-
- name: "Copy file using file_pull"
62-
nxos_file_copy: &copy_pull
63-
file_pull: True
64-
file_pull_timeout: 1200
65-
remote_file: "/network-integration.cfg"
66-
local_file: "network-integration_copy.cfg"
67-
local_file_directory: "dir1/dir2/dir3"
68-
remote_scp_server: "{{ inventory_hostname_short }}"
69-
remote_scp_server_user: "{{ ansible_ssh_user }}"
70-
remote_scp_server_password: "{{ ansible_ssh_pass }}"
71-
register: result
72-
73-
- assert: *true
74-
75-
- name: "Overwrite the file"
76-
nxos_file_copy: *copy_pull
77-
register: result
78-
79-
- assert: *true
80-
ignore_errors: yes
93+
# This step validates the ability to initiate the copy from the nxos device
94+
# to pull a file from a remote file server to the nxos bootflash device.
95+
#
96+
# In this case we are using the nxos device as the remote file server so we
97+
# copy a file from bootflash: to bootflash:dir1/dir2/dir3
98+
- name: "Initiate copy from nxos device to copy {{ test_destination_file }} to bootflash:dir1/dir2/dir3/{{ test_destination_file }}_copy"
99+
nxos_file_copy: &copy_pull
100+
file_pull: True
101+
file_pull_timeout: 30
102+
remote_file: "/{{ test_destination_file }}"
103+
local_file: "{{ test_destination_file }}_copy"
104+
local_file_directory: "dir1/dir2/dir3"
105+
remote_scp_server: "{{ inventory_hostname_short }}"
106+
remote_scp_server_user: "{{ ansible_ssh_user }}"
107+
remote_scp_server_password: "{{ ansible_ssh_pass }}"
108+
register: result
81109

82-
rescue:
110+
- assert: &overwrite
111+
that:
112+
- "result.changed == true"
113+
- "'copy scp:' in result.copy_cmd"
114+
- "'bootflash:' in result.file_system"
115+
- "'bootflash:dir1/dir2/dir3/{{ test_destination_file }}_copy' in result.local_file"
116+
- "'/{{ test_destination_file }}' in result.remote_file"
117+
- "'Received: File copied/pulled to nxos device from remote scp server.' in result.transfer_status"
118+
- "'{{ inventory_hostname_short }}' in result.remote_scp_server"
119+
120+
- name: "Overwrite the file"
121+
nxos_file_copy: *copy_pull
122+
register: result
83123

84-
- debug: msg="TRANSPORT:CLI nxos_file_copy failure detected"
124+
- assert: *overwrite
85125

86126
always:
87127

test/integration/targets/nxos_file_copy/tests/nxapi/badtransport.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@
1212

1313
- assert:
1414
that:
15-
- result.failed and result.msg is search('Transport')
15+
- result.failed and result.msg is search('Connection type must be <network_cli>')
1616

1717
- debug: msg="END nxapi/badtransport.yaml"

test/sanity/ignore.txt

-6
Original file line numberDiff line numberDiff line change
@@ -4221,12 +4221,6 @@ lib/ansible/modules/network/nxos/nxos_feature.py validate-modules:doc-default-do
42214221
lib/ansible/modules/network/nxos/nxos_feature.py validate-modules:doc-default-incompatible-type
42224222
lib/ansible/modules/network/nxos/nxos_feature.py validate-modules:parameter-type-not-in-doc
42234223
lib/ansible/modules/network/nxos/nxos_feature.py validate-modules:doc-missing-type
4224-
lib/ansible/modules/network/nxos/nxos_file_copy.py future-import-boilerplate
4225-
lib/ansible/modules/network/nxos/nxos_file_copy.py metaclass-boilerplate
4226-
lib/ansible/modules/network/nxos/nxos_file_copy.py validate-modules:doc-default-does-not-match-spec
4227-
lib/ansible/modules/network/nxos/nxos_file_copy.py validate-modules:doc-default-incompatible-type
4228-
lib/ansible/modules/network/nxos/nxos_file_copy.py validate-modules:parameter-type-not-in-doc
4229-
lib/ansible/modules/network/nxos/nxos_file_copy.py validate-modules:doc-missing-type
42304224
lib/ansible/modules/network/nxos/nxos_gir.py future-import-boilerplate
42314225
lib/ansible/modules/network/nxos/nxos_gir.py metaclass-boilerplate
42324226
lib/ansible/modules/network/nxos/nxos_gir.py validate-modules:doc-default-does-not-match-spec

0 commit comments

Comments
 (0)