Repository: ansible-collections/community.general

Issue:
Cloudflare no longer support SPF records (They must be TXT records)
### Summary

cloudflare_dns module fails to create 'SPF' records.  Looking at cloudflare's site, and their DNS management, they no longer supports 'SPF' record type for DNS entries.  They must be 'TXT' records.

I did try to make a quick patch: https://github.com/ansible-collections/community.general/compare/main...gderber:community.general:bugfix/cloudflare_spf

My editor messed up the formatting, which is why I am not submitting it.  That's in addition to the tests that I need to learn how to run.

### Issue Type

Bug Report

### Component Name

cloudflare_dns

### Ansible Version

```
ansible [core 2.16.2]
  python version = 3.11.6 (main, Oct  8 2023, 05:06:43) [GCC 13.2.0] (/usr/bin/python3)
  jinja version = 3.1.2
  libyaml = True
```

### Community.general Version

```
community.general 8.1.0 
```

Also checked against 8.2.0

### Configuration

_No response_

### OS / Environment

_No response_

### Steps to Reproduce

```
- name: "Add or modify SPF records."
  community.general.cloudflare_dns:
    api_token: "dummyapitoken"
    zone: "example.com"
    type: "{{ item }}"
    state: "present"
    solo: true
    value: "v=spf1 mx -all"
  become: false
  loop: "{{ __spf_record_type }}"
  vars:
    __spf_record_type:
      - "SPF"
      - "TXT"
```

### Expected Results

changed: [inventory_hostname] => (item=TXT)


### Actual Results

failed: [inventory_hostname] (item=SPF) => {"ansible_loop_var": "item", "changed": false, "item": "SPF", "msg": "API bad request; Status: 400; Method: POST: Call: /zones/06b0857ee2d54423ff516ccb8802ab91/dns_records"}


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:
Files identified in the description:
* [`plugins/modules/cloudflare_dns.py`](https://github.com/ansible-collections/community.general/blob/main/plugins/modules/cloudflare_dns.py)

If these files are incorrect, 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/devel/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @mgruener
[click here for bot help](https://github.com/ansible/ansibullbot/blob/devel/ISSUE_HELP.md)
<!--- boilerplate: notify --->
As best I can tell, 'SPF' needs to be removed from lines:
- 152
- 676
- 871

Thanks for informing us!

The removal should be done in two steps:
1. Modify the documentation that SPF no longer works. This will get backported to `stable-7` and `stable-8`.
2. Actually remove it. This will stay in `main` for the next major release.
I created a PR to update the documentation in #7773.

Resolving patch:
diff --git a/plugins/modules/cloudflare_dns.py b/plugins/modules/cloudflare_dns.py
--- a/plugins/modules/cloudflare_dns.py
+++ b/plugins/modules/cloudflare_dns.py
@@ -148,9 +148,9 @@
   type:
     description:
       - The type of DNS record to create. Required if O(state=present).
-      - Note that V(SPF) is no longer supported by CloudFlare. Support for it will be removed from community.general 9.0.0.
+      - Support for V(SPF) has been removed from community.general 9.0.0 since that record type is no longer supported by CloudFlare.
     type: str
-    choices: [ A, AAAA, CNAME, DS, MX, NS, SPF, SRV, SSHFP, TLSA, CAA, TXT ]
+    choices: [ A, AAAA, CNAME, DS, MX, NS, SRV, SSHFP, TLSA, CAA, TXT ]
   value:
     description:
     - The record value.
@@ -674,7 +674,7 @@ def ensure_dns_record(self, **kwargs):
         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 (params['type'] in ['A', 'AAAA', 'CNAME', 'TXT', 'MX', 'NS']):
             if not params['value']:
                 self.module.fail_json(msg="You must provide a non-empty value to create this record type")
 
@@ -869,7 +869,7 @@ def main():
             state=dict(type='str', default='present', choices=['absent', 'present']),
             timeout=dict(type='int', default=30),
             ttl=dict(type='int', default=1),
-            type=dict(type='str', choices=['A', 'AAAA', 'CNAME', 'DS', 'MX', 'NS', 'SPF', 'SRV', 'SSHFP', 'TLSA', 'CAA', 'TXT']),
+            type=dict(type='str', choices=['A', 'AAAA', 'CNAME', 'DS', 'MX', 'NS', 'SRV', 'SSHFP', 'TLSA', 'CAA', 'TXT']),
             value=dict(type='str', aliases=['content']),
             weight=dict(type='int', default=1),
             zone=dict(type='str', required=True, aliases=['domain']),


Test patch: