Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicolai Buchwitz committed Aug 10, 2018
1 parent 59e1f32 commit df5e663
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
venv
.idea
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,37 @@
# nc_dnsapi
API wrapper for the netcup DNS API
A simple API wrapper for the netcup DNS API

```python
import nc_dnsapi

customer = 123456
api_key = "your-personal-api-key"
api_password = "your-private-api-password"

with nc_dnsapi.Client(customer, api_key, api_password) as api:
# fetch records
records = api.dns_records("example.com")
print(records)

# fetch zone details
zone = api.dns_zone("example.com")
print(zone)

# update single record
api.update_dns_record("example.com", DNSRecord("my-hostname", "A", "127.0.0.2", id=108125))

# update list of records
api.update_dns_record("example.com", [ DNSRecord("my-hostname", "A", "127.0.0.2", id=108125),
DNSRecord("my-hostname2", "A", "127.0.0.2", id=108126)])

# delete record
api.delete_dns_record("example.com", DNSRecord("my-hostname", "A", "127.0.0.2", id=108125))

# add record
api.add_dns_record("example.com", DNSRecord("another-host", "AAAA", "::1"))

# update zone
zone = api.dns_zone("example.com")
zone.refresh = 3600
api.update_dns_zone("example.com", zone)
```
139 changes: 139 additions & 0 deletions nc_dnsapi/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import requests
import json


class DNSZone(object):
def __init__(self, name, ttl, serial, refresh, retry, expire, dnssecstatus):
self.name = name
self.ttl = ttl
self.serial = serial
self.refresh = refresh
self.retry = retry
self.expire = expire
self.dnssecstatus = dnssecstatus

def __str__(self):
return str(self.__dict__)


class DNSRecord(object):
__valid_types = ['A', 'AAAA', 'MX', 'CNAME', 'CAA', 'SRV', 'TXT', 'TLSA', 'NS', 'DS']

def __init__(self, hostname, record_type, destination, **kwargs):
self.hostname = hostname
self.type = record_type.upper()
self.destination = destination
self.priority = kwargs.get("priority", 0)
self.id = kwargs.get("id", "")
self.deleterecord = kwargs.get("deleterecord", False)
self.state = True

if self.type not in self.__valid_types:
raise TypeError("Invalid record type: {}".format(self.type))

def __str__(self):
return str(self.__dict__)


class Client(object):
__endpoint = "https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON"
__api_session_id = None

def request(self, action, **kwargs):
params = kwargs.get("params", {})
params.update({
"apikey": self.__api_key,
"customernumber": self.__customer,
})

if "apipassword" in kwargs:
params.update({kwargs.get("apipassword")})

if self.__api_session_id:
params.update({"apisessionid": self.__api_session_id})

response = requests.post(
self.__endpoint,
data=json.dumps({
"action": action,
"param": params
}),
timeout=self.__api_timeout
)

if response.ok:
data = response.json()

if data['status'] == 'success':
return data
else:
raise Exception("{} ({})".format(data['longmessage'], data['statuscode']))
else:
raise Exception("{} ({})".format(response.reason, response.status_code))

def logout(self):
self.request("logout")

def login(self):
data = self.request("login", params={"apipassword": self.__api_password})
self.__api_session_id = data['responsedata']['apisessionid']

def add_dns_record(self, domain, record: DNSRecord):
self.update_dns_records(domain, [record])

def update_dns_record(self, domain, record: DNSRecord):
if not record.id:
raise ValueError("Missing id of record to update")

self.update_dns_records(domain, [record])

def update_dns_records(self, domain, records):
if not all(isinstance(r, DNSRecord) for r in records):
raise TypeError("Record has to be instance of DNSRecord")

self.request("updateDnsRecords", params={
"domainname": domain,
"dnsrecordset": {"dnsrecords": [record.__dict__ for record in records]}
})

def delete_dns_record(self, domain, record: DNSRecord, ignore_unknown=True):
if not record.id:
raise ValueError("Missing id of record to update")

record.deleterecord = True

try:
self.update_dns_records(domain, [record])
except Exception as ex:
if not ignore_unknown:
raise ex

def dns_records(self, domain):
data = self.request("infoDnsRecords", params={"domainname": domain})
return [DNSRecord(**r) for r in data['responsedata']['dnsrecords']]

def update_dns_zone(self, domain, zone: DNSZone):
if not isinstance(zone, DNSZone):
raise TypeError("Zone has to be instance of DNSZone")

self.request("updateDnsZone", params={
"domainname": domain,
"dnszone": zone.__dict__
})

def dns_zone(self, domain):
data = self.request("infoDnsZone", params={"domainname": domain})
return DNSZone(**data['responsedata'])

def __init__(self, customer, api_key, api_password, timeout=5):
self.__customer = customer
self.__api_key = api_key
self.__api_password = api_password
self.__api_timeout = timeout

def __enter__(self):
self.login()
return self

def __exit__(self, exc_type, exc_value, traceback):
self.logout()
27 changes: 27 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env python

from setuptools import setup

setup(
name='nc_dnsapi',
version='0.1.0',
description='API wrapper for the netcup DNS api',
author='Nicolai Buchwitz',
author_email='[email protected]',
zip_safe=False,
include_package_data=True,
classifiers=[
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Natural Language :: English',
'Operating System :: POSIX :: Linux',
'Programming Language :: Python',
],
install_requires=[
'requests',
],
packages=[
'nc_dnsapi',
],
)

0 comments on commit df5e663

Please sign in to comment.