# Buggy code
def ensure_dns_record(self, **kwargs):
    params = {}
    for param in [
        "port",
        "priority",
        "proto",
        "proxied",
        "service",
        "ttl",
        "type",
        "record",
        "value",
        "weight",
        "zone",
    ]:
        if param in kwargs:
            params[param] = kwargs[param]
        else:
            params[param] = getattr(self, param)

    search_value = params["value"]
    search_record = params["record"]
    new_record = None
    if (params["type"] is None) or (params["record"] is None):
        self.module.fail_json(
            msg="You must provide a type and a record to create a new record"
        )

    if params["type"] in ["A", "AAAA", "CNAME", "TXT", "MX", "NS", "SPF"]:
        if not params["value"]:
            self.module.fail_json(
                msg="You must provide a non-empty value to create this record type"
            )

        # there can only be one CNAME per record
        # ignoring the value when searching for existing
        # CNAME records allows us to update the value if it
        # changes
        if params["type"] == "CNAME":
            search_value = None

        new_record = {
            "type": params["type"],
            "name": params["record"],
            "content": params["value"],
            "ttl": params["ttl"],
        }

    if params["type"] in ["A", "AAAA", "CNAME"]:
        new_record["proxied"] = params["proxied"]

    if params["type"] == "MX":
        for attr in [params["priority"], params["value"]]:
            if (attr is None) or (attr == ""):
                self.module.fail_json(
                    msg="You must provide priority and a value to create this record type"
                )
        new_record = {
            "type": params["type"],
            "name": params["record"],
            "content": params["value"],
            "priority": params["priority"],
            "ttl": params["ttl"],
        }

    if params["type"] == "SRV":
        for attr in [
            params["port"],
            params["priority"],
            params["proto"],
            params["service"],
            params["weight"],
            params["value"],
        ]:
            if (attr is None) or (attr == ""):
                self.module.fail_json(
                    msg="You must provide port, priority, proto, service, weight and a value to create this record type"
                )
        srv_data = {
            "target": params["value"],
            "port": params["port"],
            "weight": params["weight"],
            "priority": params["priority"],
            "name": params["record"][: -len("." + params["zone"])],
            "proto": params["proto"],
            "service": params["service"],
        }
        new_record = {"type": params["type"], "ttl": params["ttl"], "data": srv_data}
        search_value = (
            str(params["weight"]) + "\t" + str(params["port"]) + "\t" + params["value"]
        )
        search_record = (
            params["service"] + "." + params["proto"] + "." + params["record"]
        )

    zone_id = self._get_zone_id(params["zone"])
    records = self.get_dns_records(
        params["zone"], params["type"], search_record, search_value
    )
    # in theory this should be impossible as cloudflare does not allow
    # the creation of duplicate records but lets cover it anyways
    if len(records) > 1:
        self.module.fail_json(
            msg="More than one record already exists for the given attributes. That should be impossible, please open an issue!"
        )
    # record already exists, check if it must be updated
    if len(records) == 1:
        cur_record = records[0]
        do_update = False
        if (params["ttl"] is not None) and (cur_record["ttl"] != params["ttl"]):
            do_update = True
        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"]
            ):
                do_update = True
        if (params["type"] == "CNAME") and (
            cur_record["content"] != new_record["content"]
        ):
            do_update = True
        if do_update:
            if self.module.check_mode:
                result = new_record
            else:
                result, info = self._cf_api_call(
                    "/zones/{0}/dns_records/{1}".format(zone_id, records[0]["id"]),
                    "PUT",
                    new_record,
                )
            self.changed = True
            return result, self.changed
        else:
            return records, self.changed
    if self.module.check_mode:
        result = new_record
    else:
        result, info = self._cf_api_call(
            "/zones/{0}/dns_records".format(zone_id), "POST", new_record
        )
    self.changed = True
    return result, self.changed


# Traceback (TypeError)
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()

# Fixed code
def ensure_dns_record(self, **kwargs):
    params = {}
    for param in [
        "port",
        "priority",
        "proto",
        "proxied",
        "service",
        "ttl",
        "type",
        "record",
        "value",
        "weight",
        "zone",
    ]:
        if param in kwargs:
            params[param] = kwargs[param]
        else:
            params[param] = getattr(self, param)

    search_value = params["value"]
    search_record = params["record"]
    new_record = None
    if (params["type"] is None) or (params["record"] is None):
        self.module.fail_json(
            msg="You must provide a type and a record to create a new record"
        )

    if params["type"] in ["A", "AAAA", "CNAME", "TXT", "MX", "NS", "SPF"]:
        if not params["value"]:
            self.module.fail_json(
                msg="You must provide a non-empty value to create this record type"
            )

        # there can only be one CNAME per record
        # ignoring the value when searching for existing
        # CNAME records allows us to update the value if it
        # changes
        if params["type"] == "CNAME":
            search_value = None

        new_record = {
            "type": params["type"],
            "name": params["record"],
            "content": params["value"],
            "ttl": params["ttl"],
        }

    if params["type"] in ["A", "AAAA", "CNAME"]:
        new_record["proxied"] = params["proxied"]

    if params["type"] == "MX":
        for attr in [params["priority"], params["value"]]:
            if (attr is None) or (attr == ""):
                self.module.fail_json(
                    msg="You must provide priority and a value to create this record type"
                )
        new_record = {
            "type": params["type"],
            "name": params["record"],
            "content": params["value"],
            "priority": params["priority"],
            "ttl": params["ttl"],
        }

    if params["type"] == "SRV":
        for attr in [
            params["port"],
            params["priority"],
            params["proto"],
            params["service"],
            params["weight"],
            params["value"],
        ]:
            if (attr is None) or (attr == ""):
                self.module.fail_json(
                    msg="You must provide port, priority, proto, service, weight and a value to create this record type"
                )
        srv_data = {
            "target": params["value"],
            "port": params["port"],
            "weight": params["weight"],
            "priority": params["priority"],
            "name": params["record"][: -len("." + params["zone"])],
            "proto": params["proto"],
            "service": params["service"],
        }
        new_record = {"type": params["type"], "ttl": params["ttl"], "data": srv_data}
        search_value = (
            str(params["weight"]) + "\t" + str(params["port"]) + "\t" + params["value"]
        )
        search_record = (
            params["service"] + "." + params["proto"] + "." + params["record"]
        )

    zone_id = self._get_zone_id(params["zone"])
    records = self.get_dns_records(
        params["zone"], params["type"], search_record, search_value
    )
    # in theory this should be impossible as cloudflare does not allow
    # the creation of duplicate records but lets cover it anyways
    if len(records) > 1:
        self.module.fail_json(
            msg="More than one record already exists for the given attributes. That should be impossible, please open an issue!"
        )
    # record already exists, check if it must be updated
    if len(records) == 1:
        cur_record = records[0]
        do_update = False
        if (params["ttl"] is not None) and (cur_record["ttl"] != params["ttl"]):
            do_update = True
        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"]:
                do_update = True
        if (params["type"] == "CNAME") and (
            cur_record["content"] != new_record["content"]
        ):
            do_update = True
        if do_update:
            if self.module.check_mode:
                result = new_record
            else:
                result, info = self._cf_api_call(
                    "/zones/{0}/dns_records/{1}".format(zone_id, records[0]["id"]),
                    "PUT",
                    new_record,
                )
            self.changed = True
            return result, self.changed
        else:
            return records, self.changed
    if self.module.check_mode:
        result = new_record
    else:
        result, info = self._cf_api_call(
            "/zones/{0}/dns_records".format(zone_id), "POST", new_record
        )
    self.changed = True
    return result, self.changed