#!/usr/bin/env python3 import requests, subprocess, os, uuid, datetime, csv import client_config as config # 获取或生成客户端 ID def get_client_id(): if os.path.exists(config.CLIENT_ID_FILE): return open(config.CLIENT_ID_FILE).read().strip() cid = str(uuid.uuid4()) os.makedirs(os.path.dirname(config.CLIENT_ID_FILE) or ".", exist_ok=True) open(config.CLIENT_ID_FILE,"w").write(cid) return cid # 读取本地 CSV def read_csv(file_path): if not os.path.exists(file_path): return {} with open(file_path, newline='', encoding='utf-8') as f: reader = csv.DictReader(f) return { row['image_name']: row for row in reader } # 写入 CSV 文件 def write_csv(file_path, rows): os.makedirs(os.path.dirname(file_path) or ".", exist_ok=True) with open(file_path,'w',newline='',encoding='utf-8') as f: writer = csv.DictWriter(f, fieldnames=config.CLIENT_FIELDS) writer.writeheader() writer.writerows(rows) # 获取服务器镜像列表 def get_server_images(): return requests.get(config.SERVER_API).json() # 获取本地 Docker 镜像 def get_local_images(): output = subprocess.check_output(["docker","images","--format","{{.Repository}}:{{.Tag}}"]).decode() local_images = {} for line in output.strip().split("\n"): if ":" in line: name, tag = line.split(":",1) local_images[name] = tag return local_images # 下载并加载镜像 def download_and_load(url): os.makedirs(config.DOWNLOAD_DIR, exist_ok=True) filename = os.path.join(config.DOWNLOAD_DIR, url.split("/")[-1]) print(f"下载镜像 {url} 到 {filename}") subprocess.run(["wget","-q","-O",filename,url],check=True) print(f"加载镜像 {filename} 到 Docker") subprocess.run(["docker","load","-i",filename],check=True) # 上报客户端镜像状态 def report_to_server(client_id, images): requests.post(config.CLIENT_UPDATE_API,json={"client_id":client_id,"images":images}) # 主函数 def main(): cid = get_client_id() server_images = get_server_images() local_images = get_local_images() local_csv = read_csv(config.CLIENT_FILE) report_data = [] for img in server_images: name = img["image_name"] tag = img["image_tag"] server_time_str = img["last_updated"] url = img["download_url"] server_time = datetime.datetime.strptime(server_time_str, "%Y-%m-%d %H:%M:%S") local_record = local_csv.get(name) local_tag = local_images.get(name) local_time = None if local_record: local_time = datetime.datetime.strptime(local_record["last_updated"], "%Y-%m-%d %H:%M:%S") # 判断是否需要下载 need_update = False if local_tag != tag: need_update = True elif local_time is None: need_update = True elif local_time < server_time: need_update = True if need_update: print(f"[更新] {name}:{tag}") download_and_load(url) now_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") else: print(f"[已最新] {name}:{tag}") now_str = local_time.strftime("%Y-%m-%d %H:%M:%S") if local_time else server_time_str report_data.append({"image_name":name,"image_tag":tag,"last_updated":now_str}) # 写本地 CSV write_csv(config.CLIENT_FILE, report_data) # 上报服务器 report_to_server(cid, report_data) print("✅ 客户端镜像状态已上报服务器") if __name__=="__main__": main()