1

I'm building a playbook for my Raspberry Pi 4 and I have a podman container that needs to access the printer (in /dev/bus/usb/XXX/YYY) device.

I have a task that does the job, but it uses the shell module, which is not recommended:

- name: "ScannerJS - Detect printer's USB bus"
  block:
    - name: "ScannerJS - Detect printer's USB bus"
      ansible.builtin.shell: |
        set -e -o pipefail
        lsusb | grep Epson | awk '{print "/dev/bus/usb/"$2"/"substr($4, 1, length($4)-1)}'
      args:
        executable: /bin/bash
      register: scUSBBus
      failed_when: scUSBBus.stdout | regex_search("^\/dev\/bus\/usb\/(\\d{3})\/(\\d{3})$") is none

    - name: "ScannerJS - assert the device path exists"
      ansible.builtin.stat:
        path: "{{ scUSBBus.stdout }}"
      register: scUSBBusStat
      failed_when: scUSBBusStat.stat.exists is not true

Is there a cleaner way to obtain the bus/usb for my printer ?

I tried searching in the facts, but there is nothing about USB devices and I can't find any module related to USB devices.

U880D
  • 8,601
  • 6
  • 24
  • 40
tholeb
  • 174
  • 3
  • 13
  • 1
    Does [How can I use Ansible of a serial connection instead of SSH?](https://stackoverflow.com/questions/62977303/) or [How to connect using console (serial port)?](https://stackoverflow.com/a/71598270/6771046) answer your question? It means you would need to use a [Ansible Serial Unix](https://gitlab.com/Ckarles/ansible-serial-unix) connection and would work for connection adapters USB2Serial. Connected devices are accessible via `/dev/ttyUSBx` then. If your question is just about detecting USB bus within the system ,then your `shell` approach is just OK. – U880D Dec 22 '22 at 11:20
  • Not really, I don't want to connect to anything with a tty, I just want to list all the devices and get the USB path. – tholeb Dec 22 '22 at 11:46
  • 1
    I see. So it more USB device facts gathering and so on ... Currently I am not aware of modules which are focusing on plugable hardware such as USB devices. So you are left with the `shell` approach unless you are not going to develop your own modules. – U880D Dec 22 '22 at 11:57
  • 1
    Regarding "_develop your own module_" I've done a short research for modules which would fulfill your requirements already. During this I've found a project to which I am not related in any case and which had such already implemented: [yaVDR](https://github.com/yavdr). They are [collect facts about the system with custom modules](https://github.com/yavdr/yavdr-ansible/blob/focal/Manual.org#collect-facts-about-the-system-with-custom-modules) i.e. for USB via [`hardware_facts`](https://github.com/yavdr/yavdr-ansible/blob/focal/library/hardware_facts.py). The license is GPLv3. – U880D Dec 22 '22 at 12:09
  • 1
    After a short test the `hardware_facts.py` approach seems to work. Of course, one needs to resolve dependencies like `pip install kmodpy pyusb` and to have high rights on the Remote Node, otherwise errors occur like `IOError: [Errno 13] Permission denied: '/sys/class/tty/ttyS0/irq'`, etc. ... – U880D Dec 22 '22 at 12:43
  • I'll test this out, thanks for the help. Kinda of topic, but while playing with my playbook, I found out that powering off then powering on the printer increment the device value (from `/dev/bus/usb/001/001` to `/dev/bus/usb/001/002` and so on). Is there a way to prevent this and assign a fixed device ID ? – tholeb Dec 22 '22 at 13:10
  • 1
    Regarding USB bus device enumeration process and writing udev rules other sites like unix.stackexchange.com, serverfault.com, superuser.com, etc. will fit more. – U880D Dec 22 '22 at 13:18
  • From the ansible tag: **installing ansible and prerequisites, connection issues... are off-topic** – Rob Dec 22 '22 at 14:13
  • 1
    Well, it's neither a connection issue, a question on Ansible`install or it's prerequisites, so I find the `Ansible` tag fitting to the question. – tholeb Dec 22 '22 at 14:17
  • @Rob, almost every question here regarding Ansible could be interpreted as off-topic since it is about Configuration Management. It can also be interpreted into the direction of programming depending on who looks at it and how and as I showed within the comments and my answer. – U880D Dec 22 '22 at 14:41
  • @U880D Yes, and they should be, as the rule states. It's sad it took so long for me to catch it and that I had to be the one to catch it. – Rob Dec 22 '22 at 14:57
  • @Rob, shouldn't that be a discussion for and on meta.stackoverflow.com/, like on [Are ansible/puppet/chef/salt questions on topic?](https://meta.stackoverflow.com/questions/294923/are-ansible-puppet-chef-salt-questions-on-topic) – U880D Dec 22 '22 at 15:19

1 Answers1

0

Ansible - Is there a way to get access to USB devices?

The short answer is yes, there are multiple ways possible.

Despite of the already given recommendation within the comments about using or Developing Custom Modules, regarding

Is there a cleaner way to obtain ...

you may have a look into the following approach

---
- hosts: localhost
  become: true # is necessary to gather data
  gather_facts: false

  tasks:

  - name: List USB hardware
    command: lshw -json
    register: lshw

  - name: Show USB hardware
    debug:
      msg: "{{ lshw.stdout }}"

resulting into an output (in example) of

...
    "children" : [                                                                                                                                                                                                                                                                                                                                                                                                                                                                 {
    "id" : "usb",
    "class" : "bus",
    "claimed" : true,
    "handle" : "PCI:0000:00:14.0",
    "description" : "USB controller",
    "product" : "C620 Series Chipset Family USB 3.0 xHCI Controller",
    "vendor" : "Intel Corporation",
    "physid" : "14",
    "businfo" : "pci@0000:00:14.0",
    "version" : "09",
    "width" : 64,
    "clock" : 33000000,
    "configuration" : {
      "driver" : "xhci_hcd",
      "latency" : "0"
    },
    "capabilities" : {
      "pm" : "Power Management",
      "msi" : "Message Signalled Interrupts",
      "xhci" : true,
      "bus_master" : "bus mastering",
      "cap_list" : "PCI capabilities listing"
    },
    "children" : [
      {
        "id" : "usbhost:0",
        "class" : "bus",
        "claimed" : true,
        "handle" : "USB:2:1",
        "product" : "xHCI Host Controller",
        "vendor" : "Linux 4.18.0-000.0.0.el8.x86_64 xhci-hcd",
        "physid" : "0",
        "businfo" : "usb@2",
        "logicalname" : "usb2",
        "version" : "4.18",
        "configuration" : {
          "driver" : "hub",
          "slots" : "16",
          "speed" : "480Mbit/s"
        },
        "capabilities" : {
          "usb-2.00" : "USB 2.0"
        },
        "children" : [
          {
            "id" : "usb",
            "class" : "bus",
            "claimed" : true,
            "handle" : "USB:2:3",
            "description" : "USB hub",
            "product" : "Hub",
            "vendor" : "Microchip Technology, Inc. (formerly SMSC)",
            "physid" : "3",
            "businfo" : "usb@2:3",
            "version" : "8.01",
            "configuration" : {
              "driver" : "hub",
              "maxpower" : "2mA",
              "slots" : "2",
              "speed" : "480Mbit/s"
            },
            "capabilities" : {
              "usb-2.00" : "USB 2.0"
            }
          }
        ]
      },
      {
        "id" : "usbhost:1",
        "class" : "bus",
        "claimed" : true,
        "handle" : "USB:3:1",
        "product" : "xHCI Host Controller",
        "vendor" : "Linux 4.18.0-000.0.0.el8.x86_64 xhci-hcd",
        "physid" : "1",
        "businfo" : "usb@3",
        "logicalname" : "usb3",
        "version" : "4.18",
        "configuration" : {
          "driver" : "hub",
          "slots" : "10",
          "speed" : "5000Mbit/s"
        },
        "capabilities" : {
          "usb-3.00" : true
        },
        "children" : [

        ]
      }
    ]
  }
...

Here it is assumed that lshw is pre-installed on the Remote Node(s), which is the case for certain Linux distributions. It has the capability to list information for certain object classes and can provide the output in JSON format which can easily be registered and processed via Ansible.

You can lookup the available classes via sudo lshw -short. USB devices are behind the class bus, so maybe lshw -class bus -json could be enough. I'll leave further testing and implementation up to you.

Further Reading


Regarding your comment about lsusb you could probably use an approach of pre-processing the output.

To do so, you may have a look into the tool JSON Convert (jc) and jc.parsers.lsub. Your command could change to jc lsusb -v only. The converter seems to be available as Ansible module too jc filter – Convert output of many shell commands and file-types to JSON.

In both ways you can get smaller, simpler, less and easier to maintain code, and already JSON formatted data structures. Furthermore an other kind of data processing since there is no need for grep, awk and regex_search.

U880D
  • 8,601
  • 6
  • 24
  • 40
  • Using `command` is the same as `shell` tbh, also the command return an empty array in my case (where lsusb return multiple devices). – tholeb Dec 22 '22 at 14:20
  • 1
    Of course, I've just addressed "_more cleaener_" code. And that's what the example is about. Much smaller, simpler, less code, already JSON formatted, etc. Since `command` and `shell` are not the same, you may also read about [Whats the difference between ansible 'raw', 'shell' and 'command'?](https://stackoverflow.com/a/57805603/6771046). For the empty array you may need to check your installation and permissions. – U880D Dec 22 '22 at 14:42