morgangraphics / ansible-role-nvm

Installs NVM & Node.js on Debian/Ubuntu and RHEL/CentOS

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

bash: nvm command not found

eyekelly opened this issue · comments

Describe the bug
hello, I'm not sure if this is a "bug", but I don't know where else to ask.
I'm trying to install a specific version of nvm, node, npm on a machine image using packer, however it keeps failing no matter what I try.

Expected behavior
that it installs and passes

To Reproduce

---

- hosts: all
  become: yes
  become_method: sudo

  roles:
    - role: ansible-role-nvm
      nodejs_version: "8.16.0"
      nvm_install: "curl"
      nvm_version: "0.34.0"
      nvm_profile: "/home/nodejs/.bashrc"
      nvm_dir: "/home/nodejs"
      nvm_commands:
       - "nvm install 8.16.0"
       - "nvm alias default 8.16.0"
       - "nvm exec default npm install"

Shell [e.g. Bash, Dash, ksh, tcsh, zsh]
bash
Desktop (please complete the following information):

  • OS: Debian stretch
  • Ansible Version: 2.2.1.0
  • Hypervisor Type and Version packer image on aws

Debugging output

    amazon-ebs:
    amazon-ebs: PLAY [all] *********************************************************************
    amazon-ebs:
    amazon-ebs: TASK [setup] *******************************************************************
    amazon-ebs: ok: [default]
    amazon-ebs:
    amazon-ebs: TASK [ansible-role-nvm : Check if wget or curl is installed] *******************
    amazon-ebs: changed: [default]
    amazon-ebs:
    amazon-ebs: TASK [ansible-role-nvm : Determine if install type wget] ***********************
    amazon-ebs: skipping: [default]
    amazon-ebs:
    amazon-ebs: TASK [ansible-role-nvm : Determine if install type curl] ***********************
    amazon-ebs: ok: [default]
    amazon-ebs:
    amazon-ebs: TASK [ansible-role-nvm : Create destination dir if it does not exist] **********
    amazon-ebs: changed: [default]
    amazon-ebs:
    amazon-ebs: TASK [ansible-role-nvm : Install NVM] ******************************************
    amazon-ebs: changed: [default]
    amazon-ebs:
    amazon-ebs: TASK [ansible-role-nvm : Check if git is installed] ****************************
    amazon-ebs: skipping: [default]
    amazon-ebs:
    amazon-ebs: TASK [ansible-role-nvm : Remove NVM nvm_profile] *******************************
    amazon-ebs: skipping: [default]
    amazon-ebs:
    amazon-ebs: TASK [ansible-role-nvm : Install via git] **************************************
    amazon-ebs: skipping: [default]
    amazon-ebs:
    amazon-ebs: TASK [ansible-role-nvm : Add NVM to nvm_profile] *******************************
    amazon-ebs: skipping: [default]
    amazon-ebs:
    amazon-ebs: TASK [ansible-role-nvm : Check NVM Version] ************************************
    amazon-ebs: fatal: [default]: FAILED! => {"changed": true, "cmd": "bash -ic \"nvm --version\"", "delta": "0:00:00.004018", "end": "2020-01-29 16:08:19.774321", "failed": true, "rc": 127, "start": "2020-01-29 16:08:19.770303", "stderr": "bash: cannot set terminal process group (12602): Inappropriate ioctl for device\nbash: no job control in this shell\nbash: nvm: command not found", "stdout": "", "stdout_lines": [], "warnings": []}
    amazon-ebs:         to retry, use: --limit @/home/admin/eu-sysops-packer/unified-API/unified-api-nodejs.retry
    amazon-ebs:
    amazon-ebs: PLAY RECAP *********************************************************************
    amazon-ebs: default                    : ok=5    changed=3    unreachable=0    failed=1
    amazon-ebs:

Additional context
this may be an issue with packer, the problem seems to occur whatever I do, I need to install all this under a specific user created earlier on in the AMI creation process

any advice gratefully received.

Many thanks

Thanks for the detailed report. I've finally been able to recreate part of the issue. There are actual bugs and some misunderstanding going on here.

First things first

    - role: ansible-role-nvm
      nodejs_version: "8.16.0"
      nvm_install: "curl"
      nvm_version: "0.34.0"
      nvm_profile: "/home/nodejs/.bashrc"
      nvm_dir: "/home/nodejs"
      nvm_commands:
       - "nvm install 8.16.0"       <= NOT NEEDED 
       - "nvm alias default 8.16.0" <= NOT NEEDED 
       - "nvm exec default npm install"
  • If you specify a nodejs_version it will be installed. You don't need to install it again.
  • If you are only installing one version of node with the role, it will automatically be the default version

The role will create a folder when explicitly declaring the nvm_dir variable if it doesn't exist . The role was missing become: true when creating the directory as part of the task, which would have thrown an error (BUGFIX 1)

I suspect that you are adding:

become: yes
become_method: sudo

to get around that error.

Now here comes the tricky part. .bashrc files are sourced when a user logs into the box. Whatever is inside the .bashrc file (in our case the NVM goodness) becomes part of the users context/session/profile/shell for as long as that user is logged in. That is how the nvm command works under the hood. Unfortunately, by setting become: true|yes|1 on the role, it forces the login context to change from the user you expect/want to the *root user. The nvm installation script just does what it does and adds the NVM goodness to the /root/.bashrc file IF THAT FILE EXISTS! otherwise it will dump it where it thinks is best which might not be where we expect it to be.

Now the role ensures the .bashrc file (or whatever file you've specified) is there when nvm_profile is explicitly declared so the nvm installation script knows where to add it's goodness. (BUGFIX 2)

You can check the fixes a798f47

However, here is where I believe there is a bit of confusion. With the information you've provided above, I can probably presume that there is no real nodejs user on the Debian box and that you are just storing the nodejs stuff at /home/nodejs for simplicity. This is a little confusing as /home/nodejs would suggest that there is a real nodejs user account on the machine in which you expect VNM and Node to run as (more on this below)

Because the command to check the nvm version forces the login context to be interactive (the -i in bash -ic command), the command is running in the context of the user you're logging in as/running the role as, in your case the root user. The updates that I've made to the role now provide the correct context so nvm install script will put the .bashrc file in /home/nodejs/.bashrc path as you specified. You would need to remove the become: yes and become_method: sudo from the role to see the result

However, I believe this is not really what you want anyway; the error above is an underlying symptom of a larger issue.

So there are a couple of options to fix the issue. I welcome any feedback

  1. You remove the nvm_profile: "/home/nodejs/.bashrc" and nvm_dir: "/home/nodejs" variables, the role will automatically will place the .bashrc file in the appropriate context, as the user running the playbook and the eventual user you expect NVM and Node to run as (vagrant, ec2-user, amazon-ebs etc.) and the role will work as you expect

  2. The nvm --version command is supposed to be run the same context in which Node will be running (you shouldn't be running Node as root). To fix the underlying issue you would need to create a real nodejs user on the box e.g. sudo useradd nodejs with appropriate sudoers access or with the ansible user module. You can then install the role with become_user: nodejs in which the correct context for nvm will be used and the bash -ic "nvm --version" and any NVM commands will work as expected. I believe this is technically what you are looking for. The role adding users to satisfy the nvm_profile variable is a little outside the scope of the role, but technically possible. At the very least some documentation would be needed to detail this.

  3. The role can sort of fudge the results a little by sourcing the .bashrc file (wherever it lives) before running the bash -ic "nvm --version" command (or any commands like it), something like bash -ic "source {{ nvm_profile }} && nvm --version" if the nvm_profile variable is explicitly declared. This solves the problem with the error but leaves some clarity issues fior when a user doesn't really exist, the login context is different than location of the .bashrc file or when running NVM or Node commands elsewhere or when actually logging into a machine as a default/different user. Not ideal

  4. The role can add a script to the /etc/environment folder that will source the nvm_profile variable (.bashrc file) if it is explicitly declared. Something like always_available: true. It would make it available to anyone logging in. A side effect being the bash -ic "nvm --version" should always work regardless of which user it was installed with. I am not sure this is a good thing or not. I'm leaning towards it not being good as it forgoes what user accounts are good for (sand boxing).

  5. The role could also add the NVM goodness to the global .bashrc profile and have the same effect as above but more explicit. This is something nvm install does out of the box when nvm_profile: "/home/nodejs/.bashrc" and nvm_dir: "/home/nodejs" variables are empty. Documentation would be needed to detail this.

Ok, I believe I have fulfilled the essence of what you are attempting to do by fixing the actual bugs and providing greater details in the documentation to prevent a misunderstanding of what is happening under the hood in regards to users context/session/profile/shells. If you believe that what I have done does not address your particular issue, please feel free to open a new issue.