赞
踩
import json import random from huaweicloudsdkcore.auth.credentials import BasicCredentials from huaweicloudsdkcore.exceptions import exceptions from huaweicloudsdkcore.http.http_config import HttpConfig from huaweicloudsdkecs.v2 import * from huaweicloudsdkecs.v2.region.ecs_region import EcsRegion from huaweicloudsdkims.v2 import ImsClient, ListImagesRequest from huaweicloudsdkims.v2.region.ims_region import ImsRegion from huaweicloudsdkvpc.v2 import ListSubnetsRequest, VpcClient, ListVpcsRequest, CreateVpcRequest, CreateVpcOption, \ CreateVpcRequestBody, CreateSubnetRequest, CreateSubnetOption, CreateSubnetRequestBody, ListSecurityGroupsRequest, \ CreateSecurityGroupRequest, CreateSecurityGroupOption, CreateSecurityGroupRequestBody, \ DeleteSecurityGroupRuleRequest, CreateSecurityGroupRuleRequest, CreateSecurityGroupRuleOption, \ CreateSecurityGroupRuleRequestBody from huaweicloudsdkvpc.v2.region.vpc_region import VpcRegion from base.international import t_ from app import app_settings from app.applications import logger def try_catch(func_name): def decorator(func): def execute(*args, **kwargs): try: response = func(*args, **kwargs) return response except exceptions.ClientRequestException as e: error_msg = f'status_code={e.status_code}, request_id={e.request_id}, error_code={e.error_code}, ' \ f'error_msg={e.error_msg}' logger.error(f'【{func_name}-异常(HW)】:{error_msg}') raise Exception(t_('【{0}-异常(HW)】:{1}').format(func_name, error_msg), True) except Exception as ex: error_msg = f'ex={str(ex)}' logger.error(f'【{func_name}-异常(HW)】:{error_msg}') raise Exception(t_('【{0}-异常(HW)】:{1}').format(func_name, error_msg), True) return execute return decorator class _HWCloudBaseHandler(object): def __init__(self, project_name, ak, sk, timeout=None): self.project_name = project_name # 所属项目/区域 self.ak = ak self.sk = sk self.admin_pass = app_settings.ADMIN_PASS self.timeout = timeout # 超时时间 (connect timeout, read timeout) self.image_name = app_settings.DEFAULT_IMAGE_NAME self.vpc_data = app_settings.DEFAULT_VPC_DATA self.vpc_subnet_data = app_settings.DEFAULT_VPC_SUBNET_DATA self.security_groups_name = app_settings.DEFAULT_SECURITY_GROUP_NAME self.security_group_rules = app_settings.SECURTY_GROUP_RULES self.root_volume_type = app_settings.ROOT_VOLUME_TYPE # 系统盘类型 self.data_volume_type = app_settings.DATA_VOLUME_TYPE # 数据盘类型 self.data_volume_size = app_settings.DATA_VOLUME_SIZE # 数据盘大小 self.eip_type = app_settings.EIP_TYPE # EIP的类型: 静态BGP self.eip_size = app_settings.EIP_SIZE # 带宽大小 self.eip_share_type = app_settings.EIP_SHARE_TYPE # 带宽共享类型:独享 self.eip_charge_mode = app_settings.EIP_CHARGE_MODE # 带宽计费类型:按流量计费 def ecs_client(self): """ 初始化 弹性云服务器(ESC)客户端 https://support.huaweicloud.com/sdkreference-mpc/mpc_05_0076.html 添加日志:.with_file_log() """ credentials = BasicCredentials(self.ak, self.sk) region = EcsRegion.value_of(self.project_name) ecs_client = EcsClient.new_builder() \ .with_credentials(credentials) \ .with_region(region) \ .with_http_config(self.http_config) \ .build() return ecs_client def vpc_client(self): """ 初始化 虚拟私有云 客户端 https://support.huaweicloud.com/sdkreference-mpc/mpc_05_0076.html """ credentials = BasicCredentials(self.ak, self.sk) region = VpcRegion.value_of(self.project_name) vpc_client = VpcClient.new_builder() \ .with_credentials(credentials) \ .with_region(region) \ .with_http_config(self.http_config) \ .build() return vpc_client def image_client(self): """ 初始化 镜像 客户端 https://support.huaweicloud.com/sdkreference-mpc/mpc_05_0076.html """ credentials = BasicCredentials(self.ak, self.sk) region = ImsRegion.value_of(self.project_name) image_client = ImsClient.new_builder() \ .with_credentials(credentials) \ .with_region(region) \ .with_http_config(self.http_config) \ .build() return image_client @property def http_config(self): """ 默认连接超时时间为60秒,读取超时时间为120秒 :param timeout: (connect timeout, read timeout) """ http_config = HttpConfig.get_default_config() if self.timeout: http_config.timeout = self.timeout return http_config @classmethod def format_server_ids(cls, server_ids): return [ServerId(id=item) for item in server_ids] @classmethod def format_response(cls, response): json_response = json.loads(str(response)) if json_response.get('error'): raise Exception( f'error_code={json_response["error"]["code"]}, error_message={json_response["error"]["message"]}') return json_response class _HWListAvailabilityZones(_HWCloudBaseHandler): @try_catch('查询可用区列表') def list_available_zones(self): """ 查询可用区列表 https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=NovaListAvailabilityZones :returns: list of available """ request = NovaListAvailabilityZonesRequest() response = self.ecs_client().nova_list_availability_zones(request) zone_list = response.availability_zone_info return [item.zone_name for item in zone_list] class _HWListFlavors(_HWCloudBaseHandler): @try_catch('查询规格详情和规格扩展信息列表') def list_flavors(self, zone_name): """ 查询可用区可用规格 https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/sdk?api=ListFlavors :returns: list of flavors """ request = ListFlavorsRequest() request.availability_zone = zone_name response = self.ecs_client().list_flavors(request) flavor_list = response.flavors return [item.id for item in flavor_list] class _HWListImages(_HWCloudBaseHandler): @try_catch('查询镜像列表') def list_images(self, image_name=None): """ 查询镜像列表 https://console.huaweicloud.com/apiexplorer/#/openapi/IMS/debug?locale=zh-cn&consoleCurrentProductId=ims&consoleCurrentProductshort=&api=ListImages """ _image_name = image_name or self.image_name request = ListImagesRequest() request.name = _image_name response = self.image_client().list_images(request) return json.loads(str(response))['images'] def filter_images(self, image_name=None): """ 根据 image_name 进行过滤,返回匹配的ID """ _image_name = image_name or self.image_name image_list = self.list_images(_image_name) for item in image_list: if _image_name == item.get('name'): return item['id'] class _HWListVpcs(_HWCloudBaseHandler): @try_catch('查询VPC列表') def list_vpcs(self): """ 查询VPC列表 https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?api=ListVpcs&version=v2 """ request = ListVpcsRequest() response = self.vpc_client().list_vpcs(request) return json.loads(str(response))['vpcs'] def filter_vpcs(self, vpc_name=None): """ 根据vpc_name进行过滤,返回匹配的ID """ _vpc_name = vpc_name or self.vpc_data['name'] vpc_list = self.list_vpcs() for item in vpc_list: if _vpc_name == item.get('name'): return item['id'] class _HWListSubnets(_HWCloudBaseHandler): @try_catch('查询子网列表') def list_subnet(self, vpc_id): """ 查询 vpc_id 子网信息 https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?api=ListSubnets&version=v2 """ request = ListSubnetsRequest() request.vpc_id = vpc_id response = self.vpc_client().list_subnets(request) return json.loads(str(response))['subnets'] def filter_subnets(self, vpc_id, subnet_name=None): """ 根据 subnet_name 进行过滤,返回匹配的ID """ _subnet_name = subnet_name or self.vpc_subnet_data['name'] subnet_list = self.list_subnet(vpc_id) for item in subnet_list: if _subnet_name == item.get('name'): return item['id'] class _HWListSecurityGroup(_HWCloudBaseHandler): @try_catch('查询安全组列表') def list_security_groups(self, vpc_id): """ 根据 vpc_id 查询对应安全组 https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/sdk?version=v2&api=ListSecurityGroups """ request = ListSecurityGroupsRequest() request.vpc_id = vpc_id response = self.vpc_client().list_security_groups(request) return json.loads(str(response))['security_groups'] def filter_security_groups(self, vpc_id, security_groups_name=None): """ 根据 security_groups_name 进行过滤,返回匹配的ID """ _security_groups_name = security_groups_name or self.security_groups_name security_groups_list = self.list_security_groups(vpc_id) for item in security_groups_list: if _security_groups_name == item.get('name'): return item['id'] class _HWShowJob(_HWCloudBaseHandler): @try_catch('查询任务的执行状态') def job_status(self, job_id): """ 查询任务的执行状态,成功SUCCESS、RUNNING运行中、FAIL失败、INIT正在初始化、PENDING_PAYMENT待支付 https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=ShowJob :param job_id: Job id return: { "job_id": "ff8080828848fa840189239bd5ef6c1f", "job_type": "createServer", "begin_time": "2023-07-05T01:12:42.733Z", "end_time": "2023-07-05T01:13:50.062Z", "status": "SUCCESS", "error_code": null, "fail_reason": null, "entities": { "sub_jobs_total": 1, ... } } """ request = ShowJobRequest() request.job_id = job_id response = self.ecs_client().show_job(request) return json.loads(str(response)) class _HWServiceDetails(_HWCloudBaseHandler): @try_catch("查询云服务器详情列表") def server_details(self, server_ids=None, limit=None): """ 查询云服务器详情列表 https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=ListServersDetails :param server_ids: 服务器server_id列表 :param limit: 显示多少条,默认25,最大500 return: """ request = ListServersDetailsRequest() if server_ids: request.server_id = server_ids[:500] if limit: request.limit = limit response = self.ecs_client().list_servers_details(request) # logger.info(f'server_id:{server_id}, res: {response}') return json.loads(str(response))['servers'] class _HWCreateServers(_HWCloudBaseHandler): @try_catch("创建云服务器(按需)") def create_server(self, server_name, image_id, flavor_ref, vpcid, subnet_id, security_groups=None, admin_pass=None, tags=None, count=1): """ 创建云服务器(按需):异步 https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=CreatePostPaidServers :param server_name: 服务器名,str :param image_id: 镜像ID,str :param flavor_ref: 规格名称,如:s6.small.1,str :param vpcid: vpc id, str :param subnet_id: 所属vpc的子网id :param security_groups: 安全组列表,list :param admin_pass: 服务器密码(一般私有镜像无效),str :param tags: 服务器标签,如:{"key": key, "value": value},dict :param count: 创建台数,int return: { "job_id": "ff808082739334d80173941567f21d4f", "serverIds": [ "118258c5-0c6a-4e73-8b51-8d1ea3272e1b", "e51b9e20-7088-4914-a4f3-6c76bcfed0be" ] } """ logger.info(f'【创建云服务器(按需)-开始】name={server_name}, region={self.project_name}, image_id={image_id}') server_body = PostPaidServer( name=server_name, image_ref=image_id, admin_pass=admin_pass or self.admin_pass, availability_zone=self.get_availability_zone(flavor_ref), data_volumes=self.get_data_volume(), flavor_ref=flavor_ref, nics=self.get_subnets(subnet_id), publicip=self.get_public_cip(), root_volume=self.get_volume_type(), server_tags=self.get_server_tags(tags), vpcid=vpcid, count=count, is_auto_rename=False, security_groups=self.get_security_groups(security_groups) ) request = CreatePostPaidServersRequest() request.body = CreatePostPaidServersRequestBody( server=server_body ) response = self.ecs_client().create_post_paid_servers(request) logger.info(f'【创建云服务器(按需)-请求成功】name={server_name}, image_id={image_id}, res={response}') return self.format_response(response) @classmethod def get_server_tags(cls, server_tags): if server_tags is None: return return [ PostPaidServerTag( key=server_tags['key'], value=server_tags['value'] ) ] def get_data_volume(self): """ 数据盘 """ return [ PostPaidServerDataVolume( volumetype=self.data_volume_type, size=self.data_volume_size ) ] def get_volume_type(self): """ 系统盘类型 """ return PostPaidServerRootVolume( volumetype=self.root_volume_type ) def get_public_cip(self): """ 配置云服务器的弹性IP信息 """ return PostPaidServerPublicip( eip=self.get_eip() ) def get_eip(self): """ 配置云服务器自动分配弹性IP时, 创建弹性IP的配置参数 """ return PostPaidServerEip( iptype=self.eip_type, bandwidth=self.get_bandwidth_eip() ) def get_bandwidth_eip(self): """ 弹性IP地址带宽参数 """ return PostPaidServerEipBandwidth( size=self.eip_size, sharetype=self.eip_share_type, chargemode=self.eip_charge_mode ) def get_subnets(self, subnet_id): return [PostPaidServerNic(subnet_id=subnet_id)] def get_security_groups(self, security_groups): """ 构造安全组数据 :param security_groups: 安全组列表 """ return [PostPaidServerSecurityGroup(id=item) for item in security_groups] def get_availability_zone(self, flavor_ref): """ 根据规格筛选可用可用区 (部分规格在部分可用区无法使用) """ zone_list = _HWListAvailabilityZones(project_name=self.project_name, ak=self.ak, sk=self.sk).list_available_zones() if not zone_list: raise Exception(f'当前区域:{self.project_name} 无可用区可用') available_flavor_zone = [] for item in zone_list: res = _HWListFlavors(project_name=self.project_name, ak=self.ak, sk=self.sk).list_flavors(item) if flavor_ref in res: available_flavor_zone.append(item) return random.choice(available_flavor_zone) class _HWStopServer(_HWCloudBaseHandler): @try_catch('批量关闭云服务器') def stop_servers(self, server_ids): """ 批量关闭云服务器:异步,最大1000 https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=BatchStopServers :param server_ids: 服务器server_id列表 return: { "job_id": "70a599e0-31e7-49b7-b260-868f441e862b" } """ logger.info(f'【批量关闭云服务器-开始】server_ids=[{server_ids}]') request = BatchStopServersRequest() request.body = BatchStopServersOption( servers=self.format_server_ids(server_ids) ) response = self.ecs_client().batch_stop_servers(request) logger.info(f'【批量关闭云服务器-请求成功】server_ids=[{server_ids}], response={response}') return self.format_response(response) class _HWRestartServer(_HWCloudBaseHandler): @try_catch('批量重启云服务器') def restart_servers(self, server_ids, type='SOFT'): """ 重启服务器:异步 https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=BatchRebootServers :param server_ids: 服务器server_id列表 :param type: 重启类型,SOFT/HARD return: { "job_id": "70a599e0-31e7-49b7-b260-868f441e862b" } """ logger.info(f'【批量重启云服务器-开始】server_ids=[{server_ids}]') request = BatchRebootServersRequest() request.body = BatchRebootServersRequestBody( reboot=BatchRebootSeversOption( servers=self.format_server_ids(server_ids), type=type ) ) response = self.ecs_client().batch_reboot_servers(request) logger.info(f'【批量重启云服务器-请求成功】server_ids=[{server_ids}], response={response}') return self.format_response(response) class _HWReinstallServer(_HWCloudBaseHandler): @try_catch('重装弹性云服务器操作系统(未安装Cloud init)') def reinstall_server(self, server_id): """ 重装弹性云服务器操作系统(开机状态下重建会先关闭服务器,再进行重建) https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/sdk?api=ReinstallServerWithoutCloudInit :param server_id: 服务器server_id return: { "job_id": "70a599e0-31e7-49b7-b260-868f441e862b" } """ logger.info(f'【重装弹性云服务器操作系统(未安装Cloud init)-开始】server_id=[{server_id}]') request = ReinstallServerWithoutCloudInitRequest() request.server_id = server_id os_reinstall_body = ReinstallServerWithoutCloudInitOption( mode="withStopServer" ) request.body = ReinstallServerWithoutCloudInitRequestBody( os_reinstall=os_reinstall_body ) response = self.ecs_client().reinstall_server_without_cloud_init(request) logger.info( f'【重装弹性云服务器操作系统(未安装Cloud init)-请求成功】server_ids=[{server_id}], response={response}') return self.format_response(response) class _HWDeleteServer(_HWCloudBaseHandler): @try_catch('删除云服务器') def delete_servers(self, server_ids): """ 删除服务器:异步 https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=DeleteServers :param server_ids: 服务器server_id列表 return: { "job_id": "70a599e0-31e7-49b7-b260-868f441e862b" } """ logger.info(f'【删除云服务器-开始】server_ids=[{server_ids}]') request = DeleteServersRequest() request.body = DeleteServersRequestBody( servers=self.format_server_ids(server_ids), delete_volume=True, delete_publicip=True ) response = self.ecs_client().delete_servers(request) logger.info(f'【删除云服务器-请求成功】server_ids=[{server_ids}], response={response}') return self.format_response(response) class _HWCreateVpcs(_HWCloudBaseHandler): @try_catch('创建VPC') def create_vpcs(self): """ 创建VPC https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?api=CreateVpc&version=v2 """ request = CreateVpcRequest() vpcbody = CreateVpcOption( cidr=self.vpc_data['cidr'], name=self.vpc_data['name'], description=self.vpc_data['description'] ) request.body = CreateVpcRequestBody( vpc=vpcbody ) response = self.vpc_client().create_vpc(request) return json.loads(str(response))['vpc']['id'] class _HWCreateVpcSubnet(_HWCloudBaseHandler): @try_catch('创建子网') def create_vpc_subnet(self, vpc_id): """ 创建子网 https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?api=CreateSubnet&version=v2 """ request = CreateSubnetRequest() subnetbody = CreateSubnetOption( name=self.vpc_subnet_data['name'], description=self.vpc_subnet_data['description'], cidr=self.vpc_subnet_data['cidr'], vpc_id=vpc_id, gateway_ip=self.vpc_subnet_data['gateway_ip'], dhcp_enable=self.vpc_subnet_data['dhcp_enable'] ) request.body = CreateSubnetRequestBody( subnet=subnetbody ) response = self.vpc_client().create_subnet(request) return json.loads(str(response))['subnet']['id'] class _HWCreateSecurityGroup(_HWCloudBaseHandler): @try_catch('查询安全组列表') def create_security_groups(self, vpc_id): """ 创建默认安全组 https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/debug?version=v2&api=CreateSecurityGroup """ request = CreateSecurityGroupRequest() securityGroupbody = CreateSecurityGroupOption( name=self.security_groups_name, vpc_id=vpc_id ) request.body = CreateSecurityGroupRequestBody( security_group=securityGroupbody ) response = self.vpc_client().create_security_group(request) return json.loads(str(response))['security_group'] def create_security_groups_rules(self, group_id): for group_rule in self.security_group_rules: request = CreateSecurityGroupRuleRequest() securityGroupRulebody = CreateSecurityGroupRuleOption( security_group_id=group_id, direction=group_rule["direction"], ethertype=group_rule["ethertype"] ) request.body = CreateSecurityGroupRuleRequestBody( security_group_rule=securityGroupRulebody ) self.vpc_client().create_security_group_rule(request) def delete_security_groups_rules(self, rule_ids): """ 删除安全组规则 https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/debug?version=v2&api=DeleteSecurityGroupRule """ for rule_id in rule_ids: request = DeleteSecurityGroupRuleRequest() request.security_group_rule_id = rule_id self.vpc_client().delete_security_group_rule(request) class HWQueryManager(_HWListAvailabilityZones, _HWListImages, _HWListSubnets, _HWListVpcs, _HWListFlavors, _HWListSecurityGroup, _HWShowJob, _HWServiceDetails): """ 查询类 """ pass class HWOperateManger(_HWCreateServers, _HWStopServer, _HWRestartServer, _HWReinstallServer, _HWDeleteServer, _HWCreateVpcSubnet, _HWCreateVpcs, _HWCreateSecurityGroup): """ 操作类 """ pass class HWServerManager(HWQueryManager, HWOperateManger): pass ''' 使用示例: # 查询VPC下的子网 res = HWServerManager().get_subnets() print(res) # [{"subnet_id": "93089f63-ba1e-2345-8b7a-8c58b5c123678"}] ''' settings文件:根据实际情况填写 ```python # 账户信息 HUAWEI_CLOUD_USERNAME = 'username' HUAWEI_CLOUD_AK = "ak" # 私有密钥,导出 HUAWEI_CLOUD_SK = "sk" # 私有密钥,导出 # 磁盘 ROOT_VOLUME_TYPE = "SSD" # 系统盘类型 DATA_VOLUME_TYPE = "SSD" # 数据盘类型 DATA_VOLUME_SIZE = 40 # 弹性IP信息 EIP_SHARE_TYPE = "PER" # 带宽共享类型:独享 EIP_CHARGE_MODE = 'traffic' # 带宽计费类型:按流量计费 EIP_TYPE = '5_sbgp' # EIP的类型: 静态BGP EIP_SIZE = 1 # 带宽大小 # 镜像名 DEFAULT_IMAGE_NAME = "image_name" # 安全组 DEFAULT_SECURITY_GROUP_NAME = "vpn_security_group" # VPC网络配置 DEFAULT_VPC_DATA = { "cidr": "10.10.0.0/16", "name": "vpn_vpc", "description": "用于vpn网络" } # VPC 子网配置 DEFAULT_VPC_SUBNET_DATA = { "name": "vpn_subnet", "description": "用于vpn_vpc的子网", "cidr": "10.10.10.0/24", "gateway_ip": "10.10.10.254", "dhcp_enable": True } # 安全组规则,放行所有 SECURTY_GROUP_RULES = [ {"direction": "egress", "ethertype": "IPv4"}, {"direction": "egress", "ethertype": "IPv6"}, {"direction": "ingress", "ethertype": "IPv4"}, {"direction": "ingress", "ethertype": "IPv6"}, ] # 系统密码 ADMIN_PASS = 'admin_pass' # 安全组 DEFAULT_SECURITY_GROUPS = ['feebe7f3-fdad-4b14-81c8-90febc5ea6c2'] # 查询异步job结果最长间隔 QUERY_SERVER_STATUS_INTERVAL = 120
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。