Initial commit: Tencent DNSPod DNS deployment skill
- Support for single record deployment - Batch deployment from JSON config - Service quick deployment (Web/API/CDN) - .env file support for secure credentials - Complete documentation
This commit is contained in:
171
scripts/batch_deploy.py
Executable file
171
scripts/batch_deploy.py
Executable file
@@ -0,0 +1,171 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
DNSPod批量部署脚本
|
||||
从配置文件批量创建DNS记录
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from deploy_record import (
|
||||
deploy_record,
|
||||
check_domain_exists,
|
||||
create_domain,
|
||||
load_env
|
||||
)
|
||||
|
||||
# 加载 .env
|
||||
load_env()
|
||||
|
||||
def load_config(config_file):
|
||||
"""加载配置文件"""
|
||||
if not Path(config_file).exists():
|
||||
print(f"错误: 配置文件不存在: {config_file}")
|
||||
return None
|
||||
|
||||
try:
|
||||
with open(config_file, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"错误: 配置文件格式错误: {e}")
|
||||
return None
|
||||
|
||||
def batch_deploy(domain, config, create_domain_flag=False, delay=0.5):
|
||||
"""批量部署DNS记录"""
|
||||
records = config.get('records', [])
|
||||
|
||||
if not records:
|
||||
print("错误: 配置文件中没有记录")
|
||||
return False
|
||||
|
||||
print(f"\n批量部署开始")
|
||||
print(f"域名: {domain}")
|
||||
print(f"记录数量: {len(records)}")
|
||||
print(f"延迟: {delay}s\n")
|
||||
|
||||
# 检查域名是否存在
|
||||
if not check_domain_exists(domain):
|
||||
if create_domain_flag:
|
||||
if not create_domain(domain):
|
||||
return False
|
||||
else:
|
||||
print(f"✗ 域名不存在: {domain}")
|
||||
print(f"提示: 使用 --create-domain 自动创建域名")
|
||||
return False
|
||||
|
||||
# 统计
|
||||
success_count = 0
|
||||
fail_count = 0
|
||||
skip_count = 0
|
||||
|
||||
# 部署每条记录
|
||||
for idx, record_config in enumerate(records, 1):
|
||||
print(f"\n[{idx}/{len(records)}] 正在部署...")
|
||||
|
||||
subdomain = record_config.get('subdomain', '@')
|
||||
record_type = record_config.get('type')
|
||||
value = record_config.get('value')
|
||||
line = record_config.get('line', '默认')
|
||||
ttl = record_config.get('ttl', 600)
|
||||
remark = record_config.get('remark', '')
|
||||
|
||||
if not record_type or not value:
|
||||
print(f"✗ 跳过: 缺少必要参数 (type或value)")
|
||||
skip_count += 1
|
||||
continue
|
||||
|
||||
# 部署记录
|
||||
success = deploy_record(
|
||||
domain=domain,
|
||||
subdomain=subdomain,
|
||||
record_type=record_type,
|
||||
value=value,
|
||||
line=line,
|
||||
ttl=ttl,
|
||||
force=True, # 批量模式自动更新
|
||||
create_domain_flag=False,
|
||||
remark=remark
|
||||
)
|
||||
|
||||
if success:
|
||||
success_count += 1
|
||||
else:
|
||||
fail_count += 1
|
||||
|
||||
# API限频延迟
|
||||
if idx < len(records):
|
||||
time.sleep(delay)
|
||||
|
||||
# 输出统计
|
||||
print(f"\n{'='*50}")
|
||||
print(f"批量部署完成")
|
||||
print(f" 成功: {success_count}")
|
||||
print(f" 失败: {fail_count}")
|
||||
print(f" 跳过: {skip_count}")
|
||||
print(f"{'='*50}\n")
|
||||
|
||||
return fail_count == 0
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='DNSPod批量部署', formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog='''
|
||||
配置文件格式 (JSON):
|
||||
{
|
||||
"records": [
|
||||
{
|
||||
"subdomain": "@",
|
||||
"type": "A",
|
||||
"value": "1.2.3.4",
|
||||
"line": "默认",
|
||||
"ttl": 600,
|
||||
"remark": "主域名"
|
||||
},
|
||||
{
|
||||
"subdomain": "www",
|
||||
"type": "A",
|
||||
"value": "1.2.3.4",
|
||||
"line": "默认"
|
||||
},
|
||||
{
|
||||
"subdomain": "api",
|
||||
"type": "A",
|
||||
"value": "1.2.3.5",
|
||||
"line": "电信"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
示例:
|
||||
%(prog)s --domain example.com --config dns-config.json
|
||||
%(prog)s --domain example.com --config dns-config.json --create-domain
|
||||
%(prog)s --domain example.com --config dns-config.json --delay 1.0
|
||||
''')
|
||||
|
||||
parser.add_argument('--domain', required=True, help='域名(如: example.com)')
|
||||
parser.add_argument('--config', required=True, help='配置文件路径(JSON格式)')
|
||||
parser.add_argument('--create-domain', action='store_true', help='域名不存在时自动创建')
|
||||
parser.add_argument('--delay', type=float, default=0.5, help='API调用间隔(秒, 默认: 0.5, 避免限频)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# 加载配置
|
||||
config = load_config(args.config)
|
||||
if not config:
|
||||
sys.exit(1)
|
||||
|
||||
# 批量部署
|
||||
success = batch_deploy(
|
||||
domain=args.domain,
|
||||
config=config,
|
||||
create_domain_flag=args.create_domain,
|
||||
delay=args.delay
|
||||
)
|
||||
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
68
scripts/delete_record.py
Executable file
68
scripts/delete_record.py
Executable file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
DNS记录删除脚本
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
from deploy_record import (
|
||||
call_api,
|
||||
find_record,
|
||||
load_env
|
||||
)
|
||||
|
||||
# 加载 .env
|
||||
load_env()
|
||||
|
||||
def delete_record(domain, subdomain, record_type):
|
||||
"""删除DNS记录"""
|
||||
print(f"\n删除DNS记录: {subdomain or '@'}.{domain} ({record_type})")
|
||||
|
||||
# 查找记录
|
||||
record = find_record(domain, subdomain, record_type)
|
||||
|
||||
if not record:
|
||||
print(f"✗ 记录不存在")
|
||||
return False
|
||||
|
||||
record_id = record.get("RecordId")
|
||||
current_value = record.get("Value")
|
||||
|
||||
print(f" 记录ID: {record_id}")
|
||||
print(f" 当前值: {current_value}")
|
||||
|
||||
# 确认删除
|
||||
response = input("\n确认删除? (y/N): ")
|
||||
if response.lower() != 'y':
|
||||
print(" 已取消")
|
||||
return False
|
||||
|
||||
# 调用删除API
|
||||
try:
|
||||
params = {
|
||||
"Domain": domain,
|
||||
"RecordId": record_id
|
||||
}
|
||||
result = call_api("DeleteRecord", params)
|
||||
print(f"✓ 记录删除成功")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 记录删除失败: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='删除DNS记录')
|
||||
|
||||
parser.add_argument('--domain', required=True, help='域名(如: example.com)')
|
||||
parser.add_argument('--subdomain', default='@', help='子域名(默认: @)')
|
||||
parser.add_argument('--type', required=True, help='记录类型(A/CNAME/MX等)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
success = delete_record(args.domain, args.subdomain, args.type)
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
337
scripts/deploy_record.py
Executable file
337
scripts/deploy_record.py
Executable file
@@ -0,0 +1,337 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
DNSPod单条记录部署脚本
|
||||
用于快速添加或更新DNS记录
|
||||
支持 .env 文件配置敏感信息
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import hmac
|
||||
import hashlib
|
||||
import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from urllib.parse import urlencode, quote
|
||||
|
||||
try:
|
||||
import requests
|
||||
except ImportError:
|
||||
print("错误: 缺少 requests 库")
|
||||
print("请运行: pip install -r requirements.txt")
|
||||
sys.exit(1)
|
||||
|
||||
# 加载 .env 文件
|
||||
def load_env():
|
||||
"""加载.env文件"""
|
||||
env_file = Path(__file__).parent.parent / '.env'
|
||||
if env_file.exists():
|
||||
with open(env_file, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line and not line.startswith('#') and '=' in line:
|
||||
key, value = line.split('=', 1)
|
||||
os.environ[key.strip()] = value.strip()
|
||||
|
||||
# 加载 .env
|
||||
load_env()
|
||||
|
||||
# API配置
|
||||
API_ENDPOINT = "dnspod.tencentcloudapi.com"
|
||||
API_VERSION = "2021-03-23"
|
||||
REGION = "ap-guangzhou"
|
||||
|
||||
def get_credentials():
|
||||
"""从环境变量或.env文件获取腾讯云凭证"""
|
||||
secret_id = os.getenv('TENCENT_SECRET_ID')
|
||||
secret_key = os.getenv('TENCENT_SECRET_KEY')
|
||||
|
||||
if not secret_id or not secret_key:
|
||||
print("错误: 未找到腾讯云API密钥")
|
||||
print("\n请设置环境变量或创建 .env 文件:")
|
||||
print(" 方式1: 设置环境变量")
|
||||
print(" export TENCENT_SECRET_ID=\"你的SecretId\"")
|
||||
print(" export TENCENT_SECRET_KEY=\"你的SecretKey\"")
|
||||
print("\n 方式2: 创建 .env 文件")
|
||||
print(" cp .env.example .env")
|
||||
print(" 然后编辑 .env 文件,填入你的密钥")
|
||||
print("\n获取密钥地址: https://console.cloud.tencent.com/cam/capi")
|
||||
sys.exit(1)
|
||||
|
||||
return secret_id, secret_key
|
||||
|
||||
def sign_request(secret_id, secret_key, action, params):
|
||||
"""
|
||||
生成腾讯云API签名
|
||||
文档: https://cloud.tencent.com/document/product/1427/56152
|
||||
"""
|
||||
# 1. 构造请求体
|
||||
body = json.dumps(params)
|
||||
|
||||
# 2. 构造规范请求串
|
||||
# 请求方法
|
||||
http_request_method = "POST"
|
||||
# 请求URI
|
||||
canonical_uri = "/"
|
||||
# 请求查询字符串(空)
|
||||
canonical_querystring = ""
|
||||
# 请求头
|
||||
canonical_headers = f"content-type:application/json\nhost:{API_ENDPOINT}\n"
|
||||
signed_headers = "content-type;host"
|
||||
# 请求哈希值
|
||||
hashed_request_payload = hashlib.sha256(body.encode('utf-8')).hexdigest()
|
||||
canonical_request = (
|
||||
http_request_method + "\n" +
|
||||
canonical_uri + "\n" +
|
||||
canonical_querystring + "\n" +
|
||||
canonical_headers + "\n" +
|
||||
signed_headers + "\n" +
|
||||
hashed_request_payload
|
||||
)
|
||||
|
||||
# 3. 构造待签名字符串
|
||||
algorithm = "TC3-HMAC-SHA256"
|
||||
timestamp = int(time.time())
|
||||
date = datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%d')
|
||||
credential_scope = f"{date}/{API_VERSION}/tc3_request"
|
||||
hashed_canonical_request = hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()
|
||||
string_to_sign = (
|
||||
algorithm + "\n" +
|
||||
str(timestamp) + "\n" +
|
||||
credential_scope + "\n" +
|
||||
hashed_canonical_request
|
||||
)
|
||||
|
||||
# 4. 计算签名
|
||||
def _hmac_sha256(key, msg):
|
||||
return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
|
||||
|
||||
secret_date = _hmac_sha256(f"TC3{secret_key}".encode('utf-8'), date)
|
||||
secret_service = _hmac_sha256(secret_date, API_VERSION)
|
||||
secret_signing = _hmac_sha256(secret_service, "tc3_request")
|
||||
signature = hmac.new(secret_signing, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()
|
||||
|
||||
# 5. 构造Authorization头
|
||||
authorization = (
|
||||
algorithm + " " +
|
||||
"Credential=" + secret_id + "/" + credential_scope + ", " +
|
||||
"SignedHeaders=" + signed_headers + ", " +
|
||||
"Signature=" + signature
|
||||
)
|
||||
|
||||
return {
|
||||
"authorization": authorization,
|
||||
"body": body,
|
||||
"timestamp": timestamp
|
||||
}
|
||||
|
||||
def call_api(action, params):
|
||||
"""调用腾讯云API"""
|
||||
secret_id, secret_key = get_credentials()
|
||||
|
||||
# 生成签名
|
||||
sig = sign_request(secret_id, secret_key, action, params)
|
||||
|
||||
# 构造请求头
|
||||
headers = {
|
||||
"Authorization": sig["authorization"],
|
||||
"Content-Type": "application/json",
|
||||
"Host": API_ENDPOINT,
|
||||
"X-TC-Action": action,
|
||||
"X-TC-Timestamp": str(sig["timestamp"]),
|
||||
"X-TC-Version": API_VERSION,
|
||||
"X-TC-Region": REGION
|
||||
}
|
||||
|
||||
# 发送请求
|
||||
url = f"https://{API_ENDPOINT}/"
|
||||
response = requests.post(url, headers=headers, data=sig["body"])
|
||||
|
||||
return response.json()
|
||||
|
||||
def check_domain_exists(domain):
|
||||
"""检查域名是否存在"""
|
||||
try:
|
||||
result = call_api("DescribeDomainList", {})
|
||||
domains = [d["Name"] for d in result.get("Response", {}).get("DomainList", [])]
|
||||
return domain in domains
|
||||
except Exception as e:
|
||||
print(f"检查域名失败: {e}")
|
||||
return False
|
||||
|
||||
def create_domain(domain):
|
||||
"""创建域名"""
|
||||
print(f"正在创建域名: {domain}")
|
||||
try:
|
||||
result = call_api("CreateDomain", {"Domain": domain})
|
||||
print(f"✓ 域名创建成功: {domain}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 域名创建失败: {e}")
|
||||
return False
|
||||
|
||||
def find_record(domain, subdomain, record_type):
|
||||
"""查找现有记录"""
|
||||
try:
|
||||
params = {
|
||||
"Domain": domain,
|
||||
"Subdomain": subdomain,
|
||||
"RecordType": record_type
|
||||
}
|
||||
result = call_api("DescribeRecordList", params)
|
||||
records = result.get("Response", {}).get("RecordList", [])
|
||||
|
||||
for record in records:
|
||||
if record.get("Name") == subdomain and record.get("Type") == record_type:
|
||||
return record
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"查找记录失败: {e}")
|
||||
return None
|
||||
|
||||
def create_record(domain, subdomain, record_type, value, line="默认", ttl=600, remark=""):
|
||||
"""创建DNS记录"""
|
||||
params = {
|
||||
"Domain": domain,
|
||||
"RecordType": record_type,
|
||||
"RecordLine": line,
|
||||
"Value": value,
|
||||
"TTL": ttl
|
||||
}
|
||||
|
||||
# 添加子域名
|
||||
if subdomain and subdomain != "@":
|
||||
params["SubDomain"] = subdomain
|
||||
|
||||
# 添加备注
|
||||
if remark:
|
||||
params["Remark"] = remark
|
||||
|
||||
try:
|
||||
result = call_api("CreateRecord", params)
|
||||
record_id = result.get("Response", {}).get("RecordId")
|
||||
print(f"✓ 记录创建成功: {subdomain or '@'}.{domain} ({record_type}) → {value}")
|
||||
return record_id
|
||||
except Exception as e:
|
||||
print(f"✗ 记录创建失败: {e}")
|
||||
return None
|
||||
|
||||
def modify_record(domain, record_id, subdomain, record_type, value, line="默认", ttl=600, remark=""):
|
||||
"""修改DNS记录"""
|
||||
params = {
|
||||
"Domain": domain,
|
||||
"RecordId": record_id,
|
||||
"RecordType": record_type,
|
||||
"RecordLine": line,
|
||||
"Value": value,
|
||||
"TTL": ttl
|
||||
}
|
||||
|
||||
if subdomain and subdomain != "@":
|
||||
params["SubDomain"] = subdomain
|
||||
|
||||
if remark:
|
||||
params["Remark"] = remark
|
||||
|
||||
try:
|
||||
result = call_api("ModifyRecord", params)
|
||||
print(f"✓ 记录更新成功: {subdomain or '@'}.{domain} ({record_type}) → {value}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 记录更新失败: {e}")
|
||||
return False
|
||||
|
||||
def deploy_record(domain, subdomain, record_type, value, line="默认", ttl=600, force=False, create_domain_flag=False, remark=""):
|
||||
"""部署DNS记录(创建或更新)"""
|
||||
print(f"\n部署DNS记录: {subdomain or '@'}.{domain}")
|
||||
print(f" 类型: {record_type}")
|
||||
print(f" 值: {value}")
|
||||
print(f" 线路: {line}")
|
||||
print(f" TTL: {ttl}s")
|
||||
|
||||
# 检查域名是否存在
|
||||
if not check_domain_exists(domain):
|
||||
if create_domain_flag:
|
||||
if not create_domain(domain):
|
||||
return False
|
||||
else:
|
||||
print(f"✗ 域名不存在: {domain}")
|
||||
print(f" 提示: 使用 --create-domain 自动创建域名")
|
||||
return False
|
||||
|
||||
# 查找现有记录
|
||||
existing = find_record(domain, subdomain, record_type)
|
||||
|
||||
if existing:
|
||||
if not force:
|
||||
old_value = existing.get("Value", "")
|
||||
print(f"\n记录已存在:")
|
||||
print(f" 当前值: {old_value}")
|
||||
print(f" 新值: {value}")
|
||||
|
||||
# 检查是否需要更新
|
||||
if old_value == value:
|
||||
print(" 值未变化,无需更新")
|
||||
return True
|
||||
|
||||
response = input("\n是否更新? (y/N): ")
|
||||
if response.lower() != 'y':
|
||||
print(" 已取消")
|
||||
return False
|
||||
|
||||
record_id = existing.get("RecordId")
|
||||
return modify_record(domain, record_id, subdomain, record_type, value, line, ttl, remark)
|
||||
else:
|
||||
return create_record(domain, subdomain, record_type, value, line, ttl, remark)
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='DNSPod记录快速部署', formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog='''
|
||||
示例:
|
||||
# 添加www的A记录
|
||||
%(prog)s --domain example.com --subdomain www --type A --value 1.2.3.4
|
||||
|
||||
# 添加主域名记录
|
||||
%(prog)s --domain example.com --subdomain @ --type A --value 1.2.3.4
|
||||
|
||||
# 添加CNAME记录
|
||||
%(prog)s --domain example.com --subdomain cdn --type CNAME --value cdn.example.com
|
||||
|
||||
# 强制更新现有记录
|
||||
%(prog)s --domain example.com --subdomain www --type A --value 1.2.3.5 --force
|
||||
|
||||
# 域名不存在时自动创建
|
||||
%(prog)s --domain example.com --subdomain www --type A --value 1.2.3.4 --create-domain
|
||||
''')
|
||||
|
||||
parser.add_argument('--domain', required=True, help='域名(如: example.com)')
|
||||
parser.add_argument('--subdomain', default='@', help='子域名(默认: @ 表示主域名)')
|
||||
parser.add_argument('--type', required=True, choices=['A', 'AAAA', 'CNAME', 'MX', 'TXT', 'NS', 'SRV'], help='记录类型')
|
||||
parser.add_argument('--value', required=True, help='记录值')
|
||||
parser.add_argument('--line', default='默认', help='线路(默认: 默认)')
|
||||
parser.add_argument('--ttl', type=int, default=600, help='TTL(秒, 默认: 600)')
|
||||
parser.add_argument('--force', action='store_true', help='强制更新现有记录(不询问)')
|
||||
parser.add_argument('--create-domain', action='store_true', help='域名不存在时自动创建')
|
||||
parser.add_argument('--remark', default='', help='记录备注')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# 部署记录
|
||||
success = deploy_record(
|
||||
domain=args.domain,
|
||||
subdomain=args.subdomain,
|
||||
record_type=args.type,
|
||||
value=args.value,
|
||||
line=args.line,
|
||||
ttl=args.ttl,
|
||||
force=args.force,
|
||||
create_domain_flag=args.create_domain,
|
||||
remark=args.remark
|
||||
)
|
||||
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
163
scripts/deploy_service.py
Executable file
163
scripts/deploy_service.py
Executable file
@@ -0,0 +1,163 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
快速服务部署脚本
|
||||
一键部署常见服务的DNS配置(Web服务、API服务、CDN等)
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
from deploy_record import deploy_record, load_env
|
||||
|
||||
# 加载 .env
|
||||
load_env()
|
||||
|
||||
def deploy_web_service(domain, ip, include_wildcard=False, line="默认", ttl=600):
|
||||
"""部署Web服务(主域名 + www + 可选泛域名)"""
|
||||
print(f"\n{'='*50}")
|
||||
print(f"部署Web服务: {domain}")
|
||||
print(f"目标IP: {ip}")
|
||||
print(f"{'='*50}\n")
|
||||
|
||||
success_count = 0
|
||||
total_count = 2 + (1 if include_wildcard else 0)
|
||||
|
||||
# 1. 主域名 @
|
||||
if deploy_record(domain, '@', 'A', ip, line, ttl, force=True, remark='主域名'):
|
||||
success_count += 1
|
||||
|
||||
# 2. www子域名
|
||||
if deploy_record(domain, 'www', 'A', ip, line, ttl, force=True, remark='Web服务'):
|
||||
success_count += 1
|
||||
|
||||
# 3. 泛域名 *(可选)
|
||||
if include_wildcard:
|
||||
if deploy_record(domain, '*', 'A', ip, line, ttl, force=True, remark='泛域名'):
|
||||
success_count += 1
|
||||
|
||||
print(f"\n{'='*50}")
|
||||
print(f"Web服务部署完成: {success_count}/{total_count} 成功")
|
||||
print(f"{'='*50}\n")
|
||||
|
||||
return success_count == total_count
|
||||
|
||||
def deploy_api_service(domain, ip, subdomain="api", line="默认", ttl=600):
|
||||
"""部署API服务"""
|
||||
print(f"\n{'='*50}")
|
||||
print(f"部署API服务: {subdomain}.{domain}")
|
||||
print(f"目标IP: {ip}")
|
||||
print(f"{'='*50}\n")
|
||||
|
||||
success = deploy_record(domain, subdomain, 'A', ip, line, ttl, force=True, remark='API服务')
|
||||
|
||||
print(f"\n{'='*50}")
|
||||
print(f"API服务部署{'成功' if success else '失败'}")
|
||||
print(f"{'='*50}\n")
|
||||
|
||||
return success
|
||||
|
||||
def deploy_cdn_service(domain, cdn_cname, subdomain="cdn", line="默认", ttl=600):
|
||||
"""部署CDN加速"""
|
||||
print(f"\n{'='*50}")
|
||||
print(f"部署CDN加速: {subdomain}.{domain}")
|
||||
print(f"CNAME: {cdn_cname}")
|
||||
print(f"{'='*50}\n")
|
||||
|
||||
success = deploy_record(domain, subdomain, 'CNAME', cdn_cname, line, ttl, force=True, remark='CDN加速')
|
||||
|
||||
print(f"\n{'='*50}")
|
||||
print(f"CDN部署{'成功' if success else '失败'}")
|
||||
print(f"{'='*50}\n")
|
||||
|
||||
return success
|
||||
|
||||
def deploy_mx_service(domain, mx_server, priority=10, line="默认"):
|
||||
"""部署邮件服务(MX记录)"""
|
||||
print(f"\n{'='*50}")
|
||||
print(f"部署邮件服务: {domain}")
|
||||
print(f"MX服务器: {mx_server}")
|
||||
print(f"优先级: {priority}")
|
||||
print(f"{'='*50}\n")
|
||||
|
||||
# 注意: MX记录需要特殊处理,这里简化处理
|
||||
# 实际需要调用MX专用的创建接口
|
||||
print(f"提示: MX记录部署需要手动配置")
|
||||
print(f" 记录类型: MX")
|
||||
print(f" 主机记录: @")
|
||||
print(f" 记录值: {mx_server}")
|
||||
print(f" 优先级: {priority}")
|
||||
print(f" 线路: {line}\n")
|
||||
|
||||
return True
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='快速服务部署', formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog='''
|
||||
服务类型:
|
||||
web - Web服务(@ + www)
|
||||
api - API服务(api子域名)
|
||||
cdn - CDN加速(CNAME记录)
|
||||
mx - 邮件服务(MX记录)
|
||||
|
||||
示例:
|
||||
# 部署Web服务
|
||||
%(prog)s --domain example.com --service web --ip 1.2.3.4
|
||||
|
||||
# 部署Web服务(含泛域名)
|
||||
%(prog)s --domain example.com --service web --ip 1.2.3.4 --wildcard
|
||||
|
||||
# 部署API服务
|
||||
%(prog)s --domain example.com --service api --ip 1.2.3.5 --subdomain api
|
||||
|
||||
# 部署CDN
|
||||
%(prog)s --domain example.com --service cdn --cname cdn.example.com.cdn.dnsv1.com
|
||||
|
||||
# 部署邮件服务
|
||||
%(prog)s --domain example.com --service mx --mx-server mx.example.com --priority 10
|
||||
''')
|
||||
|
||||
parser.add_argument('--domain', required=True, help='域名(如: example.com)')
|
||||
parser.add_argument('--service', required=True, choices=['web', 'api', 'cdn', 'mx'], help='服务类型')
|
||||
parser.add_argument('--ip', help='目标IP地址(A记录)')
|
||||
parser.add_argument('--cname', help='CNAME目标域名')
|
||||
parser.add_argument('--mx-server', help='MX服务器地址')
|
||||
parser.add_argument('--priority', type=int, default=10, help='MX优先级(默认: 10)')
|
||||
parser.add_argument('--subdomain', default='api', help='API子域名(默认: api)')
|
||||
parser.add_argument('--cdn-subdomain', default='cdn', help='CDN子域名(默认: cdn)')
|
||||
parser.add_argument('--line', default='默认', help='线路(默认: 默认)')
|
||||
parser.add_argument('--ttl', type=int, default=600, help='TTL(秒, 默认: 600)')
|
||||
parser.add_argument('--wildcard', action='store_true', help='Web服务是否添加泛域名解析(*.domain)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
success = False
|
||||
|
||||
if args.service == 'web':
|
||||
if not args.ip:
|
||||
print("错误: Web服务需要指定 --ip 参数")
|
||||
sys.exit(1)
|
||||
success = deploy_web_service(args.domain, args.ip, args.wildcard, args.line, args.ttl)
|
||||
|
||||
elif args.service == 'api':
|
||||
if not args.ip:
|
||||
print("错误: API服务需要指定 --ip 参数")
|
||||
sys.exit(1)
|
||||
success = deploy_api_service(args.domain, args.ip, args.subdomain, args.line, args.ttl)
|
||||
|
||||
elif args.service == 'cdn':
|
||||
if not args.cname:
|
||||
print("错误: CDN服务需要指定 --cname 参数")
|
||||
sys.exit(1)
|
||||
success = deploy_cdn_service(args.domain, args.cname, args.cdn_subdomain, args.line, args.ttl)
|
||||
|
||||
elif args.service == 'mx':
|
||||
if not args.mx_server:
|
||||
print("错误: 邮件服务需要指定 --mx-server 参数")
|
||||
sys.exit(1)
|
||||
success = deploy_mx_service(args.domain, args.mx_server, args.priority, args.line)
|
||||
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
77
scripts/list_records.py
Executable file
77
scripts/list_records.py
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
DNS记录列表查询脚本
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
|
||||
from deploy_record import call_api, load_env
|
||||
|
||||
# 加载 .env
|
||||
load_env()
|
||||
|
||||
def list_records(domain, record_type=None, subdomain=None):
|
||||
"""查询DNS记录列表"""
|
||||
params = {"Domain": domain}
|
||||
|
||||
if record_type:
|
||||
params["RecordType"] = record_type
|
||||
if subdomain:
|
||||
params["Subdomain"] = subdomain
|
||||
|
||||
try:
|
||||
result = call_api("DescribeRecordList", params)
|
||||
records = result.get("Response", {}).get("RecordList", [])
|
||||
|
||||
if not records:
|
||||
print(f"\n没有找到记录")
|
||||
return []
|
||||
|
||||
print(f"\n{'='*80}")
|
||||
print(f"DNS记录列表: {domain}")
|
||||
print(f"{'='*80}\n")
|
||||
|
||||
# 表头
|
||||
print(f"{'主机记录':<20} {'类型':<10} {'记录值':<30} {'线路':<10} {'TTL':<8} {'状态':<6}")
|
||||
print(f"{'-'*80}")
|
||||
|
||||
# 记录列表
|
||||
for record in records:
|
||||
name = record.get("Name", "")
|
||||
record_type = record.get("Type", "")
|
||||
value = record.get("Value", "")
|
||||
line = record.get("Line", "")
|
||||
ttl = record.get("TTL", 0)
|
||||
status = "启用" if record.get("Enabled", 1) == 1 else "禁用"
|
||||
|
||||
# 截断过长的值
|
||||
if len(value) > 28:
|
||||
value = value[:28] + ".."
|
||||
|
||||
print(f"{name:<20} {record_type:<10} {value:<30} {line:<10} {ttl:<8} {status:<6}")
|
||||
|
||||
print(f"{'-'*80}")
|
||||
print(f"总计: {len(records)} 条记录\n")
|
||||
|
||||
return records
|
||||
|
||||
except Exception as e:
|
||||
print(f"查询失败: {e}")
|
||||
return []
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='查询DNS记录列表')
|
||||
|
||||
parser.add_argument('--domain', required=True, help='域名(如: example.com)')
|
||||
parser.add_argument('--type', help='筛选记录类型')
|
||||
parser.add_argument('--subdomain', help='筛选子域名')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
list_records(args.domain, args.type, args.subdomain)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user