Skip to content

Commit

Permalink
docker_container: change behavior for one-port container ranges to be…
Browse files Browse the repository at this point in the history
… same as docker CLI (ansible#66382)

* Adjust docker_container behavior for one-port container ranges to be similar to docker CLI.

* Add changelog.

* Add documented examples for ports:.
  • Loading branch information
felixfontein authored Feb 3, 2020
1 parent 21ae66d commit 23b2bb4
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 2 deletions.
3 changes: 3 additions & 0 deletions changelogs/fragments/66382-docker_container-port-range.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
minor_changes:
- "docker_container - support for port ranges was adjusted to be more compatible to the ``docker`` command line utility:
a one-port container range combined with a multiple-port host range will no longer result in only the first host port be used, but the whole range being passed to Docker so that a free port in that range will be used."
1 change: 1 addition & 0 deletions docs/docsite/rst/porting_guides/porting_guide_2.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ Noteworthy module changes
* Junction points are no longer reported as ``islnk``, use ``isjunction`` to properly report these files. This behaviour matches the :ref:`win_stat <win_stat_module>`
* Directories no longer return a ``size``, this matches the ``stat`` and ``find`` behaviour and has been removed due to the difficulties in correctly reporting the size of a directory
* :ref:`docker_container <docker_container_module>` no longer passes information on non-anonymous volumes or binds as ``Volumes`` to the Docker daemon. This increases compatibility with the ``docker`` CLI program. Note that if you specify ``volumes: strict`` in ``comparisons``, this could cause existing containers created with docker_container from Ansible 2.9 or earlier to restart.
* :ref:`docker_container <docker_container_module>`'s support for port ranges was adjusted to be more compatible to the ``docker`` command line utility: a one-port container range combined with a multiple-port host range will no longer result in only the first host port be used, but the whole range being passed to Docker so that a free port in that range will be used.
* :ref:`purefb_fs <purefb_fs_module>` no longer supports the deprecated ``nfs`` option. This has been superceeded by ``nfsv3``.

Plugins
Expand Down
21 changes: 19 additions & 2 deletions lib/ansible/modules/cloud/docker/docker_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,9 @@
container port, 9000 is a host port, and 0.0.0.0 is a host interface."
- Port ranges can be used for source and destination ports. If two ranges with
different lengths are specified, the shorter range will be used.
Since Ansible 2.10, if the source port range has length 1, the port will not be assigned
to the first port of the destination range, but to a free port in that range. This is the
same behavior as for C(docker) command line utility.
- "Bind addresses must be either IPv4 or IPv6 addresses. Hostnames are *not* allowed. This
is different from the C(docker) command line utility. Use the L(dig lookup,../lookup/dig.html)
to resolve hostnames."
Expand Down Expand Up @@ -886,8 +889,16 @@
devices:
- "/dev/sda:/dev/xvda:rwm"
ports:
# Publish container port 9000 as host port 8080
- "8080:9000"
# Publish container UDP port 9001 as host port 8081 on interface 127.0.0.1
- "127.0.0.1:8081:9001/udp"
# Publish container port 9002 as a random host port
- "9002"
# Publish container port 9003 as a random host port in range 8000-8100
- "9003:8000-8100"
# Publish container ports 9010-9020 to host ports 7000-7010
- "9010-9020:7000-7010"
env:
SECRET_KEY: "ssssh"
# Values which might be parsed as numbers, booleans or other types by the YAML parser need to be quoted
Expand Down Expand Up @@ -1656,7 +1667,10 @@ def _parse_publish_ports(self):
if p_len == 1:
port_binds = len(container_ports) * [(default_ip,)]
elif p_len == 2:
port_binds = [(default_ip, port) for port in parse_port_range(parts[0], self.client)]
if len(container_ports) == 1:
port_binds = [(default_ip, parts[0])]
else:
port_binds = [(default_ip, port) for port in parse_port_range(parts[0], self.client)]
elif p_len == 3:
# We only allow IPv4 and IPv6 addresses for the bind address
ipaddr = parts[0]
Expand All @@ -1666,7 +1680,10 @@ def _parse_publish_ports(self):
if re.match(r'^\[[0-9a-fA-F:]+\]$', ipaddr):
ipaddr = ipaddr[1:-1]
if parts[1]:
port_binds = [(ipaddr, port) for port in parse_port_range(parts[1], self.client)]
if len(container_ports) == 1:
port_binds = [(ipaddr, parts[1])]
else:
port_binds = [(ipaddr, port) for port in parse_port_range(parts[1], self.client)]
else:
port_binds = len(container_ports) * [(ipaddr,)]

Expand Down
66 changes: 66 additions & 0 deletions test/integration/targets/docker_container/tasks/tests/ports.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
- name: Registering container name
set_fact:
cname: "{{ cname_prefix ~ '-options' }}"
cname2: "{{ cname_prefix ~ '-options-h1' }}"
- name: Registering container name
set_fact:
cnames: "{{ cnames + [cname, cname2] }}"

####################################################################
## published_ports: all ############################################
Expand Down Expand Up @@ -156,6 +160,68 @@
- published_ports_2 is not changed
- published_ports_3 is changed

####################################################################
## published_ports: one-element container port range ###############
####################################################################

- name: published_ports -- one-element container port range
docker_container:
image: alpine:3.8
command: '/bin/sh -c "sleep 10m"'
name: "{{ item }}"
state: started
published_ports:
- "9010-9050:9010"
force_kill: yes
loop:
- '{{ cname }}'
- '{{ cname2 }}'
register: published_ports_1

- name: published_ports -- one-element container port range (idempotency)
docker_container:
image: alpine:3.8
command: '/bin/sh -c "sleep 10m"'
name: "{{ item }}"
state: started
published_ports:
- "9010-9050:9010"
force_kill: yes
loop:
- '{{ cname }}'
- '{{ cname2 }}'
register: published_ports_2

- name: published_ports -- one-element container port range (different range)
docker_container:
image: alpine:3.8
command: '/bin/sh -c "sleep 10m"'
name: "{{ item }}"
state: started
published_ports:
- "9010-9051:9010"
force_kill: yes
loop:
- '{{ cname }}'
- '{{ cname2 }}'
register: published_ports_3

- name: cleanup
docker_container:
name: "{{ item }}"
state: absent
force_kill: yes
loop:
- '{{ cname }}'
- '{{ cname2 }}'
diff: no

- assert:
that:
- published_ports_1 is changed
- published_ports_2 is not changed
- published_ports_3 is changed

####################################################################
## published_ports: IPv6 addresses #################################
####################################################################
Expand Down

0 comments on commit 23b2bb4

Please sign in to comment.