Repository: ansible-collections/community.general

Issue:
docker_container does not revoke published_ports if image has port set as exposed
<!--- Verify first that your issue is not already reported on GitHub -->
<!--- Also test if the latest release and devel branch are affected too -->
<!--- Complete *all* sections as described, this form is processed automatically -->

##### SUMMARY
<!--- Explain the problem briefly below -->
When a Docker image has been created with the `EXPOSE` keyword in the Dockerfile, when a container is created publishing this port, `docker_container` is unable to remove this port at a later stage.

It seem like `docker_container` treats the following 2 container setups the same:
* Published:
```
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
b24845764792        nginx               "/docker-entrypoint.…"   4 seconds ago       Up 3 seconds        0.0.0.0:80->80/tcp   nginx
```
* Exposed, but not published:
```
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
e08d50b17a5a        nginx               "/docker-entrypoint.…"   9 seconds ago       Up 8 seconds        80/tcp              nginx
```

The latter is the expected result after running the example playbook below.


##### ISSUE TYPE
- Bug Report

##### COMPONENT NAME
<!--- Write the short name of the module, plugin, task or feature below, use your best guess if unsure -->
docker_container

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes -->
```paste below
ansible-playbook 2.9.13
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/husjon/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.8/site-packages/ansible
  executable location = /usr/bin/ansible-playbook
  python version = 3.8.5 (default, Sep  5 2020, 10:50:12) [GCC 10.2.0]
```

##### CONFIGURATION
<!--- Paste verbatim output from "ansible-config dump --only-changed" between quotes -->
```paste below
# No output
```

##### OS / ENVIRONMENT
<!--- Provide all relevant information below, e.g. target OS versions, network device firmware, etc. -->
```
Linux workstation 5.8.10-arch1-1 #1 SMP PREEMPT Thu, 17 Sep 2020 18:01:06 +0000 x86_64 GNU/Linux
```

##### STEPS TO REPRODUCE
<!--- Describe exactly how to reproduce the problem, using a minimal test-case -->
The following playbook example can reproduce this issue.

<!--- Paste example playbooks or commands between quotes below -->
```yaml
---
- name: deploy nginx
  hosts: localhost

  tasks:
    - name: deploy container with published ports
      docker_container:
        name: nginx
        image: nginx:latest

        published_ports: [ "80:80" ]

    - name: deploy container without published ports (revokal)"
      docker_container:
        name: nginx
        image: nginx:latest

        comparisons:
          '*': strict

        published_ports: []
```

<!--- HINT: You can paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- Describe what you expected to happen when running the steps above -->
The published ports should be removed.

##### ACTUAL RESULTS
<!--- Describe what actually happened. If possible run with extra verbosity (-vvvv) -->
The published ports remains as they where initially from the first task.
Docker output after first task has run:
```
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
b24845764792        nginx               "/docker-entrypoint.…"   4 seconds ago       Up 3 seconds        0.0.0.0:80->80/tcp   nginx
```
Docker output after second task has run:
```
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
b24845764792        nginx               "/docker-entrypoint.…"   9 seconds ago       Up 8seconds        0.0.0.0:80->80/tcp   nginx
```

<!--- Paste verbatim command output between quotes -->
Added as gist, since the output is about 1200 lines.
https://gist.github.com/husjon/ae88c6e8a94b9aea4b4bb7633d5c135f


Discussion:
Files identified in the description:
* [`plugins/modules/cloud/docker/docker_container.py`](https://github.com/ansible-collections/community.general/blob/master/plugins/modules/cloud/docker/docker_container.py)

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

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @DBendit @WojciechowskiPiotr @akshay196 @chouseknecht @danihodovic @dariko @dusdanig @felixfontein @jwitko @kassiansun @softzilla @tbouvet @zfil
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
This is caused because the code does not distinguish between `[]` and `None` in one case. I'll prepare a fix.
resolved_by_pr #979

Resolving patch:
diff --git a/plugins/modules/cloud/docker/docker_container.py b/plugins/modules/cloud/docker/docker_container.py
--- a/plugins/modules/cloud/docker/docker_container.py
+++ b/plugins/modules/cloud/docker/docker_container.py
@@ -2400,7 +2400,7 @@ def _get_expected_entrypoint(self):
         return shlex.split(self.parameters.entrypoint)
 
     def _get_expected_ports(self):
-        if not self.parameters.published_ports:
+        if self.parameters.published_ports is None:
             return None
         expected_bound_ports = {}
         for container_port, config in self.parameters.published_ports.items():


Test patch:
diff --git a/tests/integration/targets/docker_container/tasks/tests/options.yml b/tests/integration/targets/docker_container/tasks/tests/options.yml
--- a/tests/integration/targets/docker_container/tasks/tests/options.yml
+++ b/tests/integration/targets/docker_container/tasks/tests/options.yml
@@ -2873,6 +2873,18 @@ avoid such warnings, please quote the value.' in log_options_2.warnings"
     force_kill: yes
   register: published_ports_5
 
+- name: published_ports (no published ports)
+  docker_container:
+    image: alpine:3.8
+    command: '/bin/sh -c "sleep 10m"'
+    name: "{{ cname }}"
+    state: started
+    published_ports: []
+    comparisons:
+      published_ports: strict
+    force_kill: yes
+  register: published_ports_6
+
 - name: cleanup
   docker_container:
     name: "{{ cname }}"
@@ -2887,6 +2899,7 @@ avoid such warnings, please quote the value.' in log_options_2.warnings"
     - published_ports_3 is not changed
     - published_ports_4 is changed
     - published_ports_5 is changed
+    - published_ports_6 is changed
 
 ####################################################################
 ## pull ############################################################