1cloudflare-python 2================= 3 4Installation 5------------ 6 7Two methods are provided to install this software. Use PyPi (see 8`package <https://pypi.python.org/pypi/cloudflare>`__ details) or GitHub 9(see `package <https://github.com/cloudflare/python-cloudflare>`__ 10details). 11 12Via PyPI 13~~~~~~~~ 14 15.. code:: bash 16 17 $ sudo pip install cloudflare 18 $ 19 20Yes - that simple! (the sudo may not be needed in some cases). 21 22Via github 23~~~~~~~~~~ 24 25.. code:: bash 26 27 $ git clone https://github.com/cloudflare/python-cloudflare 28 $ cd python-cloudflare 29 $ ./setup.py build 30 $ sudo ./setup.py install 31 $ 32 33Or whatever variance of that you want to use. There is a Makefile 34included. 35 36Cloudflare name change - dropping the capital F 37----------------------------------------------- 38 39In Sepember/October 2016 the company modified its company name and 40dropped the capital F. However, for now (and for backward compatibility 41reasons) the class name stays the same. 42 43Cloudflare API version 4 44------------------------ 45 46The Cloudflare API can be found `here <https://api.cloudflare.com/>`__. 47Each API call is provided via a similarly named function within the 48**CloudFlare** class. A full list is provided below. 49 50Example code 51------------ 52 53All example code is available on GitHub (see 54`package <https://github.com/cloudflare/python-cloudflare>`__ in the 55`examples <https://github.com/cloudflare/python-cloudflare/tree/master/examples>`__ 56folder). 57 58Blog 59---- 60 61This package was initially introduced 62`here <https://blog.cloudflare.com/python-cloudflare/>`__ via 63Cloudflare's `blog <https://blog.cloudflare.com/>`__. 64 65Getting Started 66--------------- 67 68A very simple listing of zones within your account; including the IPv6 69status of the zone. 70 71.. code:: python 72 73 import CloudFlare 74 75 def main(): 76 cf = CloudFlare.CloudFlare() 77 zones = cf.zones.get() 78 for zone in zones: 79 zone_id = zone['id'] 80 zone_name = zone['name'] 81 print zone_id, zone_name 82 83 if __name__ == '__main__': 84 main() 85 86This example works when there are less than 50 zones (50 is the default 87number of values returned from a query like this). 88 89Now lets expand on that and add code to show the IPv6 and SSL status of 90the zones. Lets also query 100 zones. 91 92.. code:: python 93 94 import CloudFlare 95 96 def main(): 97 cf = CloudFlare.CloudFlare() 98 zones = cf.zones.get(params = {'per_page':100}) 99 for zone in zones: 100 zone_id = zone['id'] 101 zone_name = zone['name'] 102 103 settings_ssl = cf.zones.settings.ssl.get(zone_id) 104 ssl_status = settings_ssl['value'] 105 106 settings_ipv6 = cf.zones.settings.ipv6.get(zone_id) 107 ipv6_status = settings_ipv6['value'] 108 109 print zone_id, zone_name, ssl_status, ipv6_status 110 111 if __name__ == '__main__': 112 main() 113 114In order to query more than a single page of zones, we would have to use 115the raw mode (described more below). We can loop over many get calls and 116pass the page parameter to facilitate the paging. 117 118Raw mode is only needed when a get request has the possibility of 119returning many items. 120 121.. code:: python 122 123 import CloudFlare 124 125 def main(): 126 cf = CloudFlare.CloudFlare(raw=True) 127 page_number = 0 128 while True: 129 page_number += 1 130 raw_results = cf.zones.get(params={'per_page':5,'page':page_number}) 131 zones = raw_results['result'] 132 133 for zone in zones: 134 zone_id = zone['id'] 135 zone_name = zone['name'] 136 print zone_id, zone_name 137 138 total_pages = raw_results['result_info']['total_pages'] 139 if page_number == total_pages: 140 break 141 142 if __name__ == '__main__': 143 main() 144 145A more complex example follows. 146 147.. code:: python 148 149 import CloudFlare 150 151 def main(): 152 zone_name = 'example.com' 153 154 cf = CloudFlare.CloudFlare() 155 156 # query for the zone name and expect only one value back 157 try: 158 zones = cf.zones.get(params = {'name':zone_name,'per_page':1}) 159 except CloudFlare.exceptions.CloudFlareAPIError as e: 160 exit('/zones.get %d %s - api call failed' % (e, e)) 161 except Exception as e: 162 exit('/zones.get - %s - api call failed' % (e)) 163 164 if len(zones) == 0: 165 exit('No zones found') 166 167 # extract the zone_id which is needed to process that zone 168 zone = zones[0] 169 zone_id = zone['id'] 170 171 # request the DNS records from that zone 172 try: 173 dns_records = cf.zones.dns_records.get(zone_id) 174 except CloudFlare.exceptions.CloudFlareAPIError as e: 175 exit('/zones/dns_records.get %d %s - api call failed' % (e, e)) 176 177 # print the results - first the zone name 178 print zone_id, zone_name 179 180 # then all the DNS records for that zone 181 for dns_record in dns_records: 182 r_name = dns_record['name'] 183 r_type = dns_record['type'] 184 r_value = dns_record['content'] 185 r_id = dns_record['id'] 186 print '\t', r_id, r_name, r_type, r_value 187 188 exit(0) 189 190 if __name__ == '__main__': 191 main() 192 193Providing Cloudflare Username and API Key 194----------------------------------------- 195 196When you create a **CloudFlare** class you can pass up to four 197parameters. 198 199- API Token or API Key 200- Account email (only if an API Key is being used) 201- Optional Origin-CA Certificate Token 202- Optional Debug flag (True/False) 203- Optional Profile name (the default is ``Cloudflare``) 204 205.. code:: python 206 207 import CloudFlare 208 209 # A minimal call - reading values from environment variables or configuration file 210 cf = CloudFlare.CloudFlare() 211 212 # A minimal call with debug enabled 213 cf = CloudFlare.CloudFlare(debug=True) 214 215 # An authenticated call using an API Token (note the missing email) 216 cf = CloudFlare.CloudFlare(token='00000000000000000000000000000000') 217 218 # An authenticated call using an API Key 219 cf = CloudFlare.CloudFlare(email='user@example.com', token='00000000000000000000000000000000') 220 221 # An authenticated call using an API Key and CA-Origin info 222 cf = CloudFlare.CloudFlare(email='user@example.com', token='00000000000000000000000000000000', certtoken='v1.0-...') 223 224 # An authenticated call using using a stored profile (see below) 225 cf = CloudFlare.CloudFlare(profile="CompanyX")) 226 227If the account email and API key are not passed when you create the 228class, then they are retrieved from either the users exported shell 229environment variables or the .cloudflare.cfg or ~/.cloudflare.cfg or 230~/.cloudflare/cloudflare.cfg files, in that order. 231 232If you're using an API Token, any ``cloudflare.cfg`` file must either 233not contain an ``email`` attribute or be a zero length string and the 234``CF_API_EMAIL`` environment variable must be unset or be a zero length 235string, otherwise the token will be treated as a key and will throw an 236error. 237 238There is one call that presently doesn't need any email or token 239certification (the */ips* call); hence you can test without any values 240saved away. 241 242Using shell environment variables 243~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 244 245.. code:: bash 246 247 $ export CF_API_EMAIL='user@example.com' # Do not set if using an API Token 248 $ export CF_API_KEY='00000000000000000000000000000000' 249 $ export CF_API_CERTKEY='v1.0-...' 250 $ 251 252These are optional environment variables; however, they do override the 253values set within a configuration file. 254 255Using configuration file to store email and keys 256~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 257 258.. code:: bash 259 260 $ cat ~/.cloudflare/cloudflare.cfg 261 [CloudFlare] 262 email = user@example.com # Do not set if using an API Token 263 token = 00000000000000000000000000000000 264 certtoken = v1.0-... 265 extras = 266 $ 267 268More than one profile can be stored within that file. Here's an example 269for a work and home setup (in this example work has an API Token and 270home uses email/token). 271 272.. code:: bash 273 274 $ cat ~/.cloudflare/cloudflare.cfg 275 [Work] 276 token = 00000000000000000000000000000000 277 [Home] 278 email = home@example.com 279 token = 00000000000000000000000000000000 280 $ 281 282To select a profile, use the ``--profile profile-name`` option for 283``cli4`` command or use ``profile="profile-name"`` in the library call. 284 285.. code:: bash 286 287 $ cli4 --profile Work /zones | jq '.[]|.name' | wc -l 288 13 289 $ 290 291 $ cli4 --profile Home /zones | jq '.[]|.name' | wc -l 292 1 293 $ 294 295Here is the same in code. 296 297.. code:: python 298 299 #!/usr/bin/env python 300 301 import CloudFlare 302 303 def main(): 304 cf = CloudFlare.CloudFlare(profile="Work") 305 ... 306 307Advanced use of configuration file for authentication based on method 308~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 309 310The configuration file can have values that are both generic and 311specific to the method. Here's an example where a project has a 312different API Token for reading and writing values. 313 314.. code:: bash 315 316 $ cat ~/.cloudflare/cloudflare.cfg 317 [Work] 318 token = 0000000000000000000000000000000000000000 319 token.get = 0123456789012345678901234567890123456789 320 $ 321 322When a GET call is processed then the second token is used. For all 323other calls the first token is used. Here's a more explict verion of 324that config: 325 326.. code:: bash 327 328 $ cat ~/.cloudflare/cloudflare.cfg 329 [Work] 330 token.delete = 0000000000000000000000000000000000000000 331 token.get = 0123456789012345678901234567890123456789 332 token.patch = 0000000000000000000000000000000000000000 333 token.post = 0000000000000000000000000000000000000000 334 token.put = 0000000000000000000000000000000000000000 335 $ 336 337This can be used with email values also. 338 339About /certificates and certtoken 340~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 341 342The *CF\_API\_CERTKEY* or *certtoken* values are used for the Origin-CA 343*/certificates* API calls. You can leave *certtoken* in the 344configuration with a blank value (or omit the option variable fully). 345 346The *extras* values are used when adding API calls outside of the core 347codebase. Technically, this is only useful for internal testing within 348Cloudflare. You can leave *extras* in the configuration with a blank 349value (or omit the option variable fully). 350 351Exceptions and return values 352---------------------------- 353 354Response data 355~~~~~~~~~~~~~ 356 357The response is build from the JSON in the API call. It contains the 358**results** values; but does not contain the paging values. 359 360You can return all the paging values by calling the class with raw=True. 361Here's an example without paging. 362 363.. code:: python 364 365 #!/usr/bin/env python 366 367 import json 368 import CloudFlare 369 370 def main(): 371 cf = CloudFlare.CloudFlare() 372 zones = cf.zones.get(params={'per_page':5}) 373 print len(zones) 374 375 if __name__ == '__main__': 376 main() 377 378The results are as follows. 379 380:: 381 382 5 383 384When you add the raw option; the APIs full structure is returned. This 385means the paging values can be seen. 386 387.. code:: python 388 389 #!/usr/bin/env python 390 391 import json 392 import CloudFlare 393 394 def main(): 395 cf = CloudFlare.CloudFlare(raw=True) 396 zones = cf.zones.get(params={'per_page':5}) 397 print zones.length() 398 print json.dumps(zones, indent=4, sort_keys=True) 399 400 if __name__ == '__main__': 401 main() 402 403This produces. 404 405:: 406 407 5 408 { 409 "result": [ 410 ... 411 ], 412 "result_info": { 413 "count": 5, 414 "page": 1, 415 "per_page": 5, 416 "total_count": 31, 417 "total_pages": 7 418 } 419 } 420 421A full example of paging is provided below. 422 423Exceptions 424~~~~~~~~~~ 425 426The library will raise **CloudFlareAPIError** when the API call fails. 427The exception returns both an integer and textual message in one value. 428 429.. code:: python 430 431 import CloudFlare 432 433 ... 434 try 435 r = ... 436 except CloudFlare.exceptions.CloudFlareAPIError as e: 437 exit('api error: %d %s' % (e, e)) 438 ... 439 440The other raised response is **CloudFlareInternalError** which can 441happen when calling an invalid method. 442 443In some cases more than one error is returned. In this case the return 444value **e** is also an array. You can iterate over that array to see the 445additional error. 446 447.. code:: python 448 449 import sys 450 import CloudFlare 451 452 ... 453 try 454 r = ... 455 except CloudFlare.exceptions.CloudFlareAPIError as e: 456 if len(e) > 0: 457 sys.stderr.write('api error - more than one error value returned!\n') 458 for x in e: 459 sys.stderr.write('api error: %d %s\n' % (x, x)) 460 exit('api error: %d %s' % (e, e)) 461 ... 462 463Exception examples 464~~~~~~~~~~~~~~~~~~ 465 466Here's examples using the CLI command cli4 of the responses passed back 467in exceptions. 468 469First a simple get with a clean (non-error) response. 470 471:: 472 473 $ cli4 /zones/:example.com/dns_records | jq -c '.[]|{"name":.name,"type":.type,"content":.content}' 474 {"name":"example.com","type":"MX","content":"something.example.com"} 475 {"name":"something.example.com","type":"A","content":"10.10.10.10"} 476 $ 477 478Next a simple/single error response. This is simulated by providing 479incorrect authentication information. 480 481:: 482 483 $ CF_API_EMAIL='someone@example.com' cli4 /zones/ 484 cli4: /zones - 9103 Unknown X-Auth-Key or X-Auth-Email 485 $ 486 487More than one call can be done on the same command line. In this mode, 488the connection is preserved between calls. 489 490:: 491 492 $ cli4 /user/organizations /user/invites 493 ... 494 $ 495 496Note that the output is presently two JSON structures one after the 497other - so less useful that you may think. 498 499Finally, a command that provides more than one error response. This is 500simulated by passing an invalid IPv4 address to a DNS record creation. 501 502:: 503 504 $ cli4 --post name='foo' type=A content="1" /zones/:example.com/dns_records 505 cli4: /zones/:example.com/dns_records - 9005 Content for A record is invalid. Must be a valid IPv4 address 506 cli4: /zones/:example.com/dns_records - 1004 DNS Validation Error 507 $ 508 509Included example code 510--------------------- 511 512The 513`examples <https://github.com/cloudflare/python-cloudflare/tree/master/examples>`__ 514folder contains many examples in both simple and verbose formats. 515 516A DNS zone code example 517----------------------- 518 519.. code:: python 520 521 #!/usr/bin/env python 522 523 import sys 524 import CloudFlare 525 526 def main(): 527 zone_name = sys.argv[1] 528 cf = CloudFlare.CloudFlare() 529 zone_info = cf.zones.post(data={'jump_start':False, 'name': zone_name}) 530 zone_id = zone_info['id'] 531 532 dns_records = [ 533 {'name':'foo', 'type':'AAAA', 'content':'2001:d8b::1'}, 534 {'name':'foo', 'type':'A', 'content':'192.168.0.1'}, 535 {'name':'duh', 'type':'A', 'content':'10.0.0.1', 'ttl':120}, 536 {'name':'bar', 'type':'CNAME', 'content':'foo'}, 537 {'name':'shakespeare', 'type':'TXT', 'content':"What's in a name? That which we call a rose by any other name ..."} 538 ] 539 540 for dns_record in dns_records: 541 r = cf.zones.dns_records.post(zone_id, data=dns_record) 542 exit(0) 543 544 if __name__ == '__main__': 545 main() 546 547A DNS zone delete code example (be careful) 548------------------------------------------- 549 550.. code:: python 551 552 #!/usr/bin/env python 553 554 import sys 555 import CloudFlare 556 557 def main(): 558 zone_name = sys.argv[1] 559 cf = CloudFlare.CloudFlare() 560 zone_info = cf.zones.get(params={'name': zone_name}) 561 zone_id = zone_info['id'] 562 563 dns_name = sys.argv[2] 564 dns_records = cf.zones.dns_records.get(zone_id, params={'name':dns_name + '.' + zone_name}) 565 for dns_record in dns_records: 566 dns_record_id = dns_record['id'] 567 r = cf.zones.dns_records.delete(zone_id, dns_record_id) 568 exit(0) 569 570 if __name__ == '__main__': 571 main() 572 573CLI 574--- 575 576All API calls can be called from the command line. The command will 577convert domain names prefixed with a colon (``:``) into 578zone\_identifiers: e.g. to view ``example.com`` you must use 579``cli4 /zones/:example.com`` (the zone ID cannot be used). 580 581.. code:: bash 582 583 $ cli4 [-V|--version] [-h|--help] [-v|--verbose] [-q|--quiet] [-j|--json] [-y|--yaml] [-r|--raw] [-d|--dump] [--get|--patch|--post|--put|--delete] [item=value ...] /command... 584 585CLI parameters for POST/PUT/PATCH 586~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 587 588For API calls that need to pass data or parameters there is various 589formats to use. 590 591The simplest form is ``item=value``. This passes the value as a string 592within the APIs JSON data. 593 594If you need a numeric value passed then **==** can be used to force the 595value to be treated as a numeric value within the APIs JSON data. For 596example: ``item==value``. 597 598if you need to pass a list of items; then **[]** can be used. For 599example: 600 601:: 602 603 pool_id1="11111111111111111111111111111111" 604 pool_id2="22222222222222222222222222222222" 605 pool_id3="33333333333333333333333333333333" 606 cli4 --post global_pools="[ ${pool_id1}, ${pool_id2}, ${pool_id3} ]" region_pools="[ ]" /user/load_balancers/maps 607 608Data or parameters can be either named or unnamed. It can not be both. 609Named is the majority format; as described above. Unnamed parameters 610simply don't have anything before the **=** sign, as in ``=value``. This 611format is presently only used by the Cloudflare Load Balancer API calls. 612For example: 613 614:: 615 616 cli4 --put ="00000000000000000000000000000000" /user/load_balancers/maps/:00000000000000000000000000000000/region/:WNAM 617 618Data can also be uploaded from file contents. Using the 619``item=@filename`` format will open the file and the contents uploaded 620in the POST. 621 622CLI output 623~~~~~~~~~~ 624 625The output from the CLI command is in JSON or YAML format (and human 626readable). This is controled by the **--yaml** or **--json** flags (JSON 627is the default). 628 629Simple CLI examples 630~~~~~~~~~~~~~~~~~~~ 631 632- ``cli4 /user/billing/profile`` 633- ``cli4 /user/invites`` 634 635- ``cli4 /zones/:example.com`` 636- ``cli4 /zones/:example.com/dnssec`` 637- ``cli4 /zones/:example.com/settings/ipv6`` 638- ``cli4 --put /zones/:example.com/activation_check`` 639- ``cli4 /zones/:example.com/keyless_certificates`` 640 641- ``cli4 /zones/:example.com/analytics/dashboard`` 642 643More complex CLI examples 644~~~~~~~~~~~~~~~~~~~~~~~~~ 645 646Here is the creation of a DNS entry, followed by a listing of that entry 647and then the deletion of that entry. 648 649.. code:: bash 650 651 $ $ cli4 --post name="test" type="A" content="10.0.0.1" /zones/:example.com/dns_records 652 { 653 "id": "00000000000000000000000000000000", 654 "name": "test.example.com", 655 "type": "A", 656 "content": "10.0.0.1", 657 ... 658 } 659 $ 660 661 $ cli4 /zones/:example.com/dns_records/:test.example.com | jq '{"id":.id,"name":.name,"type":.type,"content":.content}' 662 { 663 "id": "00000000000000000000000000000000", 664 "name": "test.example.com", 665 "type": "A", 666 "content": "10.0.0.1" 667 } 668 669 $ cli4 --delete /zones/:example.com/dns_records/:test.example.com | jq -c . 670 {"id":"00000000000000000000000000000000"} 671 $ 672 673There's the ability to handle dns entries with multiple values. This 674produces more than one API call within the command. 675 676:: 677 678 $ cli4 /zones/:example.com/dns_records/:test.example.com | jq -c '.[]|{"id":.id,"name":.name,"type":.type,"content":.content}' 679 {"id":"00000000000000000000000000000000","name":"test.example.com","type":"A","content":"192.168.0.1"} 680 {"id":"00000000000000000000000000000000","name":"test.example.com","type":"AAAA","content":"2001:d8b::1"} 681 $ 682 683Here are the cache purging commands. 684 685.. code:: bash 686 687 $ cli4 --delete purge_everything=true /zones/:example.com/purge_cache | jq -c . 688 {"id":"00000000000000000000000000000000"} 689 $ 690 691 $ cli4 --delete files='[http://example.com/css/styles.css]' /zones/:example.com/purge_cache | jq -c . 692 {"id":"00000000000000000000000000000000"} 693 $ 694 695 $ cli4 --delete files='[http://example.com/css/styles.css,http://example.com/js/script.js]' /zones/:example.com/purge_cache | jq -c . 696 {"id":"00000000000000000000000000000000"} 697 $ 698 699 $ cli4 --delete tags='[tag1,tag2,tag3]' /zones/:example.com/purge_cache | jq -c . 700 cli4: /zones/:example.com/purge_cache - 1107 Only enterprise zones can purge by tag. 701 $ 702 703A somewhat useful listing of available plans for a specific zone. 704 705.. code:: bash 706 707 $ cli4 /zones/:example.com/available_plans | jq -c '.[]|{"id":.id,"name":.name}' 708 {"id":"00000000000000000000000000000000","name":"Pro Website"} 709 {"id":"00000000000000000000000000000000","name":"Business Website"} 710 {"id":"00000000000000000000000000000000","name":"Enterprise Website"} 711 {"id":"0feeeeeeeeeeeeeeeeeeeeeeeeeeeeee","name":"Free Website"} 712 $ 713 714Cloudflare CA CLI examples 715~~~~~~~~~~~~~~~~~~~~~~~~~~ 716 717Here's some Cloudflare CA examples. Note the need of the zone\_id= 718parameter with the basic **/certificates** call. 719 720.. code:: bash 721 722 $ cli4 /zones/:example.com | jq -c '.|{"id":.id,"name":.name}' 723 {"id":"12345678901234567890123456789012","name":"example.com"} 724 $ 725 726 $ cli4 zone_id=12345678901234567890123456789012 /certificates | jq -c '.[]|{"id":.id,"expires_on":.expires_on,"hostnames":.hostnames,"certificate":.certificate}' 727 {"id":"123456789012345678901234567890123456789012345678","expires_on":"2032-01-29 22:36:00 +0000 UTC","hostnames":["*.example.com","example.com"],"certificate":"-----BEGIN CERTIFICATE-----\n ... "} 728 {"id":"123456789012345678901234567890123456789012345678","expires_on":"2032-01-28 23:23:00 +0000 UTC","hostnames":["*.example.com","example.com"],"certificate":"-----BEGIN CERTIFICATE-----\n ... "} 729 {"id":"123456789012345678901234567890123456789012345678","expires_on":"2032-01-28 23:20:00 +0000 UTC","hostnames":["*.example.com","example.com"],"certificate":"-----BEGIN CERTIFICATE-----\n ... "} 730 $ 731 732A certificate can be viewed via a simple GET request. 733 734.. code:: bash 735 736 $ cli4 /certificates/:123456789012345678901234567890123456789012345678 737 { 738 "certificate": "-----BEGIN CERTIFICATE-----\n ... ", 739 "expires_on": "2032-01-29 22:36:00 +0000 UTC", 740 "hostnames": [ 741 "*.example.com", 742 "example.com" 743 ], 744 "id": "123456789012345678901234567890123456789012345678", 745 "request_type": "origin-rsa" 746 } 747 $ 748 749Creating a certificate. This is done with a **POST** request. Note the 750use of **==** in order to pass a decimal number (vs. string) in JSON. 751The CSR is not shown for simplicity sake. 752 753.. code:: bash 754 755 $ CSR=`cat example.com.csr` 756 $ cli4 --post hostnames='["example.com","*.example.com"]' requested_validity==365 request_type="origin-ecc" csr="$CSR" /certificates 757 { 758 "certificate": "-----BEGIN CERTIFICATE-----\n ... ", 759 "csr": "-----BEGIN CERTIFICATE REQUEST-----\n ... ", 760 "expires_on": "2018-09-27 21:47:00 +0000 UTC", 761 "hostnames": [ 762 "*.example.com", 763 "example.com" 764 ], 765 "id": "123456789012345678901234567890123456789012345678", 766 "request_type": "origin-ecc", 767 "requested_validity": 365 768 } 769 $ 770 771Deleting a certificate can be done with a **DELETE** call. 772 773.. code:: bash 774 775 $ cli4 --delete /certificates/:123456789012345678901234567890123456789012345678 776 { 777 "id": "123456789012345678901234567890123456789012345678", 778 "revoked_at": "0000-00-00T00:00:00Z" 779 } 780 $ 781 782Paging CLI examples 783~~~~~~~~~~~~~~~~~~~ 784 785The **--raw** command provides access to the paging returned values. See 786the API documentation for all the info. Here's an example of how to page 787thru a list of zones (it's included in the examples folder as 788**example\_paging\_thru\_zones.sh**). 789 790.. code:: bash 791 792 : 793 tmp=/tmp/$$_ 794 trap "rm ${tmp}; exit 0" 0 1 2 15 795 PAGE=0 796 while true 797 do 798 cli4 --raw per_page=5 page=${PAGE} /zones > ${tmp} 799 domains=`jq -c '.|.result|.[]|.name' < ${tmp} | tr -d '"'` 800 result_info=`jq -c '.|.result_info' < ${tmp}` 801 COUNT=` echo "${result_info}" | jq .count` 802 PAGE=` echo "${result_info}" | jq .page` 803 PER_PAGE=` echo "${result_info}" | jq .per_page` 804 TOTAL_COUNT=`echo "${result_info}" | jq .total_count` 805 TOTAL_PAGES=`echo "${result_info}" | jq .total_pages` 806 echo COUNT=${COUNT} PAGE=${PAGE} PER_PAGE=${PER_PAGE} TOTAL_COUNT=${TOTAL_COUNT} TOTAL_PAGES=${TOTAL_PAGES} -- ${domains} 807 if [ "${PAGE}" == "${TOTAL_PAGES}" ] 808 then 809 ## last section 810 break 811 fi 812 # grab the next page 813 PAGE=`expr ${PAGE} + 1` 814 done 815 816It produces the following results. 817 818:: 819 820 COUNT=5 PAGE=1 PER_PAGE=5 TOTAL_COUNT=31 TOTAL_PAGES=7 -- accumsan.example auctor.example consectetur.example dapibus.example elementum.example 821 COUNT=5 PAGE=2 PER_PAGE=5 TOTAL_COUNT=31 TOTAL_PAGES=7 -- felis.example iaculis.example ipsum.example justo.example lacus.example 822 COUNT=5 PAGE=3 PER_PAGE=5 TOTAL_COUNT=31 TOTAL_PAGES=7 -- lectus.example lobortis.example maximus.example morbi.example pharetra.example 823 COUNT=5 PAGE=4 PER_PAGE=5 TOTAL_COUNT=31 TOTAL_PAGES=7 -- porttitor.example potenti.example pretium.example purus.example quisque.example 824 COUNT=5 PAGE=5 PER_PAGE=5 TOTAL_COUNT=31 TOTAL_PAGES=7 -- sagittis.example semper.example sollicitudin.example suspendisse.example tortor.example 825 COUNT=1 PAGE=7 PER_PAGE=5 TOTAL_COUNT=31 TOTAL_PAGES=7 -- varius.example vehicula.example velit.example velit.example vitae.example 826 COUNT=5 PAGE=6 PER_PAGE=5 TOTAL_COUNT=31 TOTAL_PAGES=7 -- vivamus.example 827 828Paging thru lists (using cursors) 829~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 830 831Some API calls use cursors to read beyond the initally returned values. 832See the API page in order to see which API calls do this. 833 834:: 835 836 $ ACCOUNT_ID="00000000000000000000000000000000" 837 $ LIST_ID="00000000000000000000000000000000" 838 $ 839 $ cli4 --raw /accounts/::${ACCOUNT_ID}/rules/lists/::${LIST_ID}/items > /tmp/page1.json 840 $ after=`jq -r '.result_info.cursors.after' < /tmp/page1.json` 841 $ echo "after=$after" 842 after=Mxm4GVmKjYbFjy2VxMPipnJigm1M_s6lCS9ABR9wx-RM2A 843 $ 844 845Once we have the ``after`` value, we can pass it along in order to read 846the next hunk of values. We finish when ``after`` returns as null (or 847isn't present). 848 849:: 850 851 $ cli4 --raw cursor="$after" /accounts/::${ACCOUNT_ID}/rules/lists/::${LIST_ID}/items > /tmp/page2.json 852 $ after=`jq -r '.result_info.cursors.after' < /tmp/page2.json` 853 $ echo "after=$after" 854 after=null 855 $ 856 857We can see the results now in two files. 858 859:: 860 861 $ jq -c '.result[]' < /tmp/page1.json | wc -l 862 25 863 $ 864 865 $ jq -c '.result[]' < /tmp/page2.json | wc -l 866 5 867 $ 868 869 $ for f in /tmp/page?.json ; do jq -r '.result[]|.id,.ip,.comment' < $f | paste - - - ; done | column -s' ' -t 870 0fe44928258549feb47126a966fbf4a0 0.0.0.0 all zero 871 2e1e02120f5e466f8c0e26375e4cf4c8 1.0.0.1 Cloudflare DNS a 872 9ca5fd0ac6f54fdbb9dedd3fb72ce2da 1.1.1.1 Cloudflare DNS b 873 b3654987446743738c782f36ebe074f5 10.0.0.0/8 RFC1918 space 874 90bec8ce37d242faa2e27d1e78c1d8e2 103.21.244.0/22 Cloudflare IP 875 970a3c810cda41af9bef2c36a1892f7e 103.22.200.0/22 Cloudflare IP 876 3ec8516158bf4f3cac18210f611ee541 103.31.4.0/22 Cloudflare IP 877 ee9d268367204e6bb8e5e4c907f22de8 104.16.0.0/12 Cloudflare IP 878 93ae02eda9774c45840af367a02fe529 108.162.192.0/18 Cloudflare IP 879 62891ebf6db44aa494d79a6401af185e 131.0.72.0/22 Cloudflare IP 880 cac40cd940cc470582b8c912a8a12bea 141.101.64.0/18 Cloudflare IP 881 f6d5eacd81a2407f8e0d81caee21e7f8 162.158.0.0/15 Cloudflare IP 882 3d538dfc38ab471d9d3fe78332acfa4e 172.16.0.0/12 RFC1918 space 883 f353cb8f98424837ad35382a22b9debe 172.64.0.0/13 Cloudflare IP 884 78f3e1a0bafc41f88d4d40ad49a642e0 173.245.48.0/20 Cloudflare IP 885 c23a545475c54c32a7681c6b508d3e80 188.114.96.0/20 Cloudflare IP 886 f693237c9e294fe481221cbc2d7c20ef 190.93.240.0/20 Cloudflare IP 887 6d465ab3a0994c07827ebdcf8f34d977 192.168.0.0/16 RFC1918 space 888 1ad1e634b3664bac939086185c62faf7 197.234.240.0/22 Cloudflare IP 889 5d2968e7b3114d8e869a379d71c8ba86 198.41.128.0/17 Cloudflare IP 890 6a69de60b31448fa864f0a3ac5abe8d0 224.0.0.0/24 Multicast 891 30749cce89af4ab3a80e308294f46a46 240.0.0.0/4 Class E 892 2b32c67ea4d044628abe39f28662d8f0 255.255.255.255 all ones 893 cc7cd828b2fb4bcfb9391c2d3ef8d068 2400:cb00::/32 Cloudflare IP 894 b30d4cbd7dcd48729e8ebeda552e48a8 2405:8100::/32 Cloudflare IP 895 49db60758c8344959c338a74afc9748a 2405:b500::/32 Cloudflare IP 896 96e9eca1923c40d5a84865145f5a5d6a 2606:4700::/32 Cloudflare IP 897 21bc52a26e10405d89b7180ddcf49302 2803:f800::/32 Cloudflare IP 898 ff78f842188e4b869eb5389ae9ab8f41 2a06:98c0::/29 Cloudflare IP 899 0880cdfc40b14f6fa0639522a728859d 2c0f:f248::/32 Cloudflare IP 900 $ 901 902The ``result_info.cursors`` area also contains a ``before`` value for 903reverse scrolling. 904 905As with ``per_page`` scrolling, raw mode is used. 906 907DNSSEC CLI examples 908~~~~~~~~~~~~~~~~~~~ 909 910.. code:: bash 911 912 $ cli4 /zones/:example.com/dnssec | jq -c '{"status":.status}' 913 {"status":"disabled"} 914 $ 915 916 $ cli4 --patch status=active /zones/:example.com/dnssec | jq -c '{"status":.status}' 917 {"status":"pending"} 918 $ 919 920 $ cli4 /zones/:example.com/dnssec 921 { 922 "algorithm": "13", 923 "digest": "41600621c65065b09230ebc9556ced937eb7fd86e31635d0025326ccf09a7194", 924 "digest_algorithm": "SHA256", 925 "digest_type": "2", 926 "ds": "example.com. 3600 IN DS 2371 13 2 41600621c65065b09230ebc9556ced937eb7fd86e31635d0025326ccf09a7194", 927 "flags": 257, 928 "key_tag": 2371, 929 "key_type": "ECDSAP256SHA256", 930 "modified_on": "2016-05-01T22:42:15.591158Z", 931 "public_key": "mdsswUyr3DPW132mOi8V9xESWE8jTo0dxCjjnopKl+GqJxpVXckHAeF+KkxLbxILfDLUT0rAK9iUzy1L53eKGQ==", 932 "status": "pending" 933 } 934 $ 935 936Zone file upload and download CLI examples (uses BIND format files) 937~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 938 939Refer to `Import DNS 940records <https://api.cloudflare.com/#dns-records-for-a-zone-import-dns-records>`__ 941on API documentation for this feature. 942 943.. code:: bash 944 945 $ cat zone.txt 946 example.com. IN SOA somewhere.example.com. someone.example.com. ( 947 2017010101 948 3H 949 15 950 1w 951 3h 952 ) 953 954 record1.example.com. IN A 10.0.0.1 955 record2.example.com. IN AAAA 2001:d8b::2 956 record3.example.com. IN CNAME record1.example.com. 957 record4.example.com. IN TXT "some text" 958 $ 959 960 $ cli4 --post file=@zone.txt /zones/:example.com/dns_records/import 961 { 962 "recs_added": 4, 963 "total_records_parsed": 4 964 } 965 $ 966 967The following is documented within the **Advanced** option of the DNS 968page within the Cloudflare portal. 969 970:: 971 972 $ cli4 /zones/:example.com/dns_records/export | egrep -v '^;;|^$' 973 $ORIGIN . 974 @ 3600 IN SOA example.com. root.example.com. ( 975 2025552311 ; serial 976 7200 ; refresh 977 3600 ; retry 978 86400 ; expire 979 3600) ; minimum 980 example.com. 300 IN NS REPLACE&ME$WITH^YOUR@NAMESERVER. 981 record4.example.com. 300 IN TXT "some text" 982 record3.example.com. 300 IN CNAME record1.example.com. 983 record1.example.com. 300 IN A 10.0.0.1 984 record2.example.com. 300 IN AAAA 2001:d8b::2 985 $ 986 987The egrep is used for documentation brevity. 988 989This can also be done via Python code with the following example. 990 991:: 992 993 #!/usr/bin/env python 994 import sys 995 import CloudFlare 996 997 def main(): 998 zone_name = sys.argv[1] 999 cf = CloudFlare.CloudFlare() 1000 1001 zones = cf.zones.get(params={'name': zone_name}) 1002 zone_id = zones[0]['id'] 1003 1004 dns_records = cf.zones.dns_records.export.get(zone_id) 1005 for l in dns_records.splitlines(): 1006 if len(l) == 0 or l[0] == ';': 1007 continue 1008 print l 1009 exit(0) 1010 1011 if __name__ == '__main__': 1012 main() 1013 1014Cloudflare Workers 1015~~~~~~~~~~~~~~~~~~ 1016 1017Cloudflare Workers are described on the Cloudflare blog at 1018`here <https://blog.cloudflare.com/introducing-cloudflare-workers/>`__ 1019and 1020`here <https://blog.cloudflare.com/code-everywhere-cloudflare-workers/>`__, 1021with the beta release announced 1022`here <https://blog.cloudflare.com/cloudflare-workers-is-now-on-open-beta/>`__. 1023 1024The Python libraries now support the Cloudflare Workers API calls. The 1025following javascript is lifted from https://cloudflareworkers.com/ and 1026slightly modified. 1027 1028:: 1029 1030 $ cat modify-body.js 1031 addEventListener("fetch", event => { 1032 event.respondWith(fetchAndModify(event.request)); 1033 }); 1034 1035 async function fetchAndModify(request) { 1036 console.log("got a request:", request); 1037 1038 // Send the request on to the origin server. 1039 const response = await fetch(request); 1040 1041 // Read response body. 1042 const text = await response.text(); 1043 1044 // Modify it. 1045 const modified = text.replace( 1046 "<body>", 1047 "<body style=\"background: #ff0;\">"); 1048 1049 // Return modified response. 1050 return new Response(modified, { 1051 status: response.status, 1052 statusText: response.statusText, 1053 headers: response.headers 1054 }); 1055 } 1056 $ 1057 1058Here's the website with it's simple ``<body>`` statement 1059 1060:: 1061 1062 $ curl -sS https://example.com/ | fgrep '<body' 1063 <body> 1064 $ 1065 1066Now lets add the script. Looking above, you will see that it's simple 1067action is to modify the ``<body>`` statement and make the background 1068yellow. 1069 1070:: 1071 1072 $ cli4 --put @- /zones/:example.com/workers/script < modify-body.js 1073 { 1074 "etag": "1234567890123456789012345678901234567890123456789012345678901234", 1075 "id": "example-com", 1076 "modified_on": "2018-02-15T00:00:00.000000Z", 1077 "script": "addEventListener(\"fetch\", event => {\n event.respondWith(fetchAndModify(event.request));\n});\n\nasync function fetchAndModify(request) {\n console.log(\"got a request:\", request);\n\n // Send the request on to the origin server.\n const response = await fetch(request);\n\n // Read response body.\n const text = await response.text();\n\n // Modify it.\n const modified = text.replace(\n \"<body>\",\n \"<body style=\\\"background: #ff0;\\\">\");\n\n // Return modified response.\n return new Response(modified, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers\n });\n}\n", 1078 "size": 603 1079 } 1080 $ 1081 1082The following call checks that the script is associated with the zone. 1083In this case, it's the only script added by this user. 1084 1085:: 1086 1087 $ cli4 /user/workers/scripts 1088 [ 1089 { 1090 "created_on": "2018-02-15T00:00:00.000000Z", 1091 "etag": "1234567890123456789012345678901234567890123456789012345678901234", 1092 "id": "example-com", 1093 "modified_on": "2018-02-15T00:00:00.000000Z" 1094 } 1095 ] 1096 $ 1097 1098Next step is to make sure a route is added for that script on that zone. 1099 1100:: 1101 1102 $ cli4 --post pattern="example.com/*" script="example-com" /zones/:example.com/workers/routes 1103 { 1104 "id": "12345678901234567890123456789012" 1105 } 1106 $ 1107 1108 $ cli4 /zones/:example.com/workers/routes 1109 [ 1110 { 1111 "id": "12345678901234567890123456789012", 1112 "pattern": "example.com/*", 1113 "script": "example-com" 1114 } 1115 ] 1116 $ 1117 1118With that script added to the zone and the route added, we can now see 1119the website has been modified because of the Cloudflare Worker. 1120 1121:: 1122 1123 $ curl -sS https://example.com/ | fgrep '<body' 1124 <body style="background: #ff0;"> 1125 $ 1126 1127All this can be removed; hence bringing the website back to its initial 1128state. 1129 1130:: 1131 1132 $ cli4 --delete /zones/:example.com/workers/script 1133 12345678901234567890123456789012 1134 $ cli4 --delete /zones/:example.com/workers/routes/:12345678901234567890123456789012 1135 true 1136 $ 1137 1138 $ curl -sS https://example.com/ | fgrep '<body' 1139 <body> 1140 $ 1141 1142Refer to the Cloudflare Workers API documentation for more information. 1143 1144Cloudflare GraphQL 1145------------------ 1146 1147The GraphQL interface can be accessed via the command line or via 1148Python. 1149 1150:: 1151 1152 query=""" 1153 query { 1154 viewer { 1155 zones(filter: {zoneTag: "%s"} ) { 1156 httpRequests1dGroups(limit:40, filter:{date_lt: "%s", date_gt: "%s"}) { 1157 sum { countryMap { bytes, requests, clientCountryName } } 1158 dimensions { date } 1159 } 1160 } 1161 } 1162 } 1163 """ % (zone_id, date_before[0:10], date_after[0:10]) 1164 1165 r = cf.graphql.post(data={'query':query}) 1166 1167 httpRequests1dGroups = zone_info = r['data']['viewer']['zones'][0]['httpRequests1dGroups'] 1168 1169See the `examples/example\_graphql.sh <examples/example_graphql.sh>`__ 1170and `examples/example\_graphql.py <examples/example_graphql.py>`__ files 1171for working examples. Here is the working example of the shell version: 1172 1173:: 1174 1175 $ examples/example_graphql.sh example.com 1176 2020-07-14T02:00:00Z 34880 1177 2020-07-14T03:00:00Z 18953 1178 2020-07-14T04:00:00Z 28700 1179 2020-07-14T05:00:00Z 2358 1180 2020-07-14T06:00:00Z 34905 1181 2020-07-14T07:00:00Z 779 1182 2020-07-14T08:00:00Z 35450 1183 2020-07-14T10:00:00Z 17803 1184 2020-07-14T11:00:00Z 32678 1185 2020-07-14T12:00:00Z 19947 1186 2020-07-14T13:00:00Z 4956 1187 2020-07-14T14:00:00Z 34585 1188 2020-07-14T15:00:00Z 3022 1189 2020-07-14T16:00:00Z 5224 1190 2020-07-14T18:00:00Z 79482 1191 2020-07-14T21:00:00Z 10609 1192 2020-07-14T22:00:00Z 5740 1193 2020-07-14T23:00:00Z 2545 1194 2020-07-15T01:00:00Z 10777 1195 $ 1196 1197For more information on how to use GraphQL at Cloudflare, refer to the 1198`Cloudflare GraphQL Analytics 1199API <https://developers.cloudflare.com/analytics/graphql-api>`__. It 1200contains a full overview of Cloudflare's GraphQL features and keywords. 1201 1202Implemented API calls 1203--------------------- 1204 1205The **--dump** argument to cli4 will produce a list of all the call 1206implemented within the library. 1207 1208.. code:: bash 1209 1210 $ cli4 --dump 1211 /certificates 1212 /ips 1213 /organizations 1214 ... 1215 /zones/ssl/analyze 1216 /zones/ssl/certificate_packs 1217 /zones/ssl/verification 1218 $ 1219 1220Table of commands 1221~~~~~~~~~~~~~~~~~ 1222 1223+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1224| ``GET`` | ``PUT`` | ``POST`` | ``PATCH`` | ``DELETE`` | API call | 1225+===========+===========+============+=============+==============+===============================================================+ 1226| ``GET`` | | ``POST`` | | ``DELETE`` | /certificates | 1227+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1228| ``GET`` | | | | | /ips | 1229+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1230| ``GET`` | | | ``PATCH`` | | /organizations | 1231+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1232| ``GET`` | | ``POST`` | ``PATCH`` | ``DELETE`` | /organizations/:identifier/firewall/access\_rules/rules | 1233+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1234| | | | ``PATCH`` | | /organizations/:identifier/invite | 1235+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1236| ``GET`` | | ``POST`` | | ``DELETE`` | /organizations/:identifier/invites | 1237+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1238| ``GET`` | | | ``PATCH`` | ``DELETE`` | /organizations/:identifier/members | 1239+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1240| ``GET`` | | ``POST`` | ``PATCH`` | ``DELETE`` | /organizations/:identifier/railguns | 1241+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1242| ``GET`` | | | | | /organizations/:identifier/railguns/:identifier/zones | 1243+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1244| ``GET`` | | | | | /organizations/:identifier/roles | 1245+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1246| ``GET`` | | ``POST`` | ``PATCH`` | ``DELETE`` | /organizations/:identifier/virtual\_dns | 1247+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1248| ``GET`` | | ``POST`` | ``PATCH`` | ``DELETE`` | /railguns | 1249+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1250| ``GET`` | | | | | /railguns/:identifier/zones | 1251+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1252| ``GET`` | | | ``PATCH`` | | /user | 1253+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1254| ``GET`` | | | | | /user/billing/history | 1255+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1256| ``GET`` | | | | | /user/billing/profile | 1257+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1258| ``GET`` | | | | | /user/billing/subscriptions/apps | 1259+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1260| ``GET`` | | | | | /user/billing/subscriptions/zones | 1261+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1262| ``GET`` | | ``POST`` | ``PATCH`` | ``DELETE`` | /user/firewall/access\_rules/rules | 1263+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1264| ``GET`` | | | ``PATCH`` | | /user/invites | 1265+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1266| ``GET`` | | | | ``DELETE`` | /user/organizations | 1267+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1268| ``GET`` | | ``POST`` | ``PATCH`` | ``DELETE`` | /user/virtual\_dns | 1269+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1270| ``GET`` | | ``POST`` | ``PATCH`` | ``DELETE`` | /zones | 1271+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1272| | ``PUT`` | | | | /zones/:identifier/activation\_check | 1273+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1274| ``GET`` | | | | | /zones/:identifier/analytics/colos | 1275+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1276| ``GET`` | | | | | /zones/:identifier/analytics/dashboard | 1277+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1278| ``GET`` | | | | | /zones/:identifier/available\_plans | 1279+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1280| | ``PUT`` | | | | /zones/:identifier/custom\_certificates/prioritize | 1281+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1282| ``GET`` | | ``POST`` | ``PATCH`` | ``DELETE`` | /zones/:identifier/custom\_certificates | 1283+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1284| ``GET`` | ``PUT`` | | | | /zones/:identifier/custom\_pages | 1285+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1286| ``GET`` | ``PUT`` | ``POST`` | | ``DELETE`` | /zones/:identifier/dns\_records | 1287+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1288| ``GET`` | | | ``PATCH`` | | /zones/:identifier/firewall/waf/packages/:identifier/groups | 1289+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1290| ``GET`` | | | ``PATCH`` | | /zones/:identifier/firewall/waf/packages/:identifier/rules | 1291+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1292| ``GET`` | | | ``PATCH`` | | /zones/:identifier/firewall/waf/packages | 1293+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1294| ``GET`` | | ``POST`` | ``PATCH`` | ``DELETE`` | /zones/:identifier/firewall/access\_rules/rules | 1295+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1296| ``GET`` | | ``POST`` | ``PATCH`` | ``DELETE`` | /zones/:identifier/keyless\_certificates | 1297+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1298| ``GET`` | ``PUT`` | ``POST`` | ``PATCH`` | ``DELETE`` | /zones/:identifier/pagerules | 1299+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1300| | | | | ``DELETE`` | /zones/:identifier/purge\_cache | 1301+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1302| ``GET`` | | | | | /zones/:identifier/railguns/:identifier/diagnose | 1303+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1304| ``GET`` | | | ``PATCH`` | | /zones/:identifier/railguns | 1305+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1306| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings | 1307+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1308| ``GET`` | | | | | /zones/:identifier/settings/advanced\_ddos | 1309+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1310| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/always\_online | 1311+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1312| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/browser\_cache\_ttl | 1313+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1314| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/browser\_check | 1315+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1316| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/cache\_level | 1317+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1318| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/challenge\_ttl | 1319+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1320| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/development\_mode | 1321+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1322| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/email\_obfuscation | 1323+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1324| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/hotlink\_protection | 1325+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1326| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/ip\_geolocation | 1327+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1328| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/ipv6 | 1329+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1330| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/minify | 1331+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1332| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/mirage | 1333+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1334| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/mobile\_redirect | 1335+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1336| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/origin\_error\_page\_pass\_thru | 1337+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1338| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/polish | 1339+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1340| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/prefetch\_preload | 1341+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1342| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/response\_buffering | 1343+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1344| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/rocket\_loader | 1345+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1346| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/security\_header | 1347+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1348| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/security\_level | 1349+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1350| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/server\_side\_exclude | 1351+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1352| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/sort\_query\_string\_for\_cache | 1353+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1354| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/ssl | 1355+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1356| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/tls\_1\_2\_only | 1357+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1358| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/tls\_client\_auth | 1359+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1360| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/true\_client\_ip\_header | 1361+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1362| ``GET`` | | | ``PATCH`` | | /zones/:identifier/settings/waf | 1363+-----------+-----------+------------+-------------+--------------+---------------------------------------------------------------+ 1364 1365Adding extra API calls manually 1366------------------------------- 1367 1368Extra API calls can be added via the configuration file 1369 1370.. code:: bash 1371 1372 $ cat ~/.cloudflare/cloudflare.cfg 1373 [CloudFlare] 1374 extras = 1375 /client/v4/command 1376 /client/v4/command/:command_identifier 1377 /client/v4/command/:command_identifier/settings 1378 $ 1379 1380While it's easy to call anything within Cloudflare's API, it's not very 1381useful to add items in here as they will simply return API URL errors. 1382Technically, this is only useful for internal testing within Cloudflare. 1383 1384Issues 1385------ 1386 1387The following error can be caused by an out of date SSL/TLS library 1388and/or out of date Python. 1389 1390:: 1391 1392 /usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util/ssl_.py:318: SNIMissingWarning: An HTTPS request has been made, but the SNI (Subject Name Indication) extension to TLS is not available on this platform. This may cause the server to present an incorrect TLS certificate, which can cause validation failures. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#snimissingwarning. 1393 SNIMissingWarning 1394 /usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util/ssl_.py:122: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning. 1395 InsecurePlatformWarning 1396 1397The solution can be found 1398`here <https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning>`__ 1399and/or 1400`here <http://stackoverflow.com/questions/35144550/how-to-install-cryptography-on-ubuntu>`__. 1401 1402Python 2.x vs 3.x support 1403------------------------- 1404 1405As of May/June 2016 the code is now tested against pylint. This was 1406required in order to move the codebase into Python 3.x. The motivation 1407for this came from `Danielle Madeley 1408(danni) <https://github.com/danni>`__. 1409 1410[STRIKEOUT:While the codebase has been edited to run on Python 3.x, 1411there's not been enough Python 3.x testing performed.] [STRIKEOUT:If you 1412can help in this regard; please contact the maintainers.] 1413 1414As of January 2020 the code is Python3 clean. 1415 1416As of January 2020 the code is shipped up to pypi with Python2 support 1417removed. 1418 1419As of January 2020 the code is Python3.8 clean. The new 1420``SyntaxWarning`` messages (i.e. 1421``SyntaxWarning: "is" with a literal. Did you mean "=="?``) meant minor 1422edits were needed. 1423 1424Credit 1425------ 1426 1427This is based on work by `Felix Wong 1428(gnowxilef) <https://github.com/gnowxilef>`__ found 1429`here <https://github.com/cloudflare-api/python-cloudflare-v4>`__. It 1430has been seriously expanded upon. 1431 1432Changelog 1433--------- 1434 1435An automatically generated CHANGELOG is provided 1436`here <CHANGELOG.md>`__. 1437 1438Copyright 1439--------- 1440 1441Portions copyright `Felix Wong 1442(gnowxilef) <https://github.com/gnowxilef>`__ 2015 and Cloudflare 2016. 1443