Skip to content

Commit

Permalink
Merge pull request #23 from mxmehl/url-type
Browse files Browse the repository at this point in the history
Handle URL record type
  • Loading branch information
mxmehl authored Mar 18, 2024
2 parents ff3c9ac + b2bdc7c commit 6d212f0
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 20 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Note: This is no official software project by INWX, it just kindly uses their pu
- [Debug and dry-run](#debug-and-dry-run)
- [I deleted all my productive records!](#i-deleted-all-my-productive-records)
- [Simulate API response](#simulate-api-response)
- [URL records](#url-records)
- [License](#license)


Expand Down Expand Up @@ -216,6 +217,11 @@ This could look like the following:
In order to get this output from an existing domain, you can run the program with the `--debug` flag and search for the line starting with `Response (nameserver.info):`.


### URL Records

INWX has [URL records](https://kb.inwx.com/en-us/3-nameserver/106-how-can-i-forward-a-domain-to-an-internet-address) that allow for redirections of a domain to another domain. These records are somewhat supported by this tool, but there are [several issues and bugs](https://github.com/mxmehl/inwx-dns-recordmaster/pull/23). It's recommended to add and edit these records in the web interface and not via this tool as the INWX API doesn't seem to be reliable, but you can still store these configurations locally.


## License

The main license of this project is the GNU General Public License 3.0, no later version (`GPL-3.0-only`), Copyright Max Mehl.
Expand Down
16 changes: 15 additions & 1 deletion recordmaster/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,21 @@

__version__ = version("inwx-dns-recordmaster")

RECORD_KEYS = ("id", "name", "type", "content", "ttl", "prio")
# All record keys
RECORD_KEYS = (
"id",
"name",
"type",
"content",
"ttl",
"prio",
"urlRedirectType",
"urlRedirectTitle",
"urlRedirectDescription",
"urlRedirectFavIcon",
"urlRedirectKeywords",
"urlAppend",
)

DEFAULT_APP_CONFIG = """# App configuration for INWX DNS Recordmaster.
# This is not the place for domain records, these can be anywhere and used with the -c flag
Expand Down
5 changes: 5 additions & 0 deletions recordmaster/_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ def inwx_api(
logging.info("API call for '%s' has not been executed in dry-run mode", method)
return {}

# Convert boolean values to 0/1 as this is what the INWX seems to expect
for key, value in params.items():
if isinstance(value, bool):
params[key] = 1 if value else 0

api_result = api.call_api(api_method=method, method_params=params)

# Handle return codes
Expand Down
20 changes: 14 additions & 6 deletions recordmaster/_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@


@dataclass
class Record:
class Record: # pylint: disable=too-many-instance-attributes
"""Dataclass holding a nameserver record, be it remote or local"""

# nameserver details
Expand All @@ -28,6 +28,13 @@ class Record:
content: str = ""
ttl: int = 3600
prio: int = 0
# pylint: disable=invalid-name
urlRedirectType: str = ""
urlRedirectTitle: str = ""
urlRedirectDescription: str = ""
urlRedirectFavIcon: str = ""
urlRedirectKeywords: str = ""
urlAppend: bool = False

def import_records(self, data: dict, domain: str = "", root: str = ""):
"""Update records by providing a dict"""
Expand Down Expand Up @@ -85,11 +92,12 @@ def to_local_conf_format(self, records: list[Record], ignore_types: list) -> dic

# Type and content are straightforward, we don't need to convert it
rec_yaml: dict[str, str | int] = {"type": rec.type, "content": rec.content}
# TTL and prio will be set unless it's the default value
if rec.ttl != Record.ttl:
rec_yaml["ttl"] = rec.ttl
if rec.prio != Record.prio:
rec_yaml["prio"] = rec.prio

# All the other attributes unless they have the default value
# This is, in RECORD_KEYS, all from the 5th element, ttl
for attr in RECORD_KEYS[4:]:
if getattr(rec, attr) != getattr(Record, attr):
rec_yaml[attr] = getattr(rec, attr)

data[name].append(rec_yaml)

Expand Down
30 changes: 17 additions & 13 deletions recordmaster/_sync_records.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ def sync_existing_local_to_remote(
api: ApiClient, domain: Domain, dry: bool, interactive: bool
) -> None:
"""Compare previously matched local records to remote ones. If differences, update remote"""
# pylint: disable=too-many-nested-blocks
# Loop over local records which have an ID, so matched to a remote entry
for loc_rec in [loc_rec for loc_rec in domain.local_records if loc_rec.id]:
# For each ID, compare content, ttl and prio
for key in ("content", "ttl", "prio"):
# For each ID, compare content, ttl, prio etc, collect changes, and make API call
changes = {}
for key in RECORD_KEYS[3:]:
# Get local and corresponding remote attribute
loc_val = getattr(loc_rec, key)
rem_val = next(
Expand All @@ -30,10 +30,10 @@ def sync_existing_local_to_remote(
if rem_rec.id == loc_rec.id
)
# Update attribute at remote if values differ
if loc_val and (loc_val != rem_val):
if loc_val != rem_val:
# Log and update record
logging.info(
"[%s] Updating '%s' record of '%s': '%s' from '%s' to '%s'",
"[%s] Update '%s' record of '%s': '%s' from '%s' to '%s'",
domain.name,
loc_rec.type,
loc_rec.name,
Expand All @@ -43,20 +43,24 @@ def sync_existing_local_to_remote(
)

# Update record via API call
inwx_api(
api,
"nameserver.updateRecord",
interactive=interactive,
dry=dry,
id=loc_rec.id,
**{key: loc_val},
)
changes[key] = loc_val
else:
# No action needed as records are equal or undefined
logging.debug(
"[%s] (%s) %s equal: %s = %s", loc_rec.name, loc_rec.id, key, rem_val, loc_val
)

# Execute collected changes for this ID, if they exist
if changes:
inwx_api(
api,
"nameserver.updateRecord",
interactive=interactive,
dry=dry,
id=loc_rec.id,
**changes,
)


def create_missing_at_remote(
api: ApiClient, domain: Domain, records: list[Record], dry: bool, interactive: bool
Expand Down

0 comments on commit 6d212f0

Please sign in to comment.