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/
|
||||
/cfg/
|
||||
/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
|
||||
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 ipaddress
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
@ -8,14 +11,16 @@ from nc_dnsapi import Client, DNSRecord
|
||||
|
||||
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()]
|
||||
for file in files:
|
||||
cfg_files = [file for file in cfg_dir.iterdir() if file.name.endswith('.ini') and file.is_file()]
|
||||
for cfg_file in cfg_files:
|
||||
cfg = configparser.ConfigParser()
|
||||
cfg.read(file)
|
||||
cfg.read(cfg_file)
|
||||
customer = cfg['credentials']['customer']
|
||||
api_key = cfg['credentials']['api_key']
|
||||
api_password = cfg['credentials']['api_password']
|
||||
@ -25,8 +30,13 @@ def main():
|
||||
with Client(customer, api_key, api_password) as api:
|
||||
for domain in domains:
|
||||
hostname = cfg[domain]['hostname']
|
||||
type_ = cfg[domain]['type']
|
||||
update_record_destination(api, domain, hostname, type_, destination)
|
||||
type_ = cfg[domain]['type'].upper()
|
||||
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:
|
||||
@ -45,8 +55,10 @@ def get_record(api: Client, domain: str, hostname: str, type_: str) -> DNSRecord
|
||||
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
|
||||
"""
|
||||
|
||||
@ -67,7 +79,7 @@ def external_ipv4() -> str:
|
||||
requests.packages.urllib3.util.connection.HAS_IPV6 = False
|
||||
|
||||
# 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.
|
||||
# Some services, such as e.g. v4.ident.me, sometimes return IPv6.
|
||||
ipv4 = ipaddress.ip_address(ip)
|
Loading…
Reference in New Issue
Block a user