368 lines
17 KiB
Java
368 lines
17 KiB
Java
package com.loadcenter.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.loadcenter.common.aliyun.model.InstanceSpecification;
|
||
import com.loadcenter.common.aliyun.config.AliConfig;
|
||
import com.loadcenter.common.domain.InstancesInformation;
|
||
import com.loadcenter.common.redis.service.RedisService;
|
||
import com.loadcenter.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;
|
||
import java.util.concurrent.atomic.AtomicInteger;
|
||
|
||
/**
|
||
* @ClassName AliYunEcsService
|
||
* @Description 阿里云ecs服务器openAPI调用
|
||
* @Author Can.J
|
||
* @Date 2024/4/16
|
||
*/
|
||
@Component
|
||
@Slf4j
|
||
public class AliYunEcsService {
|
||
/*
|
||
*实例规格,用于创建实例
|
||
* */
|
||
@Autowired
|
||
private InstanceSpecification instanceSpecification;
|
||
|
||
|
||
//应用阿里云客户端配置
|
||
private final AliConfig aliConfig;
|
||
private final Client client;
|
||
|
||
public AliYunEcsService(AliConfig aliConfig, Client client) {
|
||
this.aliConfig = aliConfig;
|
||
this.client = client;
|
||
}
|
||
|
||
/*
|
||
* redis服务
|
||
* */
|
||
@Autowired
|
||
private RedisService redisService;
|
||
|
||
/**
|
||
* 获取指定区域的实例ID列表
|
||
* @return
|
||
* @throws Exception
|
||
*/
|
||
public List<String> getIDList() throws Exception {
|
||
|
||
|
||
java.util.List<String> 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<DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance> instances = resp.body.instances.instance;
|
||
com.aliyun.teaconsole.Client.log(regionId + " 下 ECS 实例列表:");
|
||
|
||
//存储结果的List
|
||
ArrayList<String> result = new ArrayList<>();
|
||
for (DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance instance : instances) {
|
||
com.aliyun.teaconsole.Client.log("主机名:" + 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,用英文逗号分隔
|
||
* @param instanceIds
|
||
* @throws Exception
|
||
*/
|
||
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);
|
||
}
|
||
|
||
/**
|
||
* 查询要删除的实例
|
||
* @param client
|
||
* @param regionId
|
||
* @param instanceIds
|
||
* @param instanceName
|
||
* @return
|
||
* @throws Exception
|
||
*/
|
||
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;
|
||
}
|
||
|
||
/**
|
||
* 修改实例的属性 取消 ‘释放保护’
|
||
* @param client
|
||
* @param instatnceId
|
||
* @throws Exception
|
||
*/
|
||
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 + "释放保护取消成功--------------------");
|
||
}
|
||
|
||
/**
|
||
* 执行释放实例
|
||
* @param client
|
||
* @param regionId
|
||
* @param instanceIds
|
||
* @param force
|
||
* @throws Exception
|
||
*/
|
||
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)));
|
||
}
|
||
|
||
/**
|
||
* 创建并运行实例
|
||
* @return
|
||
* @throws Exception
|
||
*/
|
||
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);
|
||
}
|
||
|
||
/**
|
||
* RunInstances
|
||
* 通过备选实例规格创建ECS实例最佳实践
|
||
* 该场景中,在调用RunInstances创建ECS实例时判断是否发生库存不足等错误,
|
||
* 如果发生错误,将调用DescribeRecommendInstanceType查询备选实例,
|
||
* 然后通过备选实例规格重新创建ECS实例。
|
||
* @param client
|
||
* @param regionId
|
||
* @param imageId
|
||
* @param instanceType
|
||
* @param securityGroupId
|
||
* @param vSwitchId
|
||
* @param internetMaxBandwidthOut
|
||
* @param internetChargeType
|
||
* @param size
|
||
* @param category
|
||
* @param instanceChargeType
|
||
* @return
|
||
* @throws Exception
|
||
*/
|
||
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;
|
||
}
|
||
|
||
/**
|
||
* 查询一台或多台实例的信息 多台实例用英文逗号拼接
|
||
* @param instanceIds
|
||
* @return
|
||
* @throws Exception
|
||
*/
|
||
public List<DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance> queryInstancesInformation(String instanceIds) throws Exception {
|
||
//初始化计数器
|
||
AtomicInteger count = new AtomicInteger();
|
||
|
||
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<DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance> instances = null;
|
||
|
||
try {
|
||
// 复制代码运行请自行打印 API 的返回值
|
||
DescribeInstancesResponse describeInstancesResponse = client.describeInstancesWithOptions(describeInstancesRequest, runtime);
|
||
DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstances bodyInstances = describeInstancesResponse.getBody().getInstances();
|
||
|
||
instances = bodyInstances.getInstance();
|
||
|
||
//新建List,用于redis存储实例信息
|
||
ArrayList<InstancesInformation> instancesInformations = new ArrayList<>();
|
||
|
||
for (DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance item : instances) {
|
||
log.info("查询第{" + count.get() + 1 + "}个实例的ID:" + item.getInstanceId());
|
||
log.info("名称:" + item.getInstanceName());
|
||
log.info("地域ID:" + item.getRegionId());
|
||
log.info("状态:" + item.getStatus());
|
||
log.info("类型:" + item.getInstanceType());
|
||
log.info("CPU核心数:" + item.getCpu());
|
||
log.info("内存大小:" + item.getMemory() + "MB");
|
||
log.info("磁盘大小:" + item.getLocalStorageCapacity() + "G");
|
||
log.info("操作系统:" + item.getOSName());
|
||
log.info("网络类型:" + item.getInstanceNetworkType());
|
||
log.info("公网出带宽值:" + item.getInternetMaxBandwidthOut() + "Mbit/s");
|
||
log.info("公网入带宽值:" + item.getInternetMaxBandwidthIn() + "Mbit/s");
|
||
log.info("公网IP:" + UserUtil.removeBrackets(item.getPublicIpAddress().getIpAddress().toString()));
|
||
log.info("私网IP:" + UserUtil.removeBrackets(item.getVpcAttributes().getPrivateIpAddress().ipAddress.toString()));
|
||
log.info("专有网络VPCID:" + item.getVpcAttributes().getVpcId());
|
||
log.info("安全组ID:" + UserUtil.removeBrackets(item.getSecurityGroupIds().getSecurityGroupId().toString()));
|
||
log.info("创建时间:" + item.getCreationTime());
|
||
log.info("到期时间:" + item.getExpiredTime());
|
||
log.info("是否可以回收:" + (item.getRecyclable() ? "是" : "否") + "\n\n");
|
||
|
||
//存入集合
|
||
instancesInformations.add(
|
||
new InstancesInformation(
|
||
item.getInstanceId(),
|
||
item.getInstanceName(),
|
||
item.getStatus(),
|
||
UserUtil.removeBrackets(item.getPublicIpAddress().getIpAddress().toString()),
|
||
UserUtil.removeBrackets(item.getVpcAttributes().getPrivateIpAddress().ipAddress.toString()),
|
||
item.getCreationTime(),
|
||
item.getExpiredTime(),
|
||
item.getRecyclable()
|
||
)
|
||
);
|
||
|
||
count.getAndIncrement();
|
||
}
|
||
//缓存数据
|
||
redisService.deleteObject("服务器信息:");
|
||
redisService.setCacheList("服务器信息:", instancesInformations);
|
||
|
||
} 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;
|
||
}
|
||
}
|