Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Role fails on nvm commands if connection=local #41

Closed
neutralalice opened this issue Jul 25, 2023 · 9 comments
Closed

Role fails on nvm commands if connection=local #41

neutralalice opened this issue Jul 25, 2023 · 9 comments
Assignees
Labels

Comments

@neutralalice
Copy link

neutralalice commented Jul 25, 2023

Describe the bug
The role fails on the first nvm command it comes across if the role is run with a local connection rather than ssh. It doesn't have access to the nvm commands as they aren't being sourced.

Expected behavior
nvm.sh needs to be sourced in the tasks that utilize nvm so that the shell module can be run locally successfully. Normally this would be fine when connection method is ssh because they get sourced via .bashrc (although this role generates it's own in the playbooks directory in this scenario as well), but running locally doesn't seem to exhibit this behavior

To Reproduce
Ubuntu 22.04 host image
In a directory with the playbook, and relevant cloned /roles/ansible-role-nvm folder (or .ansible/roles etc)

- name: nvm test playbook
  hosts: 127.0.0.1
  connection: local
  roles:
    - role: ansible-role-nvm

Shell [e.g. Bash, Dash, ksh, tcsh, zsh]
bash

Desktop (please complete the following information):

  • OS: Ubuntu 22.04
  • Ansible Version : 2.12.0
  • Hypervisor Type and Version: WSL2 1.2.5.0

Debugging output

TASK [ansible-role-nvm : Check NVM Version] *********************************************************************************************************************************************************
task path: /home/pickles/ubuntu2204-wsl/roles/ansible-role-nvm/tasks/nvm.yml:157
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: pickles
<127.0.0.1> EXEC /bin/sh -c 'echo ~pickles && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/pickles/.ansible/tmp `"&& mkdir "` echo /home/pickles/.ansible/tmp/ansible-tmp-1690297067.3967338-22793-207818345201238 `" && echo ansible-tmp-1690297067.3967338-22793-207818345201238="` echo /home/pickles/.ansible/tmp/ansible-tmp-1690297067.3967338-22793-207818345201238 `" ) && sleep 0'                         Using module file /usr/lib/python3/dist-packages/ansible/modules/command.py
<127.0.0.1> PUT /home/pickles/.ansible/tmp/ansible-local-21568_10qrebw/tmpt0rp4hlp TO /home/pickles/.ansible/tmp/ansible-tmp-1690297067.3967338-22793-207818345201238/AnsiballZ_command.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/pickles/.ansible/tmp/ansible-tmp-1690297067.3967338-22793-207818345201238/ /home/pickles/.ansible/tmp/ansible-tmp-1690297067.3967338-22793-207818345201238/AnsiballZ_command.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/bin/python3 /home/pickles/.ansible/tmp/ansible-tmp-1690297067.3967338-22793-207818345201238/AnsiballZ_command.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /home/pickles/.ansible/tmp/ansible-tmp-1690297067.3967338-22793-207818345201238/ > /dev/null 2>&1 && sleep 0'
fatal: [localhost]: FAILED! => {
"changed": true,
"cmd": "/usr/bin/bash -ic \"nvm --version\"",
"delta": "0:00:00.107722",
"end": "2023-07-25 15:57:47.708570",
"invocation": {
     "module_args": {
            "_raw_params": "/usr/bin/bash -ic \"nvm --version\"",
            "_uses_shell": true, 
            "argv": null,
            "chdir": null,
            "creates": null,
            "executable": null,
            "removes": null,
            "stdin": null,
            "stdin_add_newline": true,
            "strip_empty_ends": true,
            "warn": false
        }
    },
    "msg": "non-zero return code",
    "rc": 127,
    "start": "2023-07-25 15:57:47.600848",
    "stderr": "Command 'nvm' not found, did you mean:\n  command 'gvm' from snap gvm (1.1.0)\n  command 'nsm' from snap nift (3.0.2)\n  command 'nvim' from snap nvim (v0.9.1)\n  command 'nam' from deb nam (1.15-5.2)\n  command 'npm' from deb npm (8.5.1~ds-1)\n  command 'nvme' from deb nvme-cli (1.16-3ubuntu0.1)\n  command 'nsm' from deb linuxptp (3.1.1-3)\n  command 'nvi' from deb nvi (1.81.6-17)\n  command 'nvim' from deb neovim (0.6.1-3)\n  command 'num' from deb quickcal (2.4-1)\n  command 'lvm' from deb lvm2 (2.03.11-2.1ubuntu4)\n  command 'nm' from deb binutils (2.38-4ubuntu2.2)\n  command 'kvm' from deb qemu-system-x86 (1:6.2+dfsg-2ubuntu6.12)\n  command 'vm' from deb mgetty-voice (1.2.1-1.1)\n  command 'pvm' from deb pvm (3.4.6-3.2)\nSee 'snap info <snapname>' for additional versions.",
    "stderr_lines": [
        "Command 'nvm' not found, did you mean:",
        "  command 'gvm' from snap gvm (1.1.0)",
        "  command 'nsm' from snap nift (3.0.2)",
        "  command 'nvim' from snap nvim (v0.9.1)",
        "  command 'nam' from deb nam (1.15-5.2)",
        "  command 'npm' from deb npm (8.5.1~ds-1)",
        "  command 'nvme' from deb nvme-cli (1.16-3ubuntu0.1)",
        "  command 'nsm' from deb linuxptp (3.1.1-3)",
        "  command 'nvi' from deb nvi (1.81.6-17)",
        "  command 'nvim' from deb neovim (0.6.1-3)",
        "  command 'num' from deb quickcal (2.4-1)",
        "  command 'lvm' from deb lvm2 (2.03.11-2.1ubuntu4)",
        "  command 'nm' from deb binutils (2.38-4ubuntu2.2)",
        "  command 'kvm' from deb qemu-system-x86 (1:6.2+dfsg-2ubuntu6.12)",
        "  command 'vm' from deb mgetty-voice (1.2.1-1.1)",
        "  command 'pvm' from deb pvm (3.4.6-3.2)",
        "See 'snap info <snapname>' for additional versions."
    ],
    "stdout": "",
    "stdout_lines": []
}

Additional context
I question if this is the same as #15 but since they didn't give enough information, it is hard to tell. You can test whether or not the local (sub)shell will have access to nvm by entering bash in a terminal and trying any nvm command.

@neutralalice neutralalice changed the title Playbook fails on nvm commands if run locally role fails on nvm commands if run locally/ connection local Jul 25, 2023
@neutralalice neutralalice changed the title role fails on nvm commands if run locally/ connection local Role fails on nvm commands if connection=local Jul 25, 2023
@morgangraphics morgangraphics self-assigned this Jul 25, 2023
@morgangraphics
Copy link
Owner

i'll take a look.

@neutralalice
Copy link
Author

neutralalice commented Jul 26, 2023

The more I thought about it today I'm wondering if it actually has to do with it being run locally, and in the non-home directory; I wondered if my statement in the op "although this role generates it's own in the playbooks directory in this scenario as well" with respect to .bashrc is the real core of the problem. Since the generated .bashrc will be in a nonstandard directory(i.e. where the playbook lives /home/pickles/ubuntu2204-wsl), and not be sourced by the shell when it sets up the local connection.

If I set nvm_profile "~/.bashrc" instead of letting it default nvm_profile: ".bashrc" as well as remove the becomes from the nvm tasks(there's 3 of them) so it doesn't expand out to /root/.bashrc then it runs fine locally.

I think the removing the become arguments may be reasonable for the same reasons as described in the readme. Unless I'm missing something, I don't think those specific tasks should actually need to be elevated? In the "best" example for the role import, it would context switch to the user anyway, and so I'm not sure what purpose those would be serving; The become for those tasks is either defaulting to root, or to the user which has already been context switched to in the play itself.

@morgangraphics
Copy link
Owner

The ansible-role-nvm runs in the context of the user currently running the role.

So, if you are running the role and have become: true or become: yes or become: 1 at the top of your playbook (scoped globally) the ansible-role-nvm will run as root user

OR

have any of those declarations as part of the ansible-role-nvm role itself, the ansible-role-nvm will run as root user

OR

are running the role as the mustard user, the ansible-role-nvm will run as mustard user and install in /home/mustard/ directory

👎 This is likely NOT what you want

- hosts: all
  become: true           # THIS RUNS ALL TASKS, FOR ALL HOSTS, AS ROOT_USER
  become_method: sudo    # THIS RUNS ALL TASKS, FOR ALL HOSTS, AS ROOT_USER

  roles:
    - role: ansible-role-nvm     # installs nvm in the root user directory /root/.bashrc
      nodejs_version: "8.16.0"
      nvm_commands:
       - "nvm exec default npm install"

    - role: some-other-role
      ...

Secondly, if the user pickles is not a real user on the machine, the role will not work as expected. You will need to generate the user and home directory first, then install the role as that user.

- hosts: host1

  pre_tasks:

    - name: add new user
      user:
        name: "pickles"
      become: true

  roles:

    - role: ansible-role-nvm
      nodejs_version: "8.16.0"
      nvm_profile: "/home/pickles/.bashrc"
      nvm_commands:
        - "whoami"
        - "node --version"
        - "nvm --version"
        - "npm --version"
      become_user: pickles
      become: true

In the example above, the nvm_profile key is optional, I use it for illustrative purposes in case people have renamed or have different .bashrc file.

It also scopes the install of NVM to the user it is destined for (in this case pickles). This is particularly useful when:

  1. You are running the role as the mustard user
  2. You have no other option because other roles need become: true or become: yes or become: 1 to work properly

@neutralalice
Copy link
Author

neutralalice commented Jul 26, 2023

pickles is a real user (it was a test vm), and the playbook listed was the playbook utilized with zero changes; In other words, I did not set become in the playbook. Because it's run locally without a "become_user: pickles" in the role include, when it gets to the become commands in the actual tasks, it becomes as root by default. The example playbooks listed in the readme (super simple, simple, more complex) will also exhibit this behavior.

If run locally as the user scoped in the playbook with become commands, there would be no problem. the tasks themselves don't need to attempt to become anything since "become: true" is set your examples in the above.

The problem is that the tasks which utilize the defaults variable generate relative ".bashrc". When you run a playbook locally it scopes to the directory that the playbook is run in, not the home directory of the user context. So in my case, with no changes to the role it will generate a .bashrc in the playbook directory (i.e. /home/pickles/ubuntu2204-wsl/.bashrc with root:root owner/group) and not adjust the actual sourced .bashrc (i.e. /home/pickles/.bashrc) for the user.

@morgangraphics
Copy link
Owner

Ahh, ok

The problem is that the tasks which utilize the defaults variable generate relative ".bashrc". When you run a playbook locally it scopes to the directory that the playbook is run in, not the home directory of the user context.

That was helpful.

Putting this all together, I see a few fixes here:

  1. The default .bashrc file path should be ~/.bashrc instead of .bashrc as you pointed out
  2. When creating/modifying the .bashrc file, I should add the owner:group attributes so the file is scoped to the user appropriately

@morgangraphics
Copy link
Owner

morgangraphics commented Aug 1, 2023

Would you mind testing this branch to see if this addresses your issue?

https://github.com/morgangraphics/ansible-role-nvm/tree/bugfix/41-connection-local

Or provide me with your playbook, so I can test

@neutralalice
Copy link
Author

neutralalice commented Aug 2, 2023

I will give it a go shortly.

I did find a different issue, but I'll open up a separate issue for the role if I can figure out exactly what's triggering it( I believe it's related to the interactive shell usage option).

@neutralalice
Copy link
Author

neutralalice commented Aug 2, 2023

The branch worked using the same playbook as listed in the OP (and also setting become as a local user, but not one running the playbook)

  • able to be run on a fresh vm
  • able to be repeated after installation
  • .bashrc is edited for the local user running the playbook if become is unset
  • if scoping "become" to a different local user, their .bashrc is edited as appropriate
  • nvm/npm available as expected after a terminal reload

@morgangraphics
Copy link
Owner

I believe the original issue has been addressed. If you are still having issues, please open another ticket. Thanks for participating in the process and helping with the project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants