From 4739615ca4e580206f8468d7ea4e653e81486f67 Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Sun, 2 Nov 2025 02:12:33 -0500 Subject: [PATCH] [IMP] script deployment DNS with cloudflare --- requirement/erplibre_require-ments.txt | 1 + script/deployment/README.md | 5 + script/deployment/cloudflare_dns.py | 127 +++++++++++++++++++++ script/deployment/update_dns_cloudflare.py | 4 +- 4 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 script/deployment/README.md create mode 100755 script/deployment/cloudflare_dns.py diff --git a/requirement/erplibre_require-ments.txt b/requirement/erplibre_require-ments.txt index d33a715..13de743 100644 --- a/requirement/erplibre_require-ments.txt +++ b/requirement/erplibre_require-ments.txt @@ -27,6 +27,7 @@ urwid python-dateutil unidecode sshconf +cloudflare # Force upgrade package to fix Ubuntu 25.04 virtualenv==20.30.0 diff --git a/script/deployment/README.md b/script/deployment/README.md new file mode 100644 index 0000000..2e44ad4 --- /dev/null +++ b/script/deployment/README.md @@ -0,0 +1,5 @@ +# Information about deployment with cloudflare + +The script update_dns_cloudflare.py is used to update all DNS for case of DDNS, when ip address change, with a cron. This version support an old version of cloudflare==2.20.0 + +The script cloudflare_dns.py is used to update specific address at a deployment. diff --git a/script/deployment/cloudflare_dns.py b/script/deployment/cloudflare_dns.py new file mode 100755 index 0000000..45a5744 --- /dev/null +++ b/script/deployment/cloudflare_dns.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +# © 2021-2024 TechnoLibre (http://www.technolibre.ca) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +import argparse +import logging +import os +from datetime import datetime + +import requests +import tldextract +from cloudflare import Cloudflare + +logging.basicConfig() +logging.getLogger().setLevel(logging.INFO) +_logger = logging.getLogger(__name__) + + +def get_config(): + """Parse command line arguments, extracting the config file name, + returning the union of config file and command line arguments + + :return: dict of config file settings and command line arguments + """ + + # TODO update description + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description="""\ + You need to setup your environment key CLOUDFLARE_API_TOKEN +""", + epilog="""\ +""", + ) + parser.add_argument( + "--ip", required=False, help="Ip to replace the old ip." + ) + parser.add_argument( + "--domain", + required=False, + help="DNS name to output his ip and sync.", + ) + parser.add_argument( + "--zone_name", + required=False, + help="The CloudFlare zone name to check.", + ) + args = parser.parse_args() + return args + + +class ManageCloudFlare: + @staticmethod + def get_public_ip(): + r = requests.get(r"https://api.ipify.org") + ip = r.text + return ip + + def set_ip_to_domain(self, parser): + api_token = os.environ.get("CLOUDFLARE_API_TOKEN") + if not api_token: + raise Exception( + "Missing environment variable CLOUDFLARE_API_TOKEN" + ) + public_ip = parser.ip + website_domain = parser.domain + cf = Cloudflare(api_token=api_token) + url_extract = tldextract.extract(website_domain) + url_domain_only = url_extract.top_domain_under_public_suffix + domain_to_create = url_extract.fqdn + zones = [a for a in cf.zones.list() if a.name == url_domain_only] + if not zones: + raise Exception( + "Cannot found domain %s on your cloudflare account." + % url_domain_only + ) + zone = zones[0] + # id_zone = zone.account.id + id_zone = zone.id + + # Comment is limited to 100 char + records_dns = cf.dns.records.list( + zone_id=id_zone, name=domain_to_create + ) + lst_dns = [a for a in records_dns] + if lst_dns: + for dns in lst_dns: + # update comment + comment = dns.comment + new_comment = "Updated from ERPLibre at %s" % (datetime.now(),) + # if comment: + # comment += "\n" + new_comment + # else: + # comment = new_comment + comment = new_comment + try: + record_response = cf.dns.records.edit( + zone_id=id_zone, + content=public_ip, + dns_record_id=dns.id, + name=domain_to_create, + type="A", + comment=comment, + ) + except Exception as e: + _logger.error(e) + else: + try: + record_response = cf.dns.records.create( + zone_id=id_zone, + name=domain_to_create, + type="A", + content=public_ip, + comment="Generated with ERPLibre", + ) + except Exception as e: + _logger.error(e) + + +def main(): + config = get_config() + cl = ManageCloudFlare() + cl.set_ip_to_domain(config) + + +if __name__ == "__main__": + main() diff --git a/script/deployment/update_dns_cloudflare.py b/script/deployment/update_dns_cloudflare.py index 1263b90..98d1d27 100755 --- a/script/deployment/update_dns_cloudflare.py +++ b/script/deployment/update_dns_cloudflare.py @@ -5,8 +5,8 @@ import argparse import logging -import CloudFlare import requests +from cloudflare import Cloudflare logging.basicConfig() logging.getLogger().setLevel(logging.INFO) @@ -82,7 +82,7 @@ def get_config(): class ManageCloudFlare: def __init__(self, profile, debug=False, raw=False): - self.cf = CloudFlare.CloudFlare(profile=profile, debug=debug, raw=raw) + self.cf = Cloudflare(profile=profile, debug=debug, raw=raw) self.raw = raw @staticmethod