mirror of
https://codeberg.org/privacy1st/netcup-dns
synced 2024-12-22 23:36:04 +01:00
feat: license, cronjob, requirements and packaging
This commit is contained in:
parent
bc17a5d458
commit
6c04860119
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,5 @@
|
|||||||
/.idea/
|
/.idea/
|
||||||
/cfg/
|
/cfg/
|
||||||
/venv/
|
/venv/
|
||||||
|
/build/
|
||||||
|
**/*.egg-info/
|
||||||
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Daniel Langbein <daniel@systemli.org>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
11
cron.d/netcup-dns
Normal file
11
cron.d/netcup-dns
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Run command every 3min
|
||||||
|
# - https://crontab.guru/every-3-minutes
|
||||||
|
# `/etc/cron.d/` requires user field
|
||||||
|
# - https://unix.stackexchange.com/questions/458713/how-are-files-under-etc-cron-d-used#comment1019389_458715
|
||||||
|
# Some users report that files in `/etc/cron.d/` containing `-` are not executed
|
||||||
|
# - https://unix.stackexchange.com/questions/296347/crontab-never-running-while-in-etc-cron-d#comment640748_296351
|
||||||
|
# PATH is restricted to `/bin:/usr/bin` but `de-p1st-execNotify` resides in `/usr/local/bin/`
|
||||||
|
# - https://serverfault.com/a/449652
|
||||||
|
|
||||||
|
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin/
|
||||||
|
*/3 * * * * root de-p1st-execNotify netcup-dns > /var/log/netcup-dns.cron 2>&1
|
8
pyproject.toml
Normal file
8
pyproject.toml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# https://packaging.python.org/tutorials/packaging-projects/#creating-pyproject-toml
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = [
|
||||||
|
"setuptools>=42",
|
||||||
|
"wheel"
|
||||||
|
]
|
||||||
|
build-backend = "setuptools.build_meta"
|
@ -1 +1,2 @@
|
|||||||
nc-dnsapi
|
nc-dnsapi
|
||||||
|
requests
|
||||||
|
35
setup.cfg
Normal file
35
setup.cfg
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
; setup.cfg is the configuration file for setuptools.
|
||||||
|
; https://packaging.python.org/tutorials/packaging-projects/#configuring-metadata
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
name = netcup_dns
|
||||||
|
version = 0.1.0
|
||||||
|
author = Daniel Langbein
|
||||||
|
author_email = daniel@systemli.org
|
||||||
|
description = Update DNS records with your current external IP address using the netcup DNS API.
|
||||||
|
long_description = file: README.md
|
||||||
|
long_description_content_type = text/markdown
|
||||||
|
url = https://codeberg.org/privacy1st/netcup-dns
|
||||||
|
project_urls =
|
||||||
|
Bug Tracker = https://codeberg.org/privacy1st/netcup-dns/issues
|
||||||
|
|
||||||
|
; https://pypi.org/classifiers/
|
||||||
|
classifiers =
|
||||||
|
Development Status :: 4 - Beta
|
||||||
|
Programming Language :: Python :: 3
|
||||||
|
License :: OSI Approved :: MIT License
|
||||||
|
Operating System :: Unix
|
||||||
|
|
||||||
|
[options]
|
||||||
|
package_dir =
|
||||||
|
= src
|
||||||
|
packages = find:
|
||||||
|
python_requires = >=3.6.9
|
||||||
|
|
||||||
|
[options.packages.find]
|
||||||
|
where = src
|
||||||
|
|
||||||
|
[options.entry_points]
|
||||||
|
; https://setuptools.readthedocs.io/en/latest/userguide/entry_point.html
|
||||||
|
console_scripts=
|
||||||
|
netcup-dns = netcup_dns.main:main
|
0
src/netcup_dns/__init__.py
Normal file
0
src/netcup_dns/__init__.py
Normal file
@ -1,5 +1,8 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
import configparser
|
import configparser
|
||||||
import ipaddress
|
import ipaddress
|
||||||
|
from functools import lru_cache
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
@ -8,14 +11,16 @@ from nc_dnsapi import Client, DNSRecord
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""
|
"""
|
||||||
https://github.com/nbuchwitz/nc_dnsapi
|
The main effort is done by https://github.com/nbuchwitz/nc_dnsapi
|
||||||
"""
|
"""
|
||||||
destination = external_ipv4()
|
cfg_dir = Path('cfg')
|
||||||
|
if not cfg_dir.exists():
|
||||||
|
raise Exception(f'The config directory is missing: {cfg_dir}')
|
||||||
|
|
||||||
files = [file for file in Path('cfg').iterdir() if file.name.endswith('.cfg') and file.is_file()]
|
cfg_files = [file for file in cfg_dir.iterdir() if file.name.endswith('.ini') and file.is_file()]
|
||||||
for file in files:
|
for cfg_file in cfg_files:
|
||||||
cfg = configparser.ConfigParser()
|
cfg = configparser.ConfigParser()
|
||||||
cfg.read(file)
|
cfg.read(cfg_file)
|
||||||
customer = cfg['credentials']['customer']
|
customer = cfg['credentials']['customer']
|
||||||
api_key = cfg['credentials']['api_key']
|
api_key = cfg['credentials']['api_key']
|
||||||
api_password = cfg['credentials']['api_password']
|
api_password = cfg['credentials']['api_password']
|
||||||
@ -25,8 +30,13 @@ def main():
|
|||||||
with Client(customer, api_key, api_password) as api:
|
with Client(customer, api_key, api_password) as api:
|
||||||
for domain in domains:
|
for domain in domains:
|
||||||
hostname = cfg[domain]['hostname']
|
hostname = cfg[domain]['hostname']
|
||||||
type_ = cfg[domain]['type']
|
type_ = cfg[domain]['type'].upper()
|
||||||
update_record_destination(api, domain, hostname, type_, destination)
|
if type_ == 'A':
|
||||||
|
destination = external_ipv4()
|
||||||
|
update_record_destination(api, domain, hostname, type_, destination=destination)
|
||||||
|
print(f'Set {hostname}.{domain} {type_} record to {destination}')
|
||||||
|
else:
|
||||||
|
raise Exception(f'DNS record type {type_} is not supported.')
|
||||||
|
|
||||||
|
|
||||||
def update_record_destination(api: Client, domain: str, hostname: str, type_: str, destination: str) -> None:
|
def update_record_destination(api: Client, domain: str, hostname: str, type_: str, destination: str) -> None:
|
||||||
@ -45,8 +55,10 @@ def get_record(api: Client, domain: str, hostname: str, type_: str) -> DNSRecord
|
|||||||
return matches[0]
|
return matches[0]
|
||||||
|
|
||||||
|
|
||||||
def external_ipv4() -> str:
|
@lru_cache(maxsize=None)
|
||||||
|
def external_ipv4(timeout=5) -> str:
|
||||||
"""
|
"""
|
||||||
|
:argument timeout: Timeout for each IP detection webservice in seconds.
|
||||||
:return: Public IPv4 address
|
:return: Public IPv4 address
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -67,7 +79,7 @@ def external_ipv4() -> str:
|
|||||||
requests.packages.urllib3.util.connection.HAS_IPV6 = False
|
requests.packages.urllib3.util.connection.HAS_IPV6 = False
|
||||||
|
|
||||||
# Timeout after 5 seconds.
|
# Timeout after 5 seconds.
|
||||||
ip = requests.get(endpoint, timeout=5).text.strip()
|
ip = requests.get(endpoint, timeout=timeout).text.strip()
|
||||||
# Check if it is actually an IPv4 address.
|
# Check if it is actually an IPv4 address.
|
||||||
# Some services, such as e.g. v4.ident.me, sometimes return IPv6.
|
# Some services, such as e.g. v4.ident.me, sometimes return IPv6.
|
||||||
ipv4 = ipaddress.ip_address(ip)
|
ipv4 = ipaddress.ip_address(ip)
|
Loading…
Reference in New Issue
Block a user