package com.lyh.common.aliyun.service; import com.alibaba.fastjson2.JSON; import com.aliyun.ecs20140526.Client; import com.aliyun.ecs20140526.models.*; import com.aliyun.tea.TeaException; import com.aliyun.teautil.Common; import com.aliyun.teautil.models.RuntimeOptions; import com.lyh.common.aliyun.config.AliConfig; import com.lyh.common.aliyun.model.InstanceSpecification; import com.lyh.common.utils.user.UserUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * 阿里云ecs服务器openAPI调用 * * @ProjectName: LoadCenter * @Author: LiuYunHu * @CreateTime: 2024/4/16 */ @Component @Slf4j public class AliYunEcsService { /** * 应用阿里云客户端配置 */ private final AliConfig aliConfig; private final Client client; /** * 实例规格,用于创建实例 */ @Autowired private InstanceSpecification instanceSpecification; public AliYunEcsService(AliConfig aliConfig, Client client) { this.aliConfig = aliConfig; this.client = client; } /** * 查询要删除的实例 * * @Author: LiuYunHu * @Date: 2024/4/16 20:31 * @Param: [client, regionId, instanceIds, instanceName] * @Return: DescribeInstancesResponse **/ public static DescribeInstancesResponse DescribeInstances(Client client, String regionId, String instanceIds, String instanceName) throws Exception { DescribeInstancesRequest req = new DescribeInstancesRequest() .setRegionId(regionId) .setInstanceName(instanceName); if (!Common.empty(instanceIds)) { req.instanceIds = Common.toJSONString(com.aliyun.darabonbastring.Client.split(instanceIds, ",", 50)); } DescribeInstancesResponse resp = client.describeInstances(req); com.aliyun.teaconsole.Client.log("--------------------查询需要删除的实例--------------------"); return resp; } /** * 修改实例的属性 取消 ‘释放保护’ * * @Author: LiuYunHu * @Date: 2024/4/16 20:33 * @Param: [client, instatnceId] * @Return: void **/ public static void ModifyInstanceAttribute(Client client, String instatnceId) throws Exception { ModifyInstanceAttributeRequest req = new ModifyInstanceAttributeRequest() .setInstanceId(instatnceId) .setDeletionProtection(false);//设置删除保护为false client.modifyInstanceAttribute(req); com.aliyun.teaconsole.Client.log("--------------------" + instatnceId + "释放保护取消成功--------------------"); } /** * 执行释放实例 * * @Author: LiuYunHu * @Date: 2024/4/16 20:35 * @Param: [client, regionId, instanceIds, force] * @Return: void **/ public static void DeleteInstances(com.aliyun.ecs20140526.Client client, String regionId, String instanceIds, String force) throws Exception { DeleteInstancesRequest req = new DeleteInstancesRequest() .setRegionId(regionId) .setInstanceId(com.aliyun.darabonbastring.Client.split(instanceIds, ",", 50)) .setForce(Common.equalString(force, "true")); DeleteInstancesResponse resp = client.deleteInstances(req); com.aliyun.teaconsole.Client.log("--------------------实例释放成功--------------------"); com.aliyun.teaconsole.Client.log(Common.toJSONString(Common.toMap(resp))); } /** * RunInstances 通过备选实例规格创建ECS实例最佳实践 * 该场景中,在调用RunInstances创建ECS实例时判断是否发生库存不足等错误,如果发生错误,将调用DescribeRecommendInstanceType查询备选实例,然后通过备选实例规格重新创建ECS实例。 */ public static String RunInstances(Client client, String regionId, String imageId, String instanceType, String securityGroupId, String vSwitchId, Integer internetMaxBandwidthOut, String internetChargeType, String size, String category, String instanceChargeType) throws Exception { RunInstancesRequest request = new RunInstancesRequest() .setRegionId(regionId) .setImageId(imageId) .setInstanceType(instanceType) .setSecurityGroupId(securityGroupId) .setVSwitchId(vSwitchId) .setInstanceName("自动创建的实例节点") .setDescription(new Date().toLocaleString() + " 创建的实例节点") .setInternetMaxBandwidthOut(internetMaxBandwidthOut) .setInternetChargeType(internetChargeType) .setInstanceChargeType(instanceChargeType) // 批量创建五台ECS实例,如果不设置该参数,默认创建一台ECS实例。 // amount = 5, // 如果缺少库存可以接受的最低创建数量。 // minAmount = 2, // 打开预检参数功能,不会实际创建ECS实例,只检查参数正确性、用户权限或者ECS库存等问题。 // 实际情况下,设置了DryRun参数后,Amount必须为1,MinAmount必须为空,您可以根据实际需求修改代码。 // .setDryRun(true) .setDryRun(false) .setSystemDisk(new RunInstancesRequest.RunInstancesRequestSystemDisk() .setSize(size) .setCategory(category)); String result = ""; try { com.aliyun.teaconsole.Client.log("--------------------批量创建实例开始--------------------"); RunInstancesResponse responces = client.runInstances(request); com.aliyun.teaconsole.Client.log("--------------------创建实例成功,实例ID:" + Common.toJSONString(responces.body.instanceIdSets.instanceIdSet) + "--------------------"); //返回实例ID result = responces.body.instanceIdSets.instanceIdSet + "";//前后带 [] result = UserUtil.removeBrackets(result);//前后不带[] } catch (TeaException error) { com.aliyun.teaconsole.Client.log("--------------------创建实例失败:" + Common.toJSONString(error.code) + "--------------------" + error.message); } catch (Exception _error) { TeaException error = new TeaException(_error.getMessage(), _error); com.aliyun.teaconsole.Client.log("--------------------创建实例失败:" + Common.toJSONString(error.code) + "--------------------" + error.message); } return result; } /** * 获取指定区域的实例ID列表 * * @Date: 2024/4/19 20:02 * @Param: [] * @Return: java.util.List **/ public List getIDList() throws Exception { java.util.List regionIds = com.aliyun.darabonbastring.Client.split(aliConfig.getRegionId(), ",", 50); String regionId = regionIds.get(0); DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest() .setPageSize(100) .setRegionId(regionId); DescribeInstancesResponse resp = this.client.describeInstances(describeInstancesRequest); java.util.List instances = resp.body.instances.instance; log.info("{} 下 ECS 实例列表:", regionId); //存储结果的List ArrayList result = new ArrayList<>(); for (DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance instance : instances) { // log.info("主机名:" + instance.hostName + " 实例ID:" + instance.instanceId + " CPU:" + instance.cpu + " 内存:" + instance.memory + " MB 规格:" + instance.instanceType + " 系统:" + instance.OSType + "(" + instance.OSName + ") 状态:" + instance.status); result.add(instance.instanceId); } //将查询到的ecs服务器id列表 打印控制台 log.info(JSON.toJSONString(result)); //返回结果 return result; } /** * 通过实例ID释放实例 多个实例ID,用英文逗号分隔 * * @Author: LiuYunHu * @Date: 2024/4/16 20:19 * @Description: * @Param: instanceIds 要删除实例ID **/ public void releaseInstances(String instanceIds) throws Exception { // 实例名称,支持使用通配符*进行模糊搜索 String instanceName = "*"; // 强制删除有删除保护的机器 String deleteProtected = "true"; // 强制删除运行中的机器 String force = "true"; //判断是否为强制删除 if (Common.equalString(deleteProtected, "true")) { DescribeInstancesResponse describeInstancesResp = DescribeInstances(client, aliConfig.getRegionId(), instanceIds, instanceName); instanceIds = ""; for (DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance instance : describeInstancesResp.body.instances.instance) { instanceIds = instance.instanceId + "," + instanceIds; if (instance.deletionProtection) { ModifyInstanceAttribute(client, instance.instanceId); } } instanceIds = com.aliyun.darabonbastring.Client.subString(instanceIds, 0, -1); } //如果入参为空 if (Common.empty(instanceIds)) { com.aliyun.teaconsole.Client.log("--------------------无有效实例可删除--------------------"); return; } DeleteInstances(client, aliConfig.getRegionId(), instanceIds, force); } /** * 创建并运行实例 * * @Author: LiuYunHu * @Date: 2024/4/16 21:44 * @Param: [] * @Return: java.lang.String **/ public String createAndRunInstance() throws Exception { //获取实例规格 // 地域Id String regionId = aliConfig.getRegionId(); // 镜像 ID,启动实例时选择的镜像资源。 String imageId = instanceSpecification.getImageId(); // 实例规格 String instanceType = instanceSpecification.getInstanceType(); // 新创建实例所属于的安全组 ID。 String securityGroupId = instanceSpecification.getSecurityGroupId(); // 虚拟交换机 ID。 String vSwitchId = instanceSpecification.getVSwitchId(); // 公网出带宽最大值,单位为 Mbit/s。取值范围:0~100。 默认值:0。 Integer internetMaxBandwidthOut = com.aliyun.darabonbanumber.Client.parseInt(instanceSpecification.getInternetMaxBandwidthOut()); // 网络计费类型。取值范围: // PayByBandwidth: 按固定带宽计费。 // PayByTraffic: 按使用流量计费。 // 默认值:PayByTraffic。 String internetChargeType = instanceSpecification.getInternetChargeType(); // 系统盘大小 String size = instanceSpecification.getSize(); // 系统盘的云盘种类 String category = instanceSpecification.getCategory(); // ECS实例的计费方式 // PrePaid:包年包月 // PostPaid:按量付费 String instanceChargeType = instanceSpecification.getInstanceChargeType(); // 批量创建实例 return RunInstances(client, regionId, imageId, instanceType, securityGroupId, vSwitchId, internetMaxBandwidthOut, internetChargeType, size, category, instanceChargeType); } /** * 查询一台或多台实例的信息 多台实例用英文逗号拼接 * * @Author: LiuYunHu * @Date: 2024/4/16 22:02 * @Param: [instanceIds] i-uf6chlqotgoc9h173alu **/ public List queryInstancesInformation(String instanceIds) { DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest() .setRegionId(aliConfig.getRegionId()) .setInstanceName("*") .setInstanceIds(Common.toJSONString(com.aliyun.darabonbastring.Client.split(instanceIds, ",", 50))) .setPageSize(10); RuntimeOptions runtime = new RuntimeOptions(); //初始化返回值 List instances = null; try { // 复制代码运行请自行打印 API 的返回值 DescribeInstancesResponse describeInstancesResponse = client.describeInstancesWithOptions(describeInstancesRequest, runtime); DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstances bodyInstances = describeInstancesResponse.getBody().getInstances(); // instances = bodyInstances.getInstance(); } catch (TeaException error) { // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 // 错误 message log.error(error.getMessage()); // 诊断地址 log.error(error.getData().get("Recommend").toString()); com.aliyun.teautil.Common.assertAsString(error.message); } catch (Exception _error) { TeaException error = new TeaException(_error.getMessage(), _error); // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 // 错误 message log.error(error.getMessage()); // 诊断地址 log.error(error.getData().get("Recommend").toString()); Common.assertAsString(error.message); } return instances; } }