Repository: ansible/ansible

Issue:
cloudflare_dns fails on combination of SRV record and python3
<!---
Verify first that your issue/request is not already reported on GitHub.
THIS FORM WILL BE READ BY A MACHINE, COMPLETE ALL SECTIONS AS DESCRIBED.
Also test if the latest release, and devel branch are affected too.
ALWAYS add information AFTER (OUTSIDE) these html comments.
Otherwise it may end up being automatically closed by our bot. -->

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
<!--- Insert, BELOW THIS COMMENT, the name of the module, plugin, task or feature.
Do not include extra details here, e.g. "vyos_command" not "the network module vyos_command" or the full path-->
cloudflare_dns

##### ANSIBLE VERSION
<!--- Paste, BELOW THIS COMMENT, verbatim output from "ansible --version" between quotes below -->
```
ansible 2.5.3
  config file = /tank/appdata/ansible/ansible.cfg
  configured module search path = [u'/home/jendrik/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.12 (default, Dec  4 2017, 14:50:18) [GCC 5.4.0 20160609]
```

##### CONFIGURATION
<!--- If using Ansible 2.4 or above, paste, BELOW THIS COMMENT, the results of "ansible-config dump --only-changed"
Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).-->
CACHE_PLUGIN(/tank/appdata/ansible/ansible.cfg) = jsonfile
CACHE_PLUGIN_CONNECTION(/tank/appdata/ansible/ansible.cfg) = /tank/appdata/ansible/fact-cache
CACHE_PLUGIN_TIMEOUT(/tank/appdata/ansible/ansible.cfg) = 86400
DEFAULT_GATHERING(/tank/appdata/ansible/ansible.cfg) = smart
DEFAULT_GATHER_SUBSET(/tank/appdata/ansible/ansible.cfg) = !facter,!ohai
DEFAULT_HOST_LIST(/tank/appdata/ansible/ansible.cfg) = [u'/tank/appdata/ansible/inventory']
DEFAULT_ROLES_PATH(/tank/appdata/ansible/ansible.cfg) = [u'/tank/appdata/ansible/roles']

##### OS / ENVIRONMENT
<!--- Mention, BELOW THIS COMMENT, the OS you are running Ansible from, and the OS you are
managing, or say "N/A" for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.-->
Tested on Ubuntu 16.04

##### SUMMARY
<!--- Explain the problem briefly -->
Creating a SRV record with cloudflare_dns and python3 - if the record already exists the module fails. Running the same code via python2 works fine.

##### STEPS TO REPRODUCE
<!--- For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used. -->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- cloudflare_dns:
    account_email: "{{ cloudflare_account_email }}"
    account_api_token: "{{ cloudflare_account_api_token }}"
    record: "ts.{{ ansible_fqdn }}"
    port: '9987'
    proto: 'udp'
    service: 'ts3'
    type: 'SRV'
    value: "ts.{{ ansible_fqdn }}"
    weight: '1'
    zone: "{{ ansible_domain }}"
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
Cloudflare_dns returns ok if the record already exists.

From my limited understanding of python the problem is with:https://github.com/ansible/ansible/blob/44d9dd2c77841686bead7bfae0282851a66db5d7/lib/ansible/modules/net_tools/cloudflare_dns.py#L561
AFAIK and based on what I've found via google this checks whether the 'data' field in cur_record and new_record are unequal. The above works on python2 due to some undocumented method that doesn't exist in python3.
I've tried overriding this module with a local version (./library/cloudflare_dns.py) and replaced the line with `if (cur_record['data'] != new_record['data']):`. This produces the expected result (i.e. changed on first run, ok afterwards).
##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
fatal: [pgg-02]: FAILED! => {
    "changed": false, 
    "module_stderr": "OpenSSH_7.2p2 Ubuntu-4ubuntu2.4, OpenSSL 1.0.2g  1 Mar 2016\r\ndebug1: Reading configuration data /home/jendrik/.ssh/config\r\ndebug1: Reading configuration data /etc/ssh/ssh_config\r\ndebug1: /etc/ssh/ssh_config line 50: Applying options for *\r\ndebug1: /etc/ssh/ssh_config line 57: Deprecated option \"useroaming\"\r\ndebug1: auto-mux: Trying existing master\r\ndebug2: fd 3 setting O_NONBLOCK\r\ndebug2: mux_client_hello_exchange: master version 4\r\ndebug3: mux_client_forwards: request forwardings: 0 local, 0 remote\r\ndebug3: mux_client_request_session: entering\r\ndebug3: mux_client_request_alive: entering\r\ndebug3: mux_client_request_alive: done pid = 4839\r\ndebug3: mux_client_request_session: session request sent\r\ndebug1: mux_client_request_session: master session id: 2\r\ndebug3: mux_client_read_packet: read header failed: Broken pipe\r\ndebug2: Received exit status from master 1\r\nShared connection to 185.228.136.105 closed.\r\n", 
    "module_stdout": "Traceback (most recent call last):\r\n  File \"/tmp/ansible_83rsy26q/ansible_module_cloudflare_dns.py\", line 659, in <module>\r\n    main()\r\n  File \"/tmp/ansible_83rsy26q/ansible_module_cloudflare_dns.py\", line 647, in main\r\n    result, changed = cf_api.ensure_dns_record()\r\n  File \"/tmp/ansible_83rsy26q/ansible_module_cloudflare_dns.py\", line 577, in ensure_dns_record\r\n    if (cur_record['data'] > new_record['data']) - (cur_record['data'] < new_record['data']):\r\nTypeError: unorderable types: dict() > dict()\r\n", 
    "msg": "MODULE FAILURE", 
    "rc": 1
}

Traceback (most recent call last):\r\n  File \"/tmp/ansible_83rsy26q/ansible_module_cloudflare_dns.py\", line 659, in <module>
    main()\r\n  File \"/tmp/ansible_83rsy26q/ansible_module_cloudflare_dns.py\", line 647, in main
    result, changed = cf_api.ensure_dns_record()
  File \"/tmp/ansible_83rsy26q/ansible_module_cloudflare_dns.py\", line 577, in ensure_dns_record
    if (cur_record['data'] > new_record['data']) - (cur_record['data'] < new_record['data']):
TypeError: unorderable types: dict() > dict()
```



Discussion:
Files identified in the description:
* [lib/ansible/modules/net_tools/cloudflare_dns.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/net_tools/cloudflare_dns.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 @andreaso @mgruener
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
Thanks for reporting this issue. I can confirm that I run into the same problem while trying to create SRV records using Python3.

Will have to get back to you in regards to what is what.
I was doing some cleanup and noticed I've still got my local override for this bug, is there any update on this available?
Yeah, now that I have had few weeks of vacation I'm much more up to looking at Ansible bugs :-)

After having done a bit of reading as well as a bit of testing I'm convinced that your suggestion `cur_record['data'] != new_record['data']` is the test we want.

@sevs44936 : Feel like submitting the PR yourself, or do you want me to do it?

I hope that I've done this correctly: https://github.com/ansible/ansible/pull/42910
The change itself looks good!

@sevs44936 Regarding the PR it's possible that you might want to recreate it with its own branch. That is, instead of using `sevs44936:devel` you will want to use `sevs44936:some-specific-branch-name`, where that specific branch is created from the devel branch.

In addition to general tidyness it also matters since any push to the PR branch in question triggers an update of the PR, including the Shippable test.

Resolving patch:
diff --git a/lib/ansible/modules/net_tools/cloudflare_dns.py b/lib/ansible/modules/net_tools/cloudflare_dns.py
--- a/lib/ansible/modules/net_tools/cloudflare_dns.py
+++ b/lib/ansible/modules/net_tools/cloudflare_dns.py
@@ -558,7 +558,7 @@ def ensure_dns_record(self, **kwargs):
             if (params['priority'] is not None) and ('priority' in cur_record) and (cur_record['priority'] != params['priority']):
                 do_update = True
             if ('data' in new_record) and ('data' in cur_record):
-                if (cur_record['data'] > new_record['data']) - (cur_record['data'] < new_record['data']):
+                if (cur_record['data'] != new_record['data']):
                     do_update = True
             if (params['type'] == 'CNAME') and (cur_record['content'] != new_record['content']):
                 do_update = True


Test patch: