From 15be9161f30940fa43423a0c32726f84ce05988a Mon Sep 17 00:00:00 2001 From: hyunjujeong Date: Wed, 6 Sep 2023 14:49:10 +0900 Subject: [PATCH] =?UTF-8?q?-=20command=20type=20=EC=9D=B4=20deploy=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=EC=9D=BC=20=EA=B2=BD=EC=9A=B0=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DeviceDeployerApplication.java | 11 +++ .../application/BashCommand.java | 3 +- .../application/CommandInfo.java | 2 +- .../application/CommandInvoker.java | 22 +++-- .../application/DefaultDeployerService.java | 25 ++---- .../application/DeployCommand.java | 11 +-- .../application/DeployCommandInvoker.java | 23 +++++- .../application/DeployerService.java | 4 +- .../application/DockerCommand.java | 4 +- .../application/JsonCommand.java | 3 +- .../application/SystemdCommand.java | 3 +- .../devicedeployer/domain/DeployRequest.java | 16 +--- .../domain/OutboundMessage.java | 63 ++++++++++----- .../devicedeployer/domain/Result.java | 10 +++ .../devicedeployer/domain/Status.java | 9 ++- .../devicedeployer/domain/SubCommandType.java | 3 +- .../mqtt/InboundDeployMessagePayload.java | 9 +-- .../mqtt/OutboundMessagePayload.java | 1 - .../relational/AssetAppEntity.java | 28 +++++-- .../AssetAppRelationalRepository.java | 7 +- .../relational/DeployRequestEntity.java | 10 +-- .../DeployRequestRelationalRepository.java | 2 - .../presentation/DeployerController.java | 35 ++++++-- .../presentation/GiteaApiRequestHandler.java | 80 +++++++++++++++++++ .../presentation/OutboundMessageResource.java | 4 +- .../OutboundMessageResourceConverter.java | 10 +-- .../exception/ControllerAdvice.java | 12 +++ .../exception/NotFoundException.java | 12 +++ .../RestTemplateResponseErrorHandler.java | 28 +++++++ src/main/resources/application-dev.yml | 2 +- src/main/resources/application-local.yml | 2 +- 31 files changed, 327 insertions(+), 127 deletions(-) create mode 100644 src/main/java/inc/sdt/blokworks/devicedeployer/domain/Result.java create mode 100644 src/main/java/inc/sdt/blokworks/devicedeployer/presentation/GiteaApiRequestHandler.java create mode 100644 src/main/java/inc/sdt/blokworks/devicedeployer/presentation/exception/NotFoundException.java create mode 100644 src/main/java/inc/sdt/blokworks/devicedeployer/presentation/rest/RestTemplateResponseErrorHandler.java diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/DeviceDeployerApplication.java b/src/main/java/inc/sdt/blokworks/devicedeployer/DeviceDeployerApplication.java index c469804..56c4466 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/DeviceDeployerApplication.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/DeviceDeployerApplication.java @@ -1,7 +1,11 @@ package inc.sdt.blokworks.devicedeployer; +import inc.sdt.blokworks.devicedeployer.presentation.rest.RestTemplateResponseErrorHandler; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; @SpringBootApplication public class DeviceDeployerApplication { @@ -10,4 +14,11 @@ public class DeviceDeployerApplication { SpringApplication.run(DeviceDeployerApplication.class, args); } + @Bean + public RestTemplate restTemplate(RestTemplateBuilder builder) { + return builder + .errorHandler(new RestTemplateResponseErrorHandler()) + .build(); + } + } diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/application/BashCommand.java b/src/main/java/inc/sdt/blokworks/devicedeployer/application/BashCommand.java index ddf6367..867c470 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/application/BashCommand.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/application/BashCommand.java @@ -8,7 +8,8 @@ import java.util.LinkedHashMap; @Component public class BashCommand implements CommandInfo{ @Override - public LinkedHashMap put(OutboundMessage message, LinkedHashMap map) { + public LinkedHashMap put(OutboundMessage message) { + LinkedHashMap map = new LinkedHashMap<>(); map.put("cmd", message.getCommand()); return map; } diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/application/CommandInfo.java b/src/main/java/inc/sdt/blokworks/devicedeployer/application/CommandInfo.java index 60cf095..3ee1e3d 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/application/CommandInfo.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/application/CommandInfo.java @@ -5,5 +5,5 @@ import inc.sdt.blokworks.devicedeployer.domain.OutboundMessage; import java.util.LinkedHashMap; public interface CommandInfo { - LinkedHashMap put(OutboundMessage message, LinkedHashMap map); + LinkedHashMap put(OutboundMessage message); } diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/application/CommandInvoker.java b/src/main/java/inc/sdt/blokworks/devicedeployer/application/CommandInvoker.java index d69635e..aa3fdef 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/application/CommandInvoker.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/application/CommandInvoker.java @@ -1,6 +1,7 @@ package inc.sdt.blokworks.devicedeployer.application; import inc.sdt.blokworks.devicedeployer.domain.OutboundMessage; +import inc.sdt.blokworks.devicedeployer.presentation.GiteaApiRequestHandler; import org.springframework.stereotype.Component; import java.util.LinkedHashMap; @@ -13,7 +14,11 @@ public class CommandInvoker { private final JsonCommand jsonCommand; private final DeployCommandInvoker deployCommandInvoker; - public CommandInvoker(BashCommand bashCommand, SystemdCommand systemdCommand, DockerCommand dockerCommand, JsonCommand jsonCommand, DeployCommandInvoker deployCommandInvoker) { + public CommandInvoker(BashCommand bashCommand, + SystemdCommand systemdCommand, + DockerCommand dockerCommand, + JsonCommand jsonCommand, + DeployCommandInvoker deployCommandInvoker) { this.bashCommand = bashCommand; this.systemdCommand = systemdCommand; this.dockerCommand = dockerCommand; @@ -21,22 +26,25 @@ public class CommandInvoker { this.deployCommandInvoker = deployCommandInvoker; } - public LinkedHashMap invoke(OutboundMessage message, LinkedHashMap map) { + public LinkedHashMap invoke(OutboundMessage message) { + if(message.getCommandType() == null) { + throw new IllegalArgumentException(); + } switch (message.getCommandType()) { case bash -> { - return bashCommand.put(message, map); + return bashCommand.put(message); } case systemd -> { - return systemdCommand.put(message, map); + return systemdCommand.put(message); } case docker -> { - return dockerCommand.put(message, map); + return dockerCommand.put(message); } case deploy -> { - return deployCommandInvoker.invoke(message, map); + return deployCommandInvoker.invoke(message); } default -> { - return jsonCommand.put(message, map); + return jsonCommand.put(message); } } } diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/application/DefaultDeployerService.java b/src/main/java/inc/sdt/blokworks/devicedeployer/application/DefaultDeployerService.java index d0d5c9f..33164ac 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/application/DefaultDeployerService.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/application/DefaultDeployerService.java @@ -5,12 +5,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import inc.sdt.blokworks.devicedeployer.domain.*; import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.InboundDeployMessagePayload; import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.OutboundMessagePayload; +import inc.sdt.blokworks.devicedeployer.presentation.GiteaApiRequestHandler; import org.eclipse.paho.client.mqttv3.IMqttClient; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; @@ -25,36 +25,27 @@ public class DefaultDeployerService implements DeployerService{ private final ObjectMapper objectMapper; private final DeployerRepositoryDelegate deployerRepositoryDelegate; private final DeployRequestRepositoryDelegate requestRepositoryDelegate; - private final CommandInvoker commandInvoker; public DefaultDeployerService(IMqttClient mqttClient, ObjectMapper objectMapper, DeployerRepositoryDelegate deployerRepositoryDelegate, - DeployRequestRepositoryDelegate requestRepositoryDelegate, - CommandInvoker commandInvoker) { + DeployRequestRepositoryDelegate requestRepositoryDelegate) { this.log = LoggerFactory.getLogger(this.getClass()); this.mqttClient = mqttClient; this.objectMapper = objectMapper; this.deployerRepositoryDelegate = deployerRepositoryDelegate; this.requestRepositoryDelegate = requestRepositoryDelegate; - this.commandInvoker = commandInvoker; } @Override - public void publish(OutboundMessage outboundMessage, String assetCode) { - log.info("[publish] deployMessage = {}, assetCode = {}", outboundMessage, assetCode); - final DeviceType deviceType = outboundMessage.getDeviceType(); - LinkedHashMap commandInfo = new LinkedHashMap<>(); - + public void publish(OutboundMessage outboundMessage) { + log.info("[publish] outboundMessage = {}", outboundMessage); try { - commandInfo = commandInvoker.invoke(outboundMessage, commandInfo); - OutboundMessagePayload payload = new OutboundMessagePayload( - commandInfo, + outboundMessage.getCommandInfo(), outboundMessage.getCommandType(), outboundMessage.getSubCommandType(), - deviceType, - assetCode, + outboundMessage.getAssetCode(), outboundMessage.getRequestId() ); @@ -62,8 +53,8 @@ public class DefaultDeployerService implements DeployerService{ MqttMessage message = new MqttMessage(); message.setPayload(bytes); - mqttClient.publish("/devicecontrol/"+deviceType+"/"+assetCode, message); - log.info("[publish] message = {}", message); + mqttClient.publish("/device-control/"+outboundMessage.getAssetCode(), message); + log.info("[publish] payload = {}", payload); }catch (JsonProcessingException | MqttException e) { throw new IllegalArgumentException(); } diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/application/DeployCommand.java b/src/main/java/inc/sdt/blokworks/devicedeployer/application/DeployCommand.java index fb0d1af..3ef0d71 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/application/DeployCommand.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/application/DeployCommand.java @@ -8,19 +8,14 @@ import java.util.LinkedHashMap; @Component public class DeployCommand implements CommandInfo { - private final String filePath; - - public DeployCommand(@Value("${stackbase.api.host}") String filePath) { - this.filePath = filePath; - } @Override - public LinkedHashMap put(OutboundMessage message, LinkedHashMap map) { - final String url = filePath + message.getFileId(); + public LinkedHashMap put(OutboundMessage message) { + LinkedHashMap map = new LinkedHashMap<>(); map.put("cmd", message.getCommand()); map.put("appName", message.getAppName()); map.put("name", message.getName()); - map.put("fileUrl", url); + map.put("fileUrl", message.getUrl()); map.put("fileType", message.getFileType()); return map; } diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/application/DeployCommandInvoker.java b/src/main/java/inc/sdt/blokworks/devicedeployer/application/DeployCommandInvoker.java index 5f53f1d..985e823 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/application/DeployCommandInvoker.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/application/DeployCommandInvoker.java @@ -1,27 +1,42 @@ package inc.sdt.blokworks.devicedeployer.application; import inc.sdt.blokworks.devicedeployer.domain.OutboundMessage; +import inc.sdt.blokworks.devicedeployer.domain.SubCommandType; +import inc.sdt.blokworks.devicedeployer.presentation.GiteaApiRequestHandler; import org.springframework.stereotype.Component; import java.util.LinkedHashMap; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; @Component public class DeployCommandInvoker { private final DockerCommand dockerCommand; private final DeployCommand deployCommand; + private final JsonCommand jsonCommand; - public DeployCommandInvoker(DockerCommand dockerCommand, DeployCommand deployCommand) { + public DeployCommandInvoker(DockerCommand dockerCommand, DeployCommand deployCommand, JsonCommand jsonCommand) { this.dockerCommand = dockerCommand; this.deployCommand = deployCommand; + this.jsonCommand = jsonCommand; } - public LinkedHashMap invoke(OutboundMessage message, LinkedHashMap map) { + public LinkedHashMap invoke(OutboundMessage message) { + if(message.getSubCommandType() == null) { + throw new IllegalArgumentException(); + } + switch (message.getSubCommandType()) { case systemd -> { - return deployCommand.put(message, map); + return deployCommand.put(message); + } + case docker -> { + return dockerCommand.put(message); } default -> { - return dockerCommand.put(message, map); + return jsonCommand.put(message); } } } diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/application/DeployerService.java b/src/main/java/inc/sdt/blokworks/devicedeployer/application/DeployerService.java index 0ac5f75..449b42e 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/application/DeployerService.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/application/DeployerService.java @@ -7,10 +7,12 @@ import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.InboundDeployMessage import org.springframework.data.domain.Page; import reactor.core.publisher.Mono; +import java.util.LinkedHashMap; +import java.util.Optional; import java.util.function.Function; public interface DeployerService extends Function> { - void publish(OutboundMessage assetApp, String assetCode); + void publish(OutboundMessage message); DeployRequest save(DeployRequest deployRequest); Page getAll(String assetCode, int page, int size); } diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/application/DockerCommand.java b/src/main/java/inc/sdt/blokworks/devicedeployer/application/DockerCommand.java index 30f6441..657cb25 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/application/DockerCommand.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/application/DockerCommand.java @@ -9,8 +9,10 @@ import java.util.LinkedHashMap; public class DockerCommand implements CommandInfo { @Override - public LinkedHashMap put(OutboundMessage message, LinkedHashMap map) { + public LinkedHashMap put(OutboundMessage message) { + LinkedHashMap map = new LinkedHashMap<>(); map.put("cmd", message.getCommand()); + map.put("appName", message.getAppName()); map.put("name", message.getName()); // container 이름 map.put("image", message.getImage()); map.put("options", message.getOptions()); diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/application/JsonCommand.java b/src/main/java/inc/sdt/blokworks/devicedeployer/application/JsonCommand.java index 8eea938..02f2a06 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/application/JsonCommand.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/application/JsonCommand.java @@ -8,7 +8,8 @@ import java.util.LinkedHashMap; @Component public class JsonCommand implements CommandInfo { @Override - public LinkedHashMap put(OutboundMessage message, LinkedHashMap map) { + public LinkedHashMap put(OutboundMessage message) { + LinkedHashMap map = new LinkedHashMap<>(); map.put("cmd", String.valueOf(message.getCommandType())); map.put("appName", message.getAppName()); map.put("parameter", message.getParameters()); diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/application/SystemdCommand.java b/src/main/java/inc/sdt/blokworks/devicedeployer/application/SystemdCommand.java index dd6118c..8355867 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/application/SystemdCommand.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/application/SystemdCommand.java @@ -8,7 +8,8 @@ import java.util.LinkedHashMap; @Component public class SystemdCommand implements CommandInfo { @Override - public LinkedHashMap put(OutboundMessage message, LinkedHashMap map) { + public LinkedHashMap put(OutboundMessage message) { + LinkedHashMap map = new LinkedHashMap<>(); map.put("cmd", message.getCommand()); map.put("service", message.getAppName()); return map; diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/domain/DeployRequest.java b/src/main/java/inc/sdt/blokworks/devicedeployer/domain/DeployRequest.java index da0a0fc..e899942 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/domain/DeployRequest.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/domain/DeployRequest.java @@ -5,18 +5,16 @@ public class DeployRequest { private String assetCode; private String appName; private OperationType operationType; - private DeviceType deviceType; private CommandType commandType; private SubCommandType subCommandType; protected DeployRequest() {} - public DeployRequest(String requestId, String assetCode, String appName, OperationType operationType, DeviceType deviceType, CommandType commandType, SubCommandType subCommandType) { + public DeployRequest(String requestId, String assetCode, String appName, OperationType operationType, CommandType commandType, SubCommandType subCommandType) { this.requestId = requestId; this.assetCode = assetCode; this.appName = appName; this.operationType = operationType; - this.deviceType = deviceType; this.commandType = commandType; this.subCommandType = subCommandType; } @@ -37,10 +35,6 @@ public class DeployRequest { return operationType; } - public DeviceType getDeviceType() { - return deviceType; - } - public CommandType getCommandType() { return commandType; } @@ -56,7 +50,6 @@ public class DeployRequest { ", assetCode='" + assetCode + '\'' + ", appName='" + appName + '\'' + ", operationType=" + operationType + - ", deviceType=" + deviceType + ", commandType=" + commandType + ", subCommandType=" + subCommandType + '}'; @@ -71,7 +64,6 @@ public class DeployRequest { private String assetCode; private String appName; private OperationType operationType; - private DeviceType deviceType; private CommandType commandType; private SubCommandType subCommandType; @@ -95,11 +87,6 @@ public class DeployRequest { return this; } - public Builder deviceType(DeviceType deviceType) { - this.deviceType = deviceType; - return this; - } - public Builder commandType(CommandType commandType) { this.commandType = commandType; return this; @@ -116,7 +103,6 @@ public class DeployRequest { deployRequest.assetCode = this.assetCode; deployRequest.appName = this.appName; deployRequest.operationType = this.operationType; - deployRequest.deviceType = this.deviceType; deployRequest.commandType = this.commandType; deployRequest.subCommandType = this.subCommandType; return deployRequest; diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/domain/OutboundMessage.java b/src/main/java/inc/sdt/blokworks/devicedeployer/domain/OutboundMessage.java index 4b9888d..8ba80c1 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/domain/OutboundMessage.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/domain/OutboundMessage.java @@ -3,29 +3,38 @@ package inc.sdt.blokworks.devicedeployer.domain; import java.util.LinkedHashMap; public class OutboundMessage { - private String fileId; + private String url; private String fileType; + private String assetCode; private String appName; // 사용자가 정한 파일 이름 private String name; // stackbase 에 저장된 파일 이름 private String image; private LinkedHashMap options; private String command; private String requestId; - private DeviceType deviceType; private CommandType commandType; private SubCommandType subCommandType; private LinkedHashMap parameters; + private LinkedHashMap commandInfo; protected OutboundMessage() {} - public String getFileId() { - return fileId; + public String getUrl() { + return url; } public String getFileType() { return fileType; } + public String getAssetCode() { + return assetCode; + } + + public void setAssetCode(String assetCode) { + this.assetCode = assetCode; + } + public String getAppName() { return appName; } @@ -54,10 +63,6 @@ public class OutboundMessage { return requestId; } - public DeviceType getDeviceType() { - return deviceType; - } - public CommandType getCommandType() { return commandType; } @@ -70,21 +75,30 @@ public class OutboundMessage { return parameters; } + public LinkedHashMap getCommandInfo() { + return commandInfo; + } + + public void setCommandInfo(LinkedHashMap commandInfo) { + this.commandInfo = commandInfo; + } + @Override public String toString() { return "OutboundMessage{" + - "fileId='" + fileId + '\'' + + "url='" + url + '\'' + ", fileType='" + fileType + '\'' + + ", assetCode='" + assetCode + '\'' + ", appName='" + appName + '\'' + ", name='" + name + '\'' + ", image='" + image + '\'' + ", options=" + options + ", command='" + command + '\'' + ", requestId='" + requestId + '\'' + - ", deviceType=" + deviceType + ", commandType=" + commandType + ", subCommandType=" + subCommandType + ", parameters=" + parameters + + ", commandInfo=" + commandInfo + '}'; } @@ -93,21 +107,22 @@ public class OutboundMessage { } public static final class Builder { - private String fileId; + private String url; private String fileType; + private String assetCode; private String appName; private String name; private String image; private LinkedHashMap options; private String command; private String requestId; - private DeviceType deviceType; private CommandType commandType; private SubCommandType subCommandType; private LinkedHashMap parameters; + private LinkedHashMap commandInfo; - public Builder fileId(String fileId) { - this.fileId = fileId; + public Builder url(String url) { + this.url = url; return this; } @@ -116,6 +131,11 @@ public class OutboundMessage { return this; } + public Builder assetCode(String assetCode) { + this.assetCode = assetCode; + return this; + } + public Builder appName(String appName) { this.appName = appName; return this; @@ -146,11 +166,6 @@ public class OutboundMessage { return this; } - public Builder deviceType(DeviceType deviceType) { - this.deviceType = deviceType; - return this; - } - public Builder commandType(CommandType commandType) { this.commandType = commandType; return this; @@ -166,20 +181,26 @@ public class OutboundMessage { return this; } + public Builder commandInfo(LinkedHashMap commandInfo) { + this.commandInfo = commandInfo; + return this; + } + public OutboundMessage build() { OutboundMessage deployMessage = new OutboundMessage(); - deployMessage.fileId = this.fileId; + deployMessage.url = this.url; deployMessage.fileType = this.fileType; + deployMessage.assetCode = this.assetCode; deployMessage.appName = this.appName; deployMessage.name = this.name; deployMessage.image = this.image; deployMessage.options = this.options; deployMessage.command = this.command; deployMessage.requestId = this.requestId; - deployMessage.deviceType = this.deviceType; deployMessage.commandType = this.commandType; deployMessage.subCommandType = this.subCommandType; deployMessage.parameters = this.parameters; + deployMessage.commandInfo = this.commandInfo; return deployMessage; } } diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/domain/Result.java b/src/main/java/inc/sdt/blokworks/devicedeployer/domain/Result.java new file mode 100644 index 0000000..9956d52 --- /dev/null +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/domain/Result.java @@ -0,0 +1,10 @@ +package inc.sdt.blokworks.devicedeployer.domain; + +public record Result( + String name, + int pid, + int size, + String message, + long releasedAt, + long updatedAt +){} \ No newline at end of file diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/domain/Status.java b/src/main/java/inc/sdt/blokworks/devicedeployer/domain/Status.java index 3a4b522..fede63e 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/domain/Status.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/domain/Status.java @@ -1,6 +1,7 @@ package inc.sdt.blokworks.devicedeployer.domain; -public enum Status { - success, - fail -} +public record Status( + int succeed, + int statusCode, + String errMsg +){} \ No newline at end of file diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/domain/SubCommandType.java b/src/main/java/inc/sdt/blokworks/devicedeployer/domain/SubCommandType.java index cc8305f..bd53a3f 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/domain/SubCommandType.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/domain/SubCommandType.java @@ -2,5 +2,6 @@ package inc.sdt.blokworks.devicedeployer.domain; public enum SubCommandType { systemd, - docker + docker, + single } diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/mqtt/InboundDeployMessagePayload.java b/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/mqtt/InboundDeployMessagePayload.java index 3e7473d..f22f754 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/mqtt/InboundDeployMessagePayload.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/mqtt/InboundDeployMessagePayload.java @@ -1,5 +1,6 @@ package inc.sdt.blokworks.devicedeployer.infrastructure.mqtt; +import inc.sdt.blokworks.devicedeployer.domain.Result; import inc.sdt.blokworks.devicedeployer.domain.Status; public record InboundDeployMessagePayload( @@ -9,12 +10,4 @@ public record InboundDeployMessagePayload( Result result, String requestId ) { - public record Result( - String name, - int pid, - int size, - String message, - long releasedAt, - long updatedAt - ){} } \ No newline at end of file diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/mqtt/OutboundMessagePayload.java b/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/mqtt/OutboundMessagePayload.java index 6650c91..8b84c20 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/mqtt/OutboundMessagePayload.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/mqtt/OutboundMessagePayload.java @@ -10,7 +10,6 @@ public record OutboundMessagePayload( HashMap cmdInfo, CommandType cmdType, SubCommandType subCmdType, - DeviceType deviceType, String assetCode, String requestId ) { diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/AssetAppEntity.java b/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/AssetAppEntity.java index ceff864..a0b14bb 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/AssetAppEntity.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/AssetAppEntity.java @@ -1,6 +1,5 @@ package inc.sdt.blokworks.devicedeployer.infrastructure.relational; -import inc.sdt.blokworks.devicedeployer.domain.Status; import jakarta.persistence.*; @Entity(name = "asset_app") @@ -21,20 +20,25 @@ class AssetAppEntity { private Long updatedAt; @Column(name = "pid") private int pid; - @Column(name = "status") - @Enumerated(EnumType.STRING) - private Status status; + @Column(name = "succeed") + private int succeed; + @Column(name = "statusCode") + private int statusCode; + @Column(name = "error_message") + private String errorMessage; protected AssetAppEntity() {} - public AssetAppEntity(String assetCode, String name, int size, Long releasedAt, Long updatedAt, int pid, Status status) { + public AssetAppEntity(String assetCode, String name, int size, Long releasedAt, Long updatedAt, int pid, int succeed, int statusCode, String errorMessage) { this.assetCode = assetCode; this.name = name; this.size = size; this.releasedAt = releasedAt; this.updatedAt = updatedAt; this.pid = pid; - this.status = status; + this.succeed = succeed; + this.statusCode = statusCode; + this.errorMessage = errorMessage; } public String getId() { @@ -65,7 +69,15 @@ class AssetAppEntity { return pid; } - public Status getStatus() { - return status; + public int getSucceed() { + return succeed; + } + + public int getStatusCode() { + return statusCode; + } + + public String getErrorMessage() { + return errorMessage; } } diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/AssetAppRelationalRepository.java b/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/AssetAppRelationalRepository.java index 5415321..c156a17 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/AssetAppRelationalRepository.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/AssetAppRelationalRepository.java @@ -2,6 +2,7 @@ package inc.sdt.blokworks.devicedeployer.infrastructure.relational; import inc.sdt.blokworks.devicedeployer.application.DeployerRepositoryDelegate; import inc.sdt.blokworks.devicedeployer.domain.AssetApp; +import inc.sdt.blokworks.devicedeployer.domain.Status; import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.InboundDeployMessagePayload; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,7 +53,9 @@ public class AssetAppRelationalRepository implements DeployerRepositoryDelegate assetApp.getReleaseAt(), assetApp.getUpdatedAt(), assetApp.getPid(), - assetApp.getStatus() + assetApp.getStatus().succeed(), + assetApp.getStatus().statusCode(), + assetApp.getStatus().errMsg() ); } @@ -64,7 +67,7 @@ public class AssetAppRelationalRepository implements DeployerRepositoryDelegate .pid(entity.getPid()) .releasedAt(entity.getReleasedAt()) .updatedAt(entity.getUpdatedAt()) - .status(entity.getStatus()) + .status(new Status(entity.getSucceed(), entity.getStatusCode(), entity.getErrorMessage())) .build(); } diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/DeployRequestEntity.java b/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/DeployRequestEntity.java index f95066b..50f04d1 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/DeployRequestEntity.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/DeployRequestEntity.java @@ -22,9 +22,6 @@ public class DeployRequestEntity { @Column(name = "operation_type", length = 255) private OperationType operationType; @Enumerated(EnumType.STRING) - @Column(name = "device_type", length = 255) - private DeviceType deviceType; - @Enumerated(EnumType.STRING) @Column(name = "command_type", length = 255) private CommandType commandType; @Enumerated(EnumType.STRING) @@ -33,12 +30,11 @@ public class DeployRequestEntity { protected DeployRequestEntity() {} - public DeployRequestEntity(String requestId, String assetCode, String appName, OperationType operationType, DeviceType deviceType, CommandType commandType, SubCommandType subCommandType) { + public DeployRequestEntity(String requestId, String assetCode, String appName, OperationType operationType, CommandType commandType, SubCommandType subCommandType) { this.requestId = requestId; this.assetCode = assetCode; this.appName = appName; this.operationType = operationType; - this.deviceType = deviceType; this.commandType = commandType; this.subCommandType = subCommandType; } @@ -63,10 +59,6 @@ public class DeployRequestEntity { return operationType; } - public DeviceType getDeviceType() { - return deviceType; - } - public CommandType getCommandType() { return commandType; } diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/DeployRequestRelationalRepository.java b/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/DeployRequestRelationalRepository.java index c9c956d..d85d90d 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/DeployRequestRelationalRepository.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/infrastructure/relational/DeployRequestRelationalRepository.java @@ -40,7 +40,6 @@ public class DeployRequestRelationalRepository implements DeployRequestRepositor deployRequest.getAssetCode(), deployRequest.getAppName(), deployRequest.getOperationType(), - deployRequest.getDeviceType(), deployRequest.getCommandType(), deployRequest.getSubCommandType() ); @@ -52,7 +51,6 @@ public class DeployRequestRelationalRepository implements DeployRequestRepositor .assetCode(entity.getAssetCode()) .appName(entity.getAppName()) .operationType(entity.getOperationType()) - .deviceType(entity.getDeviceType()) .commandType(entity.getCommandType()) .subCommandType(entity.getSubCommandType()) .build(); diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/DeployerController.java b/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/DeployerController.java index 27ceec9..34df636 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/DeployerController.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/DeployerController.java @@ -1,8 +1,12 @@ package inc.sdt.blokworks.devicedeployer.presentation; +import inc.sdt.blokworks.devicedeployer.application.CommandInvoker; +import inc.sdt.blokworks.devicedeployer.application.DeployCommandInvoker; import inc.sdt.blokworks.devicedeployer.application.DeployerService; import inc.sdt.blokworks.devicedeployer.domain.*; import inc.sdt.blokworks.devicedeployer.infrastructure.amqp.ResourceMapping; +import inc.sdt.blokworks.devicedeployer.presentation.exception.NotFoundException; +import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,8 +15,11 @@ import org.springframework.data.domain.Page; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; +import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.Optional; import java.util.UUID; +import java.util.function.Consumer; @RestController public class DeployerController { @@ -20,14 +27,20 @@ public class DeployerController { private final DeployerService deployerService; private final OutboundMessageResourceConverter outboundMessageResourceConverter; private final AssetAppResourceConverter assetAppResourceConverter; + private final CommandInvoker commandInvoker; + private final GiteaApiRequestHandler giteaApiRequestHandler; public DeployerController(DeployerService deployerService, OutboundMessageResourceConverter outboundMessageResourceConverter, - AssetAppResourceConverter assetAppResourceConverter) { + AssetAppResourceConverter assetAppResourceConverter, + CommandInvoker commandInvoker, + GiteaApiRequestHandler giteaApiRequestHandler) { this.log = LoggerFactory.getLogger(this.getClass()); this.deployerService = deployerService; this.outboundMessageResourceConverter = outboundMessageResourceConverter; this.assetAppResourceConverter = assetAppResourceConverter; + this.commandInvoker = commandInvoker; + this.giteaApiRequestHandler = giteaApiRequestHandler; } /** @@ -39,24 +52,36 @@ public class DeployerController { @ResponseStatus(HttpStatus.CREATED) @PostMapping("/assets/{assetCode}/apps") public void deploy(@PathVariable String assetCode, - @RequestBody OutboundMessageResource resource) { + @RequestBody OutboundMessageResource resource, + HttpServletRequest httpServletRequest) { log.info("[deploy] assetCode = {}, resource = {}", assetCode, resource); + String authorization = httpServletRequest.getHeader("Authorization"); String requestId = UUID.randomUUID().toString(); + OutboundMessage outboundMessage = outboundMessageResourceConverter.fromResource(resource); outboundMessage.setRequestId(requestId); + outboundMessage.setAssetCode(assetCode); + outboundMessage.setCommandInfo(commandInvoker.invoke(outboundMessage)); + + if(resource.commandType() == null) { + throw new IllegalArgumentException(); + } + + if(resource.commandType() == CommandType.deploy) { + giteaApiRequestHandler.get(authorization, outboundMessage); + } DeployRequest deployRequest = DeployRequest.builder() .requestId(requestId) .assetCode(assetCode) .appName(outboundMessage.getName()) .operationType(OperationType.DEPLOY) - .deviceType(resource.deviceType()) .commandType(resource.commandType()) .subCommandType(resource.subCommandType()) .build(); - DeployRequest request = deployerService.save(deployRequest); - deployerService.publish(outboundMessage, assetCode); + deployerService.save(deployRequest); + deployerService.publish(outboundMessage); } /** diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/GiteaApiRequestHandler.java b/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/GiteaApiRequestHandler.java new file mode 100644 index 0000000..3a1d525 --- /dev/null +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/GiteaApiRequestHandler.java @@ -0,0 +1,80 @@ +package inc.sdt.blokworks.devicedeployer.presentation; + +import inc.sdt.blokworks.devicedeployer.domain.OutboundMessage; +import inc.sdt.blokworks.devicedeployer.domain.SubCommandType; +import inc.sdt.blokworks.devicedeployer.presentation.exception.NotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +@Component +public class GiteaApiRequestHandler { + private final Logger log; + private final RestTemplate restTemplate; + private final String url; + private final List extensions; + + public GiteaApiRequestHandler(RestTemplate restTemplate, + @Value("${stackbase.api.host}") String url) { + this.log = LoggerFactory.getLogger(this.getClass()); + this.restTemplate = restTemplate; + this.url = url; + this.extensions = Arrays.asList(".py", ".jar", ".sh", ".service", ".json", ".yaml"); + } + + public void get(String authorization, OutboundMessage message) { + log.info("[get] message = {}", message); + if(message.getSubCommandType() == null) { + throw new IllegalArgumentException(); + } + + if(message.getSubCommandType() == SubCommandType.systemd) { + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", authorization); + + try { + download(message.getAssetCode(), message.getUrl()); + }catch (IOException e) { + throw new RuntimeException(); + } + } + } + + private void download(String assetCode, String url) throws IOException { + log.info("[download] assetCode = {}, url = {}", assetCode, url); + byte[] bytes = restTemplate.getForObject(url, byte[].class); + + File tempFile = File.createTempFile(assetCode+"_"+LocalDateTime.now(), ".zip"); + try(FileOutputStream fos = new FileOutputStream(tempFile)) { + assert bytes != null; + fos.write(bytes); + } + + try(ZipInputStream zis = new ZipInputStream(Files.newInputStream(Path.of(tempFile.getAbsolutePath())))) { + ZipEntry zipEntry; + while((zipEntry = zis.getNextEntry()) != null) { + if(!zipEntry.isDirectory()) { + String extension = zipEntry.getName().split("\\.")[1]; + if(!extensions.toString().contains(extension)) { + throw new NotFoundException("Executable file not found."); + } + } + } + } + } + +} diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/OutboundMessageResource.java b/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/OutboundMessageResource.java index 6fa4e54..172eb6b 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/OutboundMessageResource.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/OutboundMessageResource.java @@ -4,17 +4,17 @@ import inc.sdt.blokworks.devicedeployer.domain.CommandType; import inc.sdt.blokworks.devicedeployer.domain.DeviceType; import inc.sdt.blokworks.devicedeployer.domain.SubCommandType; import org.wildfly.common.annotation.NotNull; +import org.wildfly.common.annotation.Nullable; import java.util.LinkedHashMap; record OutboundMessageResource( - String fileId, + String url, String fileType, String appName, // 사용자가 정한 파일 이름 String name, // stackbase 에 저장된 파일 이름 String image, String command, - DeviceType deviceType, CommandType commandType, SubCommandType subCommandType, LinkedHashMap options, diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/OutboundMessageResourceConverter.java b/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/OutboundMessageResourceConverter.java index 94ee875..c59a5c6 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/OutboundMessageResourceConverter.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/OutboundMessageResourceConverter.java @@ -1,8 +1,8 @@ package inc.sdt.blokworks.devicedeployer.presentation; import inc.sdt.blokworks.devicedeployer.domain.CommandType; -import inc.sdt.blokworks.devicedeployer.domain.DeviceType; import inc.sdt.blokworks.devicedeployer.domain.OutboundMessage; +import inc.sdt.blokworks.devicedeployer.domain.SubCommandType; import org.springframework.stereotype.Component; import java.util.*; @@ -11,15 +11,15 @@ import java.util.*; public class OutboundMessageResourceConverter { public OutboundMessage fromResource(OutboundMessageResource resource) { return OutboundMessage.builder() - .fileId(resource.fileId()) + .url(resource.url()) .fileType(resource.fileType()) - .appName(resource.appName() == null ? "" : resource.appName()) + .appName(resource.appName()) .name(resource.name()) - .image(resource.image() == null ? "" : resource.image()) + .image(resource.image()) .command(resource.command()) .options(resource.options() == null ? new LinkedHashMap<>() : resource.options()) - .deviceType(resource.deviceType() == null ? DeviceType.ecn : resource.deviceType()) .commandType(resource.commandType() == null ? CommandType.deploy : resource.commandType()) + .subCommandType(resource.subCommandType() == null ? SubCommandType.single : resource.subCommandType()) .parameters(resource.parameters() == null ? new LinkedHashMap<>() : resource.parameters()) .build(); diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/exception/ControllerAdvice.java b/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/exception/ControllerAdvice.java index be4436e..12ea8f8 100644 --- a/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/exception/ControllerAdvice.java +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/exception/ControllerAdvice.java @@ -32,4 +32,16 @@ class ControllerAdvice { public ErrorResponse handleConflictException(Exception exception) { return new ErrorResponse(HttpStatus.CONFLICT, exception.getMessage()); } + + @ExceptionHandler(NotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public ErrorResponse handleNotFoundException(Exception exception) { + return new ErrorResponse(HttpStatus.NOT_FOUND, exception.getMessage()); + } + + @ExceptionHandler(UnauthorizedException.class) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public ErrorResponse handleUnauthorizedException(Exception exception) { + return new ErrorResponse(HttpStatus.UNAUTHORIZED, exception.getMessage()); + } } diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/exception/NotFoundException.java b/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/exception/NotFoundException.java new file mode 100644 index 0000000..e58f763 --- /dev/null +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/exception/NotFoundException.java @@ -0,0 +1,12 @@ +package inc.sdt.blokworks.devicedeployer.presentation.exception; + +public class NotFoundException extends RuntimeException{ + private static final String DEFAULT_MESSAGE = "File not found"; + public NotFoundException() { + super(DEFAULT_MESSAGE); + } + + public NotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/rest/RestTemplateResponseErrorHandler.java b/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/rest/RestTemplateResponseErrorHandler.java new file mode 100644 index 0000000..268528f --- /dev/null +++ b/src/main/java/inc/sdt/blokworks/devicedeployer/presentation/rest/RestTemplateResponseErrorHandler.java @@ -0,0 +1,28 @@ +package inc.sdt.blokworks.devicedeployer.presentation.rest; + +import inc.sdt.blokworks.devicedeployer.presentation.exception.UnauthorizedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.client.DefaultResponseErrorHandler; + +import java.io.IOException; + +public class RestTemplateResponseErrorHandler extends DefaultResponseErrorHandler { + private final Logger log; + + public RestTemplateResponseErrorHandler() { + this.log = LoggerFactory.getLogger(this.getClass()); + } + + @Override + protected void handleError(ClientHttpResponse response, HttpStatusCode statusCode) throws IOException { + log.error("[handleError] statusCode = {}, response = {}", statusCode, response); + if(response.getStatusCode() == HttpStatus.UNAUTHORIZED) { + throw new UnauthorizedException(); + } + + } +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index a872951..a244809 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -16,7 +16,7 @@ inbound: username: ${INBOUND_MQTT_CREDENTIALS_USERNAME} password: ${INBOUND_MQTT_CREDENTIALS_PASSWORD} topics: - - /devicecontrol/result/+/+/+ + - /device-control/+/result iam: enabled: ${IAM_REGISTER_ENABLED} diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 0c1ca25..4f5af0e 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -17,7 +17,7 @@ inbound: username: sdt password: 251327 topics: - - /devicecontrol/result/+/+/+ + - /device-control/+/result stackbase: api: