dns/lexicon: Tidying up the push function

This commit is contained in:
Alexandre Aubin 2021-08-31 18:33:15 +02:00
parent 4089c34685
commit 1c2fff750d

View file

@ -26,9 +26,6 @@
import os import os
import re import re
from lexicon.client import Client
from lexicon.config import ConfigResolver
from moulinette import m18n, Moulinette from moulinette import m18n, Moulinette
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import mkdir, read_yaml, write_to_yaml from moulinette.utils.filesystem import mkdir, read_yaml, write_to_yaml
@ -469,96 +466,81 @@ def domain_registrar_push(operation_logger, domain):
""" """
Send DNS records to the previously-configured registrar of the domain. Send DNS records to the previously-configured registrar of the domain.
""" """
# Generate the records
from lexicon.client import Client as LexiconClient
from lexicon.config import ConfigResolver as LexiconConfigResolver
if domain not in domain_list()["domains"]: if domain not in domain_list()["domains"]:
raise YunohostValidationError("domain_name_unknown", domain=domain) raise YunohostValidationError("domain_name_unknown", domain=domain)
dns_conf = _build_dns_conf(domain)
dns_zone = _get_domain_settings(domain)["dns_zone"] dns_zone = _get_domain_settings(domain)["dns_zone"]
registrar_setting = _get_registrar_settings(dns_zone) registrar_settings = _get_registrar_settingss(dns_zone)
if not registrar_setting: if not registrar_settings:
# FIXME add locales
raise YunohostValidationError("registrar_is_not_set", domain=domain) raise YunohostValidationError("registrar_is_not_set", domain=domain)
# Generate the records
dns_conf = _build_dns_conf(domain)
# Flatten the DNS conf # Flatten the DNS conf
flatten_dns_conf = [] dns_conf = [record for record in records_for_category for records_for_category in dns_conf.values()]
for key in dns_conf:
list_of_records = dns_conf[key] # FIXME Lexicon does not support CAA records
for record in list_of_records: # See https://github.com/AnalogJ/lexicon/issues/282 and https://github.com/AnalogJ/lexicon/pull/371
# FIXME Lexicon does not support CAA records # They say it's trivial to implement it!
# See https://github.com/AnalogJ/lexicon/issues/282 and https://github.com/AnalogJ/lexicon/pull/371 # And yet, it is still not done/merged
# They say it's trivial to implement it! dns_conf = [record for record in dns_conf if record["type"] != "CAA"]
# And yet, it is still not done/merged
if record["type"] != "CAA": # We need absolute names? FIXME: should we add a trailing dot needed here ?
# Add .domain.tdl to the name entry for record in dns_conf:
record["name"] = "{}.{}".format(record["name"], domain) record["name"] = f"{record['name']}.{domain}"
flatten_dns_conf.append(record)
# Construct the base data structure to use lexicon's API. # Construct the base data structure to use lexicon's API.
base_config = { base_config = {
"provider_name": registrar_setting["name"], "provider_name": registrar_settings["name"],
"domain": domain, # domain name "domain": domain,
registrar_settings["name"]: registrar_settings["options"]
} }
base_config[registrar_setting["name"]] = registrar_setting["options"]
# Get types present in the generated records
types = set()
for record in flatten_dns_conf:
types.add(record["type"])
operation_logger.start() operation_logger.start()
# Fetch all types present in the generated records # Fetch all types present in the generated records
distant_records = {} current_remote_records = {}
# Get unique types present in the generated records
types = {record["type"] for record in dns_conf}
for key in types: for key in types:
record_config = { fetch_records_for_type = {
"action": "list", "action": "list",
"type": key, "type": key,
} }
final_lexicon = ( query = (
ConfigResolver() LexiconConfigResolver()
.with_dict(dict_object=base_config) .with_dict(dict_object=base_config)
.with_dict(dict_object=record_config) .with_dict(dict_object=fetch_records_for_type)
) )
# print('final_lexicon:', final_lexicon); current_remote_records[key] = LexiconClient(query).execute()
client = Client(final_lexicon)
distant_records[key] = client.execute()
for key in types: for key in types:
for distant_record in distant_records[key]: for current_remote_record in current_remote_records[key]:
logger.debug(f"distant_record: {distant_record}") logger.debug(f"current_remote_record: {current_remote_record}")
for local_record in flatten_dns_conf: for local_record in dns_conf:
print("local_record:", local_record) print("local_record:", local_record)
# Push the records # Push the records
for record in flatten_dns_conf: for record in dns_conf:
# For each record, first check if one record exists for the same (type, name) couple
it_exists = False
# TODO do not push if local and distant records are exactly the same ?
# is_the_same_record = False
for distant_record in distant_records[record["type"]]: # For each record, first check if one record exists for the same (type, name) couple
if ( # TODO do not push if local and distant records are exactly the same ?
distant_record["type"] == record["type"] type_and_name = (record["type"], record["name"])
and distant_record["name"] == record["name"] already_exists = any((r["type"], r["name"]) == type_and_name
): for r in current_remote_records[record["type"]])
it_exists = True
# see previous TODO
# if distant_record["ttl"] = ... and distant_record["name"] ...
# is_the_same_record = True
# Finally, push the new record or update the existing one # Finally, push the new record or update the existing one
record_config = { record_to_push = {
"action": "update" "action": "update" if already_exists else "create"
if it_exists "type": record["type"]
else "create", # create, list, update, delete
"type": record[
"type"
], # specify a type for record filtering, case sensitive in some cases.
"name": record["name"], "name": record["name"],
"content": record["value"], "content": record["value"],
# FIXME Removed TTL, because it doesn't work with Gandi. # FIXME Removed TTL, because it doesn't work with Gandi.
@ -566,14 +548,15 @@ def domain_registrar_push(operation_logger, domain):
# But I think there is another issue with Gandi. Or I'm misusing the API... # But I think there is another issue with Gandi. Or I'm misusing the API...
# "ttl": record["ttl"], # "ttl": record["ttl"],
} }
final_lexicon = (
print("pushed_record:", record_to_push, "", end=" ")
query = (
ConfigResolver() ConfigResolver()
.with_dict(dict_object=base_config) .with_dict(dict_object=base_config)
.with_dict(dict_object=record_config) .with_dict(dict_object=record_to_push)
) )
client = Client(final_lexicon) results = LexiconClient(query).execute()
print("pushed_record:", record_config, "", end=" ")
results = client.execute()
print("results:", results) print("results:", results)
# print("Failed" if results == False else "Ok") # print("Failed" if results == False else "Ok")