"""Deploy blog to RackNerd via JD Cloud jumphost""" import paramiko import os import time import glob # JD Cloud jumphost JD_HOST = "111.228.37.165" JD_USER = "root" JD_PASS = "Liudecai110" # RackNerd target RN_HOST = "107.174.186.162" RN_USER = "root" RN_PASS = "liudapao2026" RN_DIR = "/var/www/blog/" BASE_DIR = os.path.dirname(os.path.abspath(__file__)) def deploy(): # Find latest packages output_pkgs = sorted(glob.glob(os.path.join(BASE_DIR, "blog-deploy-*.tar.gz"))) tools_pkgs = sorted(glob.glob(os.path.join(BASE_DIR, "blog-tools-*.tar.gz"))) if not output_pkgs or not tools_pkgs: print("ERROR: No deployment packages found. Run build first.") return output_pkg = output_pkgs[-1] tools_pkg = tools_pkgs[-1] print(f"Deploying: {os.path.basename(output_pkg)}, {os.path.basename(tools_pkg)}") # Step 1: Connect to JD Cloud print("\n[1/5] Connecting to JD Cloud jumphost...") jd = paramiko.SSHClient() jd.set_missing_host_key_policy(paramiko.AutoAddPolicy()) jd.connect(JD_HOST, port=22, username=JD_USER, password=JD_PASS, timeout=20, banner_timeout=60, allow_agent=False, look_for_keys=False) print(" Connected to JD Cloud") # Step 2: Upload packages to JD Cloud print("\n[2/5] Uploading packages to JD Cloud...") sftp = jd.open_sftp() remote_output = f"/tmp/{os.path.basename(output_pkg)}" remote_tools = f"/tmp/{os.path.basename(tools_pkg)}" for local, remote in [(output_pkg, remote_output), (tools_pkg, remote_tools)]: size_mb = os.path.getsize(local) / (1024*1024) print(f" Uploading {os.path.basename(local)} ({size_mb:.1f} MB)...") sftp.put(local, remote) print(f" Uploaded to {remote}") sftp.close() # Step 3: SCP from JD Cloud to RackNerd print("\n[3/5] SCP packages to RackNerd...") # Install sshpass if not present jd.exec_command("which sshpass || apt-get install -y sshpass", timeout=30) time.sleep(2) scp_cmd = f"sshpass -p '{RN_PASS}' scp -o StrictHostKeyChecking=no {remote_output} {remote_tools} {RN_USER}@{RN_HOST}:/tmp/" print(f" Running: {scp_cmd[:80]}...") stdin, stdout, stderr = jd.exec_command(scp_cmd, timeout=120) exit_code = stdout.channel.recv_exit_status() if exit_code != 0: err = stderr.read().decode() print(f" SCP error (exit {exit_code}): {err[:200]}") # Try again print(" Retrying...") time.sleep(3) stdin, stdout, stderr = jd.exec_command(scp_cmd, timeout=120) exit_code = stdout.channel.recv_exit_status() if exit_code != 0: print(f" SCP failed again: {stderr.read().decode()[:200]}") jd.close() return print(" SCP complete") # Step 4: Extract on RackNerd print("\n[4/5] Extracting on RackNerd...") extract_cmd = f"""sshpass -p '{RN_PASS}' ssh -o StrictHostKeyChecking=no {RN_USER}@{RN_HOST} ' cd {RN_DIR} echo "Extracting output..." tar -xzf /tmp/{os.path.basename(output_pkg)} echo "Extracting tools..." mkdir -p tools tar -xzf /tmp/{os.path.basename(tools_pkg)} -C tools/ echo "Setting permissions..." chmod -R 644 *.html tools/*.html 2>/dev/null chmod 755 . tools/ tools/ar tools/es tools/zh tools/md 2>/dev/null echo "Cleaning up /tmp..." rm -f /tmp/{os.path.basename(output_pkg)} /tmp/{os.path.basename(tools_pkg)} echo "DONE" '""" stdin, stdout, stderr = jd.exec_command(extract_cmd, timeout=60) output = stdout.read().decode() err = stderr.read().decode() print(f" Output: {output}") if err: print(f" Stderr: {err[:200]}") # Step 5: Verify print("\n[5/5] Verifying deployment...") verify_cmd = f"""sshpass -p '{RN_PASS}' ssh -o StrictHostKeyChecking=no {RN_USER}@{RN_HOST} ' echo "HTML files in root: $(ls {RN_DIR}*.html 2>/dev/null | wc -l)" echo "HTML files in tools: $(ls {RN_DIR}tools/*.html 2>/dev/null | wc -l)" echo "Sitemap size: $(wc -l < {RN_DIR}sitemap.xml 2>/dev/null)" echo "IndexNow key: $(cat {RN_DIR}72aa77b68704abcfada4020ba81f7c5a.txt 2>/dev/null | head -1)" echo "BingSiteAuth: $(cat {RN_DIR}BingSiteAuth.xml 2>/dev/null | head -1)" '""" stdin, stdout, stderr = jd.exec_command(verify_cmd, timeout=30) print(stdout.read().decode()) # Clean up JD Cloud temp files jd.exec_command(f"rm -f {remote_output} {remote_tools}", timeout=10) jd.close() print("\nDeployment complete!") if __name__ == "__main__": deploy()