master
youys 2 years ago
parent a882531be6
commit 579c42e620

@ -0,0 +1,132 @@
package net.educoder;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.RuntimeUtil;
import com.google.common.cache.Cache;
import lombok.extern.slf4j.Slf4j;
import net.educoder.constant.CommonConstants;
import net.educoder.model.dto.CreateCloudHostDto;
import net.educoder.util.JCloudUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/**
* @Author: youys
* @Date: 2022/8/18
* @Description:
*/
@Slf4j
@Service
public class CloudHostService {
@Value("${jcloud.username}")
private String username;
@Value("${jcloud.password}")
private String password;
@Value("${jcloud.imageId}")
private String imageId;
@Value("${jcloud.frpc.template}")
private String frpcTemplate;
@Value("${jcloud.frpc.host}")
private String frpcHost;
@Autowired
@Qualifier("guavaCache")
private Cache<String, String> guavaCache;
/**
*
* 1
* 2ip
* 3ip
*
* @param port 穿
* @return
*/
public CreateCloudHostDto oneStepCreateCloudHost(int port) {
String apiToken = guavaCache.getIfPresent(CommonConstants.API_TOKEN);
if (StringUtils.isBlank(apiToken)) {
apiToken = refreshApiToken();
}
// 创建云主机
CreateCloudHostDto createCloudHostDto = JCloudUtil.oneStepCreateCloudHost(apiToken, imageId);
String template = frpcTemplate.replaceAll("\\{param1}", frpcHost).replaceAll("\\{param2}", String.valueOf(port));
// 通过浮动ip+port 连接ssh执行脚本
String command = StringUtils.join("sshpass -p ", createCloudHostDto.getPassword(), " ssh -o UserKnownHostsFile=/dev/null ",
createCloudHostDto.getUsername(), "@", createCloudHostDto.getFloatingIp(), " \"", "cd /root/frp_0.44.0_linux_amd64; echo \'", template, "\' > frpc.ini", "\"");
String uuid = RandomUtil.randomString(16);
log.info("id{},配置内网穿透命令:{}", uuid, command);
String execResult = RuntimeUtil.execForStr(command);
log.info("id{},执行结果:{}", uuid, execResult);
return createCloudHostDto;
}
/**
*
*
* @return
*/
public String getCloudHostList() {
String apiToken = guavaCache.getIfPresent(CommonConstants.API_TOKEN);
if (StringUtils.isBlank(apiToken)) {
apiToken = refreshApiToken();
}
return JCloudUtil.getCloudListDetail(apiToken);
}
/**
*
*
* @param serverId
* @return
*/
public boolean resetCloudHost(String serverId) {
String apiToken = guavaCache.getIfPresent(CommonConstants.API_TOKEN);
if (StringUtils.isBlank(apiToken)) {
apiToken = refreshApiToken();
}
return JCloudUtil.rebuildCloud(apiToken, serverId);
}
/**
*
*
* @param serverId
* @return
*/
public boolean destroyCloudHost(String serverId) {
String apiToken = guavaCache.getIfPresent(CommonConstants.API_TOKEN);
if (StringUtils.isBlank(apiToken)) {
apiToken = refreshApiToken();
}
JCloudUtil.oneStepDestroyCloudHost(apiToken, serverId);
return true;
}
/**
* token
*/
private String refreshApiToken() {
String apiToken = JCloudUtil.getApiToken(username, password);
log.info("token refresh--------{}", apiToken);
guavaCache.put(CommonConstants.API_TOKEN, apiToken);
return apiToken;
}
}

@ -7,12 +7,24 @@ package net.educoder.constant;
*/
public class CommonConstants {
public static final String SUCCESS = "success";
public static final String FAILED = "failed";
public static final String API_TOKEN = "api_token";
/**
*
*/
public static final String DEFAULT_ROOT = "root";
/**
*
*/
public static final String DEFAULT_PASSWORD = "Educoder123";
public static final String DEFAULT_PASSWORD = "Educoder_123123";
/**
* id
*/
public static final String FIXED_IP_TYPE = "fixed";
/**
* ip
*/
public static final String FLOATING_IP_TYPE = "floating";
}

@ -1,14 +1,10 @@
package net.educoder.controller;
import com.google.common.cache.Cache;
import lombok.extern.slf4j.Slf4j;
import net.educoder.constant.CommonConstants;
import net.educoder.util.JCloudUtil;
import net.educoder.CloudHostService;
import net.educoder.model.dto.CreateCloudHostDto;
import net.educoder.util.ResponseResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -23,16 +19,8 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/jcloud")
public class CloudController {
@Value("${jcloud.username}")
private String username;
@Value("${jcloud.password}")
private String password;
@Autowired
@Qualifier("guavaCache")
private Cache<String, String> guavaCache;
private CloudHostService cloudHostService;
/**
@ -41,14 +29,9 @@ public class CloudController {
* @return
*/
@PostMapping("/createCloudHost")
public ResponseResult<String> createCloudHost() {
String apiToken = guavaCache.getIfPresent(CommonConstants.API_TOKEN);
if (StringUtils.isBlank(apiToken)) {
apiToken = refreshApiToken();
}
JCloudUtil.createCloudHost(apiToken, JCloudUtil.defaultCreateCloudHostParam());
return ResponseResult.success();
public ResponseResult<CreateCloudHostDto> createCloudHost(int port) {
CreateCloudHostDto createCloudHostDto = cloudHostService.oneStepCreateCloudHost(port);
return ResponseResult.success(createCloudHostDto);
}
@ -59,13 +42,7 @@ public class CloudController {
*/
@PostMapping("/getCloudHostList")
public ResponseResult<String> getCloudHostList() {
String apiToken = guavaCache.getIfPresent(CommonConstants.API_TOKEN);
if (StringUtils.isBlank(apiToken)) {
apiToken = refreshApiToken();
}
String cloudHost = JCloudUtil.createCloudHost(apiToken, JCloudUtil.defaultCreateCloudHostParam());
String cloudHost = cloudHostService.getCloudHostList();
return ResponseResult.success(cloudHost);
}
@ -78,38 +55,27 @@ public class CloudController {
@PostMapping("/resetCloudHost")
public ResponseResult resetCloudHost(String serverId) {
String apiToken = guavaCache.getIfPresent(CommonConstants.API_TOKEN);
if (StringUtils.isBlank(apiToken)) {
apiToken = refreshApiToken();
}
boolean status = JCloudUtil.rebuildCloud(apiToken, serverId);
boolean status = cloudHostService.resetCloudHost(serverId);
if (!status) {
return ResponseResult.failed(-1, "重置云主机失败");
}
// 等待30秒再重置密码
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 重置之后需要再更新密码
boolean changePwdStatus = JCloudUtil.changePassword(apiToken, serverId, CommonConstants.DEFAULT_PASSWORD);
return changePwdStatus ? ResponseResult.success() : ResponseResult.failed(-1,"重置密码失败");
return ResponseResult.success();
}
/**
* token
*
*
* @return
*/
private String refreshApiToken() {
String apiToken = JCloudUtil.getApiToken(username, password);
log.info("token refresh--------{}", apiToken);
guavaCache.put(CommonConstants.API_TOKEN, apiToken);
@PostMapping("/destroyCloudHost")
public ResponseResult destroyCloudHost(String serverId) {
return apiToken;
boolean status = cloudHostService.destroyCloudHost(serverId);
if (!status) {
return ResponseResult.failed(-1, "销毁云主机失败");
}
return ResponseResult.success();
}
}

@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j;
import net.educoder.exception.BusinessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ -21,7 +22,7 @@ public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
@ResponseBody
public ResponseEntity<JSONObject> handleBridgeExceptions(BusinessException e) {
public ResponseEntity<JSONObject> handleBusinessException(BusinessException e) {
log.error("捕获到BusinessException", e);
JSONObject jsonObj = new JSONObject();
@ -31,6 +32,18 @@ public class GlobalExceptionHandler {
return new ResponseEntity<>(jsonObj, HttpStatus.OK);
}
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
@ResponseBody
public ResponseEntity<JSONObject> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
log.error("捕获到HttpRequestMethodNotSupportedException", e);
JSONObject jsonObj = new JSONObject();
jsonObj.put("code", -1);
jsonObj.put("msg", "请求方法错误");
return new ResponseEntity<>(jsonObj, HttpStatus.OK);
}
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseEntity<JSONObject> handleOtherExceptions(Exception e) {
@ -38,10 +51,8 @@ public class GlobalExceptionHandler {
JSONObject jsonObj = new JSONObject();
if (e.getMessage().contains("Maximum upload size exceeded")) {
jsonObj.put("code", -1);
jsonObj.put("msg", "未知错误!" + e.getMessage());
}
jsonObj.put("code", -1);
jsonObj.put("msg", "系统错误!");
return new ResponseEntity<>(jsonObj, HttpStatus.OK);
}

@ -0,0 +1,50 @@
package net.educoder.model.dto;
import lombok.Data;
/**
* @Author: youys
* @Date: 2022/8/18
* @Description:
*/
@Data
public class CreateCloudHostDto {
/**
* id
*/
private String serverId;
/**
* ip
*/
private String fixedIp;
/**
* id
*/
private String floatingIp;
/**
* ip id
*/
private String floatingIpId;
/**
* ip
*/
private String ip;
/**
*
*/
private String username;
/**
*
*/
private String password;
/**
*
*/
private int port;
}

@ -6,7 +6,9 @@ import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import net.educoder.constant.CommonConstants;
import net.educoder.exception.BusinessException;
import net.educoder.model.dto.CreateCloudHostDto;
import net.educoder.model.param.CreateCloudHostParam;
import org.apache.commons.lang3.StringUtils;
@ -21,6 +23,65 @@ import java.util.concurrent.atomic.AtomicReference;
@Slf4j
public class JCloudUtil {
/**
* api token
*
* @param username
* @param password
* @return
*/
public static String getApiToken(String username, String password) {
/**
* {
* "auth": {
* "identity": {
* "methods": [
* "password"
* ],
* "password": {
* "user": {
* "name": "admin",
* "domain": {
* "name": "Default"
* },
* "password": "devstacker"
* }
* }
* }
* }
* }
*/
JSONObject domain = new JSONObject();
domain.put("name", "Default");
JSONObject user = new JSONObject();
user.put("name", username);
user.put("password", password);
user.put("domain", domain);
JSONObject passwordJson = new JSONObject();
passwordJson.put("user", user);
JSONObject identity = new JSONObject();
identity.put("methods", Arrays.asList("password"));
identity.put("password", passwordJson);
JSONObject auth = new JSONObject();
auth.put("identity", identity);
JSONObject requestBody = new JSONObject();
requestBody.put("auth", auth);
HttpResponse response = HttpRequest.post("https://home.jcloud.sjtu.edu.cn:5000/v3/auth/tokens").header("Content-Type", "application/json").body(requestBody.toJSONString()).execute();
if (response.isOk()) {
String token = response.header("X-Subject-Token");
log.info("交我算平台获取token成功,token: {}", token);
return token;
}
log.info("交我算平台获取token失败,body:{}", response.body());
return "";
}
/**
*
@ -97,6 +158,29 @@ public class JCloudUtil {
return result;
}
/**
*
*
* @param token
* @param serverId
* @return
*/
public static boolean deleteCloudHost(String token, String serverId) {
String url = "https://home.jcloud.sjtu.edu.cn:8774/v2.1/servers/{server_id}".replaceAll("\\{server_id}", serverId);
long start = System.currentTimeMillis();
try {
String result = HttpRequest.delete(url).header("Content-Type", "application/json").header("X-Auth-Token", token).execute().body();
long end = System.currentTimeMillis();
log.info("交大云删除云主机返回结果:{},耗时:{}ms", result, (end - start));
} catch (Exception e) {
log.error("交大云删除云主机异常", e);
return false;
}
return true;
}
/**
*
*
@ -124,7 +208,7 @@ public class JCloudUtil {
String result = HttpRequest.post(url).header("Content-Type", "application/json").header("X-Auth-Token", token).body(requestBody.toJSONString()).execute().body();
long end = System.currentTimeMillis();
log.info("交大云更改云主机密码返回结果:{},耗时:{}ms", result, (end - start));
return StringUtils.isNotBlank(result);
return StringUtils.isBlank(result);
}
/**
@ -158,26 +242,9 @@ public class JCloudUtil {
return true;
}
/**
*
*
* @param serverId
* @param token
* @return
*/
public static boolean deleteCloudHost(String serverId, String token) {
String url = "https://home.jcloud.sjtu.edu.cn:8774/v2.1/servers/{server_id}".replaceAll("\\{server_id}", serverId);
long start = System.currentTimeMillis();
String result = HttpRequest.delete(url).header("Content-Type", "application/json").header("X-Auth-Token", token).execute().body();
long end = System.currentTimeMillis();
log.info("交大云删除云主机返回结果:{},耗时:{}ms", result, (end - start));
return StringUtils.isBlank(result);
}
/**
* id
* ip
*
* @param token
* @return
@ -193,10 +260,30 @@ public class JCloudUtil {
String result = HttpRequest.post(url).header("Content-Type", "application/json").header("X-Auth-Token", token).body(body.toJSONString()).execute().body();
long end = System.currentTimeMillis();
log.info("交大云创建浮动id返回结果:{},耗时:{}ms", result, (end - start));
return result;
}
/**
* ip
*
* @param token
* @return
*/
public static boolean deleteFloatingIp(String token, String floatingIpId) {
String url = "https://home.jcloud.sjtu.edu.cn:8774/v2.1/os-floating-ips/{floating_ip_id}".replaceAll("\\{floating_ip_id}", floatingIpId);
long start = System.currentTimeMillis();
try {
String result = HttpRequest.delete(url).header("Content-Type", "application/json").header("X-Auth-Token", token).execute().body();
long end = System.currentTimeMillis();
log.info("交大云创删除浮动ip返回结果:{},耗时:{}ms", result, (end - start));
} catch (Exception e) {
return false;
}
return true;
}
/**
* ip
@ -226,80 +313,13 @@ public class JCloudUtil {
/**
* api token
*
*
* @return token
* @param apiToken
*/
public static String getApiToken(String username, String password) {
/**
* {
* "auth": {
* "identity": {
* "methods": [
* "password"
* ],
* "password": {
* "user": {
* "name": "admin",
* "domain": {
* "name": "Default"
* },
* "password": "devstacker"
* }
* }
* }
* }
* }
*/
JSONObject domain = new JSONObject();
domain.put("name", "Default");
JSONObject user = new JSONObject();
user.put("name", username);
user.put("password", password);
user.put("domain", domain);
JSONObject passwordJson = new JSONObject();
passwordJson.put("user", user);
JSONObject identity = new JSONObject();
identity.put("methods", Arrays.asList("password"));
identity.put("password", passwordJson);
JSONObject auth = new JSONObject();
auth.put("identity", identity);
JSONObject requestBody = new JSONObject();
requestBody.put("auth", auth);
HttpResponse response = HttpRequest.post("https://home.jcloud.sjtu.edu.cn:5000/v3/auth/tokens").header("Content-Type", "application/json").body(requestBody.toJSONString()).execute();
if (response.isOk()) {
String token = response.header("X-Subject-Token");
log.info("交我算平台获取token成功,token: {}", token);
return token;
}
log.info("交我算平台获取token失败,body:{}", response.body());
return "";
}
public static void main(String[] args) {
String username = "educoder01";
String password = "Educoder123";
String apiToken = getApiToken(username, password);
stepCreate(apiToken);
// boolean changeStatus = changePassword(apiToken, "d1efeec9-9087-4b83-a8df-557b226f7031", "Educoder123");
// if (!changeStatus) {
// System.out.println("修改密码失败");
// return;
// }
}
private static void stepCreate(String apiToken){
public static CreateCloudHostDto oneStepCreateCloudHost(String apiToken, String imageId) {
// 创建云主机
String createCloudHost = createCloudHost(apiToken, defaultCreateCloudHostParam());
String createCloudHost = createCloudHost(apiToken, defaultCreateCloudHostParam(imageId));
// 获取serverId
String serverId = JSONObject.parseObject(createCloudHost).getJSONObject("server").getString("id");
@ -308,23 +328,13 @@ public class JCloudUtil {
// 轮询查询创建云主机状态
int number = 120;
while (!"ACTIVE".equals(getServerStatus(cloudDetail = getCloudDetail(apiToken, serverId))) && number-- > 0) {
sleep(1000);
SleepUtil.sleep(1000);
}
if(number <= 0){
if (number <= 0) {
// 说明创建云主机失败了
System.out.println("云主机创建失败");
return;
}
sleep(1000);
// 修改密码
boolean changeStatus = changePassword(apiToken, serverId, "Educoder123");
if (!changeStatus) {
System.out.println("修改密码失败");
return;
log.error("serverId:{}云主机创建失败", serverId);
throw new BusinessException("云主机创建失败");
}
/**
@ -339,16 +349,52 @@ public class JCloudUtil {
* }
* }
*/
// String fixedIp = getFixedIp(cloudDetail);
// String fixedIp = getCloudHostIp(cloudDetail, CommonConstants.FIXED_IP_TYPE);
//
// String floatingIpStr = createFloatingIp(apiToken);
// JSONObject floatingIpObj = JSONObject.parseObject(floatingIpStr).getJSONObject("floating_ip");
// String floatingIp = floatingIpObj.getString("ip");
//
// String floatingIpId = floatingIpObj.getString("id");
//
// // 云主机绑定浮动ip
// serverBindFloatingIp(apiToken, serverId, fixedIp, floatingIp);
// System.out.println("------------云主机创建完成------------");
log.info("serverId:{}------------云主机创建完成------------", serverId);
CreateCloudHostDto createCloudHostDto = new CreateCloudHostDto();
createCloudHostDto.setServerId(serverId);
// createCloudHostDto.setFixedIp(fixedIp);
// createCloudHostDto.setFloatingIp(floatingIp);
// createCloudHostDto.setFloatingIpId(floatingIpId);
createCloudHostDto.setUsername(CommonConstants.DEFAULT_ROOT);
createCloudHostDto.setPassword(CommonConstants.DEFAULT_PASSWORD);
return createCloudHostDto;
}
/**
*
*
* @param apiToken
*/
public static void oneStepDestroyCloudHost(String apiToken, String serverId) {
// 获取云主机详情
JSONObject cloudDetail = getCloudDetail(apiToken, serverId);
String floatingIp = getCloudHostIp(cloudDetail, CommonConstants.FLOATING_IP_TYPE);
// 删除云主机
deleteCloudHost(apiToken, serverId);
// if(StringUtils.isNotBlank(floatingIp)){
//
//
// // 删除浮动ip
// deleteFloatingIp(apiToken, floatingIpId);
//
// }
}
@ -360,41 +406,42 @@ public class JCloudUtil {
*
* @return
*/
public static CreateCloudHostParam defaultCreateCloudHostParam() {
public static CreateCloudHostParam defaultCreateCloudHostParam(String imageId) {
CreateCloudHostParam createCloudHost = new CreateCloudHostParam();
createCloudHost.setName(RandomUtil.randomString(10));
createCloudHost.setImageRef("31a54313-bcfe-4c6e-9e19-dcad8360ef56");
// 镜像id
createCloudHost.setImageRef(imageId);
createCloudHost.setFlavorRef("02723f5f-5518-4031-bd5e-dfecae675606");
// 网络id
createCloudHost.setNetworkId("f41ece4b-ff14-4444-8d1d-c730779a0df2");
return createCloudHost;
}
/**
* ip
*
* @param cloudDetail
* @return
*/
private static String getFixedIp(JSONObject cloudDetail) {
private static String getCloudHostIp(JSONObject cloudDetail, String type) {
JSONObject addresses = cloudDetail.getJSONObject("server").getJSONObject("addresses");
AtomicReference<String> fixedIp = new AtomicReference<>();
AtomicReference<String> ip = new AtomicReference<>();
addresses.forEach((key, value) -> {
JSONArray networks = (JSONArray) value;
for (Object o : networks) {
JSONObject addressDetail = (JSONObject) o;
if ("fixed".equals(addressDetail.getString("OS-EXT-IPS:type"))) {
fixedIp.set(addressDetail.getString("addr"));
if (type.equals(addressDetail.getString("OS-EXT-IPS:type"))) {
ip.set(addressDetail.getString("addr"));
break;
}
}
});
return fixedIp.get();
return ip.get();
}
@ -409,12 +456,15 @@ public class JCloudUtil {
return server.getString("status");
}
private static void sleep(long time){
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
public static void main(String[] args) {
String username = "educoder01";
String password = "Educoder123";
String apiToken = getApiToken(username, password);
String imageId = "8abf7057-95db-4b57-9a64-8249a4c64680";
oneStepCreateCloudHost(apiToken, imageId);
}

@ -0,0 +1,20 @@
package net.educoder.util;
/**
* @Author: youys
* @Date: 2022/8/18
* @Description: 线
*/
public class SleepUtil {
/**
*
* @param time
*/
public static void sleep(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
}
}
}

@ -7,3 +7,14 @@ server:
jcloud:
username: educoder01
password: Educoder123
imageId: 8abf7057-95db-4b57-9a64-8249a4c64680
frpc:
host: 39.104.50.181
template: "[common]
server_addr = {param1}
server_port = 7000
[ssh{param2}]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = {param2}"

Loading…
Cancel
Save