From 403ae1fe4981f3e47041cc44b55f912c49617518 Mon Sep 17 00:00:00 2001 From: jingrow Date: Sat, 26 Jul 2025 23:04:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9ENewJsiteServer.vue=E5=8F=8Aal?= =?UTF-8?q?iyun=5Fserver=5Flight.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dashboard/src2/pages/NewJsiteServer.vue | 693 ++++++++++++++++++++++++ jcloud/api/aliyun_server_light.py | 376 +++++++++++++ 2 files changed, 1069 insertions(+) create mode 100644 dashboard/src2/pages/NewJsiteServer.vue create mode 100644 jcloud/api/aliyun_server_light.py diff --git a/dashboard/src2/pages/NewJsiteServer.vue b/dashboard/src2/pages/NewJsiteServer.vue new file mode 100644 index 0000000..a5882dd --- /dev/null +++ b/dashboard/src2/pages/NewJsiteServer.vue @@ -0,0 +1,693 @@ + + + + + diff --git a/jcloud/api/aliyun_server_light.py b/jcloud/api/aliyun_server_light.py new file mode 100644 index 0000000..bbf3a0b --- /dev/null +++ b/jcloud/api/aliyun_server_light.py @@ -0,0 +1,376 @@ +import jingrow +import os +import sys +from typing import Dict, Any + +from alibabacloud_swas_open20200601.client import Client as SWAS_OPEN20200601Client +from alibabacloud_credentials.client import Client as CredentialClient +from alibabacloud_tea_openapi import models as open_api_models +from alibabacloud_swas_open20200601 import models as swas__open20200601_models +from alibabacloud_tea_util import models as util_models +from alibabacloud_tea_util.client import Client as UtilClient + + +class AliyunLightServerManager: + """阿里云轻量应用服务器管理器""" + _instance = None + _clients = {} # 缓存不同地域的客户端 + + @classmethod + def get_instance(cls): + """获取单例实例""" + if cls._instance is None: + cls._instance = cls() + return cls._instance + + def __init__(self): + """初始化管理器""" + if AliyunLightServerManager._instance is not None: + raise Exception("请使用 AliyunLightServerManager.get_instance() 获取实例") + + # 初始化配置 + self._initialize_credentials() + + def _initialize_credentials(self): + """初始化阿里云凭据""" + try: + settings = jingrow.get_single("Jcloud Settings") + if not settings: + jingrow.log_error("阿里云凭据初始化失败", "无法获取Jcloud Settings配置") + raise Exception("Jcloud Settings配置不存在") + + self.access_key_id = settings.get("aliyun_access_key_id") + self.access_secret = settings.get_password("aliyun_access_secret") if settings.get("aliyun_access_secret") else None + + if not self.access_key_id or not self.access_secret: + jingrow.log_error("阿里云凭据初始化失败", "阿里云凭据未配置,请在Jcloud Settings中配置aliyun_access_key_id和aliyun_access_secret") + raise Exception("阿里云凭据未配置") + + except Exception as e: + jingrow.log_error(f"阿里云凭据初始化失败: {str(e)}") + self.access_key_id = None + self.access_secret = None + raise + + def _get_client(self, region_id: str = 'cn-shanghai') -> SWAS_OPEN20200601Client: + """获取指定地域的客户端,使用缓存机制""" + if region_id not in self._clients: + try: + # 直接使用凭据创建配置 + config = open_api_models.Config( + access_key_id=self.access_key_id, + access_key_secret=self.access_secret + ) + config.endpoint = f'swas.{region_id}.aliyuncs.com' + self._clients[region_id] = SWAS_OPEN20200601Client(config) + except Exception as e: + jingrow.log_error("阿里云客户端创建失败", f"创建客户端时发生错误: {str(e)}") + raise + + return self._clients[region_id] + + def _convert_response_to_dict(self, response_body): + """将阿里云SDK响应对象转换为可序列化的字典""" + if response_body is None: + return None + + result = {} + # 获取所有公共属性 + for attr_name in dir(response_body): + if not attr_name.startswith('_') and not callable(getattr(response_body, attr_name)): + attr_value = getattr(response_body, attr_name) + if attr_value is not None: + if hasattr(attr_value, '__dict__') and not isinstance(attr_value, (str, int, float, bool)): + # 如果是复杂对象,递归转换 + result[attr_name] = self._convert_response_to_dict(attr_value) + elif isinstance(attr_value, list): + # 如果是列表,转换列表中的每个元素 + converted_list = [] + for item in attr_value: + if hasattr(item, '__dict__') and not isinstance(item, (str, int, float, bool)): + converted_list.append(self._convert_response_to_dict(item)) + else: + converted_list.append(item) + result[attr_name] = converted_list + else: + # 基本类型直接赋值 + result[attr_name] = attr_value + + return result + + def create_instance(self, plan_id, image_id, period=1, region_id='cn-shanghai'): + """创建轻量应用服务器实例""" + client = self._get_client(region_id) + try: + request = swas__open20200601_models.CreateInstancesRequest( + region_id=region_id, + plan_id=plan_id, + image_id=image_id, + period=period + ) + runtime = util_models.RuntimeOptions() + response = client.create_instances_with_options(request, runtime) + return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '实例创建成功'} + except Exception as e: + jingrow.log_error("创建实例失败", f"创建实例时发生错误: {str(e)}") + return {'success': False, 'error': str(e), 'message': '实例创建失败'} + + def start_instance(self, instance_id, region_id='cn-shanghai'): + """启动实例""" + client = self._get_client(region_id) + try: + request = swas__open20200601_models.StartInstanceRequest( + region_id=region_id, + instance_id=instance_id + ) + runtime = util_models.RuntimeOptions() + response = client.start_instance_with_options(request, runtime) + return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '实例启动成功'} + except Exception as e: + jingrow.log_error("启动实例失败", f"启动实例 {instance_id} 时发生错误: {str(e)}") + return {'success': False, 'error': str(e), 'message': '实例启动失败'} + + def stop_instance(self, instance_id, region_id='cn-shanghai'): + """停止实例""" + client = self._get_client(region_id) + try: + request = swas__open20200601_models.StopInstanceRequest( + region_id=region_id, + instance_id=instance_id + ) + runtime = util_models.RuntimeOptions() + response = client.stop_instance_with_options(request, runtime) + return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '实例停止成功'} + except Exception as e: + jingrow.log_error("停止实例失败", f"停止实例 {instance_id} 时发生错误: {str(e)}") + return {'success': False, 'error': str(e), 'message': '实例停止失败'} + + def upgrade_instance(self, instance_id, plan_id, region_id='cn-shanghai'): + """升级实例配置""" + client = self._get_client(region_id) + try: + request = swas__open20200601_models.UpgradeInstanceRequest( + region_id=region_id, + instance_id=instance_id, + plan_id=plan_id + ) + runtime = util_models.RuntimeOptions() + response = client.upgrade_instance_with_options(request, runtime) + return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '实例升级成功'} + except Exception as e: + jingrow.log_error("升级实例失败", f"升级实例 {instance_id} 时发生错误: {str(e)}") + return {'success': False, 'error': str(e), 'message': '实例升级失败'} + + def renew_instance(self, instance_id, period=1, period_unit='Month', region_id='cn-shanghai'): + """续费实例""" + client = self._get_client(region_id) + try: + request = swas__open20200601_models.RenewInstanceRequest( + region_id=region_id, + instance_id=instance_id, + period=period, + period_unit=period_unit + ) + runtime = util_models.RuntimeOptions() + response = client.renew_instance_with_options(request, runtime) + return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '实例续费成功'} + except Exception as e: + jingrow.log_error("续费实例失败", f"续费实例 {instance_id} 时发生错误: {str(e)}") + return {'success': False, 'error': str(e), 'message': '实例续费失败'} + + def reset_system(self, instance_id, image_id, password=None, region_id='cn-shanghai'): + """重置系统""" + client = self._get_client(region_id) + try: + request = swas__open20200601_models.ResetSystemRequest( + region_id=region_id, + instance_id=instance_id, + image_id=image_id + ) + if password: + request.password = password + runtime = util_models.RuntimeOptions() + response = client.reset_system_with_options(request, runtime) + return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '系统重置成功'} + except Exception as e: + jingrow.log_error("重置系统失败", f"重置实例 {instance_id} 系统时发生错误: {str(e)}") + return {'success': False, 'error': str(e), 'message': '系统重置失败'} + + def get_instance_info(self, instance_id, region_id='cn-shanghai'): + """获取实例信息""" + client = self._get_client(region_id) + try: + request = swas__open20200601_models.GetInstanceRequest( + region_id=region_id, + instance_id=instance_id + ) + runtime = util_models.RuntimeOptions() + response = client.get_instance_with_options(request, runtime) + return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '获取实例信息成功'} + except Exception as e: + jingrow.log_error("获取实例信息失败", f"获取实例 {instance_id} 信息时发生错误: {str(e)}") + return {'success': False, 'error': str(e), 'message': '获取实例信息失败'} + + def list_instances(self, page_number=1, page_size=20, region_id='cn-shanghai'): + """获取实例列表""" + client = self._get_client(region_id) + try: + request = swas__open20200601_models.ListInstancesRequest( + region_id=region_id, + page_number=page_number, + page_size=page_size + ) + runtime = util_models.RuntimeOptions() + response = client.list_instances_with_options(request, runtime) + return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '获取实例列表成功'} + except Exception as e: + jingrow.log_error("获取实例列表失败", f"获取实例列表时发生错误: {str(e)}") + return {'success': False, 'error': str(e), 'message': '获取实例列表失败'} + + def delete_instance(self, instance_id, region_id='cn-shanghai'): + """删除实例""" + client = self._get_client(region_id) + try: + request = swas__open20200601_models.DeleteInstanceRequest( + region_id=region_id, + instance_id=instance_id + ) + runtime = util_models.RuntimeOptions() + response = client.delete_instance_with_options(request, runtime) + return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '实例删除成功'} + except Exception as e: + jingrow.log_error("删除实例失败", f"删除实例 {instance_id} 时发生错误: {str(e)}") + return {'success': False, 'error': str(e), 'message': '实例删除失败'} + + def get_plans(self, region_id='cn-shanghai'): + """获取可用套餐列表""" + client = self._get_client(region_id) + try: + request = swas__open20200601_models.ListPlansRequest( + region_id=region_id + ) + runtime = util_models.RuntimeOptions() + response = client.list_plans_with_options(request, runtime) + return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '获取套餐列表成功'} + except Exception as e: + jingrow.log_error("获取套餐列表失败", f"获取套餐列表时发生错误: {str(e)}") + return {'success': False, 'error': str(e), 'message': '获取套餐列表失败'} + + def get_images(self, image_type='system', region_id='cn-shanghai'): + """获取可用镜像列表""" + client = self._get_client(region_id) + try: + request = swas__open20200601_models.ListImagesRequest( + region_id=region_id, + image_type=image_type + ) + runtime = util_models.RuntimeOptions() + response = client.list_images_with_options(request, runtime) + return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '获取镜像列表成功'} + except Exception as e: + jingrow.log_error("获取镜像列表失败", f"获取镜像列表时发生错误: {str(e)}") + return {'success': False, 'error': str(e), 'message': '获取镜像列表失败'} + + def get_regions(self): + """获取可用地域列表""" + try: + # 直接使用凭据创建配置 + config = open_api_models.Config( + access_key_id=self.access_key_id, + access_key_secret=self.access_secret + ) + # 默认用上海endpoint,获取所有地域 + config.endpoint = 'swas.cn-shanghai.aliyuncs.com' + client = SWAS_OPEN20200601Client(config) + request = swas__open20200601_models.ListRegionsRequest(accept_language='zh-CN') + runtime = util_models.RuntimeOptions() + response = client.list_regions_with_options(request, runtime) + return {'success': True, 'data': self._convert_response_to_dict(response.body), 'message': '获取地域列表成功'} + except Exception as e: + jingrow.log_error("获取地域列表失败", f"获取地域列表时发生错误: {str(e)}") + return {'success': False, 'error': str(e), 'message': '获取地域列表失败'} + + +# 全局管理器实例 +_aliyun_manager = None + +def _get_manager(): + """获取阿里云管理器实例""" + global _aliyun_manager + if _aliyun_manager is None: + _aliyun_manager = AliyunLightServerManager.get_instance() + return _aliyun_manager + + +# API函数 - 使用@jingrow.whitelist()装饰器 +@jingrow.whitelist() +def create_aliyun_instance(plan_id, image_id, period=1, region_id='cn-shanghai'): + """创建轻量应用服务器实例""" + manager = _get_manager() + return manager.create_instance(plan_id, image_id, period, region_id) + +@jingrow.whitelist() +def start_aliyun_instance(instance_id, region_id='cn-shanghai'): + """启动实例""" + manager = _get_manager() + return manager.start_instance(instance_id, region_id) + +@jingrow.whitelist() +def stop_aliyun_instance(instance_id, region_id='cn-shanghai'): + """停止实例""" + manager = _get_manager() + return manager.stop_instance(instance_id, region_id) + +@jingrow.whitelist() +def upgrade_aliyun_instance(instance_id, plan_id, region_id='cn-shanghai'): + """升级实例配置""" + manager = _get_manager() + return manager.upgrade_instance(instance_id, plan_id, region_id) + +@jingrow.whitelist() +def renew_aliyun_instance(instance_id, period=1, period_unit='Month', region_id='cn-shanghai'): + """续费实例""" + manager = _get_manager() + return manager.renew_instance(instance_id, period, period_unit, region_id) + +@jingrow.whitelist() +def reset_aliyun_instance_system(instance_id, image_id, password=None, region_id='cn-shanghai'): + """重置系统""" + manager = _get_manager() + return manager.reset_system(instance_id, image_id, password, region_id) + +@jingrow.whitelist() +def get_aliyun_instance_info(instance_id, region_id='cn-shanghai'): + """获取实例信息""" + manager = _get_manager() + return manager.get_instance_info(instance_id, region_id) + +@jingrow.whitelist() +def list_aliyun_instances(page_number=1, page_size=20, region_id='cn-shanghai'): + """获取实例列表""" + manager = _get_manager() + return manager.list_instances(page_number, page_size, region_id) + +@jingrow.whitelist() +def delete_aliyun_instance(instance_id, region_id='cn-shanghai'): + """删除实例""" + manager = _get_manager() + return manager.delete_instance(instance_id, region_id) + +@jingrow.whitelist() +def get_aliyun_plans(region_id='cn-shanghai'): + """获取可用套餐列表""" + manager = _get_manager() + return manager.get_plans(region_id) + +@jingrow.whitelist() +def get_aliyun_images(image_type='system', region_id='cn-shanghai'): + """获取可用镜像列表""" + manager = _get_manager() + return manager.get_images(image_type, region_id) + +@jingrow.whitelist() +def get_aliyun_regions(): + """通过阿里云SDK实时获取可用地域列表""" + manager = _get_manager() + return manager.get_regions() \ No newline at end of file