ansible-collections / community.general

Ansible Community General Collection
https://galaxy.ansible.com/ui/repo/published/community/general/
GNU General Public License v3.0
832 stars 1.53k forks source link

cargo fails to find standard homedir path for cargo binary #4407

Closed hammerandtongs closed 1 year ago

hammerandtongs commented 2 years ago

Summary

the cargo module fails with -

TASK [Install tokei Rust package] *************************************************************************************************************************** fatal: [hostname]: FAILED! => {"changed": false, "msg": "Failed to find required executable \"cargo\" in paths: /usr/local/bin:/usr/bin:/bin:/usr/games:/sbin:/usr/sbin:/usr/local/sbin"}

cargo executable is located in default rustup install location /home/username/.cargo/bin/

Issue Type

Bug Report

Component Name

cargo

Ansible Version

$ ansible --version
ansible [core 2.12.3]
  config file = /home/username/foo/ansible.cfg
  configured module search path = ['/home/username/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/username/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.9.10 (main, Feb 22 2022, 13:54:07) [GCC 11.2.0]
  jinja version = 3.0.3
  libyaml = True

Community.general Version

$ ansible-galaxy collection list community.general

# /usr/lib/python3/dist-packages/ansible_collections
Collection        Version
----------------- -------
community.general 4.5.0  

Configuration

$ ansible-config dump --only-changed
DEFAULT_HOST_LIST(/home/username/foo/ansible.cfg) = ['/home/username/foo/HOSTS']

OS / Environment

Debian Bookworm targeting Bookworm

Steps to Reproduce

Run this module against home directory with the default rustup install location.

Expected Results

cargo installs the package

Actual Results

TASK [Install tokei Rust package] ***************************************************************************************************************************
fatal: [hostname]: FAILED! => {"changed": false, "msg": "Failed to find required executable \"cargo\" in paths: /usr/local/bin:/usr/bin:/bin:/usr/games:/sbin:/usr/sbin:/usr/local/sbin"}

Code of Conduct

ansibullbot commented 2 years ago

Files identified in the description:

If these files are incorrect, please update the component name section of the description or use the !component bot command.

click here for bot help

ansibullbot commented 2 years ago

cc @radek-sprta click here for bot help

felixfontein commented 2 years ago

Ansible looks in /sbin, /usr/sbin, /usr/local/sbin and $PATH. Your $PATH only seems to contain /usr/local/bin, /usr/bin, and /bin, but not /home/username/.cargo/bin/.

hammerandtongs commented 2 years ago

Yes ansible is ignoring the expanded path from the .bashrc and .profile (and this is how ansible normally works).

Rustup puts a . ~/.cargo/env in profile or bashrc and this is being ignored by ansible and so the cargo module can't work with this setup.

There is mention of this in the ansible cargo docs as working better with the hardcoded bin paths probably because of this issue.

edit-

This seems like a case where the module cargo should use something like -

shell: bash -ilc 'which cargo'

So that the proper environment is found.

felixfontein commented 2 years ago

Ansible does nowhere document that these files are loaded and/or interpreted. So why is this a bug? It is a mismatched expectation / missing feature (ability to specify extra paths where to look, diectly path to executable, or automatically add ~/.cargo/bin/ to search path), but I don't see how this is a bug.

hammerandtongs commented 2 years ago

This module seems like a busy sysadmins trap.

It doesn't detect the default install location for most peoples development environment (ie rustup based) that it's failing to find.

It's also going to invoke cargo install (which does build things) without respecting the developer rust environment.

There are many potential bugs by hardcoding things like this.

Right now this module seems unsuitable for a developer workstation deploy.

The module can work for people that only want to install ripgrep via an os installed cargo (thus bypassing the os installed ripgrep).

I think I would have nacked this module until both the path and cargo respected the remote environment.

But really it needs some rustup integration as well, as a big chunk of developer tooling is in rustup. -

https://github.com/hurricanehrndz/ansible-rustup

This following yaml was robust and useful in deploying a workstation

---
- hosts: workstations
  vars:
    cargo_installs: [tokei,cargo-crev,flamegraph]
    rustup_installs: [rustfmt, rust-src, clippy]
  tasks:
  - name: check if cargo is installed
    shell: bash -lc "command -v cargo"
    register: cargo_exists
    ignore_errors: no
  - name: Download rustup
    when: cargo_exists is failed
    get_url:
      url: https://sh.rustup.rs
      dest: /tmp/sh.rustup.rs
      mode: '0750'
      force: 'yes'
    tags:
      - rust
  - name: install rust/cargo
    when: cargo_exists is failed
    shell: /tmp/sh.rustup.rs -y
    tags:
      - rust
  - name: do the cargo installs
    with_items: "{{cargo_installs}}"
    shell: "bash -lc 'cargo install -q {{item}}'"
    loop: "{{cargo_installs}}"
    register: op
  - name: do the rustup installs
    with_items: "{{rustup_installs}}"
    shell: "bash -lc 'rustup component add {{item}}'"
  - name: rustup update
    shell: bash -lc "rustup update"

original source - https://waylonwalker.com/til/install-rust/#full-install-playbook

radek-sprta commented 2 years ago

I think implementing executable argument to specify path to the binary (like some of the other modules do) seems to be the best solution.

hammerandtongs commented 2 years ago

@radek-sprta I think that would solve the immediate issue but I'm not sure it will be correct in the medium term.

When you run "~/.cargo/bin/cargo" or the found cargo directly its still going to ignore -

https://doc.rust-lang.org/cargo/reference/environment-variables.html

If you don't run cargo install within the shell environment.

I have no idea who or in what circumstances would get future confusion or bugs.

radek-sprta commented 2 years ago

Whjen I get back from PTO, I'll take a look at implementing those.

ansibullbot commented 2 years ago

Files identified in the description:

If these files are incorrect, please update the component name section of the description or use the !component bot command.

click here for bot help

autra commented 1 year ago

It's old, but searches brings here. My current workaround is to directly alter the PATH:

- name: install rust stuff
  environment:
    PATH: "{{ansible_env.PATH}}:{{ ansible_env.HOME }}/.cargo/bin"
  community.general.cargo:
    name:
      - ...

It has the advantage of making it explicit which cargo I target (but for that I would prefer an executable option still).