Skip to content

Commit

Permalink
Add support for IONOS (#2127)
Browse files Browse the repository at this point in the history
* Support for IONOS (WIP)

* Added link to IONOS API documentation to README

* Updated provider doc

* IONOS: implemented create, update, delete

* IONOS: made integration tests pass

* IONOS: added integration tests

* IONOS: added cassette

* IONOS: added to CODEOWNERS

* Default an environment variable

---------

Co-authored-by: Adrien Ferrand <ferrand.ad@gmail.com>
  • Loading branch information
texttheater and adferrand authored Dec 6, 2024
1 parent f49f85d commit bd436d9
Show file tree
Hide file tree
Showing 33 changed files with 5,930 additions and 18 deletions.
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ lexicon/providers/hover.py @bkanuka
lexicon/providers/infomaniak.py @l3o-pold
lexicon/providers/internetbs.py @edausq
lexicon/providers/inwx.py @lociii
lexicon/providers/ionos.py @texttheater
lexicon/providers/joker.py @adferrand
lexicon/providers/linode.py @trinopoty
lexicon/providers/linode4.py @trinopoty
Expand Down
37 changes: 20 additions & 17 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,39 +75,41 @@ The current supported providers are:
.. tag: providers-table-begin
+-----------------+-----------------+-----------------+-----------------+-----------------+
| aliyun_ | aurora_ | azure_ | cloudflare_ | cloudns_ |
| aliyun_ | arvancloud_ | aurora_ | azure_ | cloudflare_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| cloudxns_ | conoha_ | constellix_ | ddns_ | digitalocean_ |
| cloudns_ | cloudxns_ | conoha_ | constellix_ | ddns_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| dinahosting_ | directadmin_ | dnsimple_ | dnsmadeeasy_ | dnspark_ |
| digitalocean_ | dinahosting_ | directadmin_ | dnsimple_ | dnsmadeeasy_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| dnspod_ | dnsservices_ | dreamhost_ | duckdns_ | dynu_ |
| dnspark_ | dnspod_ | dnsservices_ | dreamhost_ | duckdns_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| easydns_ | easyname_ | euserv_ | exoscale_ | flexibleengine_ |
| dynu_ | easydns_ | easyname_ | euserv_ | exoscale_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| gandi_ | gehirn_ | glesys_ | godaddy_ | googleclouddns_ |
| flexibleengine_ | gandi_ | gehirn_ | glesys_ | godaddy_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| gransy_ | gratisdns_ | henet_ | hetzner_ | hostingde_ |
| googleclouddns_ | gransy_ | gratisdns_ | henet_ | hetzner_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| hover_ | infoblox_ | infomaniak_ | internetbs_ | inwx_ |
| hostingde_ | hover_ | infoblox_ | infomaniak_ | internetbs_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| joker_ | linode_ | linode4_ | localzone_ | luadns_ |
| inwx_ | ionos_ | joker_ | linode_ | linode4_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| memset_ | misaka_ | mythicbeasts_ | namecheap_ | namecom_ |
| localzone_ | luadns_ | memset_ | misaka_ | mythicbeasts_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| namesilo_ | netcup_ | nfsn_ | njalla_ | nsone_ |
| namecheap_ | namecom_ | namesilo_ | netcup_ | nfsn_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| oci_ | onapp_ | online_ | ovh_ | plesk_ |
| njalla_ | nsone_ | oci_ | onapp_ | online_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| pointhq_ | porkbun_ | powerdns_ | qcloud_ | rackspace_ |
| ovh_ | plesk_ | pointhq_ | porkbun_ | powerdns_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| rage4_ | rcodezero_ | route53_ | safedns_ | sakuracloud_ |
| qcloud_ | rackspace_ | rage4_ | rcodezero_ | route53_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| softlayer_ | timeweb_ | transip_ | ultradns_ | valuedomain_ |
| safedns_ | sakuracloud_ | softlayer_ | timeweb_ | transip_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| vercel_ | vultr_ | webgo_ | wedos_ | yandex_ |
| ultradns_ | valuedomain_ | vercel_ | vultr_ | webgo_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| yandexcloud_ | zeit_ | zilore_ | zonomi_ | |
| wedos_ | yandex_ | yandexcloud_ | zeit_ | zilore_ |
+-----------------+-----------------+-----------------+-----------------+-----------------+
| zonomi_ | | | | |
+-----------------+-----------------+-----------------+-----------------+-----------------+

.. tag: providers-table-end
Expand Down Expand Up @@ -153,6 +155,7 @@ The current supported providers are:
.. _infomaniak: https://www.infomaniak.com
.. _internetbs: https://internetbs.net/resellerregistrardomainnameapi
.. _inwx: https://www.inwx.de/en/offer/api
.. _ionos: https://developer.hosting.ionos.de/docs/dns
.. _joker: https://joker.com/faq/index.php?action=show&cat=39
.. _linode: https://www.linode.com/api/dns
.. _linode4: https://developers.linode.com/api/docs/v4#tag/domains
Expand Down
2 changes: 1 addition & 1 deletion docs/providers/arvancloud.rst
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
arvancloud
* ``auth_token`` Specify api key for authentication
* ``auth_token`` Specify key for authentication (api key)
2 changes: 2 additions & 0 deletions docs/providers/ionos.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ionos
* ``api_key`` Ionos api key: public prefix + period + key proper
3 changes: 3 additions & 0 deletions docs/providers_options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ List of options
.. _inwx:
.. include:: providers/inwx.rst

.. _ionos:
.. include:: providers/ionos.rst

.. _joker:
.. include:: providers/joker.rst

Expand Down
99 changes: 99 additions & 0 deletions src/lexicon/_private/providers/ionos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import requests

from lexicon.interfaces import Provider as BaseProvider


_ZONES_API = 'https://api.hosting.ionos.com/dns/v1/zones'


class Provider(BaseProvider):

@staticmethod
def get_nameservers():
return ['ui-dns.com', 'ui-dns.org', 'ui-dns.de', 'ui-dns.biz']

@staticmethod
def configure_parser(parser):
parser.add_argument(
'--api-key',
required=True,
help='IONOS api key: public prefix + period + key proper',
)

def authenticate(self):
zones = self._get(_ZONES_API)
for zone in zones:
if zone['name'] == self.domain:
self.domain_id = zone['id']
return
raise Exception('domain not found: ' + self.domain)

def create_record(self, rtype, name, content):
self._post(
_ZONES_API + '/' + self.domain_id + '/records',
data=[{
'name': self._full_name(name),
'type': rtype,
'content': content,
'ttl': self._get_lexicon_option('ttl'),
'prio': 0,
'disabled': False,
}],
)
return True

def list_records(self, rtype=None, name=None, content=None):
query_params = {}
if rtype:
query_params['recordType'] = rtype
if name:
query_params['recordName'] = self._full_name(name)
data = self._get(_ZONES_API + '/' + self.domain_id, query_params)
records = data['records']
records = [{
'type': r['type'],
'name': r['name'],
'ttl': r['ttl'],
'content': r['content'],
'id': r['id'],
} for r in records]
for record in records:
self._clean_TXT_record(record)
if content:
records = [r for r in records if r['content'] == content]
return records

def update_record(self, identifier, rtype, name, content):
self.delete_record(identifier, rtype, name, None)
return self.create_record(rtype, name, content)

def delete_record(self, identifier=None, rtype=None, name=None, content=None):
if identifier:
identifiers = [identifier]
else:
identifiers = [
r['id']
for r in self.list_records(rtype, name, content)
]
for identifier in identifiers:
self._delete(
_ZONES_API + '/' + self.domain_id + '/records/' + identifier
)
return True

def _request(self, action='GET', url='/', data=None, query_params=None):
response = requests.request(
action,
url,
params=query_params,
json=data,
headers={
'accept': 'application/json',
'x-api-key': self._get_provider_option('api_key'),
},
)
response.raise_for_status()
try:
return response.json()
except requests.exceptions.JSONDecodeError:
return True
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
interactions:
- request:
body: null
headers:
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
User-Agent:
- python-requests/2.32.3
accept:
- application/json
method: GET
uri: https://api.hosting.ionos.com/dns/v1/zones
response:
body:
string: '[{"name": "example.com", "id": "4c9feb47-2a4d-11ec-bda4-0a5864441f49",
"type": "NATIVE"}]'
headers:
Access-Control-Allow-Origin:
- '*'
Connection:
- keep-alive
Content-Length:
- '582'
Content-Type:
- application/json
Date:
- Thu, 28 Nov 2024 13:45:42 GMT
Keep-Alive:
- timeout=15
cache-control:
- no-cache, no-store, max-age=0, must-revalidate
expires:
- '0'
pragma:
- no-cache
referrer-policy:
- no-referrer
vary:
- Origin
- Access-Control-Request-Method
- Access-Control-Request-Headers
- Origin
via:
- kong/3.0.0
x-content-type-options:
- nosniff
x-frame-options:
- DENY
x-kong-proxy-latency:
- '1'
x-kong-upstream-latency:
- '5'
x-xss-protection:
- '0'
status:
code: 200
message: OK
version: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
interactions:
- request:
body: null
headers:
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
User-Agent:
- python-requests/2.32.3
accept:
- application/json
method: GET
uri: https://api.hosting.ionos.com/dns/v1/zones
response:
body:
string: '[{"name": "example.com", "id": "4c9feb47-2a4d-11ec-bda4-0a5864441f49",
"type": "NATIVE"}]'
headers:
Access-Control-Allow-Origin:
- '*'
Connection:
- keep-alive
Content-Length:
- '582'
Content-Type:
- application/json
Date:
- Thu, 28 Nov 2024 13:45:42 GMT
Keep-Alive:
- timeout=15
cache-control:
- no-cache, no-store, max-age=0, must-revalidate
expires:
- '0'
pragma:
- no-cache
referrer-policy:
- no-referrer
vary:
- Origin
- Access-Control-Request-Method
- Access-Control-Request-Headers
- Origin
via:
- kong/3.0.0
x-content-type-options:
- nosniff
x-frame-options:
- DENY
x-kong-proxy-latency:
- '0'
x-kong-upstream-latency:
- '5'
x-xss-protection:
- '0'
status:
code: 200
message: OK
version: 1
Loading

0 comments on commit bd436d9

Please sign in to comment.