Repository: ansible-collections/community.general

Issue:
nmcli: new arguments to ignore automatic dns servers and gateways
<!--- Verify first that your feature was not already discussed on GitHub -->
<!--- Complete *all* sections as described, this form is processed automatically -->

##### SUMMARY
<!--- Describe the new feature/improvement briefly below -->
It'd be nice to be able to control whether routes and dns servers from automatic sources are ignored.  This is especially handy if you have multiple DHCP connections and wish to ignore the DNS servers and gateways from the others.  Basically to add the following new arguments:

| `nmcli` module argument | NetworkManager setting |
|-------------------------|------------------------| 
| `dns4_ignore_auto` | `ipv4.ignore-auto-dns` |
| `gw4_ignore_auto` | `ipv4.ignore-auto-routes` |
| `dns6_ignore_auto` | `ipv6.ignore-auto-dns` |
| `gw6_ignore_auto` | `ipv6.ignore-auto-routes` |

##### ISSUE TYPE
- Feature Idea

##### COMPONENT NAME
<!--- Write the short name of the module, plugin, task or feature below, use your best guess if unsure -->
`nmcli`

##### ADDITIONAL INFORMATION
<!--- Describe how the feature would be used, why it is needed and what it would solve -->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: 'primary connection'
  nmcli:
    conn_name: primary
    type: ethernet
    ifname: eth0
- name: 'secondary connection'
  nmcli:
    conn_name: secondary
    type: ethernet
    ifname: eth1
    dns4_ignore_auto: true
    dns6_ignore_auto: true
    gw4_ignore_auto: true
    gw6_ignore_auto: true
```

Note: these would be nice to have in implementing this feature:
* The IPv4 and IPv6 methods could be explicitly set (e.g., to `auto`).
* The `Nmcli` connection creation/modification methods modified IP settings consistently across connection types.



Discussion:
Files identified in the description:
* [`plugins/modules/net_tools/nmcli.py`](https://github.com/ansible-collections/community.general/blob/master/plugins/modules/net_tools/nmcli.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 @alcamie101 @nerzhul
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
+label waiting_on_contributor
I'm interested in implementing this feature and I have a prototype in https://github.com/yan12125/community.general/commit/5ff202c066adc71a9097b56b85efe9454e498283. However, later I noticed that there is a `has_pr` label for this issue. I assume that means there is already a pull request fixing this issue, but I didn't find one. Did I miss something?
@yan12125 the label is there because this issue was mentioned in a PR: #1113. That PR only says "The following are easier to address with these changes: [...] Additional DNS settings: #1087" though, so the label isn't really correct. In any case, please feel free to create a PR for your change! (BTW, you'll need to add `version_added: 3.2.0` for the new options, and add a [changelog fragment](https://docs.ansible.com/ansible/devel/community/development_process.html#changelogs-how-to).)
Thanks for kind hints! I will cleanup my commit and create a pull request.

Resolving patch:
diff --git a/plugins/modules/net_tools/nmcli.py b/plugins/modules/net_tools/nmcli.py
--- a/plugins/modules/net_tools/nmcli.py
+++ b/plugins/modules/net_tools/nmcli.py
@@ -77,6 +77,12 @@
             - Use the format C(192.0.2.1).
             - This parameter is mutually_exclusive with never_default4 parameter.
         type: str
+    gw4_ignore_auto:
+        description:
+            - Ignore automatically configured IPv4 routes.
+        type: bool
+        default: false
+        version_added: 3.2.0
     routes4:
         description:
             - The list of ipv4 routes.
@@ -107,6 +113,12 @@
             - A list of DNS search domains.
         elements: str
         type: list
+    dns4_ignore_auto:
+        description:
+            - Ignore automatically configured IPv4 name servers.
+        type: bool
+        default: false
+        version_added: 3.2.0
     method4:
         description:
             - Configuration method to be used for IPv4.
@@ -125,6 +137,12 @@
             - The IPv6 gateway for this interface.
             - Use the format C(2001:db8::1).
         type: str
+    gw6_ignore_auto:
+        description:
+            - Ignore automatically configured IPv6 routes.
+        type: bool
+        default: false
+        version_added: 3.2.0
     dns6:
         description:
             - A list of up to 3 dns servers.
@@ -136,6 +154,12 @@
             - A list of DNS search domains.
         elements: str
         type: list
+    dns6_ignore_auto:
+        description:
+            - Ignore automatically configured IPv6 name servers.
+        type: bool
+        default: false
+        version_added: 3.2.0
     method6:
         description:
             - Configuration method to be used for IPv6
@@ -648,16 +672,20 @@ def __init__(self, module):
         self.type = module.params['type']
         self.ip4 = module.params['ip4']
         self.gw4 = module.params['gw4']
+        self.gw4_ignore_auto = module.params['gw4_ignore_auto']
         self.routes4 = module.params['routes4']
         self.route_metric4 = module.params['route_metric4']
         self.never_default4 = module.params['never_default4']
         self.dns4 = module.params['dns4']
         self.dns4_search = module.params['dns4_search']
+        self.dns4_ignore_auto = module.params['dns4_ignore_auto']
         self.method4 = module.params['method4']
         self.ip6 = module.params['ip6']
         self.gw6 = module.params['gw6']
+        self.gw6_ignore_auto = module.params['gw6_ignore_auto']
         self.dns6 = module.params['dns6']
         self.dns6_search = module.params['dns6_search']
+        self.dns6_ignore_auto = module.params['dns6_ignore_auto']
         self.method6 = module.params['method6']
         self.mtu = module.params['mtu']
         self.stp = module.params['stp']
@@ -729,7 +757,9 @@ def connection_options(self, detect_change=False):
                 'ipv4.dhcp-client-id': self.dhcp_client_id,
                 'ipv4.dns': self.dns4,
                 'ipv4.dns-search': self.dns4_search,
+                'ipv4.ignore-auto-dns': self.dns4_ignore_auto,
                 'ipv4.gateway': self.gw4,
+                'ipv4.ignore-auto-routes': self.gw4_ignore_auto,
                 'ipv4.routes': self.routes4,
                 'ipv4.route-metric': self.route_metric4,
                 'ipv4.never-default': self.never_default4,
@@ -737,7 +767,9 @@ def connection_options(self, detect_change=False):
                 'ipv6.addresses': self.ip6,
                 'ipv6.dns': self.dns6,
                 'ipv6.dns-search': self.dns6_search,
+                'ipv6.ignore-auto-dns': self.dns6_ignore_auto,
                 'ipv6.gateway': self.gw6,
+                'ipv6.ignore-auto-routes': self.gw6_ignore_auto,
                 'ipv6.method': self.ipv6_method,
             })
 
@@ -900,7 +932,11 @@ def settings_type(setting):
         if setting in ('bridge.stp',
                        'bridge-port.hairpin-mode',
                        'connection.autoconnect',
-                       'ipv4.never-default'):
+                       'ipv4.never-default',
+                       'ipv4.ignore-auto-dns',
+                       'ipv4.ignore-auto-routes',
+                       'ipv6.ignore-auto-dns',
+                       'ipv6.ignore-auto-routes'):
             return bool
         elif setting in ('ipv4.dns',
                          'ipv4.dns-search',
@@ -1116,17 +1152,21 @@ def main():
                       ]),
             ip4=dict(type='str'),
             gw4=dict(type='str'),
+            gw4_ignore_auto=dict(type='bool', default=False),
             routes4=dict(type='list', elements='str'),
             route_metric4=dict(type='int'),
             never_default4=dict(type='bool', default=False),
             dns4=dict(type='list', elements='str'),
             dns4_search=dict(type='list', elements='str'),
+            dns4_ignore_auto=dict(type='bool', default=False),
             method4=dict(type='str', choices=['auto', 'link-local', 'manual', 'shared', 'disabled']),
             dhcp_client_id=dict(type='str'),
             ip6=dict(type='str'),
             gw6=dict(type='str'),
+            gw6_ignore_auto=dict(type='bool', default=False),
             dns6=dict(type='list', elements='str'),
             dns6_search=dict(type='list', elements='str'),
+            dns6_ignore_auto=dict(type='bool', default=False),
             method6=dict(type='str', choices=['ignore', 'auto', 'dhcp', 'link-local', 'manual', 'shared']),
             # Bond Specific vars
             mode=dict(type='str', default='balance-rr',


Test patch:
diff --git a/tests/unit/plugins/modules/net_tools/test_nmcli.py b/tests/unit/plugins/modules/net_tools/test_nmcli.py
--- a/tests/unit/plugins/modules/net_tools/test_nmcli.py
+++ b/tests/unit/plugins/modules/net_tools/test_nmcli.py
@@ -95,8 +95,12 @@
 ipv4.method:                            manual
 ipv4.addresses:                         10.10.10.10/24
 ipv4.gateway:                           10.10.10.1
+ipv4.ignore-auto-dns:                   no
+ipv4.ignore-auto-routes:                no
 ipv4.never-default:                     no
 ipv6.method:                            auto
+ipv6.ignore-auto-dns:                   no
+ipv6.ignore-auto-routes:                no
 """
 
 TESTCASE_GENERIC_DNS4_SEARCH = [
@@ -120,10 +124,14 @@
 ipv4.method:                            manual
 ipv4.addresses:                         10.10.10.10/24
 ipv4.gateway:                           10.10.10.1
+ipv4.ignore-auto-dns:                   no
+ipv4.ignore-auto-routes:                no
 ipv4.never-default:                     no
 ipv4.dns-search:                        search.redhat.com
 ipv6.dns-search:                        search6.redhat.com
 ipv6.method:                            auto
+ipv6.ignore-auto-dns:                   no
+ipv6.ignore-auto-routes:                no
 """
 
 TESTCASE_GENERIC_ZONE = [
@@ -147,8 +155,12 @@
 ipv4.method:                            manual
 ipv4.addresses:                         10.10.10.10/24
 ipv4.gateway:                           10.10.10.1
+ipv4.ignore-auto-dns:                   no
+ipv4.ignore-auto-routes:                no
 ipv4.never-default:                     no
 ipv6.method:                            auto
+ipv6.ignore-auto-dns:                   no
+ipv6.ignore-auto-routes:                no
 """
 
 TESTCASE_BOND = [
@@ -172,8 +184,12 @@
 ipv4.method:                            manual
 ipv4.addresses:                         10.10.10.10/24
 ipv4.gateway:                           10.10.10.1
+ipv4.ignore-auto-dns:                   no
+ipv4.ignore-auto-routes:                no
 ipv4.never-default:                     no
 ipv6.method:                            auto
+ipv6.ignore-auto-dns:                   no
+ipv6.ignore-auto-routes:                no
 bond.options:                           mode=active-backup,primary=non_existent_primary
 """
 
@@ -199,8 +215,12 @@
 ipv4.method:                            manual
 ipv4.addresses:                         10.10.10.10/24
 ipv4.gateway:                           10.10.10.1
+ipv4.ignore-auto-dns:                   no
+ipv4.ignore-auto-routes:                no
 ipv4.never-default:                     no
 ipv6.method:                            auto
+ipv6.ignore-auto-dns:                   no
+ipv6.ignore-auto-routes:                no
 bridge.mac-address:                     52:54:00:AB:CD:EF
 bridge.stp:                             yes
 bridge.max-age:                         100
@@ -252,8 +272,12 @@
 ipv4.method:                            manual
 ipv4.addresses:                         10.10.10.10/24
 ipv4.gateway:                           10.10.10.1
+ipv4.ignore-auto-dns:                   no
+ipv4.ignore-auto-routes:                no
 ipv4.never-default:                     no
 ipv6.method:                            auto
+ipv6.ignore-auto-dns:                   no
+ipv6.ignore-auto-routes:                no
 vlan.id:                                10
 """
 
@@ -343,8 +367,12 @@
 802-3-ethernet.mtu:                     auto
 ipv4.method:                            auto
 ipv4.dhcp-client-id:                    00:11:22:AA:BB:CC:DD
+ipv4.ignore-auto-dns:                   no
+ipv4.ignore-auto-routes:                no
 ipv4.never-default:                     no
 ipv6.method:                            auto
+ipv6.ignore-auto-dns:                   no
+ipv6.ignore-auto-routes:                no
 """
 
 TESTCASE_ETHERNET_STATIC = [
@@ -368,9 +396,13 @@
 ipv4.method:                            manual
 ipv4.addresses:                         10.10.10.10/24
 ipv4.gateway:                           10.10.10.1
+ipv4.ignore-auto-dns:                   no
+ipv4.ignore-auto-routes:                no
 ipv4.never-default:                     no
 ipv4.dns:                               1.1.1.1,8.8.8.8
 ipv6.method:                            auto
+ipv6.ignore-auto-dns:                   no
+ipv6.ignore-auto-routes:                no
 """