Skip to content

Updates to the EOS driver based on PR comments from #365#368

Merged
itdependsnetworks merged 8 commits intonetworktocode:developfrom
jtdub:u/jtdub-eos-device-updates
Apr 14, 2026
Merged

Updates to the EOS driver based on PR comments from #365#368
itdependsnetworks merged 8 commits intonetworktocode:developfrom
jtdub:u/jtdub-eos-device-updates

Conversation

@jtdub
Copy link
Copy Markdown
Contributor

@jtdub jtdub commented Apr 14, 2026

Summary

Addresses review comments from @gsnider2195 on PR #365. Resolves 12 items across eos_device.py and test_eos_device.py.

Production code (pyntc/devices/eos_device.py)

  • Fail-fast validation: Scheme and query string checks moved before open()/enable() so invalid inputs error without connecting to the device.
  • EOS hashing algorithm validation: get_remote_checksum now validates against an EOS-specific subset (md5, sha1, sha256, sha512) and raises a clear ValueError for unsupported algorithms.
  • Checksum parsing simplified: Replaced regex with str.split("=") for parsing verify command output.
  • Destination filename in copy commands: Both _build_url_copy_command_simple and _build_url_copy_command_with_creds now include the destination filename so URL-derived names (e.g., download) don't override the intended filename.
  • Query string rejection: URLs with ? are rejected since EOS CLI cannot handle them.
  • netloc for host:port: Replaced manual hostname/port construction with computed netloc.
  • Credential routing simplified: Removed include_username parameter. Routing is now based on src.username: if None, uses the simple builder; otherwise uses the creds builder. Token-only auth (no username) correctly falls through to the simple builder.
  • clean_url instead of download_url: Command builders use src.clean_url to prevent credential leakage.
  • verify_file improvements: Early return when file doesn't exist; case-insensitive checksum comparison.
  • Error detection extracted: Duplicate error-checking blocks consolidated into _check_copy_output_for_errors.
  • Module-level constants: EOS_SUPPORTED_SCHEMES and EOS_SUPPORTED_HASHING_ALGORITHMS are now sets at module scope.

Tests (tests/unit/test_devices/test_eos_device.py)

  • Removed hypothesis import block and all standalone @given/@pytest.mark.parametrize test functions.
  • Consolidated into unittest.TestCase classes with self.assertRaises, self.assertEqual, and self.subTest.
  • Removed duplicate TestRemoteFileCopyCommandExecution class (tests already covered by TestRemoteFileCopy).
  • Removed stale # TODO: unit test for remote_file_copy.
  • Added tests for unsupported scheme, query string rejection, and token-only auth routing.

Test plan

  • poetry run python -m pytest tests/unit/test_devices/test_eos_device.py — 65 passed, 19 subtests passed
  • poetry run ruff check — all checks passed

🤖 Generated with Claude Code

% source .env && poetry run pytest tests/integration/test_eos_device.py -v
===================================================================================== test session starts =====================================================================================
platform darwin -- Python 3.12.11, pytest-9.0.3, pluggy-1.6.0 -- /Users/jameswilliams/Library/Caches/pypoetry/virtualenvs/pyntc-gs002iVE-py3.12/bin/python
cachedir: .pytest_cache
rootdir: /Users/jameswilliams/Documents/code/pyntc
configfile: pyproject.toml
plugins: f5-sdk-3.0.21, requests-mock-1.12.1
collected 10 items

tests/integration/test_eos_device.py::test_device_connects PASSED                                                                                                                       [ 10%]
tests/integration/test_eos_device.py::test_check_file_exists_false PASSED                                                                                                               [ 20%]
tests/integration/test_eos_device.py::test_get_remote_checksum_after_exists PASSED                                                                                                      [ 30%]
tests/integration/test_eos_device.py::test_remote_file_copy_ftp PASSED                                                                                                                  [ 40%]
tests/integration/test_eos_device.py::test_remote_file_copy_tftp PASSED                                                                                                                 [ 50%]
tests/integration/test_eos_device.py::test_remote_file_copy_scp PASSED                                                                                                                  [ 60%]
tests/integration/test_eos_device.py::test_remote_file_copy_http PASSED                                                                                                                 [ 70%]
tests/integration/test_eos_device.py::test_remote_file_copy_https FAILED                                                                                                                [ 80%]
tests/integration/test_eos_device.py::test_remote_file_copy_sftp PASSED                                                                                                                 [ 90%]
tests/integration/test_eos_device.py::test_verify_file_after_copy PASSED                                                                                                                [100%]

The EOS device I'm testing against doesn't support the TLS version required by the server.

FAILED tests/integration/test_eos_device.py::test_remote_file_copy_https - pyntc.errors.FileTransferError: FileTransferError:
Error detected in copy command output:
cd `https://192.0.2.1/' [Waiting for response...]

% Error copying https://192.0.2.1/nautobot.png to flash: (
---- Connecting to 192.0.2.1 (192.0.2.1) port 8443
**** send: gnutls_handshake: A TLS fatal alert has been received.
**** recv: gnutls_handshake: A TLS fatal alert has been received.
cd: Fatal error: gnutls_handshake: A TLS fatal alert has been received.

see above for details
)

@jtdub jtdub marked this pull request as draft April 14, 2026 15:48
jtdub and others added 2 commits April 14, 2026 10:57
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jtdub jtdub marked this pull request as ready for review April 14, 2026 16:03
Comment thread pyntc/devices/eos_device.py
Comment thread pyntc/devices/eos_device.py Outdated
Copy link
Copy Markdown
Contributor

@jeffkala jeffkala left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 comments, but seems good for me

jtdub and others added 2 commits April 14, 2026 12:17
Fixed copy command builders to include the source file path in the URL
and use `flash:` as destination, matching EOS CLI conventions. Fixed
password-prompt handling to wait for transfer completion. Fixed
`_uptime_to_string` integer division, and `check_file_exists` /
`get_remote_checksum` to open SSH before use. Added integration tests
and updated changelog fragments.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ecated facts()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jtdub
Copy link
Copy Markdown
Contributor Author

jtdub commented Apr 14, 2026

Responding to @jeffkala's comments:


Re: _check_copy_output_for_errors readability (comment)

Good callout on readability, but the logic isn't quite the same — if output.lower() in ["error", "invalid", "failed"] checks if the entire output string equals one of those words. What we need is substring matching: does the output contain any of those words. For example, "% Error copying ftp://..." would not match with in, but does match with the any() approach.


Re: half-baked typing (comment)

Fair point. Adding type hints to the remote_file_copy signature in the next push.

jtdub and others added 3 commits April 14, 2026 12:22
Addresses review feedback from jeffkala.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces write_channel + separate send_command_timing with a single
send_command_timing(src.token) that sends the password and waits for
transfer completion in one step.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Moves URL parsing into the model so it happens once instead of on every
command builder call. The EOS driver now reads src.hostname, src.port,
and src.path directly, eliminating urlparse calls from the copy command
builders. Other drivers can adopt the new fields incrementally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jtdub jtdub requested a review from jeffkala April 14, 2026 18:04
Copy link
Copy Markdown
Contributor

@smk4664 smk4664 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing those issues I pointed out!

@itdependsnetworks itdependsnetworks merged commit 4a9bec4 into networktocode:develop Apr 14, 2026
10 checks passed
@jtdub jtdub deleted the u/jtdub-eos-device-updates branch April 14, 2026 18:27
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.

4 participants