Skip to content

Conversation

@timway
Copy link

@timway timway commented Oct 22, 2025

SUMMARY
  • The Cisco SSH server only supports the SCP protocol and subsequent attempts to interact with the device after a fetch or a put will fail. This patch addresses that in the libssh connection plugin while also reworking net_put
  • As I researched my own troubles in leveraging libssh on an older container image I wrote this patch. It needs a lot more work including at least:
    • (DONE) Need to add check mode support
    • (DONE) Need to finish the idempotency checking (namely the reporting back to Ansible)
    • (DONE) Need to fix the paramiko support
    • (DONE) Need to reinstate the check for only network_cli connection types
  • Was tested using 358553e9765e7873a9d3972dd877dfe415c1dc06 of libssh from https://gitlab.com/libssh/libssh-mirror/
  • Was tested against:
    • Cisco 2960X running 15.1 using libssh and paramiko
    • Mikrotik RouterOS running 7.20.2 (ansible_network_os: community.network.routeros) using libssh and paramiko

This patch-set support adds check and diff mode support to the module for both binary and text files. The binary diff mode uses a prepared statement to display the checksums. The text file displays the normal before and after message.

I'm working this in conjunction with troubleshooting this issue: https://gitlab.com/libssh/libssh-mirror/-/issues/321

ISSUE TYPE
  • Bugfix Pull Request
COMPONENT NAME

net_put

* The Cisco SSH server only supports the SCP protocol and subsequent attempts to interact with the device after a fetch or a put will fail. This patch addresses >
* As I researched my own troubles in leveraging `libssh` on an older container image I wrote this patch. It needs a lot more work including at least:
    * Need to add check	mode support
    * Need to finish the idempotency checking (namely the reporting back to Ansible)
    * Need to fix the `paramiko` support
    * Need to reinstate	the check for only `network_cli` connection types
* Was tested using 358553e9765e7873a9d3972dd877dfe415c1dc06 of libssh from https://gitlab.com/libssh/libssh-mirror/
* Was tested using a Cisco 2960X running 15.1
@KB-perByte
Copy link
Collaborator

@timway Considering this PR is in draft, do note we do not have support for Cisco IOS 15.x versions
Even though the net_put modules are kinda generic in nature. We still need it to work well with most network collection maintained. A PR tested over a non supported applaince would be staged and will be tested when my team gets time to check it alongside other vendors and also check if the patch impacts operation of transport as paramiko. Then only we can merge it.
Regards.

* Swap to `get_file` and `copy_file` from `Connection` in `network_cli.py` to support both `libssh` and `paramiko`
* Restore the `network_cli` check
* Add diff mode support, prepared with information on checksums with binary files, and text diffs when files are text mode
* Add check mode support
@timway
Copy link
Author

timway commented Nov 2, 2025

A test run where there is flash:scratch.1 and flash:scratch.2 on the switch. I modify scratch.1 locally (dd if=/dev/random of=scratch.1 bs=128K count=2). This is meant to show the prepared diff message on a binary file (checksum comparison). Additionally, I add a 3rd binary file via paramiko called scratch.3. I also test the template functionality and toggle the values to show the text mode diff output.

playbook.yml

---
# podman run --rm --interactive --tty --volume $HOME/Projects:/projects:z --volume $(pwd):/scratch:z --workdir /scratch quay.io/centos/centos:stream8 bash

- name: Test `ansible.netcommon.net_put` with `libssh`
  hosts: all
  tags:
    - libssh

  tasks:
    - name: Copy the files
      ansible.netcommon.net_put:
        dest: "flash:{{ item }}"
        src: "{{ item }}"
      loop:
        - scratch.1
        - scratch.2

    - name: Template out a file
      ansible.netcommon.net_put:
        dest: flash:template.1
        mode: text
        src: thing.j2
      vars:
        thing: abcd

  vars:
    ansible_network_cli_ssh_type: libssh

- name: Test `ansible.netcommon.net_put` with `paramiko`
  hosts: all
  tags:
    - paramiko

  tasks:
    - name: Copy the 1st file
      ansible.netcommon.net_put:
        dest: "flash:{{ item }}"
        src: "{{ item }}"
      loop:
        - scratch.1
        - scratch.2
        - scratch.3

    - name: Template out a file
      ansible.netcommon.net_put:
        dest: flash:template.1
        mode: text
        src: thing.j2
      vars:
        thing: abcd

    - name: Template out a file
      ansible.netcommon.net_put:
        dest: flash:template.1
        mode: text
        src: thing.j2
      vars:
        thing: efgh

  vars:
    ansible_network_cli_ssh_type: paramiko

Execution Output

ANSIBLE_COLLECTIONS_PATH=/collections LD_LIBRARY_PATH=/build/lib ansible-playbook --inventory hosts playbook.yml -v --diff
No config file found; using defaults

PLAY [Test `ansible.netcommon.net_put` with `libssh`] ***************************************************************

TASK [Gathering Facts] **********************************************************************************************
ok: [sw2960x-15-1]

TASK [Copy the files] ***********************************************************************************************
changed: [sw2960x-15-1] => (item=scratch.1) => {"ansible_loop_var": "item", "changed": true, "item": "scratch.1", "prepared": "File checksum mismatch, will replace files! The source checksum is a9d97e20cb751764db602c407706509c525dc4bc and the destination is 7174784130bf3ed79567c210ce7e71a72bc0e902"}
ok: [sw2960x-15-1] => (item=scratch.2) => {"ansible_loop_var": "item", "changed": false, "item": "scratch.2"}

TASK [Template out a file] ******************************************************************************************
ok: [sw2960x-15-1] => {"changed": false}

PLAY [Test `ansible.netcommon.net_put` with `paramiko`] *************************************************************

TASK [Gathering Facts] **********************************************************************************************
ok: [sw2960x-15-1]

TASK [Copy the 1st file] ********************************************************************************************
ok: [sw2960x-15-1] => (item=scratch.1) => {"ansible_loop_var": "item", "changed": false, "item": "scratch.1"}
ok: [sw2960x-15-1] => (item=scratch.2) => {"ansible_loop_var": "item", "changed": false, "item": "scratch.2"}
changed: [sw2960x-15-1] => (item=scratch.3) => {"ansible_loop_var": "item", "changed": true, "item": "scratch.3", "prepared": "File checksum mismatch, will replace files! The source checksum is 5c131ee1fcc79b7fd4b2e2fbb21af4b01ef4bb05 and the destination is da39a3ee5e6b4b0d3255bfef95601890afd80709"}

TASK [Template out a file] ******************************************************************************************
ok: [sw2960x-15-1] => {"changed": false}

TASK [Template out a file] ******************************************************************************************
--- before
+++ after
@@ -1 +1 @@
-some random abcd!
\ No newline at end of file
+some random efgh!
\ No newline at end of file

changed: [sw2960x-15-1] => {"changed": true}

PLAY RECAP **********************************************************************************************************
sw2960x-15-1                  : ok=7    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

The next step is to test this patch-set against an IOS-XE switch running more modern code to confirm it works as well. I haven't implemented the parameter from your PR @KB-perByte. If we think that's needed as well we can roll that in of course to skip pulling the file.

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.

Lingering Temporary Files In net_put socket path does not exist or cannot be found Ansible copying Cisco Bin File locally/remotely at the same time

2 participants