# 功能实现

- 增加打包工具
- 优化docker打包结构
- 增加首次强制刷新
This commit is contained in:
yshtcn
2024-06-03 22:55:03 +08:00
parent dd4eb1ec44
commit aba948bc2b
4 changed files with 123 additions and 23 deletions

View File

@@ -3,28 +3,33 @@ import json
import requests import requests
import time import time
import shutil import shutil
import logging
from requests.exceptions import RequestException from requests.exceptions import RequestException
from aliyunsdkcore.client import AcsClient from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException, ServerException from aliyunsdkcore.acs_exception.exceptions import ClientException, ServerException
from aliyunsdkecs.request.v20140526 import DescribeSecurityGroupAttributeRequest, AuthorizeSecurityGroupRequest, RevokeSecurityGroupRequest from aliyunsdkecs.request.v20140526 import DescribeSecurityGroupAttributeRequest, AuthorizeSecurityGroupRequest, RevokeSecurityGroupRequest
# 设置日志记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
logger = logging.getLogger()
# 从配置文件加载配置信息 # 从配置文件加载配置信息
def load_config(config_file, sample_config_file): def load_config(config_file, sample_config_file):
if not os.path.exists(config_file): if not os.path.exists(config_file):
print(f"配置文件 {config_file} 不存在。") logger.error(f"配置文件 {config_file} 不存在。")
print(f"将从样例配置文件 {sample_config_file} 复制一份。") logger.info(f"将从样例配置文件 {sample_config_file} 复制一份。")
shutil.copy(sample_config_file, config_file) shutil.copy(sample_config_file, config_file)
print(f"请在 {config_file} 中配置您的设置。") logger.info(f"请在 {config_file} 中配置您的设置。")
raise FileNotFoundError(f"配置文件 {config_file} 不存在。") raise FileNotFoundError(f"配置文件 {config_file} 不存在。")
try: try:
with open(config_file, 'r') as file: with open(config_file, 'r') as file:
config = json.load(file) config = json.load(file)
return config return config
except FileNotFoundError: except FileNotFoundError:
print(f"配置文件 {config_file} 未找到。") logger.error(f"配置文件 {config_file} 未找到。")
raise raise
except json.JSONDecodeError: except json.JSONDecodeError:
print(f"配置文件 {config_file} 解析错误。") logger.error(f"配置文件 {config_file} 解析错误。")
raise raise
# 获取IP地址 # 获取IP地址
@@ -35,7 +40,7 @@ def get_ip_from_service(url):
ip = response.text.strip() ip = response.text.strip()
return ip return ip
except RequestException as e: except RequestException as e:
print(f"无法从 {url} 获取IP地址: {e}") logger.error(f"无法从 {url} 获取IP地址: {e}")
raise raise
# 获取当前安全组的规则 # 获取当前安全组的规则
@@ -49,7 +54,7 @@ def get_security_group_rules(client, security_group_id):
rules = json.loads(response) rules = json.loads(response)
return rules.get('Permissions', {}).get('Permission', []) return rules.get('Permissions', {}).get('Permission', [])
except (ClientException, ServerException) as e: except (ClientException, ServerException) as e:
print(f"无法获取安全组规则: {e}") logger.error(f"无法获取安全组规则: {e}")
raise raise
# 删除带有标记的旧规则 # 删除带有标记的旧规则
@@ -67,7 +72,7 @@ def delete_old_rules(client, security_group_id, tag):
request.set_NicType(rule['NicType']) request.set_NicType(rule['NicType'])
client.do_action_with_exception(request) client.do_action_with_exception(request)
except (ClientException, ServerException) as e: except (ClientException, ServerException) as e:
print(f"无法删除旧的安全组规则: {e}") logger.error(f"无法删除旧的安全组规则: {e}")
raise raise
# 更新安全组白名单 # 更新安全组白名单
@@ -91,9 +96,9 @@ def update_security_group_white_list(client, security_group_id, ip, ports, tag,
request.set_Priority(priority) request.set_Priority(priority)
response = client.do_action_with_exception(request) response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8')) logger.info(str(response, encoding='utf-8'))
except (ClientException, ServerException) as e: except (ClientException, ServerException) as e:
print(f"无法更新安全组白名单: {e}") logger.error(f"无法更新安全组白名单: {e}")
raise raise
# 记录IP地址到本地文件 # 记录IP地址到本地文件
@@ -102,7 +107,7 @@ def record_ip(ip_record_file, ip_records):
with open(ip_record_file, 'w') as file: with open(ip_record_file, 'w') as file:
json.dump(ip_records, file) json.dump(ip_records, file)
except IOError as e: except IOError as e:
print(f"无法写入IP记录文件 {ip_record_file}: {e}") logger.error(f"无法写入IP记录文件 {ip_record_file}: {e}")
raise raise
# 读取本地记录的IP地址 # 读取本地记录的IP地址
@@ -115,17 +120,17 @@ def load_ip_records(ip_record_file):
else: else:
return {} return {}
except IOError as e: except IOError as e:
print(f"无法读取IP记录文件 {ip_record_file}: {e}") logger.error(f"无法读取IP记录文件 {ip_record_file}: {e}")
raise raise
except json.JSONDecodeError as e: except json.JSONDecodeError as e:
print(f"IP记录文件 {ip_record_file} 解析错误: {e}") logger.error(f"IP记录文件 {ip_record_file} 解析错误: {e}")
raise raise
def main(): def main():
try: try:
# 加载配置文件 # 加载配置文件
config_path = os.environ.get('CONFIG_PATH', 'config.json') config_path = os.environ.get('CONFIG_PATH', '/config/config.json')
sample_config_path = os.environ.get('SAMPLE_CONFIG_PATH', 'config.sample.json') sample_config_path = os.environ.get('SAMPLE_CONFIG_PATH', '/config/config.sample.json')
config = load_config(config_path, sample_config_path) config = load_config(config_path, sample_config_path)
ACCESS_KEY_ID = config['ACCESS_KEY_ID'] ACCESS_KEY_ID = config['ACCESS_KEY_ID']
@@ -136,30 +141,45 @@ def main():
GETIP_URLS = config['GETIP_URLS'] GETIP_URLS = config['GETIP_URLS']
PORTS = config['PORTS'] PORTS = config['PORTS']
PRIORITY = config.get('PRIORITY', 1) PRIORITY = config.get('PRIORITY', 1)
IP_RECORD_FILE = config.get('IP_RECORD_FILE', 'ip_records.json') IP_RECORD_FILE = config.get('IP_RECORD_FILE', '/logs/ip_records.json')
INTERVAL_SECONDS = config.get('INTERVAL_SECONDS', 3600) INTERVAL_SECONDS = config.get('INTERVAL_SECONDS', 3600)
client = AcsClient(ACCESS_KEY_ID, ACCESS_KEY_SECRET, REGION_ID) client = AcsClient(ACCESS_KEY_ID, ACCESS_KEY_SECRET, REGION_ID)
# 忽略现有的 IP 记录文件,强制更新一次规则
new_ip_records = {}
# 获取并删除旧规则
delete_old_rules(client, SECURITY_GROUP_ID, TAG)
# 获取新的IP地址并更新安全组白名单
for url in GETIP_URLS:
ip = get_ip_from_service(url)
logger.info(f"IP from {url}: {ip}")
new_ip_records[url] = ip
# 更新安全组白名单
update_security_group_white_list(client, SECURITY_GROUP_ID, ip, PORTS, TAG, PRIORITY)
# 记录新的IP地址到本地文件
record_ip(IP_RECORD_FILE, new_ip_records)
while True: while True:
# 读取本地记录的IP地址 # 读取本地记录的IP地址
ip_records = load_ip_records(IP_RECORD_FILE) ip_records = load_ip_records(IP_RECORD_FILE)
new_ip_records = {} new_ip_records = {}
# 获取并删除旧规则
delete_old_rules(client, SECURITY_GROUP_ID, TAG)
# 获取新的IP地址并更新安全组白名单 # 获取新的IP地址并更新安全组白名单
for url in GETIP_URLS: for url in GETIP_URLS:
ip = get_ip_from_service(url) ip = get_ip_from_service(url)
print(f"IP from {url}: {ip}") logger.info(f"IP from {url}: {ip}")
new_ip_records[url] = ip new_ip_records[url] = ip
if ip_records.get(url) != ip: if ip_records.get(url) != ip:
# 更新安全组白名单 # 更新安全组白名单
update_security_group_white_list(client, SECURITY_GROUP_ID, ip, PORTS, TAG, PRIORITY) update_security_group_white_list(client, SECURITY_GROUP_ID, ip, PORTS, TAG, PRIORITY)
else: else:
print(f"IP from {url} has not changed, no update required.") logger.info(f"IP from {url} has not changed, no update required.")
# 记录新的IP地址到本地文件 # 记录新的IP地址到本地文件
record_ip(IP_RECORD_FILE, new_ip_records) record_ip(IP_RECORD_FILE, new_ip_records)
@@ -168,7 +188,7 @@ def main():
time.sleep(INTERVAL_SECONDS) time.sleep(INTERVAL_SECONDS)
except Exception as e: except Exception as e:
print(f"程序运行过程中出现错误: {e}") logger.error(f"程序运行过程中出现错误: {e}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -0,0 +1,74 @@
# Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
# <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7>Թ<EFBFBD><D4B9><EFBFBD>ԱȨ<D4B1><C8A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԱȨ<D4B1><C8A8>
Start-Process powershell -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs
exit
}
# <20>л<EFBFBD><D0BB><EFBFBD><EFBFBD>ű<EFBFBD><C5B1><EFBFBD><EFBFBD><EFBFBD>Ŀ¼
Set-Location $PSScriptRoot
Write-Host "<EFBFBD><EFBFBD>ǰĿ¼<EFBFBD><EFBFBD><EFBFBD>л<EFBFBD>Ϊ<EFBFBD>ű<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ¼: $PSScriptRoot"
# <20><>ȡ<EFBFBD><C8A1>ǰ<EFBFBD><C7B0><EFBFBD>ں<EFBFBD>ʱ<EFBFBD><CAB1>
$dateTime = Get-Date -Format "yyyyMMdd"
Write-Host "<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>: $dateTime"
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><E6B1BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һλ
$revision = Read-Host -Prompt "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>İ汾<EFBFBD><EFBFBD> ($dateTime,<2C><><EFBFBD><EFBFBD>û<EFBFBD>дΣ<D0B4><CEA3><EFBFBD>ֱ<EFBFBD>ӻس<D3BB>)"
Write-Host "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>İ汾<EFBFBD><EFBFBD>: $revision"
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6B1BE>
if ([string]::IsNullOrWhiteSpace($revision)) {
$version = "$dateTime"
} else {
$version = "$dateTime" + "_$revision"
}
Write-Host "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>İ汾<EFBFBD><EFBFBD>: $version"
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϰ汾<CFB0>ű<EFBFBD>ǩ<EFBFBD><C7A9> Docker <20><><EFBFBD><EFBFBD>
Write-Host "<EFBFBD><EFBFBD><EFBFBD>ڹ<EFBFBD><EFBFBD><EFBFBD> Docker <20><><EFBFBD><EFBFBD>..."
$tempFileBuild = [System.IO.Path]::GetTempFileName()
docker build -t yshtcn/alicloud_ip_updater:$version . 2> $tempFileBuild
if ($LASTEXITCODE -ne 0) {
Write-Host "Docker <20><><EFBFBD>񹹽<EFBFBD>ʧ<EFBFBD><CAA7>" -ForegroundColor Red
Write-Host (Get-Content $tempFileBuild) -ForegroundColor Red
Remove-Item $tempFileBuild
exit
}
Write-Host "Docker <20><><EFBFBD>񹹽<EFBFBD><F1B9B9BD>ɹ<EFBFBD>"
Remove-Item $tempFileBuild
# <20><><EFBFBD>ʹ<EFBFBD><CDB4>а<D0B0>ű<EFBFBD>ǩ<EFBFBD><C7A9> Docker <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Docker Hub
Write-Host "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Docker <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Docker Hub..."
$tempFilePush = [System.IO.Path]::GetTempFileName()
docker push yshtcn/alicloud_ip_updater:$version 2> $tempFilePush
if ($LASTEXITCODE -ne 0) {
Write-Host "Docker <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>" -ForegroundColor Red
Write-Host (Get-Content $tempFilePush) -ForegroundColor Red
Remove-Item $tempFilePush
exit
}
Write-Host "Docker <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͳɹ<CDB3>"
Remove-Item $tempFilePush
# Ϊ<><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 'latest' <20><>ǩ<EFBFBD><C7A9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Write-Host "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 'latest' <20><>ǩ<EFBFBD><C7A9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>..."
$tempFilePushLatest = [System.IO.Path]::GetTempFileName()
docker tag yshtcn/alicloud_ip_updater:$version yshtcn/alicloud_ip_updater:latest
docker push yshtcn/alicloud_ip_updater:latest 2> $tempFilePushLatest
if ($LASTEXITCODE -ne 0) {
Write-Host "Docker <20><><EFBFBD><EFBFBD> 'latest' <20><>ǩ<EFBFBD><C7A9><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>" -ForegroundColor Red
Write-Host (Get-Content $tempFilePushLatest) -ForegroundColor Red
Remove-Item $tempFilePushLatest
exit
}
Write-Host "Docker <20><><EFBFBD><EFBFBD> 'latest' <20><>ǩ<EFBFBD><C7A9><EFBFBD>ͳɹ<CDB3>"
Remove-Item $tempFilePushLatest
Write-Host "Docker <20><><EFBFBD>񹹽<EFBFBD><F1B9B9BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȫ<EFBFBD><C8AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"

View File

@@ -10,8 +10,11 @@ COPY . /app
# Install any needed packages specified in requirements.txt # Install any needed packages specified in requirements.txt
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt
# Create directories for config and logs
RUN mkdir /config /logs
# Copy the sample config file into the image # Copy the sample config file into the image
COPY config.sample.json /app/config.sample.json COPY config.sample.json /config/config.sample.json
# Run update_aliyun.py when the container launches # Run update_aliyun.py when the container launches
CMD ["python", "AliCloudIPUpdater.py"] CMD ["python", "AliCloudIPUpdater.py"]

3
requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
requests
aliyun-python-sdk-core
aliyun-python-sdk-ecs