6

I use the following block to detect if homebrew is already installed. In a new version, homebrew it is installed in the /opt/ folder and my “solution” is no longer working. What is a better way to check if a command is available?

- name: Check if homebrew is installed
  stat:
    path: "/usr/local/bin/brew"
  register: "homebrew_check"

Considerations I know which and command -v but assumed there should be something in Ansible itself, am I wrong?

Zeitounator
  • 38,476
  • 7
  • 53
  • 66
lony
  • 6,733
  • 11
  • 60
  • 92

2 Answers2

6

In respect to a

... way to check if a command is available

and which was

installed directly from a binary through a script and does not leave any traces in a package manager

it might also be feasible to check directly the version of it. To do so in example

---
- hosts: test.example.com
  become: no
  gather_facts: no

  tasks:

  - name: Gather installed Java version, if there is any
    shell:
      cmd: java -version 2>&1 | head -1 | cut -d '"' -f 2
    register: result
    check_mode: false
    changed_when: false
    failed_when: result.rc != 0 and result.rc != 127

  - name: Set default version, if there is no
    set_fact:
      result:
        stdout_lines: "0.0.0_000"
    when: "'command not found' in result.stdout"
    check_mode: false
    
  - name: Report result
    debug:
      msg: "{{ result.stdout_lines }}"
    check_mode: false

Based on the installed version an installer or updater could be called to install or update to the latest version if necessary.

Also, one could just check if the file exists somewhere via find_module.

U880D
  • 8,601
  • 6
  • 24
  • 40
3

Using which or command in a command task would be ok here IMO since homebrew is installed directly from a binary through a script and does not leave any traces in a package manager.

Meanwhile, since ansible has support for Homebrew, we can use the community.general.homebrew module to test if it is available.

Notes:

  • since I don't have Homebrew I tested my script only in that situation. Meanwhile you should get the expected result testing on a machine where it is available.
  • this method depends on the configured path to find Homebrew. Here I'm using a local connection to my local machine. When using a remote target, ansible will connect via ssh and use sh by default with a non-login shell (not loading any shell init files like login, .bashrc, ...). If your binary is installed outside the available path for the task, you'll get a false negative response.

Here is the idea, adapt to your needs.

The playbooks:

---
- name: Test homebrew presence
  hosts: localhost
  gather_facts: false

  tasks:
    - name: Check if homebrew is available
      block:
        - name: try using homebrew in check_mode (no changes)
          homebrew:
            update_homebrew: true
          check_mode: true

        - name: Homebrew available
          debug:
            msg: Homebrew is installed

      rescue:
        - name: No homebrew
          debug:
            msg: Homebrew is not installed

Gives (without homebrew):

PLAY [Test homebrew presence] ***********************************************

TASK [try using homebrew in check_mode (no changes)] ************************
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Failed to find required executable \"brew\" in paths: /usr/local/bin:/home/user/.local/bin:/home/user/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"}

TASK [No homebrew] **********************************************************
ok: [localhost] => {
    "msg": "Homebrew is not installed"
}

PLAY RECAP ******************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=1    ignored=0   

Zeitounator
  • 38,476
  • 7
  • 53
  • 66
  • Did not know the block thing, but that seems exciting. A bit strange that there is no build in method. – lony Jan 22 '22 at 13:24
  • 1
    What do you think such a builtin module would do to get the result? => Explore the current PATH in order to see if an executable exists, basically what `which` is doing. If it's your first try, implementing this in a custom module should take maximum 2 hours if you really want something cleaner. – Zeitounator Jan 22 '22 at 13:50
  • Yes, I assumed someone built such a module already. As from my experience, you cannot expect `which` to be available on all systems. So point taken :) – lony Jan 22 '22 at 21:31