Files
yakpanel-core/class/sewer/dns_providers/aliyundns.py
2026-04-07 02:04:22 +05:30

211 lines
7.8 KiB
Python

import json
try:
aliyun_dependencies = True
from aliyunsdkcore import client
from aliyunsdkalidns.request.v20150109 import DescribeDomainRecordsRequest
from aliyunsdkalidns.request.v20150109 import AddDomainRecordRequest
from aliyunsdkalidns.request.v20150109 import DeleteDomainRecordRequest
except ImportError:
aliyun_dependencies = False
from . import common
class _ResponseForAliyun(object):
"""
wrapper aliyun resp to the format sewer wanted.
"""
def __init__(self, status_code=200, content=None, headers=None):
self.status_code = status_code
self.headers = headers or {}
self.content = content or {}
self.content = json.dumps(content)
super(_ResponseForAliyun, self).__init__()
def json(self):
return json.loads(self.content)
class AliyunDns(common.BaseDns):
def __init__(self, key, secret, endpoint="cn-beijing", debug=False):
"""
aliyun model client
:param str key: access key
:param str secret: access sceret
:param str endpoint: endpoint
:param bool debug: if debug?
"""
super(AliyunDns, self).__init__()
if not aliyun_dependencies:
raise ImportError(
"""You need to install aliyunDns dependencies. run; pip3 install sewer[aliyun]"""
)
self._key = key
self._secret = secret
self._endpoint = endpoint
self._debug = debug
self.clt = client.AcsClient(self._key, self._secret, self._endpoint, debug=self._debug)
def _send_reqeust(self, request):
"""
send request to aliyun
"""
request.set_accept_format("json")
try:
status, headers, result = self.clt.implementation_of_do_action(request)
result = json.loads(result)
if "Message" in result or "Code" in result:
result["Success"] = False
self.logger.warning("aliyundns resp error: %s", result)
except Exception as exc:
self.logger.warning("aliyundns failed to send request: %s, %s", str(exc), request)
status, headers, result = 502, {}, '{"Success": false}'
result = json.loads(result)
if self._debug:
self.logger.info("aliyundns request name: %s", request.__class__.__name__)
self.logger.info("aliyundns request query: %s", request.get_query_params())
return _ResponseForAliyun(status, result, headers)
def query_recored_items(self, host, zone=None, tipe=None, page=1, psize=200):
"""
query recored items.
:param str host: like example.com
:param str zone: like menduo.example.com
:param str tipe: TXT, CNAME, IP or other
:param int page:
:param int psize:
:return dict: res = {
'DomainRecords':
{'Record': [
{
'DomainName': 'menduo.net',
'Line': 'default',
'Locked': False,
'RR': 'zb',
'RecordId': '3989515483698964',
'Status': 'ENABLE',
'TTL': 600,
'Type': 'A',
'Value': '127.0.0.1',
'Weight': 1
},
{
'DomainName': 'menduo.net',
'Line': 'default',
'Locked': False,
'RR': 'a.sub',
'RecordId': '3989515480778964',
'Status': 'ENABLE',
'TTL': 600,
'Type': 'CNAME',
'Value': 'h.p.menduo.net',
'Weight': 1
}
]
},
'PageNumber': 1,
'PageSize': 20,
'RequestId': 'FC4D02CD-EDCC-4EE8-942F-1497CCC3B10E',
'TotalCount': 95
}
"""
request = DescribeDomainRecordsRequest.DescribeDomainRecordsRequest()
request.get_action_name()
request.set_DomainName(host)
request.set_PageNumber(page)
request.set_PageSize(psize)
if zone:
request.set_RRKeyWord(zone)
if tipe:
request.set_TypeKeyWord(tipe)
resp = self._send_reqeust(request)
body = resp.json()
return body
def query_recored_id(self, root, zone, tipe="TXT"):
"""
find recored
:param str root: root host, like example.com
:param str zone: sub zone, like menduo.example.com
:param str tipe: record tipe, TXT, CNAME, IP. we use TXT
:return str:
"""
record_id = None
recoreds = self.query_recored_items(root, zone, tipe=tipe)
recored_list = recoreds.get("DomainRecords", {}).get("Record", [])
recored_item_list = [i for i in recored_list if i["RR"] == zone]
if len(recored_item_list):
record_id = recored_item_list[0]["RecordId"]
return record_id
@staticmethod
def extract_zone(domain_name):
"""
extract domain to root, sub, acme_txt
:param str domain_name: the value sewer client passed in, like *.menduo.example.com
:return tuple: root, zone, acme_txt
"""
# if we have been given a wildcard name, strip wildcard
domain_name = domain_name.lstrip("*.")
if domain_name.count(".") > 1:
zone, middle, last = str(domain_name).rsplit(".", 2)
root = ".".join([middle, last])
acme_txt = "_acme-challenge.%s" % zone
else:
zone = ""
root = domain_name
acme_txt = "_acme-challenge"
return root, zone, acme_txt
def create_dns_record(self, domain_name, domain_dns_value):
"""
create a model record
:param str domain_name: the value sewer client passed in, like *.menduo.example.com
:param str domain_dns_value: the value sewer client passed in.
:return _ResponseForAliyun:
"""
self.logger.info("create_dns_record start: %s", (domain_name, domain_dns_value))
root, _, acme_txt = self.extract_zone(domain_name)
request = AddDomainRecordRequest.AddDomainRecordRequest()
request.set_DomainName(root)
request.set_TTL(600)
request.set_RR(acme_txt)
request.set_Type("TXT")
request.set_Value(domain_dns_value)
resp = self._send_reqeust(request)
self.logger.info("create_dns_record end: %s", (domain_name, domain_dns_value, resp.json()))
return resp
def delete_dns_record(self, domain_name, domain_dns_value):
"""
delete a txt record we created just now.
:param str domain_name: the value sewer client passed in, like *.menduo.example.com
:param str domain_dns_value: the value sewer client passed in. we do not use this.
:return _ResponseForAliyun:
:return:
"""
self.logger.info("delete_dns_record start: %s", (domain_name, domain_dns_value))
root, _, acme_txt = self.extract_zone(domain_name)
record_id = self.query_recored_id(root, acme_txt)
if not record_id:
msg = "failed to find record_id of domain: %s, value: %s", domain_name, domain_dns_value
self.logger.warning(msg)
return
self.logger.info("start to delete model record, id: %s", record_id)
request = DeleteDomainRecordRequest.DeleteDomainRecordRequest()
request.set_RecordId(record_id)
resp = self._send_reqeust(request)
self.logger.info("delete_dns_record end: %s", (domain_name, domain_dns_value, resp.json()))
return resp