Add OVH support
This commit is contained in:
12
README.md
12
README.md
@@ -53,7 +53,17 @@ To get credentials, go to this link here: https://robot.hetzner.com/preferences/
|
||||
|
||||
#### OVH
|
||||
|
||||
- Work in progress
|
||||
- Supports creating, updating, and deleting DNS records using the OVH API.
|
||||
|
||||
#### Credentials
|
||||
To get credentials, go to this link here: https://github.com/ovh/php-ovh#supported-endpoints, pick the right endpoint and go to the right **/createApp/** application credentials page.
|
||||
The application needs to have the following rights:
|
||||
- GET /ip
|
||||
- GET /ip/*
|
||||
- POST /ip/*
|
||||
- DELETE /ip/*
|
||||
|
||||
Don't forget to set the right endpoint region in the config file.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
import configparser
|
||||
import requests
|
||||
|
||||
|
||||
def reverse_ip_to_standard(reverse_ip):
|
||||
parts = reverse_ip.split(".")
|
||||
parts = parts[:4]
|
||||
standard_ip = ".".join(reversed(parts))
|
||||
|
||||
return standard_ip
|
||||
|
||||
|
||||
class OvhBackend:
|
||||
def __init__(self, config_file='config.ini'):
|
||||
self.config_file = config_file
|
||||
self.username = None
|
||||
self.password = None
|
||||
|
||||
self.load_credentials()
|
||||
|
||||
def load_credentials(self):
|
||||
config = configparser.ConfigParser()
|
||||
config.read(self.config_file)
|
||||
|
||||
if "OVH" not in config:
|
||||
raise ValueError("OVH section not found in config.ini")
|
||||
|
||||
self.username = config["OVH"].get("username")
|
||||
self.password = config["OVH"].get("password")
|
||||
|
||||
if not self.username or not self.password:
|
||||
raise ValueError("OVH username or password not provided in config.ini")
|
||||
|
||||
def update_record(self, reverse_ip, record):
|
||||
# Do update record stuff here
|
||||
pass
|
||||
|
||||
def create_record(self, reverse_ip, record):
|
||||
# Do create record stuff here
|
||||
pass
|
||||
|
||||
def delete_record(self, reverse_ip):
|
||||
# Do delete record stuff here
|
||||
pass
|
||||
113
backend/ovh_backend.py
Normal file
113
backend/ovh_backend.py
Normal file
@@ -0,0 +1,113 @@
|
||||
import configparser
|
||||
import urllib
|
||||
|
||||
import ovh
|
||||
import json
|
||||
import ipaddress
|
||||
|
||||
|
||||
def reverse_ip_to_standard(reverse_ip):
|
||||
parts = reverse_ip.split(".")
|
||||
parts = parts[:4]
|
||||
standard_ip = ".".join(reversed(parts))
|
||||
|
||||
return standard_ip
|
||||
|
||||
|
||||
def ip_to_block(ip_addr, ip_blocks):
|
||||
# Remove IPv6 blocks from the list
|
||||
ip_blocks = [block for block in ip_blocks if ":" not in block]
|
||||
ip_addr = ipaddress.ip_address(ip_addr) # Convert ip_addr to an IPv4Address object
|
||||
for block in ip_blocks:
|
||||
network = ipaddress.ip_network(block)
|
||||
if ip_addr in network:
|
||||
print("IP " + str(ip_addr) + " belongs to " + block)
|
||||
return block
|
||||
|
||||
|
||||
class OvhBackend:
|
||||
def __init__(self, config_file='config.ini'):
|
||||
self.client = None
|
||||
self.config_file = config_file
|
||||
self.load_credentials()
|
||||
|
||||
def load_credentials(self):
|
||||
config = configparser.ConfigParser()
|
||||
config.read(self.config_file)
|
||||
|
||||
if "OVH" not in config:
|
||||
raise ValueError("OVH section not found in config.ini")
|
||||
|
||||
endpoint = config["OVH"]["endpoint"]
|
||||
application_key = config["OVH"]["application_key"]
|
||||
application_secret = config["OVH"]["application_secret"]
|
||||
consumer_key = config["OVH"]["consumer_key"]
|
||||
|
||||
if not endpoint or not application_key or not application_secret or not consumer_key:
|
||||
raise ValueError("OVH credentials not provided in config.ini")
|
||||
|
||||
self.client = ovh.Client(
|
||||
endpoint=endpoint,
|
||||
application_key=application_key,
|
||||
application_secret=application_secret,
|
||||
consumer_key=consumer_key
|
||||
)
|
||||
|
||||
def update_record(self, reverse_ip, record):
|
||||
# Check if the record contains the necessary data
|
||||
if not record or "content" not in record[0]:
|
||||
print("Invalid record data. 'content' field is missing.")
|
||||
return None
|
||||
|
||||
domain = record[0]["content"].strip(".")
|
||||
|
||||
ip_blocks = self.client.get("/ip")
|
||||
ip_blocks = json.dumps(ip_blocks)
|
||||
ip_blocks = json.loads(ip_blocks)
|
||||
|
||||
ip = reverse_ip_to_standard(reverse_ip)
|
||||
block = ip_to_block(ip, ip_blocks)
|
||||
|
||||
if block is None:
|
||||
print("Error: no block found for IP " + ip)
|
||||
return
|
||||
|
||||
print("Updating RDNS record for: " + ip + " in block " + block + " to: " + record[0]["content"])
|
||||
block = urllib.parse.quote(block, safe="")
|
||||
path = "/ip/" + block + "/reverse"
|
||||
try:
|
||||
self.client.post(f"{path}",
|
||||
ipReverse=ip,
|
||||
reverse=domain,
|
||||
)
|
||||
except ovh.exceptions.APIError as e:
|
||||
print("Error: " + str(e))
|
||||
else:
|
||||
print("Updated RDNS record for: " + ip)
|
||||
return None
|
||||
|
||||
def create_record(self, reverse_ip, record):
|
||||
self.update_record(reverse_ip, record)
|
||||
pass
|
||||
|
||||
def delete_record(self, reverse_ip):
|
||||
ip_blocks = self.client.get("/ip")
|
||||
ip_blocks = json.dumps(ip_blocks)
|
||||
ip_blocks = json.loads(ip_blocks)
|
||||
|
||||
ip = reverse_ip_to_standard(reverse_ip)
|
||||
block = ip_to_block(ip, ip_blocks)
|
||||
|
||||
if block is None:
|
||||
print("Error: no block found for ip " + ip)
|
||||
return
|
||||
|
||||
result = self.client.delete(f"/ip/{ip}/reverse" + block)
|
||||
if result.status_code == 200:
|
||||
print("Deleted RDNS record for: " + ip)
|
||||
return result.json()
|
||||
else:
|
||||
print(f"Failed to delete rDNS data. Status code: {result.status_code}")
|
||||
print(result.json())
|
||||
return None
|
||||
pass
|
||||
10
config.ini
10
config.ini
@@ -4,9 +4,11 @@ api_key=x
|
||||
frequency=5
|
||||
|
||||
[Hetzner]
|
||||
username=x
|
||||
password=x
|
||||
username=#ws+yimPZrpr
|
||||
password=BTJOxx@Cfk&\&!!5
|
||||
|
||||
[OVH]
|
||||
username=x
|
||||
password=x
|
||||
endpoint=ovh-ca
|
||||
application_key=x
|
||||
application_secret=x
|
||||
consumer_key=x
|
||||
6
main.py
6
main.py
@@ -4,8 +4,8 @@ import json
|
||||
import configparser
|
||||
import schedule
|
||||
import time
|
||||
from backend.hetzner import HetznerBackend
|
||||
from backend.ovh import OvhBackend
|
||||
from backend.hetzner_backend import HetznerBackend
|
||||
from backend.ovh_backend import OvhBackend
|
||||
|
||||
|
||||
def compare_zone_records(saved_records, new_records, backend_type):
|
||||
@@ -19,8 +19,10 @@ def compare_zone_records(saved_records, new_records, backend_type):
|
||||
|
||||
if backend_type == "hetzner":
|
||||
backend = HetznerBackend()
|
||||
print("Using Hetzner backend")
|
||||
elif backend_type == "ovh":
|
||||
backend = OvhBackend()
|
||||
print("Using OVH backend")
|
||||
else:
|
||||
print(f"Specified backend not supported: {backend_type}")
|
||||
return
|
||||
|
||||
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
Reference in New Issue
Block a user