cloudflare/python-cloudflare

cli4: /zones/:demo.ps/dns_records/import - demo.ps: not found

myousefblue opened this issue · 21 comments

Hello,
I've been trying to make this work with no luck:

cli4- -post file=@demo.txt /zones/:demo.ps/dns_records/import

The result is always:
cli4: /zones/:demo.ps/dns_records/import - demo.ps: not found

However most other methods are working fine, like export, add new dns record.
Can anyone help ?

mahtin commented

Looking... (but to be honest, I can't see why yet). Could you please just try this command ...

    cli4 /zones/:demo.ps/dns_records/export

... and ...

    cli4 /zones/:demo.ps/dns_records | jq -c '.[]|.id,.type,.name,.content' | paste - - - -

... which both should work fine. (Clearly something is going on here that's kinda weird). Once that's confirmed, we can proceed.

(2 mins later)

OK - I can't do an import either - but I get a different error (not on the domain, but on the verb import. Stay tuned on that one.

# cli4 /zones/:demo.ps/dns_records/export
;;
;; Domain:     demo.ps.
;; Exported:   2023-05-19 16:46:18
;;
;; This file is intended for use for informational and archival
;; purposes ONLY and MUST be edited before use on a production
;; DNS server.  In particular, you must:
;;   -- update the SOA record with the correct authoritative name server
;;   -- update the SOA record with the contact e-mail address information
;;   -- update the NS record(s) with the authoritative name servers for this domain.
;;
;; For further information, please consult the BIND documentation
;; located on the following website:
;;
;; http://www.isc.org/
;;
;; And RFC 1035:
;;
;; http://www.ietf.org/rfc/rfc1035.txt
;;
;; Please note that we do NOT offer technical support for any use
;; of this zone data, the BIND name server, or any other third-party
;; DNS software.
;;
;; Use at your own risk.
;; SOA Record
demo.ps 3600    IN      SOA     gwen.ns.cloudflare.com dns.cloudflare.com 2043618137 10000 2400 604800 3600

;; NS Records
demo.ps.        86400   IN      NS      gwen.ns.cloudflare.com.
demo.ps.        86400   IN      NS      lars.ns.cloudflare.com.

;; A Records
test1.demo.ps. 1       IN      A       10.10.10.1
....

and

#cli4 /zones/:demo.ps/dns_records | jq -c '.[]|.id,.type,.name,.content' | paste - - - -
"70e0f122f1b726d73d55878c2137ce03"      "A"     "test1.demo.ps"        "10.10.10.1"
.......

Thanks for your efforts.

mahtin commented

Cool! Glad we could remove that issue.

OK - I have found the issue in the code; it's specific to the word import being a Python keyword. There's code to handle that fact; however, (drum roll please) it's clearly not been tested in this specific case (and I can see why).

Please standby. I may not be able to push a fix till end of day (California).

Good to hear,

No problem, I'll be waiting for the push.

Thanks

mahtin commented

This is three lines of missing code within the cli4 command. You can get around that by simply adding _ (underscore) to the command; i.e. this:

    cli4 -post file=@demo.txt /zones/:demo.ps/dns_records/import_

This will work. The cli4 command is meant to do this silently for you (however, clearly it does not). If you were writing Python code, you must use the trailing underscore because the language won't let you do otherwise.

Sorry about this. It's clearly missing from the README and that also needs to be fixed.

Please retest and let me know (but don't close the issue as it's clearly in need of fixing).

mahtin commented

Pushed as version 2.11.2. Please pip upgrade and test. Thanks!

Thank you so much, working as charm after the upgrade.

By the way, I can't see how to pass the proxied flag the import function, however it exists in the CF documentation for the same API function.

mahtin commented

Please scroll down to the CLI section of the README file. You simply add proxied=true (or false) to the command line after file=.

BTW: If you're doing just a few records, the dns_record API call could be easier to use. Totally your call.

Thank you,
Actually I migrating many domains from BIND to CF, so dns_record will not work for me.

I've already tried that, but it seems not working correctly, as the records added are not proxied.
Could you please double check that this flag is passed correctly to CF API ?

My command I've tried is:

cli4 --post file=@demo.ps.db proxied=true /zones/:demo.ps/dns_records/import_

Update 1:
I've checked CF Audit logs about this action:

{
  "comment": null,
  "content": "1e9babfcb8072c208d5950c93d7ce201.a26fa0c3ce3f08723a0ca955598ad577.comodoca.com",
  "id": "a9d6770a8c7bad5c540db6ab9fbd295e",
  "name": "_4dfb6e063481b44bb6d6c46f91cbc0d6.mail.demo.ps",
  "proxied": false,
  "tags": [],
  "ttl": 3600,
  "type": "CNAME",
  "zone_name": "demp.ps"
}
mahtin commented

Strange. Run the same command with --verbose flag and you'll see the param sent over to Cloudflare. I assume you've read https://developers.cloudflare.com/api/operations/dns-records-for-a-zone-import-dns-records#Request

If you see the flag passed (which you will), then you're next stop is Cloudflare's community support.

Update 2:

I've added the -v flag, and the sent request was:

       curl -X POST "https://api.cloudflare.com/client/v4/zones/XXXXXXXX/dns_records/import" \
            --data '{"proxied": true}' \
            --form "file=@{'file': <_io.BufferedReader name='demo.ps.db'>}"

However, per this CF Documentation it must be like this:

       curl -X POST "https://api.cloudflare.com/client/v4/zones/XXXXXXXX/dns_records/import" \
            --form proxied=true
            --form "file=@{'file': <_io.BufferedReader name='demo.ps.db'>}"
mahtin commented

Well this is an issue and I know it's been worked on inside the code. This code was written a long time ago ...

    if files:
        # overwrite Content-Type as we are uploading data
        headers['Content-Type'] = 'multipart/form-data'
        # however something isn't right and this works ... look at again later!
        del headers['Content-Type']

... because the Cloudflare API does not accept the multipart/form-data as a Content-Type (and that is as-per the code examples in the API docs; however, not as-per the textual commentary. But with that said, you're right, the parameters are indeed passed incorrectly in this case (and a few other cases). I'll go work on that now. I believe that the initial code was expecting the Python requests library to just do this correctly. Le Sigh.

That's Great,
Thanks in advanced.

mahtin commented

Now pushed as 2.11.3. It was a myriad of simple things, clearly missing from the code. So ... thank you for triggering this and seeing the issue. (One of which was the curl debug printout creation code - doh!)

However, while the network debug shows the format matching the Cloudflare API page (https://developers.cloudflare.com/api/operations/dns-records-for-a-zone-import-dns-records) it still does not work. After reverting to curl commands, I've found the issue. Cloudflare only matches against true and false vs. True and False and as the lower level libraries used by this code only use True and False. This is sad.

I will open a ticket with Cloudflare. I don't know a good fix for this today.

mahtin commented

Now pushed as 2.11.4. Please upgrade via pip.

Only one change added. It can be used to get around the processing of boolean values that get sent as only True or False (which Cloudflare on the import API does not accept yet others do). The change is to allow quoting of parameter values; which gets striped before sending to Cloudflare's API. This allows true and false to be passed a strings (vs being converted to boolean values). It's a hack - but it's a legit one.

This is how you would use it (carefully note the two quotation mark usage).

    cli4 -post proxied="'true'" file=@demo.txt /zones/:demo.ps/dns_records/import

Basically, the quotes need to be quoted (it's a Unix/Linux thing!). You could also do this; but it's not as readable:

    cli4 -post proxied=\'true\' file=@demo.txt /zones/:demo.ps/dns_records/import

I've tested this with import and it works cleanly.

Please note that you can also fix record via something like this:

    cli4 --patch proxied=False /zones/:demo.ps/dns_records/:something.demo.ps
    cli4 --patch proxied=True /zones/:demo.ps/dns_records/:something.demo.ps

(Note that classic False/True or false/true work for that API endpoint! Argggg!)

I hope all this helps!

mahtin commented

@myousefblue - I've notified Cloudflare of this strange hiccup with the Boolean values passed for this API call. I know it's not a high priority for them; however, it's their issue now. You'll just have to stick to the quotation method listed above for now. I'm closing this issue if that's ok with you. Open it again if a related issue pops up for this API endpoint.

mahtin commented

@myousefblue - Cloudflare has fixed this bug at their end and you can revert back to the simple proxied=true or proxied=false (with uppercase/lowercase independence). Enjoy!

@mahtin Thank you so much for your efforts, I do appreciate it.

As I can see everything is working fine now.

Another minor issue that I have noticed in my last try to PUT a dns record of type MX, it always returns an error that the priority must be an Integer, that's because you wrap the values with single quotes, wich CF does not accept.

mahtin commented

Use ==. Please see the README section CLI parameters. It says:

The simplest form is item=value. This passes the value as a string within the APIs JSON data.

If you need a numeric value passed then == can be used to force the value to be treated as a numeric value within the APIs JSON data. For example: item==value.
mahtin commented

Using the theory of "practice what you preach", I've updated the README and appropriate example files to use == where appropriate for numeric values. Clearly the API allows both numeric and string versions of number on some API endpoints.

See #26a05cf.

@mahtin awesome!
Thank you very much.