Skip to content

Commit df5e663

Browse files
author
Nicolai Buchwitz
committed
initial commit
1 parent 59e1f32 commit df5e663

File tree

4 files changed

+204
-1
lines changed

4 files changed

+204
-1
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
venv
2+
.idea

README.md

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,37 @@
11
# nc_dnsapi
2-
API wrapper for the netcup DNS API
2+
A simple API wrapper for the netcup DNS API
3+
4+
```python
5+
import nc_dnsapi
6+
7+
customer = 123456
8+
api_key = "your-personal-api-key"
9+
api_password = "your-private-api-password"
10+
11+
with nc_dnsapi.Client(customer, api_key, api_password) as api:
12+
# fetch records
13+
records = api.dns_records("example.com")
14+
print(records)
15+
16+
# fetch zone details
17+
zone = api.dns_zone("example.com")
18+
print(zone)
19+
20+
# update single record
21+
api.update_dns_record("example.com", DNSRecord("my-hostname", "A", "127.0.0.2", id=108125))
22+
23+
# update list of records
24+
api.update_dns_record("example.com", [ DNSRecord("my-hostname", "A", "127.0.0.2", id=108125),
25+
DNSRecord("my-hostname2", "A", "127.0.0.2", id=108126)])
26+
27+
# delete record
28+
api.delete_dns_record("example.com", DNSRecord("my-hostname", "A", "127.0.0.2", id=108125))
29+
30+
# add record
31+
api.add_dns_record("example.com", DNSRecord("another-host", "AAAA", "::1"))
32+
33+
# update zone
34+
zone = api.dns_zone("example.com")
35+
zone.refresh = 3600
36+
api.update_dns_zone("example.com", zone)
37+
```

nc_dnsapi/__init__.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import requests
2+
import json
3+
4+
5+
class DNSZone(object):
6+
def __init__(self, name, ttl, serial, refresh, retry, expire, dnssecstatus):
7+
self.name = name
8+
self.ttl = ttl
9+
self.serial = serial
10+
self.refresh = refresh
11+
self.retry = retry
12+
self.expire = expire
13+
self.dnssecstatus = dnssecstatus
14+
15+
def __str__(self):
16+
return str(self.__dict__)
17+
18+
19+
class DNSRecord(object):
20+
__valid_types = ['A', 'AAAA', 'MX', 'CNAME', 'CAA', 'SRV', 'TXT', 'TLSA', 'NS', 'DS']
21+
22+
def __init__(self, hostname, record_type, destination, **kwargs):
23+
self.hostname = hostname
24+
self.type = record_type.upper()
25+
self.destination = destination
26+
self.priority = kwargs.get("priority", 0)
27+
self.id = kwargs.get("id", "")
28+
self.deleterecord = kwargs.get("deleterecord", False)
29+
self.state = True
30+
31+
if self.type not in self.__valid_types:
32+
raise TypeError("Invalid record type: {}".format(self.type))
33+
34+
def __str__(self):
35+
return str(self.__dict__)
36+
37+
38+
class Client(object):
39+
__endpoint = "https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON"
40+
__api_session_id = None
41+
42+
def request(self, action, **kwargs):
43+
params = kwargs.get("params", {})
44+
params.update({
45+
"apikey": self.__api_key,
46+
"customernumber": self.__customer,
47+
})
48+
49+
if "apipassword" in kwargs:
50+
params.update({kwargs.get("apipassword")})
51+
52+
if self.__api_session_id:
53+
params.update({"apisessionid": self.__api_session_id})
54+
55+
response = requests.post(
56+
self.__endpoint,
57+
data=json.dumps({
58+
"action": action,
59+
"param": params
60+
}),
61+
timeout=self.__api_timeout
62+
)
63+
64+
if response.ok:
65+
data = response.json()
66+
67+
if data['status'] == 'success':
68+
return data
69+
else:
70+
raise Exception("{} ({})".format(data['longmessage'], data['statuscode']))
71+
else:
72+
raise Exception("{} ({})".format(response.reason, response.status_code))
73+
74+
def logout(self):
75+
self.request("logout")
76+
77+
def login(self):
78+
data = self.request("login", params={"apipassword": self.__api_password})
79+
self.__api_session_id = data['responsedata']['apisessionid']
80+
81+
def add_dns_record(self, domain, record: DNSRecord):
82+
self.update_dns_records(domain, [record])
83+
84+
def update_dns_record(self, domain, record: DNSRecord):
85+
if not record.id:
86+
raise ValueError("Missing id of record to update")
87+
88+
self.update_dns_records(domain, [record])
89+
90+
def update_dns_records(self, domain, records):
91+
if not all(isinstance(r, DNSRecord) for r in records):
92+
raise TypeError("Record has to be instance of DNSRecord")
93+
94+
self.request("updateDnsRecords", params={
95+
"domainname": domain,
96+
"dnsrecordset": {"dnsrecords": [record.__dict__ for record in records]}
97+
})
98+
99+
def delete_dns_record(self, domain, record: DNSRecord, ignore_unknown=True):
100+
if not record.id:
101+
raise ValueError("Missing id of record to update")
102+
103+
record.deleterecord = True
104+
105+
try:
106+
self.update_dns_records(domain, [record])
107+
except Exception as ex:
108+
if not ignore_unknown:
109+
raise ex
110+
111+
def dns_records(self, domain):
112+
data = self.request("infoDnsRecords", params={"domainname": domain})
113+
return [DNSRecord(**r) for r in data['responsedata']['dnsrecords']]
114+
115+
def update_dns_zone(self, domain, zone: DNSZone):
116+
if not isinstance(zone, DNSZone):
117+
raise TypeError("Zone has to be instance of DNSZone")
118+
119+
self.request("updateDnsZone", params={
120+
"domainname": domain,
121+
"dnszone": zone.__dict__
122+
})
123+
124+
def dns_zone(self, domain):
125+
data = self.request("infoDnsZone", params={"domainname": domain})
126+
return DNSZone(**data['responsedata'])
127+
128+
def __init__(self, customer, api_key, api_password, timeout=5):
129+
self.__customer = customer
130+
self.__api_key = api_key
131+
self.__api_password = api_password
132+
self.__api_timeout = timeout
133+
134+
def __enter__(self):
135+
self.login()
136+
return self
137+
138+
def __exit__(self, exc_type, exc_value, traceback):
139+
self.logout()

setup.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env python
2+
3+
from setuptools import setup
4+
5+
setup(
6+
name='nc_dnsapi',
7+
version='0.1.0',
8+
description='API wrapper for the netcup DNS api',
9+
author='Nicolai Buchwitz',
10+
author_email='nb@tipi-net.de',
11+
zip_safe=False,
12+
include_package_data=True,
13+
classifiers=[
14+
'Development Status :: 4 - Beta',
15+
'Intended Audience :: Developers',
16+
'License :: OSI Approved :: BSD License',
17+
'Natural Language :: English',
18+
'Operating System :: POSIX :: Linux',
19+
'Programming Language :: Python',
20+
],
21+
install_requires=[
22+
'requests',
23+
],
24+
packages=[
25+
'nc_dnsapi',
26+
],
27+
)

0 commit comments

Comments
 (0)