Repository: ansible/ansible

Issue:
"docker_network" does not honor the "internal" option

##### ISSUE TYPE
 - Feature Idea

##### COMPONENT NAME
docker_network.py

##### ANSIBLE VERSION
```
ansible 2.3.2.0
```

##### SUMMARY
Docker allows to set certain [options](https://docs.docker.com/engine/reference/commandline/network_create/) (such as "--internal") when creating networks (using "docker network create"). These options are also supported by "docker-py", on which the docker support of ansible builds, as evidenced by https://github.com/docker/docker-py/blob/c9960c78b09254436f6856413c18b48801a14970/docker/api/network.py#L42 .

##### STEPS TO REPRODUCE
```yaml
- name: create internal docker network
  docker_network:
    name: "foo"
    internal: true
```
##### EXPECTED RESULTS
This should create an internal network, as if "docker network create --internal" was used.

##### ACTUAL RESULTS
Currently, this does not create an internal network, as if "docker network create --internal" was used.



Discussion:
cc @keitwb @olsaki
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
cc @chouseknecht
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/cloud/docker/docker_network.py b/lib/ansible/modules/cloud/docker/docker_network.py
--- a/lib/ansible/modules/cloud/docker/docker_network.py
+++ b/lib/ansible/modules/cloud/docker/docker_network.py
@@ -86,16 +86,25 @@
       - absent
       - present
 
+  internal:
+    version_added: 2.8
+    description:
+      - Restrict external access to the network.
+    type: bool
+    default: null
+    required: false
+
 extends_documentation_fragment:
     - docker
 
 author:
     - "Ben Keith (@keitwb)"
     - "Chris Houseknecht (@chouseknecht)"
+    - "Dave Bendit (@DBendit)"
 
 requirements:
     - "python >= 2.6"
-    - "docker-py >= 1.8.0"
+    - "docker-py >= 1.9.0"
     - "Please note that the L(docker-py,https://pypi.org/project/docker-py/) Python
        module has been superseded by L(docker,https://pypi.org/project/docker/)
        (see L(here,https://github.com/docker/docker-py/issues/1310) for details).
@@ -181,6 +190,7 @@ def __init__(self, client):
         self.ipam_options = None
         self.appends = None
         self.force = None
+        self.internal = None
         self.debug = None
 
         for key, value in client.module.params.items():
@@ -269,6 +279,15 @@ def has_different_config(self, net):
                         # key has different value
                         different = True
                         differences.append('ipam_options.%s' % key)
+        if self.parameters.internal is not None:
+            if self.parameters.internal:
+                if not net.get('Internal'):
+                    different = True
+                    differences.append('internal')
+            else:
+                if net.get('Internal'):
+                    different = True
+                    differences.append('internal')
         return different, differences
 
     def create_network(self):
@@ -291,7 +310,8 @@ def create_network(self):
                 resp = self.client.create_network(self.parameters.network_name,
                                                   driver=self.parameters.driver,
                                                   options=self.parameters.driver_options,
-                                                  ipam=ipam_config)
+                                                  ipam=ipam_config,
+                                                  internal=self.parameters.internal)
 
                 self.existing_network = self.client.inspect_network(resp['Id'])
             self.results['actions'].append("Created network %s with driver %s" % (self.parameters.network_name, self.parameters.driver))
@@ -378,12 +398,14 @@ def main():
         appends=dict(type='bool', default=False, aliases=['incremental']),
         ipam_driver=dict(type='str', default=None),
         ipam_options=dict(type='dict', default={}),
+        internal=dict(type='bool', default=None),
         debug=dict(type='bool', default=False)
     )
 
     client = AnsibleDockerClient(
         argument_spec=argument_spec,
-        supports_check_mode=True
+        supports_check_mode=True,
+        min_docker_version='1.9.0'
         # "The docker server >= 1.9.0"
     )
 


Test patch:
diff --git a/test/integration/targets/docker_network/tasks/tests/options.yml b/test/integration/targets/docker_network/tasks/tests/options.yml
new file mode 100644
--- /dev/null
+++ b/test/integration/targets/docker_network/tasks/tests/options.yml
@@ -0,0 +1,42 @@
+---
+- name: Registering network name
+  set_fact:
+    nname_1: "{{ name_prefix ~ '-network-1' }}"
+    nname_2: "{{ name_prefix ~ '-network-2' }}"
+- name: Registering network name
+  set_fact:
+    dnetworks: "{{ dnetworks }} + [nname_1, nname_2]"
+
+####################################################################
+## internal ########################################################
+####################################################################
+
+- name: internal
+  docker_network:
+    name: "{{ nname_1 }}"
+    internal: yes
+  register: internal_1
+
+- name: internal (idempotency)
+  docker_network:
+    name: "{{ nname_1 }}"
+    internal: yes
+  register: internal_2
+
+- name: internal (change)
+  docker_network:
+    name: "{{ nname_1 }}"
+    internal: no
+  register: internal_3
+
+- name: cleanup
+  docker_network:
+    name: "{{ nname_1 }}"
+    state: absent
+    force: yes
+
+- assert:
+    that:
+    - internal_1 is changed
+    - internal_2 is not changed
+    - internal_3 is changed