import logging import subprocess from concurrent.futures import ThreadPoolExecutor, as_completed import requests logger = logging.getLogger(__name__) def _get_ip(): try: # TODO make resolvers customizable output = subprocess.check_output( ["dig", "+short", "myip.opendns.com", "@resolver1.opendns.com"], stderr=subprocess.STDOUT, ) except subprocess.CalledProcessError as e: raise OSError("Unable to retrieve current IP") from e # TODO set URL global def _get_domain(domain, token): headers = {"Authorization": f"Bearer {token}"} return requests.get(url, headers=headers) def _get_domain_data(domains, token): with ThreadPoolExecutor(max_workers=10) as executor: futures = { executor.submit(_get_domain, domain, token): domain for domain in domains } for future in as_completed(futures): response = future.result() domain = futures[future] try: response.raise_for_status() except requests.HTTPError as e: logger.exception(f"Failed retrieving information for {domain}") continue yield {"domain": domain, **response.json()} # TODO set URL global def _update_domain(domain, payload, token): headers = {"Authorization": f"Bearer {token}"} return requests.put(url, data=json.dumps(payload), headers=headers) def _update_domains(updated_domains, token): with ThreadPoolExecutor(max_workers=10) as executor: futures = { executor.submit(_update_domain, domain, entries, token): domain for domain, entries in updated_domains.items() } for future in as_completed(futures): response = future.result() domain = futures[future] try: response.raise_for_status() except request.HTTPError as e: logger.exception(f"Unable to update domain {domain}") continue logger.info(f"Updated domain {domain}") def detect(domains, token): ip = _get_ip() domain_data = _get_domain_data(domains, token) updated_domains = {} for data in domain_data: dns_entries = data["dnsEntries"] domain = data["domain"] updated_entries = [] for dns_entry in dns_entries: updated_entries.append( { **dns_entry, "content": ip, } ) if dns_entries == updated_entries: continue updated_domains[domain] = {"dnsEntries": updated_entries} _update_domains(updated_domains, token)