Repository: ansible/ansible-modules-extras

Issue:
#446 broke npm state=latest for missing packages
##### Issue Type:
- Bug Report (`npm` module)
##### Ansible Version:

Running against devel:

``` console
$ ansible --version
ansible 2.1.0 (devel be5488cb60) last updated 2015/12/15 09:36:59 (GMT -400)
  lib/ansible/modules/core: (devel 6b13da738b) last updated 2015/12/15 09:38:18 (GMT -400)
  lib/ansible/modules/extras: (devel f3251de29c) last updated 2015/12/15 09:38:42 (GMT -400)
  config file = /home/tomxtobin/.ansible.cfg
  configured module search path = Default w/o overrides
```
##### Ansible Configuration:

``` ini
[defaults]
hostfile = ~/ansible/hosts
nocows = 1
```
##### Environment:

N/A (but it's Arch Linux)
##### Summary:

It looks like PR #446 broke `npm: name=foo state=latest` for a missing package `foo` (i.e., `foo` isn't present on the system yet).

Suggested fix: for `state == 'latest'`, actually differentiate between the result of checking `len(missing)` and `len(outdated)` to see whether the package is installed or not, and run either `npm.install()` or `npm.update()` as appropriate.
##### Steps To Reproduce:

Let's use the `gulp` package as an example.

On a system that doesn't already have `gulp` installed globally:

``` console
$ ansible example-host -m command -a 'npm ls -g -depth 0 gulp' 
example-host | FAILED | rc=1 >>
/usr/lib
└── (empty)npm ERR! code 1
```

``` console
$ ansible example-host -m command -a 'gulp --version' 
example-host | FAILED | rc=2 >>
[Errno 2] No such file or directory
```

Run a task against such system to install `gulp` globally:

``` console
$ ansible example-host -m npm -a 'name=gulp state=latest global=yes'
example-host | SUCCESS => {
    "changed": true
}
```
##### Expected Results:

The module (`gulp`, above) actually gets installed on the system(s) I'm running that task against.

Against such a system, I can run something like:

``` console
$ ansible example-host -m command -a 'npm ls -g -depth 0 gulp' 
example-host | SUCCESS | rc=0 >>
/usr/lib
└── gulp@3.9.0 
```

``` console
$ ansible example-host -m command -a 'gulp --version'
example-host | SUCCESS | rc=0 >>
[15:24:28] CLI version 3.9.0
```

(Assuming the latest version of `gulp` happened to be `3.9.0`.)
##### Actual Results:

Ansible claims it succeeds in running the task, but it doesn't actually install `gulp` on the system(s) in question.

On such a system:

``` console
$ ansible example-host -m command -a 'npm ls -g -depth 0 gulp' 
example-host | FAILED | rc=1 >>
/usr/lib
└── (empty)npm ERR! code 1
```

``` console
$ ansible example-host -m command -a 'gulp --version' 
example-host | FAILED | rc=2 >>
[Errno 2] No such file or directory
```

You can actually keep re-running the task over and over, and Ansible will keep claiming to successfully install `gulp`:

``` console
$ ansible example-host -m npm -a 'name=gulp state=latest global=yes'
example-host | SUCCESS => {
    "changed": true
}
$ ansible example-host -m npm -a 'name=gulp state=latest global=yes'
example-host | SUCCESS => {
    "changed": true
}
```



Discussion:
[module: npm.py]

Confirmed this one this morning. Issued a PR.

Same behaviour in current stable with npm 3.5.4 
ansible 2.0.0.2
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides

Environment: Debian jessie/64 with nodejs package from nodesource 0.10 repo

@gunzy83 Your PR looks good to me, but it's a subset of my own PR #1663, would you mind giving it a go?

@tomxtobin PR #1663 solves this problem. I tested your use case and works. Note you probably want to have latest npm as older versions have bugs that make it hard to support in the ansible module. At this time latest npm is 3.7.2 (install with npm install npm -g). In fact, it's even possible that if you have an old npm version just updating npm could fix your problem without needing the changes of PR #1663 .

I've noticed a large uptick in the number of users reporting npm package install failures when using `state=latest`, and glad to see there's already a PR to help... in the interim, would `latest` work if the package is already installed and there's a newer version? I could use that as a workaround for the time being; have one task that runs if the package isn't installed, then a second task to make sure it's 'latest'. It's a bit of a kludge, but it would get the job done.

See, for a build failure example: https://travis-ci.org/geerlingguy/ansible-role-nodejs/builds/110545132 (CentOS 6/7 aren't running latest ansible, so they pass).

Update: If you are having failures using a playbook task like:

``` yaml
- npm: name=node-sass state=latest
```

You can just add a task above to set `state=present`, then leave the second task, and Ansible will make sure the package is installed, then make sure it's at the latest version. A decent enough workaround until this bug is fixed!

``` yaml
- npm: name=node-sass state=present
- npm: name=node-sass state=latest
```

I confirm. Following command does not install nodejs module:

`ansible -s -m npm -a 'name=bower global=yes state=latest'`

+1

I can confirm that both #1498 and #1663 fix the issue. I tested them both cherry-picked against `HEAD`.

(Sorry I took so long to review those; I moved to using Docker, so the only thing I use Ansible for these days is provisioning Docker hosts.)

@moises-silva It wasn't the npm version; the problem persisted with the latest npm.

@tomxtobin Thank you for the feedback. Unfortunately the Ansible team has yet to make any comment here. This is clearly an issue for a lot of users and the module as it is currently shipped is plain broken, not sure why it takes this long just to review/merge a patch like this. I've successfully pushed a bunch of patches (both bugs and features) in the saltstack project (kinda competing Ansible solution). Takes them one day to respond, another one for me to make adjustments and they merge right away.

@geerlingguy Thanks for the workaround until this can be addressed.

See #1498 for the fix to this issue and #1675, made early this year - unfortunately not merged yet.

@chrishoffman, ping. This issue is still waiting on your response.
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)

<!--- boilerplate: issue_renotify_maintainer --->

@shane-walker, ping. This issue is still waiting on your response.
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)

<!--- boilerplate: issue_renotify_maintainer --->

Can confirm it still happen: ansible 2.1.1 npm v3.10.8

@mpdehaan - please can you get someone from Ansible team to look at this?   Installs of `npm` modules are failing due to this issue.   We have a PR that fixes issue, but no active maintainer to apply and fix.


Resolving patch:
diff --git a/packaging/language/npm.py b/packaging/language/npm.py
--- a/packaging/language/npm.py
+++ b/packaging/language/npm.py
@@ -252,7 +252,10 @@ def main():
     elif state == 'latest':
         installed, missing = npm.list()
         outdated = npm.list_outdated()
-        if len(missing) or len(outdated):
+        if len(missing):
+            changed = True
+            npm.install()
+        if len(outdated):
             changed = True
             npm.update()
     else: #absent


Test patch: