Skip to content

Fix IOS remote file copy credentials and report device copy errors - #429

Open
mattmiller87 wants to merge 5 commits into
developfrom
u/mattmiller/ios-ftp-copy-credentials
Open

mattmiller87 wants to merge 5 commits into
developfrom
u/mattmiller/ios-ftp-copy-credentials

Conversation

@mattmiller87

@mattmiller87 mattmiller87 commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

Summary

FTP transfers to Cisco IOS devices never authenticated. FileCopyModel.__post_init__ strips credentials out of the download URL (pyntc/utils/models.py:88-90), and the IOS driver sent that stripped URL to the device. It relied on answering Source username and Password prompts instead. IOS does not issue those prompts for copy ftp:. The device attempted an anonymous login, the server refused it, and the transfer failed in under half a second.

The failure was reported through a Nautobot OS upgrade workflow, which surfaced this:

FileTransferError:
An error occurred during transfer. Please make sure the local file exists and
that appropriate permissions are set on the remote device.

What Changed

  1. Fix IOS remote file copy dropping URL credentials.
  2. Report the device error when a remote file copy fails across four drivers.
  3. Bump Netmiko to 4.4.0 for SecretsFilter (note: Netmiko 4.4.0 was released in July of 2024)

Changes by driver

Repurposed existing methods to make all drivers consistent

Element Copied from
_netloc, _source_path, _build_url_copy_command_* nxos_device.py:413-438
for/else guard on the prompt loop asa_device.py:1110-1123
Error carrying the device output eos_device.py:633-637
Token masking jnpr_device.py:1829
or "" on the prompt answers nxos_device.py:596-597

ios_device.py gets the credential routing, the prompt-answer defaults, the error detail and the loop guard.

nxos_device.py, asa_device.py and iosxr_device.py get the error detail only, plus the loop guard where they lacked one. ASA and IOS-XR already logged the device output and then threw it away at the exception.

Testing

The driver was run end to end against a live device, a WS-C3650-48PQ running IOS-XE 16.12.14.

INFO pyntc: Host [redacted]: File pyntc_ftp_test.bin transferred successfully with output: Accessing ftp://*:*@[redacted]/IOS-XE/pyntc_ftp_test.bin...!
[OK - 94038/4096 bytes]

94038 bytes copied in 0.159 secs (591434 bytes/sec)

PASSED: flash:pyntc_ftp_test.bin transferred and the md5 verified.

Fifteen new unit tests cover the IOS credential routing, the non-default port, the VRF token, the error detail and the loop guard. The error and loop-guard tests are mirrored on NX-OS, ASA and IOS-XR.

tests/integration/test_ios_device.py is new and skips unless its URL environment variables are set, so it runs against a lab device on demand and never in CI.

Follow-ups, not in this PR

  • FileCopyModel.ftp_passive does nothing outside the Junos driver. IOS defaults to active FTP and would need ip ftp passive in global config.
  • Six drivers repeat the same copy-command construction and prompt walk. The logic could be collapsed into a utils.py or base.py helper. That should likely be a separate PR, if desired.
  • Standardize percent-encoded values in the URL across all drivers (fixed only in IOS).

@mattmiller87
mattmiller87 force-pushed the u/mattmiller/ios-ftp-copy-credentials branch from 5149566 to 6c2475d Compare September 23, 2026 16:47
@jtdub

jtdub commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

PRAISE: The PR fixes the root cause. IOS does not prompt for FTP credentials, so the driver now puts them into the URL. HideUrlCredentials applies only to the schemes that carry credentials. The comment at ios_device.py:949 records why the log messages use f-strings. The error detail and the for/else loop guards have the same tests on IOS, NX-OS, ASA, and IOS-XR.

Comment thread pyntc/devices/ios_device.py
Comment thread pyntc/devices/ios_device.py
Comment thread pyntc/devices/ios_device.py Outdated

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants