diff --git a/src/main/java/net/educoder/CloudHostService.java b/src/main/java/net/educoder/CloudHostService.java index 09cab9b..5c80000 100644 --- a/src/main/java/net/educoder/CloudHostService.java +++ b/src/main/java/net/educoder/CloudHostService.java @@ -1,12 +1,13 @@ 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.ShellResult; import net.educoder.model.dto.CreateCloudHostDto; import net.educoder.util.JCloudUtil; +import net.educoder.util.ShellUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -62,14 +63,17 @@ public class CloudHostService { 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 command = StringUtils.join("sshpass -p ", createCloudHostDto.getPassword(), " ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ", + createCloudHostDto.getUsername(), "@", createCloudHostDto.getFloatingIp(), " \'", + "cd /root/frp_0.44.0_linux_amd64; sudo echo -e \"", template, "\" > frpc.ini ; cat frpc.ini; nohup ./frpc >& cataline.log 2>&1 &", "\'"); String uuid = RandomUtil.randomString(16); log.info("id{},配置内网穿透命令:{}", uuid, command); - - String execResult = RuntimeUtil.execForStr(command); + String execResult = ShellUtil.execute(command); log.info("id{},执行结果:{}", uuid, execResult); + createCloudHostDto.setPort(port); + createCloudHostDto.setIp(frpcHost); + return createCloudHostDto; } @@ -105,14 +109,15 @@ public class CloudHostService { * 重置云主机 * * @param serverId + * @param floatingIpId * @return */ - public boolean destroyCloudHost(String serverId) { + public boolean destroyCloudHost(String serverId, String floatingIpId) { String apiToken = guavaCache.getIfPresent(CommonConstants.API_TOKEN); if (StringUtils.isBlank(apiToken)) { apiToken = refreshApiToken(); } - JCloudUtil.oneStepDestroyCloudHost(apiToken, serverId); + JCloudUtil.oneStepDestroyCloudHost(apiToken, serverId, floatingIpId); return true; } diff --git a/src/main/java/net/educoder/controller/CloudController.java b/src/main/java/net/educoder/controller/CloudController.java index 9b7bb77..b0ebd1b 100644 --- a/src/main/java/net/educoder/controller/CloudController.java +++ b/src/main/java/net/educoder/controller/CloudController.java @@ -7,6 +7,7 @@ import net.educoder.util.ResponseResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** @@ -69,9 +70,10 @@ public class CloudController { * @return */ @PostMapping("/destroyCloudHost") - public ResponseResult destroyCloudHost(String serverId) { + public ResponseResult destroyCloudHost(@RequestParam("serverId") String serverId, + @RequestParam("floatingIpId") String floatingIpId) { - boolean status = cloudHostService.destroyCloudHost(serverId); + boolean status = cloudHostService.destroyCloudHost(serverId,floatingIpId); if (!status) { return ResponseResult.failed(-1, "销毁云主机失败"); } diff --git a/src/main/java/net/educoder/model/ShellResult.java b/src/main/java/net/educoder/model/ShellResult.java new file mode 100644 index 0000000..e935c64 --- /dev/null +++ b/src/main/java/net/educoder/model/ShellResult.java @@ -0,0 +1,48 @@ +package net.educoder.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * shell执行结果 + * + * @author 威少 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ShellResult { + /** + * 退出码 + */ + private Integer exitStatus; + /** + * 实际输出 + */ + private String out; + + public enum ExitStatus { + /** + * 成功 + */ + SUCCESS(0), + /** + * 超时 + */ + TIMEOUT(124), + /** + * 默认失败 + */ + FAIL(-1); + + private int code; + ExitStatus(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + } +} diff --git a/src/main/java/net/educoder/util/JCloudUtil.java b/src/main/java/net/educoder/util/JCloudUtil.java index dd10f57..5365b82 100644 --- a/src/main/java/net/educoder/util/JCloudUtil.java +++ b/src/main/java/net/educoder/util/JCloudUtil.java @@ -349,26 +349,35 @@ public class JCloudUtil { * } * } */ -// 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); + 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); log.info("serverId:{}------------云主机创建完成------------", serverId); CreateCloudHostDto createCloudHostDto = new CreateCloudHostDto(); createCloudHostDto.setServerId(serverId); -// createCloudHostDto.setFixedIp(fixedIp); -// createCloudHostDto.setFloatingIp(floatingIp); -// createCloudHostDto.setFloatingIpId(floatingIpId); + createCloudHostDto.setFixedIp(fixedIp); + createCloudHostDto.setFloatingIp(floatingIp); + createCloudHostDto.setFloatingIpId(floatingIpId); createCloudHostDto.setUsername(CommonConstants.DEFAULT_ROOT); createCloudHostDto.setPassword(CommonConstants.DEFAULT_PASSWORD); + // 休眠30s再更新密码 + SleepUtil.sleep(30 * 1000); + + log.info("开始执行修改云主机:{} 密码", serverId); + boolean changePwdStatus = changePassword(apiToken, serverId, "Educoder123"); + if (!changePwdStatus) { + log.error("serverId:{}密码修改失败", serverId); + } + return createCloudHostDto; } @@ -377,24 +386,12 @@ public class JCloudUtil { * * @param apiToken */ - public static void oneStepDestroyCloudHost(String apiToken, String serverId) { - // 获取云主机详情 - JSONObject cloudDetail = getCloudDetail(apiToken, serverId); - - String floatingIp = getCloudHostIp(cloudDetail, CommonConstants.FLOATING_IP_TYPE); - + public static void oneStepDestroyCloudHost(String apiToken, String serverId, String floatingIpId) { // 删除云主机 - deleteCloudHost(apiToken, serverId); - -// if(StringUtils.isNotBlank(floatingIp)){ -// -// -// // 删除浮动ip -// deleteFloatingIp(apiToken, floatingIpId); -// -// } - - + boolean status1 = deleteCloudHost(apiToken, serverId); + // 删除浮动ip + boolean status2 = deleteFloatingIp(apiToken, floatingIpId); + log.info("删除云主机状态:{},删除浮动ip状态:{}", status1, status2); } @@ -462,8 +459,12 @@ public class JCloudUtil { String apiToken = getApiToken(username, password); - String imageId = "8abf7057-95db-4b57-9a64-8249a4c64680"; - oneStepCreateCloudHost(apiToken, imageId); +// String imageId = "8abf7057-95db-4b57-9a64-8249a4c64680"; +// oneStepCreateCloudHost(apiToken, imageId); + + String serverId = "532773ed-c022-458e-85f3-f45649b08096"; + String floatingIpId = "8adc22ff-9cbd-447d-bcdc-2c45014f651a"; + oneStepDestroyCloudHost(apiToken, serverId,floatingIpId); } diff --git a/src/main/java/net/educoder/util/ShellUtil.java b/src/main/java/net/educoder/util/ShellUtil.java new file mode 100644 index 0000000..2ec7f41 --- /dev/null +++ b/src/main/java/net/educoder/util/ShellUtil.java @@ -0,0 +1,77 @@ +package net.educoder.util; + +import net.educoder.model.ShellResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +/** + * @author guange + * @date 26/02/2017 + */ +public final class ShellUtil { + + private static final Logger logger = LoggerFactory.getLogger(ShellUtil.class); + + /** + * 执行shell命令并获取输出 + */ + public static String execute(String command) { + return executeAndGetExitStatus(command).getOut(); + } + + /** + * 执行shell命令并获得输出及退出码,失败重试 共尝试retryTimes次 + */ + public static ShellResult executeAndGetExitStatus(String command, int retryTimes) { + ShellResult result = new ShellResult(); + + for (int i = 0; i < retryTimes; i++) { + result = executeAndGetExitStatus(command); + if (result.getExitStatus() != 0) { + logger.info("执行shell错误, 再次执行 command: {}, result: {}, times: {}", command, result, i); + } else { + break; + } + } + + return result; + } + + /** + * 执行命令并获得输出以及退出码 + */ + public static ShellResult executeAndGetExitStatus(String command) { + ShellResult result = new ShellResult(); + + StringBuilder out = new StringBuilder(); + Integer exitStatus = -1; + + ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", command); + pb.redirectErrorStream(true); + try { + Process process = pb.start(); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + out.append(line); + out.append(System.getProperty("line.separator")); + } + exitStatus = process.waitFor(); + + } catch (Exception e) { + logger.error("执行shell出错, command:{}", command, e); + } + + result.setOut(out.toString().trim()); + result.setExitStatus(exitStatus); + logger.debug("execute shell command: {}, out: {}, status: {}", command, out, exitStatus); + + return result; + } + + + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3f4c12f..8ed877a 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -10,11 +10,4 @@ jcloud: 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}" + template: "[common]\nserver_addr = {param1}\nserver_port = 7000\n[ssh{param2}]\ntype = tcp\nlocal_ip = 127.0.0.1\nlocal_port = 22\nremote_port = {param2}"