diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..38c4cb4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +showAliServer/aliyun_servers_*.csv +showAliServer/config.json diff --git a/showAliServer/README.md b/showAliServer/README.md new file mode 100644 index 0000000..2269ab8 --- /dev/null +++ b/showAliServer/README.md @@ -0,0 +1,104 @@ +# 阿里云服务器信息查询工具 + +这是一个Python脚本,用于查询一个或多个阿里云账号下的所有ECS(云服务器)和轻量应用服务器的详细信息,并将结果统一导出到一个CSV文件中。 + +## 功能特性 + +- **多账号支持**: 可同时查询多个阿里云账号。 +- **全面的信息**: 获取服务器的实例ID、实例名称、公网/内网IP、配置、创建时间及到期时间。 +- **CSV导出**: 将所有查询结果保存到一个带时间戳的CSV文件中,便于归档和分析。 +- **错误处理**: 自动跳过不支持或无法访问的区域,确保脚本的健壮性。 +- **现代化的环境管理**: 使用 `uv` 进行快速的环境设置和依赖管理。 + +## 项目结构 + +``` +. +├── .venv/ # uv创建的虚拟环境目录 +├── aliyun_servers_*.csv # 脚本生成的CSV结果文件 +├── config.json # 你的账号配置文件 (需要手动创建) +├── config.json.example # 账号配置文件模板 +├── list_aliyun_servers.py # 主程序脚本 +├── requirements.txt # 项目依赖列表 +└── README.md # 本说明文件 +``` + +## 环境设置与运行 (使用 uv) + +本项目推荐使用 `uv`,一个极速的Python包安装和解析器,来管理虚拟环境和依赖。 + +### 1. 安装 uv + +如果您还没有安装 `uv`,请根据您的操作系统执行相应的命令: + +**macOS / Linux:**```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +``` + +**Windows:** +```powershell +irm https://astral.sh/uv/install.ps1 | iex +``` + +### 2. 创建虚拟环境 + +在项目根目录下,使用 `uv` 创建一个名为 `.venv` 的虚拟环境。 + +```bash +uv venv +``` + +### 3. 安装依赖 + +`uv` 会自动识别 `requirements.txt` 文件。执行以下命令来安装所有必需的Python库: + +```bash +uv pip install -r requirements.txt +``` + +### 4. 配置账号信息 + +将配置文件模板 `config.json.example` 复制一份,并重命名为 `config.json`。 + +```bash +# Linux/macOS +cp config.json.example config.json + +# Windows +copy config.json.example config.json +``` + +然后,编辑 `config.json` 文件,填入您真实的阿里云 `AccessKey ID` 和 `AccessKey Secret`。可以配置多个账号。 + +```json +[ + { + "name": "我的主账号", + "access_key_id": "YOUR_ACCESS_KEY_ID_1", + "access_key_secret": "YOUR_ACCESS_KEY_SECRET_1" + }, + { + "name": "我的测试账号", + "access_key_id": "YOUR_ACCESS_KEY_ID_2", + "access_key_secret": "YOUR_ACCESS_KEY_SECRET_2" + } +] +``` + +### 5. 运行脚本 + +激活虚拟环境并运行脚本。 + +**激活环境 (只需执行一次):** + +- **macOS / Linux:** `source .venv/bin/activate` +- **Windows (CMD):** `.venv\Scripts\activate.bat` +- **Windows (PowerShell):** `.venv\Scripts\Activate.ps1` + +**运行脚本:** + +```bash +python list_aliyun_servers.py +``` + +脚本执行完毕后,您会在项目根目录下找到一个名为 `aliyun_servers_YYYYMMDD_HHMMSS.csv` 的文件,其中包含了所有服务器的信息。 diff --git a/showAliServer/list_aliyun_servers.py b/showAliServer/list_aliyun_servers.py new file mode 100644 index 0000000..101f1af --- /dev/null +++ b/showAliServer/list_aliyun_servers.py @@ -0,0 +1,176 @@ +# -*- coding: utf-8 -*- +import os +import json +import csv +from datetime import datetime +from alibabacloud_ecs20140526.client import Client as EcsClient +from alibabacloud_swas_open20200601.client import Client as SwasClient +from alibabacloud_tea_openapi import models as open_api_models +from alibabacloud_ecs20140526 import models as ecs_models +from alibabacloud_swas_open20200601 import models as swas_models +from alibabacloud_tea_util.client import Client as UtilClient + +def create_ecs_client(access_key_id, access_key_secret, region_id): + """ + Create ECS client. + """ + config = open_api_models.Config( + access_key_id=access_key_id, + access_key_secret=access_key_secret, + region_id=region_id + ) + return EcsClient(config) + +def create_swas_client(access_key_id, access_key_secret, region_id): + """ + Create SWAS client. + """ + config = open_api_models.Config( + access_key_id=access_key_id, + access_key_secret=access_key_secret, + region_id=region_id + ) + # Explicitly set the endpoint to avoid DNS resolution issues with the default global endpoint. + config.endpoint = f'swas.{region_id}.aliyuncs.com' + return SwasClient(config) + +def get_all_regions(client): + """ + Get all available regions. + """ + try: + request = ecs_models.DescribeRegionsRequest() + response = client.describe_regions(request) + return [region.region_id for region in response.body.regions.region] + except Exception as e: + print(f"Error fetching regions: {e}") + return [] + +def list_ecs_instances(client, region_id): + """ + List all ECS instances in a specific region. + """ + all_instances = [] + try: + request = ecs_models.DescribeInstancesRequest(region_id=region_id, page_size=100) + while True: + response = client.describe_instances(request) + instances = response.body.instances.instance + if not instances: + break + all_instances.extend(instances) + if not response.body.next_token: + break + request.next_token = response.body.next_token + except Exception as e: + print(f"Error fetching ECS instances in {region_id}: {e}") + return all_instances + +def list_lightweight_servers(client, region_id): + """ + List all Lightweight Application Servers in a specific region. + """ + all_servers = [] + try: + request = swas_models.ListInstancesRequest(region_id=region_id, page_size=100) + while True: + response = client.list_instances(request) + servers = response.body.instances + if not servers: + break + all_servers.extend(servers) + if response.body.total_count == len(all_servers): + break + request.page_number = request.page_number + 1 if request.page_number else 2 + + except Exception as e: + print(f"Error fetching Lightweight Application Servers in {region_id}: {e}") + return all_servers + +def load_accounts_from_config(config_file='config.json'): + """ + Load account credentials from a JSON config file. + """ + if not os.path.exists(config_file): + print(f"错误:配置文件 '{config_file}' 不存在。") + print(f"请将 'config.json.example' 复制为 '{config_file}' 并填入您的AccessKey信息。") + return None + try: + with open(config_file, 'r', encoding='utf-8') as f: + accounts = json.load(f) + if not accounts: + print(f"错误:配置文件 '{config_file}' 为空或格式不正确。") + return None + return accounts + except json.JSONDecodeError: + print(f"错误:解析配置文件 '{config_file}' 失败,请检查JSON格式是否正确。") + return None + except Exception as e: + print(f"读取配置文件时发生未知错误: {e}") + return None + +def main(): + accounts = load_accounts_from_config() + if not accounts: + return + + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + csv_filename = f'aliyun_servers_{timestamp}.csv' + + with open(csv_filename, 'w', newline='', encoding='utf-8-sig') as csvfile: + csv_writer = csv.writer(csvfile) + csv_writer.writerow([ + '账号', '类型', '区域', '实例ID', '实例名称', '公网IP', '内网IP', + '配置', '创建/开机时间', '到期时间' + ]) + + for account in accounts: + account_name = account['name'] + print("=" * 80) + print(f"正在查询账号: {account_name}") + print("=" * 80) + + default_region = 'cn-hangzhou' + try: + ecs_client_for_regions = create_ecs_client(account['access_key_id'], account['access_key_secret'], default_region) + regions = get_all_regions(ecs_client_for_regions) + except Exception as e: + print(f"无法连接到阿里云或获取区域列表,请检查AccessKey和网络连接: {e}") + continue + + print("正在查询 ECS 实例...") + for region in regions: + ecs_client = create_ecs_client(account['access_key_id'], account['access_key_secret'], region) + instances = list_ecs_instances(ecs_client, region) + if instances: + for inst in instances: + public_ip = ", ".join(inst.public_ip_address.ip_address) if inst.public_ip_address.ip_address else "" + private_ip = ", ".join(inst.vpc_attributes.private_ip_address.ip_address) if inst.vpc_attributes and inst.vpc_attributes.private_ip_address.ip_address else "" + config_str = f"{inst.instance_type} ({inst.cpu}核 CPU, {inst.memory / 1024} GB 内存)" + + csv_writer.writerow([ + account_name, 'ECS', region, inst.instance_id, inst.instance_name, public_ip, private_ip, + config_str, inst.creation_time, inst.expired_time + ]) + + print("正在查询轻量应用服务器...") + for region in regions: + try: + swas_client = create_swas_client(account['access_key_id'], account['access_key_secret'], region) + servers = list_lightweight_servers(swas_client, region) + if servers: + for server in servers: + csv_writer.writerow([ + account_name, '轻量应用服务器', region, server.instance_id, server.instance_name, server.public_ip_address, '', + server.plan_id, server.creation_time, server.expired_time + ]) + except Exception as e: + if "not supported" in str(e) or "Unreachable" in str(e) or "Failed to resolve" in str(e): + continue + print(f"查询轻量服务器时发生错误 (区域: {region}): {e}") + + print(f"\n查询完成!结果已保存到文件: {csv_filename}") + + +if __name__ == '__main__': + main() diff --git a/showAliServer/requirements.txt b/showAliServer/requirements.txt new file mode 100644 index 0000000..0bfa886 --- /dev/null +++ b/showAliServer/requirements.txt @@ -0,0 +1,3 @@ +alibabacloud_ecs20140526 +alibabacloud_swas-open20200601 +alibabacloud_tea