Repository: ansible/ansible

Issue:
"Error retrieving container list" due to `AnsibleDockerClient.get_container()` crashing when any container is missing a name.
##### ISSUE TYPE

 - Bug Report

##### COMPONENT NAME

`AnsibleDockerClient` (`lib/ansible/module_utils/docker_common.py`)

##### ANSIBLE VERSION

```
/data01/home/jenkins/.pyenv/versions/2.7.11/lib/python2.7/site-packages/Crypto/Util/number.py:57: PowmInsecureWarning: Not using mpz_powm_sec.  You should rebuild using libgmp >= 5 to avoid timing attack vulnerability.
  _warn("Not using mpz_powm_sec.  You should rebuild using libgmp >= 5 to avoid timing attack vulnerability.", PowmInsecureWarning)
ansible 2.1.1.0
  config file =
  configured module search path = Default w/o overrides
```

##### CONFIGURATION

None

##### OS / ENVIRONMENT

Red Hat Enterprise Linux Server release 6.5 (Santiago)

##### SUMMARY

`AnsibleDockerClient.get_container()` crashes when any container is missing a name.

##### STEPS TO REPRODUCE

This is not really a steps to reproduce but I hope it gives enough context...

I'm not sure how but I have ended up with a container without a name,

```
# docker ps -a | grep -P '(^CONTAINER|f548e5960eff)'
CONTAINER ID        IMAGE                           COMMAND                CREATED             STATUS                     PORTS                                  NAMES
f548e5960eff        my-image:3.44.0-2               "/usr/local/bin/pyth   13 days ago         Dead                       8000/tcp                                            
```

I have a task like,

```yaml
    - name: my-container
      docker_container:
        name: my-container
        api_version: 1.19
        image: my-image
        user: root
        state: started
        restart_policy: on-failure
```

The task fails with this error,

```
15:10:40 TASK [my-container] *************************************************

15:10:42 fatal: [my-host]: FAILED! => {"changed": false, "failed": true, "msg": "Error retrieving container list: argument of type 'NoneType' is not iterable"}
```

I found that the error originates from [lib/ansible/module_utils/docker_common.py#L357](https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/docker_common.py#L357) and is due to assumption that [`container['Names']` is iterable](https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/docker_common.py#L345).  I suppose not only does one have to have a container missing a name but it also has to happen to appear in the containers result before the desired container.  What can I say... I'm a lucky fellow.

##### EXPECTED RESULTS

I expect the task to start the container.

##### ACTUAL RESULTS

The task fails with this error,

```
15:10:40 TASK [my-container] *************************************************

15:10:42 fatal: [my-host]: FAILED! => {"changed": false, "failed": true, "msg": "Error retrieving container list: argument of type 'NoneType' is not iterable"}
```




Discussion:
I have confirmed that this patch prevents the crash,

``` diff
--- a/docker_common.py  2016-11-15 21:47:51.034284651 +0000
+++ b/docker_common.py  2016-11-15 21:48:59.090510112 +0000
@@ -363,7 +363,7 @@
         try:
             for container in self.containers(all=True):
                 self.log("testing container: %s" % (container['Names']))
-                if search_name in container['Names']:
+                if isinstance(container['Names'], list) and search_name in container['Names']:
                     result = container
                     break
                 if container['Id'].startswith(name):
```

Looks like the missing name is due to a failure during `docker rm`,

```
Error response from daemon: Cannot destroy container my-container: Driver devicemapper failed to remove root filesystem aa48f2a0c9e362292773bd39342f8a67ab81f53c2ab3a9556a89f35fbc715d93: Device is Busy
```

@nnutter can you send a pullrequest with your patch?

needs_info

Resolving patch:
diff --git a/lib/ansible/module_utils/docker_common.py b/lib/ansible/module_utils/docker_common.py
--- a/lib/ansible/module_utils/docker_common.py
+++ b/lib/ansible/module_utils/docker_common.py
@@ -349,7 +349,7 @@ def get_container(self, name=None):
         try:
             for container in self.containers(all=True):
                 self.log("testing container: %s" % (container['Names']))
-                if search_name in container['Names']:
+                if isinstance(container['Names'], list) and search_name in container['Names']:
                     result = container
                     break
                 if container['Id'].startswith(name):


Test patch: