Repository: ansible/ansible

Issue:
(P2) nxos_overlay_global is not idempotent
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
 - nxos_overlay_global

##### NXOS VERSION
7.0(3)I5(3)

##### ANSIBLE VERSION
```
ansible 2.4.0 (devel 0fb64214a4) last updated 2017/07/27 13:55:58 (GMT -400)
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/usr/share/ansible']
  ansible python module location = /root/agents-ci/ansible/lib/ansible
  executable location = /root/agents-ci/ansible/bin/ansible
  python version = 2.7.6 (default, Oct 26 2016, 20:30:19) [GCC 4.8.4]
```

##### OS / ENVIRONMENT
Ubuntu 14.04

##### SUMMARY
The following playbook demonstrates the idempotency issue.  The configuration is applied so I suspect it's a casing issue with the mac address.

```yaml
---
- debug: msg="START TRANSPORT:{{ connection.transport }} nxos_overlay_global sanity test"

- name: "Enable nv overlay evpn"
  nxos_evpn_global: &enable_evpn
    nv_overlay_evpn: true
    provider: "{{ connection }}"
  ignore_errors: yes

# N7K? feature-set fabric

- block:
  - name: Configure overlay global
    nxos_overlay_global: &configure
      anycast_gateway_mac: "b.b.b"
      provider: "{{ connection }}"
    register: result

  - assert: &true
      that:
        - "result.changed == true"

  - name: "Check Idempotence"
    nxos_overlay_global: *configure
    register: result

  - assert: &false
      that:
        - "result.changed == false"

  always:
  - name: "Disable nv overlay evpn"
    nxos_evpn_global: &disable_evpn
      nv_overlay_evpn: false
      provider: "{{ connection }}"
    ignore_errors: yes

- debug: msg="END TRANSPORT:{{ connection.transport }} nxos_overlay_global sanity test"
```

```shell
TASK [nxos_overlay_global : Check Idempotence] ******************************************************************************************************************************************************************************************************************
task path: /root/agents-ci/ansible/test/integration/targets/nxos_overlay_global/tests/common/sanity.yaml:23
<n9k.example.com> connection transport is cli
<n9k.example.com> using connection plugin network_cli
<n9k.example.com> socket_path: /root/.ansible/pc/4cc10f215f
Using module file /root/agents-ci/ansible/lib/ansible/modules/network/nxos/nxos_overlay_global.py
<n9k.example.com> ESTABLISH LOCAL CONNECTION FOR USER: root
<n9k.example.com> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1501185415.0-138857765998437 `" && echo ansible-tmp-1501185415.0-138857765998437="` echo $HOME/.ansible/tmp/ansible-tmp-1501185415.0-138857765998437 `" ) && sleep 0'
<n9k.example.com> PUT /tmp/tmpf5GW0s TO /root/.ansible/tmp/ansible-tmp-1501185415.0-138857765998437/nxos_overlay_global.py
<n9k.example.com> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1501185415.0-138857765998437/ /root/.ansible/tmp/ansible-tmp-1501185415.0-138857765998437/nxos_overlay_global.py && sleep 0'
<n9k.example.com> EXEC /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1501185415.0-138857765998437/nxos_overlay_global.py; rm -rf "/root/.ansible/tmp/ansible-tmp-1501185415.0-138857765998437/" > /dev/null 2>&1 && sleep 0'
changed: [n9k.example.com] => {
    "changed": true, 
    "commands": [
        "fabric forwarding anycast-gateway-mac 000B.000B.000B"
    ], 
    "failed": false, 
    "invocation": {
        "module_args": {
            "anycast_gateway_mac": "b.b.b", 
            "host": null, 
            "password": null, 
            "port": null, 
            "provider": null, 
            "ssh_keyfile": null, 
            "timeout": 10, 
            "transport": "cli", 
            "use_ssl": null, 
            "username": null, 
            "validate_certs": null
        }
    }
}

TASK [nxos_overlay_global : assert] *****************************************************************************************************************************************************************************************************************************
task path: /root/agents-ci/ansible/test/integration/targets/nxos_overlay_global/tests/common/sanity.yaml:27
fatal: [n9k.example.com]: FAILED! => {
    "assertion": "result.changed == false", 
    "changed": false, 
    "evaluated_to": false, 
    "failed": true
}
```


Discussion:
cc @GGabriele @jedelman8 @privateip @rahushen @rcarrillocruz @trishnaguha
[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/network/nxos/nxos_overlay_global.py b/lib/ansible/modules/network/nxos/nxos_overlay_global.py
--- a/lib/ansible/modules/network/nxos/nxos_overlay_global.py
+++ b/lib/ansible/modules/network/nxos/nxos_overlay_global.py
@@ -72,11 +72,12 @@ def get_existing(module, args):
 
     for arg in args:
         command = PARAM_TO_COMMAND_KEYMAP[arg]
-        has_command = re.match(r'(?:{0}\s)(?P<value>.*)$'.format(command), config, re.M)
+        has_command = re.findall(r'(?:{0}\s)(?P<value>.*)$'.format(command), config, re.M)
         value = ''
         if has_command:
-            value = has_command.group('value')
+            value = has_command[0]
         existing[arg] = value
+
     return existing
 
 
@@ -102,8 +103,10 @@ def get_commands(module, existing, proposed, candidate):
         else:
             if 'anycast-gateway-mac' in key:
                 value = normalize_mac(value, module)
-            command = '{0} {1}'.format(key, value)
-            commands.append(command)
+                existing_value = existing_commands.get(key)
+                if existing_value and value != existing_value:
+                    command = '{0} {1}'.format(key, value)
+                    commands.append(command)
 
     if commands:
         candidate.add(commands, parents=[])


Test patch:
diff --git a/test/units/modules/network/nxos/fixtures/nxos_overlay_global_config.cfg b/test/units/modules/network/nxos/fixtures/nxos_overlay_global_config.cfg
new file mode 100644
--- /dev/null
+++ b/test/units/modules/network/nxos/fixtures/nxos_overlay_global_config.cfg
@@ -0,0 +1 @@
+fabric forwarding anycast-gateway-mac 000B.000B.000B
diff --git a/test/units/modules/network/nxos/test_nxos_overlay_global.py b/test/units/modules/network/nxos/test_nxos_overlay_global.py
--- a/test/units/modules/network/nxos/test_nxos_overlay_global.py
+++ b/test/units/modules/network/nxos/test_nxos_overlay_global.py
@@ -42,9 +42,10 @@ def tearDown(self):
         self.mock_get_config.stop()
 
     def load_fixtures(self, commands=None, device=''):
+        self.get_config.return_value = load_fixture('', 'nxos_overlay_global_config.cfg')
         self.load_config.return_value = None
 
     def test_nxos_overlay_global_up(self):
-        set_module_args(dict(anycast_gateway_mac="b.b.b"))
+        set_module_args(dict(anycast_gateway_mac="a.a.a"))
         result = self.execute_module(changed=True)
-        self.assertEqual(result['commands'], ['fabric forwarding anycast-gateway-mac 000B.000B.000B'])
+        self.assertEqual(result['commands'], ['fabric forwarding anycast-gateway-mac 000A.000A.000A'])