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:
OpenClaw
2026-03-01 11:44:05 +08:00
commit 7abea390ad
15 changed files with 2323 additions and 0 deletions

5
.env.example Normal file
View File

@@ -0,0 +1,5 @@
# 腾讯云DNSPod API密钥配置
# 获取方式: https://console.cloud.tencent.com/cam/capi
TENCENT_SECRET_ID=你的SecretId
TENCENT_SECRET_KEY=你的SecretKey

28
.gitignore vendored Normal file
View File

@@ -0,0 +1,28 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
# 虚拟环境
venv/
env/
ENV/
# IDE
.vscode/
.idea/
*.swp
*.swo
# 敏感信息
.env
*.key
# 日志
*.log
# 临时文件
.DS_Store
Thumbs.db

200
ENV_SETUP.md Normal file
View File

@@ -0,0 +1,200 @@
# 环境变量配置说明
## .env 文件(推荐方式)
`.env` 文件用于存储敏感配置信息,如API密钥。该文件**不会被提交到Git**(已添加到 `.gitignore`)。
### 配置步骤
1. **复制示例配置**
```bash
cp .env.example .env
```
2. **编辑 .env 文件**
```bash
# 使用你喜欢的编辑器
vim .env
# 或
nano .env
# 或
code .env
```
3. **填入你的腾讯云API密钥**
```bash
TENCENT_SECRET_ID=你的SecretId
TENCENT_SECRET_KEY=你的SecretKey
```
4. **保存文件**
### 获取API密钥
访问腾讯云控制台: https://console.cloud.tencent.com/cam/capi
- 点击「新建密钥」或查看现有密钥
- 复制 `SecretId` 和 `SecretKey`
- ⚠️ **重要:** SecretKey只在创建时显示一次,请妥善保存!
## 环境变量方式
如果不使用 `.env` 文件,可以直接设置系统环境变量。
### Linux/Mac
**临时设置(当前会话有效):**
```bash
export TENCENT_SECRET_ID="你的SecretId"
export TENCENT_SECRET_KEY="你的SecretKey"
```
**永久设置(添加到 ~/.bashrc 或 ~/.zshrc):**
```bash
echo 'export TENCENT_SECRET_ID="你的SecretId"' >> ~/.bashrc
echo 'export TENCENT_SECRET_KEY="你的SecretKey"' >> ~/.bashrc
source ~/.bashrc
```
### Windows
**PowerShell临时设置:**
```powershell
$env:TENCENT_SECRET_ID="你的SecretId"
$env:TENCENT_SECRET_KEY="你的SecretKey"
```
**PowerShell永久设置:**
```powershell
[System.Environment]::SetEnvironmentVariable('TENCENT_SECRET_ID', '你的SecretId', 'User')
[System.Environment]::SetEnvironmentVariable('TENCENT_SECRET_KEY', '你的SecretKey', 'User')
```
**CMD临时设置:**
```cmd
set TENCENT_SECRET_ID=你的SecretId
set TENCENT_SECRET_KEY=你的SecretKey
```
## 验证配置
### 方式1: 查看 .env 文件
```bash
cat .env
```
### 方式2: 查看环境变量
```bash
# Linux/Mac
echo $TENCENT_SECRET_ID
# Windows PowerShell
echo $env:TENCENT_SECRET_ID
# Windows CMD
echo %TENCENT_SECRET_ID%
```
### 方式3: 测试连接
```bash
python scripts/list_records.py --domain example.com
```
如果成功,将显示域名记录列表(可能为空)。
## 安全建议
### ✅ 推荐做法
1. **使用 .env 文件** - 方便管理,不会被Git跟踪
2. **使用 .env.example** - 提供配置模板,不含真实密钥
3. **定期轮换密钥** - 定期更换API密钥提高安全性
4. **使用子账号** - 创建独立的子账号,只授予必要权限
5. **设置IP白名单** - 在腾讯云CAM中限制API调用来源IP
### ❌ 避免做法
1. ❌ 不要将密钥硬编码在代码中
2. ❌ 不要在Git仓库中提交 .env 文件
3. ❌ 不要在生产环境使用默认密钥
4. ❌ 不要在公开场合分享密钥
5. ❌ 不要使用弱密钥或重复使用密钥
## 常见问题
### Q1: .env 文件不生效?
**原因:** 可能是文件权限问题或路径错误。
**解决:**
```bash
# 确认文件存在
ls -la .env
# 确认文件内容
cat .env
# 确认文件格式(无BOM,Unix换行符)
file .env
```
### Q2: 还是提示找不到密钥?
**解决:** 检查 `.env` 文件是否在项目根目录:
```bash
pwd # 应该在 tencent-dnspod 目录
ls .env # 应该能看到 .env 文件
```
### Q3: Git提交时意外包含了 .env?
**解决:**
```bash
# 1. 从Git中移除(但保留本地文件)
git rm --cached .env
# 2. 确认 .gitignore 包含 .env
echo ".env" >> .gitignore
# 3. 提交修改
git add .gitignore
git commit -m "Remove .env from tracking"
# 4. 更换已泄露的密钥!
# 访问: https://console.cloud.tencent.com/cam/capi
```
### Q4: 多个项目需要不同的密钥?
**解决:** 每个项目使用独立的 .env 文件:
```bash
# 项目A
cd /path/to/project-a
echo "TENCENT_SECRET_ID=项目A的ID" > .env
# 项目B
cd /path/to/project-b
echo "TENCENT_SECRET_ID=项目B的ID" > .env
```
## 权限管理建议
### 创建专用子账号
1. 访问: https://console.cloud.tencent.com/cam
2. 创建子账号,只授予DNSPod权限
3. 为子账号创建API密钥
4. 使用子账号密钥而非主账号密钥
### 最小权限原则
只授予必要的权限:
- DNSPod只读权限(查询记录)
- DNSPod读写权限(管理记录)
- 避免授予所有产品的访问权限
## 参考文档
- **腾讯云访问管理(CAM):** https://cloud.tencent.com/document/product/598
- **API密钥管理:** https://console.cloud.tencent.com/cam/capi
- **子账号权限:** https://console.cloud.tencent.com/cam/user

339
INSTALL.md Normal file
View File

@@ -0,0 +1,339 @@
# DNSPod Skill 安装指南
## 概述
本Skill已针对**域名快速部署**场景优化,提供以下核心功能:
**单条记录快速部署** - 秒级添加/更新DNS记录
**批量部署** - 从JSON配置文件一键部署多条记录
**服务快速部署** - 一键配置Web/API/CDN服务
**自动化友好** - 支持DevOps CI/CD集成
## 核心脚本
### 1. `deploy_record.py` - 单条记录部署
```bash
# 添加A记录
python scripts/deploy_record.py \
--domain example.com \
--subdomain www \
--type A \
--value 1.2.3.4
# 强制更新
python scripts/deploy_record.py \
--domain example.com \
--subdomain www \
--type A \
--value 1.2.3.5 \
--force
```
### 2. `batch_deploy.py` - 批量部署
```bash
# 从配置文件批量部署
python scripts/batch_deploy.py \
--domain example.com \
--config examples/dns-config.json
```
### 3. `deploy_service.py` - 服务快速部署
```bash
# 部署Web服务(@ + www)
python scripts/deploy_service.py \
--domain example.com \
--service web \
--ip 1.2.3.4
# 部署API服务
python scripts/deploy_service.py \
--domain example.com \
--service api \
--ip 1.2.3.5
```
### 4. `list_records.py` - 查询记录
```bash
python scripts/list_records.py --domain example.com
```
### 5. `delete_record.py` - 删除记录
```bash
python scripts/delete_record.py \
--domain example.com \
--subdomain www \
--type A
```
## 安装步骤
### 步骤1: 获取腾讯云API密钥
1. 访问: https://console.cloud.tencent.com/cam/capi
2. 创建或查看密钥(包含 `SecretId``SecretKey`)
3. ⚠️ **重要:** SecretKey只在创建时显示,请立即保存!
### 步骤2: 配置API密钥
有两种方式配置API密钥:
#### 方式1: 使用 .env 文件(推荐,更安全)
```bash
# 1. 复制示例配置
cp .env.example .env
# 2. 编辑 .env 文件,填入你的密钥
# TENCENT_SECRET_ID=你的SecretId
# TENCENT_SECRET_KEY=你的SecretKey
# 3. 确保 .env 文件不会被提交到Git(已添加到 .gitignore)
```
#### 方式2: 设置环境变量
**Linux/Mac (添加到 ~/.bashrc 或 ~/.zshrc):**
```bash
export TENCENT_SECRET_ID="你的SecretId"
export TENCENT_SECRET_KEY="你的SecretKey"
source ~/.bashrc # 重新加载
```
**Windows PowerShell:**
```powershell
[System.Environment]::SetEnvironmentVariable('TENCENT_SECRET_ID', '你的SecretId', 'User')
[System.Environment]::SetEnvironmentVariable('TENCENT_SECRET_KEY', '你的SecretKey', 'User')
```
**验证配置:**
```bash
# 方式1: 查看 .env 文件
cat .env
# 方式2: 查看环境变量
# Linux/Mac
echo $TENCENT_SECRET_ID
# Windows PowerShell
echo $env:TENCENT_SECRET_ID
```
### 步骤3: 安装Python依赖
```bash
cd tencent-dnspod
pip install -r requirements.txt
```
依赖项:
- `requests>=2.28.0` (HTTP请求库)
### 步骤4: 测试连接
```bash
python scripts/list_records.py --domain example.com
```
如果成功,将显示域名下的DNS记录列表(可能为空)。
## 典型使用场景
### 场景1: 新服务快速上线
**需求:** 将新Web服务部署到 1.2.3.4
```bash
# 一键部署主域名 + www
python scripts/deploy_service.py \
--domain example.com \
--service web \
--ip 1.2.3.4
```
**结果:**
- ✅ example.com → 1.2.3.4
- ✅ www.example.com → 1.2.3.4
### 场景2: 多环境部署
**配置文件:** `dns-config.json`
```json
{
"records": [
{"subdomain": "www", "type": "A", "value": "1.2.3.4", "line": "默认", "remark": "生产"},
{"subdomain": "dev", "type": "A", "value": "1.2.3.5", "line": "默认", "remark": "开发"},
{"subdomain": "test", "type": "A", "value": "1.2.3.6", "line": "默认", "remark": "测试"}
]
}
```
**批量部署:**
```bash
python scripts/batch_deploy.py \
--domain example.com \
--config dns-config.json
```
### 场景3: CDN加速配置
```bash
# 添加CNAME记录指向CDN
python scripts/deploy_record.py \
--domain example.com \
--subdomain cdn \
--type CNAME \
--value cdn.example.com.cdn.dnsv1.com
```
### 场景4: 智能DNS(电信/联通线路)
```bash
# 电信用户访问1.2.3.4
python scripts/deploy_record.py \
--domain example.com \
--subdomain www \
--type A \
--value 1.2.3.4 \
--line "电信"
# 联通用户访问5.6.7.8
python scripts/deploy_record.py \
--domain example.com \
--subdomain www \
--type A \
--value 5.6.7.8 \
--line "联通"
```
### 场景5: CI/CD集成
**示例: Jenkins/GitLab CI**
```bash
# 部署时自动更新DNS
pip install -r tencent-dnspod/requirements.txt
# 部署新版本
docker push registry.example.com/myapp:v1.2.3
# 更新DNS
python tencent-dnspod/scripts/deploy_record.py \
--domain example.com \
--subdomain app \
--type A \
--value $(kubectl get svc myapp -o jsonpath='{.status.loadBalancer.ingress[0].ip}') \
--force
```
## 高级功能
### 泛域名解析
```bash
# 部署Web服务时添加泛域名
python scripts/deploy_service.py \
--domain example.com \
--service web \
--ip 1.2.3.4 \
--wildcard
```
**结果:**
- ✅ example.com → 1.2.3.4
- ✅ www.example.com → 1.2.3.4
- ✅ *.example.com → 1.2.3.4
### TTL设置
```bash
# 测试环境使用较短TTL(快速生效)
python scripts/deploy_record.py \
--domain example.com \
--subdomain test \
--type A \
--value 1.2.3.10 \
--ttl 60
```
### 记录备注
```bash
# 添加备注方便管理
python scripts/deploy_record.py \
--domain example.com \
--subdomain api \
--type A \
--value 1.2.3.5 \
--remark "后端API服务"
```
## 常见问题
### Q1: 认证失败怎么办?
**错误:** `AuthFailure`
**解决:**
1. 检查环境变量是否正确设置
2. 确认SecretId和SecretKey匹配
3. 检查系统时间是否准确
### Q2: 域名不存在?
**错误:** `ResourceNotFound.Domain`
**解决:** 使用 `--create-domain` 参数自动创建:
```bash
python scripts/deploy_record.py \
--domain example.com \
--subdomain www \
--type A \
--value 1.2.3.4 \
--create-domain
```
### Q3: 记录已存在?
**错误:** `RecordAlreadyExists`
**解决:** 使用 `--force` 参数强制更新:
```bash
python scripts/deploy_record.py \
--domain example.com \
--subdomain www \
--type A \
--value 1.2.3.5 \
--force
```
### Q4: API频率限制?
**错误:** `RequestLimitExceeded`
**解决:** 批量部署时增加延迟:
```bash
python scripts/batch_deploy.py \
--domain example.com \
--config dns-config.json \
--delay 1.0 # 改为1秒延迟
```
## 文档索引
- **API认证:** [references/api-auth.md](references/api-auth.md)
- **错误处理:** [references/common-errors.md](references/common-errors.md)
- **完整文档:** [SKILL.md](SKILL.md)
## 技术支持
- **DNSPod文档:** https://cloud.tencent.com/document/product/1427/56152
- **API参考:** https://cloud.tencent.com/document/api/1427/56194
- **控制台:** https://console.dnspod.cn
## 更新日志
### v1.0.0 (2026-03-01)
- ✅ 单条记录部署
- ✅ 批量部署
- ✅ 服务快速部署
- ✅ 记录查询和删除
- ✅ 完整错误处理

258
README.md Normal file
View File

@@ -0,0 +1,258 @@
# 腾讯云DNSPod域名快速部署 Skill
这是一个用于快速部署和自动化管理腾讯云DNSPod域名解析的OpenClaw Skill。
## 功能特性
**单条记录快速部署** - 添加/更新A、CNAME、MX等记录
**批量部署** - 从JSON配置文件批量创建记录
**服务快速部署** - 一键部署Web、API、CDN等服务
**记录查询** - 查看域名下的所有解析记录
**记录删除** - 删除不需要的DNS记录
**自动域名创建** - 部署时自动创建不存在的域名
## 安装
### 1. 安装依赖
```bash
cd tencent-dnspod
pip install -r requirements.txt
```
### 2. 配置认证密钥
访问腾讯云控制台获取API密钥:
https://console.cloud.tencent.com/cam/capi
有两种配置方式:
**方式1: 使用 .env 文件(推荐)**
```bash
cp .env.example .env
# 编辑 .env 文件,填入你的密钥
```
**方式2: 设置环境变量**
```bash
export TENCENT_SECRET_ID="你的SecretId"
export TENCENT_SECRET_KEY="你的SecretKey"
```
### 3. 验证安装
```bash
python scripts/list_records.py --domain example.com
```
## 快速使用
### 场景1: 部署Web服务
一键部署主域名和www子域名:
```bash
python scripts/deploy_service.py \
--domain example.com \
--service web \
--ip 1.2.3.4
```
带泛域名解析:
```bash
python scripts/deploy_service.py \
--domain example.com \
--service web \
--ip 1.2.3.4 \
--wildcard
```
### 场景2: 部署API服务
```bash
python scripts/deploy_service.py \
--domain example.com \
--service api \
--ip 1.2.3.5 \
--subdomain api
```
### 场景3: 批量部署
从配置文件批量部署:
```bash
python scripts/batch_deploy.py \
--domain example.com \
--config examples/dns-config.json
```
### 场景4: 单条记录管理
添加A记录:
```bash
python scripts/deploy_record.py \
--domain example.com \
--subdomain www \
--type A \
--value 1.2.3.4
```
添加CNAME记录(CDN):
```bash
python scripts/deploy_record.py \
--domain example.com \
--subdomain cdn \
--type CNAME \
--value cdn.example.com.cdn.dnsv1.com
```
强制更新现有记录:
```bash
python scripts/deploy_record.py \
--domain example.com \
--subdomain www \
--type A \
--value 1.2.3.5 \
--force
```
### 场景5: 查询和删除
查询所有记录:
```bash
python scripts/list_records.py --domain example.com
```
删除记录:
```bash
python scripts/delete_record.py \
--domain example.com \
--subdomain www \
--type A
```
## 目录结构
```
tencent-dnspod/
├── SKILL.md # Skill说明文档
├── README.md # 本文件
├── requirements.txt # Python依赖
├── scripts/ # 脚本目录
│ ├── deploy_record.py # 单条记录部署
│ ├── batch_deploy.py # 批量部署
│ ├── deploy_service.py # 服务快速部署
│ ├── list_records.py # 记录查询
│ └── delete_record.py # 记录删除
├── references/ # 参考文档
│ ├── api-auth.md # API认证说明
│ └── common-errors.md # 常见错误处理
└── examples/ # 示例配置
└── dns-config.json # 批量部署配置示例
```
## 配置文件格式
批量部署配置文件(JSON格式):
```json
{
"records": [
{
"subdomain": "@",
"type": "A",
"value": "1.2.3.4",
"line": "默认",
"ttl": 600,
"remark": "主域名"
},
{
"subdomain": "www",
"type": "A",
"value": "1.2.3.4",
"line": "默认",
"remark": "Web服务"
},
{
"subdomain": "api",
"type": "A",
"value": "1.2.3.5",
"line": "电信",
"remark": "API服务"
},
{
"subdomain": "cdn",
"type": "CNAME",
"value": "cdn.example.com.cdn.dnsv1.com",
"line": "默认",
"remark": "CDN加速"
}
]
}
```
## 支持的记录类型
| 类型 | 说明 | 示例值 |
|------|------|--------|
| A | IPv4地址 | 1.2.3.4 |
| AAAA | IPv6地址 | 2001:db8::1 |
| CNAME | 别名 | cdn.example.com |
| MX | 邮件服务器 | mx.example.com |
| TXT | 文本记录 | "v=spf1 include:_spf.example.com ~all" |
| NS | 域名服务器 | ns1.example.com |
## 常用线路
- `默认` - 默认线路
- `电信` - 电信用户
- `联通` - 联通用户
- `移动` - 移动用户
- `境外` - 海外用户
- `搜索引擎` - 爬虫线路
## 最佳实践
1. **部署前测试** - 先在测试域名验证配置
2. **设置合理TTL** - 生产环境600s,测试环境60s
3. **使用批量部署** - 多条记录用配置文件管理
4. **添加记录备注** - 方便后续维护
5. **分环境管理** - 使用不同子域名(dev/stage/prod)
6. **注意API限频** - 批量操作时控制请求频率
## 常见问题
### 1. 认证失败
```
错误: AuthFailure
解决: 检查环境变量 TENCENT_SECRET_ID 和 TENCENT_SECRET_KEY
```
### 2. 域名不存在
```
错误: ResourceNotFound.Domain
解决: 使用 --create-domain 参数自动创建域名
```
### 3. 记录已存在
```
错误: RecordAlreadyExists
解决: 使用 --force 参数强制更新
```
### 4. API频率限制
```
错误: RequestLimitExceeded
解决: 批量操作时增加 --delay 参数(默认0.5秒)
```
详细错误处理见: [references/common-errors.md](references/common-errors.md)
## 技术支持
- **DNSPod API文档:** https://cloud.tencent.com/document/product/1427/56152
- **腾讯云SDK:** https://cloud.tencent.com/document/sdk
- **DNSPod控制台:** https://console.dnspod.cn
## 许可证
MIT License
## 贡献
欢迎提交Issue和Pull Request!

259
SKILL.md Normal file
View File

@@ -0,0 +1,259 @@
---
name: tencent-dnspod
description: |
腾讯云DNSPod域名快速部署工具。用于自动化部署DNS记录、批量配置域名解析、快速上线服务。
当用户需要: (1) 快速添加DNS记录部署新服务, (2) 批量配置A/CNAME/MX等记录,
(3) 域名解析自动化管理, (4) DevOps域名部署流程时触发。
---
# 腾讯云DNSPod域名快速部署
## 快速开始
### 1. 配置认证
获取API密钥: https://console.cloud.tencent.com/cam/capi
**方式1: 使用 .env 文件(推荐,更安全):**
```bash
cp .env.example .env
# 编辑 .env 文件,填入你的密钥
```
**方式2: 设置环境变量:**
```bash
export TENCENT_SECRET_ID="你的SecretId"
export TENCENT_SECRET_KEY="你的SecretKey"
```
### 2. 核心命令
**添加单条记录(最常用):**
```bash
python scripts/deploy_record.py \
--domain example.com \
--subdomain www \
--type A \
--value 1.2.3.4 \
--line "默认"
```
**批量部署(从配置文件):**
```bash
python scripts/batch_deploy.py \
--domain example.com \
--config dns-config.json
```
**快速配置服务(常用组合):**
```bash
python scripts/deploy_service.py \
--domain example.com \
--service web \
--ip 1.2.3.4
```
**删除记录:**
```bash
python scripts/delete_record.py \
--domain example.com \
--subdomain www
```
## 域名快速部署流程
### 场景1: 部署新Web服务
```bash
# 一键部署www和主域名
python scripts/deploy_service.py \
--domain example.com \
--service web \
--ip 1.2.3.4
# 自动创建:
# - example.com (A记录)
# - www.example.com (A记录)
# - *.example.com (泛域名A记录,可选)
```
### 场景2: 部署API服务
```bash
# 部署api子域名
python scripts/deploy_record.py \
--domain example.com \
--subdomain api \
--type A \
--value 1.2.3.4
```
### 场景3: 配置邮件服务
```bash
# 一键配置MX记录
python scripts/deploy_mx.py \
--domain example.com \
--mx-server mx.example.com \
--priority 10
```
### 场景4: CDN加速配置
```bash
# 添加CNAME指向CDN
python scripts/deploy_record.py \
--domain example.com \
--subdomain cdn \
--type CNAME \
--value cdn.example.com.cdn.dnsv1.com
```
### 场景5: 批量部署多个环境
```bash
# 从配置文件批量创建
python scripts/batch_deploy.py \
--domain example.com \
--config deployments/dev.json
# 配置文件示例见下文
```
## 记录类型说明
| 类型 | 用途 | 示例 |
|------|------|------|
| A | 指向IPv4地址 | www → 1.2.3.4 |
| CNAME | 指向域名别名 | www → cdn.example.com |
| MX | 邮件服务器 | @ → mx.example.com |
| TXT | 文本记录(验证/SPF) | @ → "v=spf1 include:_spf.example.com ~all" |
| AAAA | 指向IPv6地址 | www → 2001:db8::1 |
## 批量部署配置文件格式
`dns-config.json`:
```json
{
"records": [
{
"subdomain": "@",
"type": "A",
"value": "1.2.3.4",
"line": "默认"
},
{
"subdomain": "www",
"type": "A",
"value": "1.2.3.4",
"line": "默认"
},
{
"subdomain": "api",
"type": "A",
"value": "1.2.3.5",
"line": "电信"
},
{
"subdomain": "cdn",
"type": "CNAME",
"value": "cdn.example.com.cdn.dnsv1.com",
"line": "默认"
}
]
}
```
使用批量配置:
```bash
python scripts/batch_deploy.py \
--domain example.com \
--config dns-config.json
```
## 线路类型说明
常用线路值:
- `默认` - 默认线路
- `电信` - 电信用户
- `联通` - 联通用户
- `移动` - 移动用户
- `境外` - 海外用户
- `搜索引擎` - 爬虫线路
查看完整线路列表:
```bash
python scripts/list_lines.py --domain example.com
```
## 常见问题
### 1. 记录冲突
如果记录已存在,脚本会提示是否更新。使用 `--force` 强制更新。
### 2. 批量操作失败
批量操作会继续执行后续记录,最后汇总结果。检查输出中的 `[FAIL]` 标记。
### 3. API频率限制
默认限制: 20次/秒。大批量部署时会自动限速。
### 4. 域名未添加
如果域名未添加到DNSPod,使用 `--create-domain` 自动创建:
```bash
python scripts/deploy_record.py \
--domain example.com \
--create-domain \
--subdomain www \
--type A \
--value 1.2.3.4
```
## API错误处理
详细错误说明见 [common-errors.md](references/common-errors.md)
## 高级功能
### 创建快照(部署前备份)
```bash
python/scripts/snapshot.py \
--domain example.com \
--action create \
--name "部署前备份"
```
### 回滚快照
```bash
python scripts/snapshot.py \
--domain example.com \
--action rollback \
--snapshot-id <snapshot-id>
```
### 查看部署历史
```bash
python scripts/list_records.py \
--domain example.com \
--show-changes
```
## 最佳实践
1. **部署前备份** - 重大部署前先创建快照
2. **分环境管理** - 使用不同子域名(dev/stage/prod)
3. **TTL设置** - 生产环境600s,测试环境60s
4. **批量测试** - 先在测试域名验证配置,再批量部署
5. **记录备注** - 添加 `--remark` 标记记录用途
## 示例: 完整部署流程
```bash
# 1. 部署前备份
python scripts/snapshot.py --domain example.com --action create --name "部署前"
# 2. 批量部署
python scripts/batch_deploy.py \
--domain example.com \
--config dns-config.json
# 3. 验证部署
python scripts/list_records.py --domain example.com
# 4. 测试解析
dig www.example.com
```

44
examples/dns-config.json Normal file
View File

@@ -0,0 +1,44 @@
{
"records": [
{
"subdomain": "@",
"type": "A",
"value": "1.2.3.4",
"line": "默认",
"ttl": 600,
"remark": "主域名"
},
{
"subdomain": "www",
"type": "A",
"value": "1.2.3.4",
"line": "默认",
"ttl": 600,
"remark": "Web服务"
},
{
"subdomain": "api",
"type": "A",
"value": "1.2.3.5",
"line": "默认",
"ttl": 600,
"remark": "API服务"
},
{
"subdomain": "cdn",
"type": "CNAME",
"value": "cdn.example.com.cdn.dnsv1.com",
"line": "默认",
"ttl": 600,
"remark": "CDN加速"
},
{
"subdomain": "test",
"type": "A",
"value": "1.2.3.10",
"line": "默认",
"ttl": 60,
"remark": "测试环境"
}
]
}

180
references/api-auth.md Normal file
View File

@@ -0,0 +1,180 @@
# 腾讯云API认证说明
## 概述
DNSPod API使用腾讯云统一的API v3签名算法,基于HMAC-SHA256进行请求签名认证。
## 获取密钥
### 1. 访问API密钥管理页面
https://console.cloud.tencent.com/cam/capi
### 2. 创建密钥
- 点击「新建密钥」或「访问密钥」
- 系统生成 `SecretId``SecretKey`
### 3. 保存密钥
⚠️ **重要:** SecretKey只在创建时显示一次,请妥善保存!
### 4. 设置环境变量
**Linux/Mac (Bash/Zsh):**
```bash
# 添加到 ~/.bashrc 或 ~/.zshrc
export TENCENT_SECRET_ID="你的SecretId"
export TENCENT_SECRET_KEY="你的SecretKey"
# 重新加载配置
source ~/.bashrc # 或 source ~/.zshrc
```
**Windows (PowerShell):**
```powershell
# 添加到环境变量
[System.Environment]::SetEnvironmentVariable('TENCENT_SECRET_ID', '你的SecretId', 'User')
[System.Environment]::SetEnvironmentVariable('TENCENT_SECRET_KEY', '你的SecretKey', 'User')
# 临时设置(当前会话有效)
$env:TENCENT_SECRET_ID="你的SecretId"
$env:TENCENT_SECRET_KEY="你的SecretKey"
```
**验证环境变量:**
```bash
# Linux/Mac
echo $TENCENT_SECRET_ID
# Windows PowerShell
echo $env:TENCENT_SECRET_ID
```
## 签名算法详解
### 1. 构造规范请求串
**格式:**
```
HTTPRequestMethod + '\n' +
CanonicalURI + '\n' +
CanonicalQueryString + '\n' +
CanonicalHeaders + '\n' +
SignedHeaders + '\n' +
HexEncode(Hash(RequestPayload))
```
**示例:**
```
POST
/
content-type:application/json
host:dnspod.tencentcloudapi.com
content-type;host
356f92b5d0373084a2bc07df8267b0ab
```
### 2. 构造待签名字符串
**格式:**
```
Algorithm + '\n' +
RequestTimestamp + '\n' +
CredentialScope + '\n' +
HexEncode(Hash(CanonicalRequest))
```
**示例:**
```
TC3-HMAC-SHA256
1666666666
2021-03-23/dnspod/tc3_request
5c9d88e6d4c4d4c4d4c4d4c4d4c4d4c4d4c4d4c4d4c4d4c4d4c4d4c4d4c4d
```
### 3. 计算签名
使用 HMAC-SHA256 算法分三次计算:
```python
secret_date = HMAC_SHA256("TC3" + SecretKey, Date)
secret_service = HMAC_SHA256(secret_date, Service)
secret_signing = HMAC_SHA256(secret_service, "tc3_request")
signature = HMAC_SHA256(secret_signing, StringToSign)
```
### 4. 构造Authorization头
**格式:**
```
Algorithm Credential={SecretId}/{CredentialScope}, SignedHeaders={SignedHeaders}, Signature={Signature}
```
**示例:**
```
TC3-HMAC-SHA256 Credential=AKIDxxxxxxxx/2021-03-23/dnspod/tc3_request, SignedHeaders=content-type;host, Signature=5c9d88e6d4c4d4c4d4c4d4c4d4c4d4c4d4c4d4c4d4c4d4c4d4c4d4c4d4c4d
```
## 完整请求示例
### 请求头
```http
POST / HTTP/1.1
Host: dnspod.tencentcloudapi.com
Content-Type: application/json
Authorization: TC3-HMAC-SHA256 Credential=AKIDxxxxxxxx/2021-03-23/dnspod/tc3_request, SignedHeaders=content-type;host, Signature=xxxxxxxx
X-TC-Action: DescribeRecordList
X-TC-Timestamp: 1666666666
X-TC-Version: 2021-03-23
X-TC-Region: ap-guangzhou
```
### 请求体
```json
{
"Domain": "example.com"
}
```
## 请求参数说明
| 参数 | 说明 | 示例 |
|------|------|------|
| X-TC-Action | 操作名称 | CreateRecord |
| X-TC-Version | API版本 | 2021-03-23 |
| X-TC-Timestamp | 时间戳(秒) | 1666666666 |
| X-TC-Region | 地域 | ap-guangzhou |
| Authorization | 签名信息 | 见上文 |
## 地域说明
DNSPod API支持的地域:
- **ap-guangzhou** (广州,推荐)
- **ap-shanghai** (上海)
- **ap-beijing** (北京)
- **ap-chengdu** (成都)
建议选择就近地域以降低延迟。
## 安全建议
### 1. 密钥安全
- ⚠️ 不要将密钥硬编码在代码中
- ⚠️ 不要在Git仓库中提交密钥
- ✓ 使用环境变量或配置文件
- ✓ 定期轮换密钥
### 2. 权限管理
- 为不同应用创建独立的子账号
- 只授予必要的权限(最小权限原则)
- 定期审计密钥使用情况
### 3. IP白名单
- 在腾讯云访问管理(CAM)中设置IP白名单
- 限制只有特定IP才能调用API
## 参考文档
- **API签名文档:** https://cloud.tencent.com/document/product/1427/56152
- **访问管理(CAM):** https://cloud.tencent.com/document/product/598
- **SDK示例:** https://cloud.tencent.com/document/sdk

192
references/common-errors.md Normal file
View File

@@ -0,0 +1,192 @@
# DNSPod API常见错误处理
## 错误码说明
### 认证相关
#### AuthFailure
**错误:** 签名验证失败
**原因:**
- SecretId或SecretKey错误
- 签名算法错误
- 请求时间戳偏差过大
**解决方案:**
1. 检查环境变量 `TENCENT_SECRET_ID``TENCENT_SECRET_KEY`
2. 确认密钥未过期且状态正常
3. 检查系统时间是否准确(误差不超过5分钟)
#### AuthFailure.SecretIdNotFound
**错误:** SecretId不存在
**原因:**
- SecretId输入错误
- 密钥已被删除
**解决方案:**
- 访问 https://console.cloud.tencent.com/cam/capi 重新获取
### 域名相关
#### ResourceNotFound.Domain
**错误:** 域名不存在
**原因:**
- 域名未添加到DNSPod
- 域名名称输入错误
**解决方案:**
- 检查域名拼写
- 使用 `--create-domain` 自动创建域名
- 手动在DNSPod控制台添加域名
#### ResourceNotFound.DomainOffline
**错误:** 域名已停用
**原因:**
- 域名已被禁用
**解决方案:**
- 登录DNSPod控制台重新启用域名
### 记录相关
#### InvalidParameter.RecordAlreadyExists
**错误:** 记录已存在
**原因:**
- 相同的主机记录、类型、线路的记录已存在
**解决方案:**
- 使用 `--force` 参数强制更新
- 先删除现有记录再创建
#### InvalidParameter.RecordNotFound
**错误:** 记录不存在
**原因:**
- RecordId错误
- 记录已被删除
**解决方案:**
- 使用 `list_records.py` 查询正确的记录ID
#### InvalidParameter.RecordValueInvalid
**错误:** 记录值格式错误
**原因:**
- IP地址格式错误
- CNAME目标域名格式错误
- 记录值与类型不匹配
**解决方案:**
- A记录值必须是IPv4地址(如: 1.2.3.4)
- CNAME记录值必须是域名(如: cdn.example.com)
- MX记录值格式: `mx.example.com` (优先级单独设置)
### 限频相关
#### RequestLimitExceeded
**错误:** 请求频率超限
**原因:**
- API调用超过频率限制(默认: 20次/秒)
**解决方案:**
- 降低请求频率
- 批量操作时增加 `--delay` 参数
- 使用批量API代替循环调用
#### LimitExceeded.DomainRecord
**错误:** 域名记录数超限
**原因:**
- 该域名下的记录数超过套餐限制
**解决方案:**
- 删除不需要的记录
- 升级DNSPod套餐
### 参数相关
#### InvalidParameter
**错误:** 参数错误
**原因:**
- 必填参数缺失
- 参数格式错误
- 参数值超出范围
**解决方案:**
- 检查命令行参数拼写
- 确认参数值格式正确
- 查看API文档确认参数要求
#### MissingParameter
**错误:** 缺少必填参数
**原因:**
- 未提供必要的参数
**解决方案:**
- 使用 `--help` 查看必填参数
- 补充完整的参数
### 其他常见错误
#### UnknownParameter
**错误:** 未知参数
**原因:**
- 传递了不支持的参数
**解决方案:**
- 检查参数名称拼写
- 确认API版本支持该参数
#### UnsupportedOperation
**错误:** 不支持的操作
**原因:**
- 当前套餐不支持该功能
- 域名状态不允许该操作
**解决方案:**
- 升级DNSPod套餐
- 检查域名状态
## 调试技巧
### 1. 开启详细日志
在脚本中添加调试输出:
```python
import logging
logging.basicConfig(level=logging.DEBUG)
```
### 2. 打印API响应
查看完整的API错误信息:
```python
print(json.dumps(result, indent=2, ensure_ascii=False))
```
### 3. 验证参数
在调用API前打印参数:
```python
print(f"参数: {params}")
```
### 4. 测试连通性
检查网络连接:
```bash
ping dnspod.tencentcloudapi.com
curl -I https://dnspod.tencentcloudapi.com
```
## 获取帮助
- **API文档:** https://cloud.tencent.com/document/product/1427/56152
- **错误码参考:** https://cloud.tencent.com/document/product/1427/56190
- **工单系统:** https://console.cloud.tencent.com/workorder
- **技术支持:** 95716 (DNSPod技术热线)

2
requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
requests>=2.28.0
python-dotenv>=1.0.0

171
scripts/batch_deploy.py Executable file
View 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
View 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
View 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
View 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
View 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()