From 3b4784dcb20dfd5ce773c957ce0c92c5f309dbc6 Mon Sep 17 00:00:00 2001 From: sonny Date: Sun, 27 Dec 2020 13:40:35 +0100 Subject: [PATCH] Mockup code --- ip_listener/cli.py | 7 +++- ip_listener/main.py | 97 +++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 2 +- 3 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 ip_listener/main.py diff --git a/ip_listener/cli.py b/ip_listener/cli.py index 6e79d73..08bddd9 100644 --- a/ip_listener/cli.py +++ b/ip_listener/cli.py @@ -1,6 +1,9 @@ import click +from ip_listener.main import detect + @click.command() -def test(): - click.echo("Hello world") +@click.argument() +def run(): + detect() diff --git a/ip_listener/main.py b/ip_listener/main.py new file mode 100644 index 0000000..10f3774 --- /dev/null +++ b/ip_listener/main.py @@ -0,0 +1,97 @@ +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) diff --git a/pyproject.toml b/pyproject.toml index cb2226e..dbf1407 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ isort = "^5.6.4" autoflake = "^1.4" [tool.poetry.scripts] -ip_listen = "ip_listener.cli:test" +ip_listen = "ip_listener.cli:run" [build-system] requires = ["poetry>=0.12"]