- command type 이 deploy 타입일 경우 파일 유효성 검사 로직 추가
This commit is contained in:
parent
c625560cc6
commit
15be9161f3
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@ import java.util.LinkedHashMap;
|
|||
@Component
|
||||
public class BashCommand implements CommandInfo{
|
||||
@Override
|
||||
public LinkedHashMap<String, Object> put(OutboundMessage message, LinkedHashMap<String, Object> map) {
|
||||
public LinkedHashMap<String, Object> put(OutboundMessage message) {
|
||||
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("cmd", message.getCommand());
|
||||
return map;
|
||||
}
|
||||
|
|
|
@ -5,5 +5,5 @@ import inc.sdt.blokworks.devicedeployer.domain.OutboundMessage;
|
|||
import java.util.LinkedHashMap;
|
||||
|
||||
public interface CommandInfo {
|
||||
LinkedHashMap<String, Object> put(OutboundMessage message, LinkedHashMap<String, Object> map);
|
||||
LinkedHashMap<String, Object> put(OutboundMessage message);
|
||||
}
|
||||
|
|
|
@ -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<String, Object> invoke(OutboundMessage message, LinkedHashMap<String, Object> map) {
|
||||
public LinkedHashMap<String, Object> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String, Object> 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();
|
||||
}
|
||||
|
|
|
@ -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<String, Object> put(OutboundMessage message, LinkedHashMap<String, Object> map) {
|
||||
final String url = filePath + message.getFileId();
|
||||
public LinkedHashMap<String, Object> put(OutboundMessage message) {
|
||||
LinkedHashMap<String, Object> 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;
|
||||
}
|
||||
|
|
|
@ -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<String, Object> invoke(OutboundMessage message, LinkedHashMap<String, Object> map) {
|
||||
public LinkedHashMap<String, Object> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<InboundDeployMessagePayload, Mono<Void>> {
|
||||
void publish(OutboundMessage assetApp, String assetCode);
|
||||
void publish(OutboundMessage message);
|
||||
DeployRequest save(DeployRequest deployRequest);
|
||||
Page<AssetApp> getAll(String assetCode, int page, int size);
|
||||
}
|
||||
|
|
|
@ -9,8 +9,10 @@ import java.util.LinkedHashMap;
|
|||
public class DockerCommand implements CommandInfo {
|
||||
|
||||
@Override
|
||||
public LinkedHashMap<String, Object> put(OutboundMessage message, LinkedHashMap<String, Object> map) {
|
||||
public LinkedHashMap<String, Object> put(OutboundMessage message) {
|
||||
LinkedHashMap<String, Object> 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());
|
||||
|
|
|
@ -8,7 +8,8 @@ import java.util.LinkedHashMap;
|
|||
@Component
|
||||
public class JsonCommand implements CommandInfo {
|
||||
@Override
|
||||
public LinkedHashMap<String, Object> put(OutboundMessage message, LinkedHashMap<String, Object> map) {
|
||||
public LinkedHashMap<String, Object> put(OutboundMessage message) {
|
||||
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("cmd", String.valueOf(message.getCommandType()));
|
||||
map.put("appName", message.getAppName());
|
||||
map.put("parameter", message.getParameters());
|
||||
|
|
|
@ -8,7 +8,8 @@ import java.util.LinkedHashMap;
|
|||
@Component
|
||||
public class SystemdCommand implements CommandInfo {
|
||||
@Override
|
||||
public LinkedHashMap<String, Object> put(OutboundMessage message, LinkedHashMap<String, Object> map) {
|
||||
public LinkedHashMap<String, Object> put(OutboundMessage message) {
|
||||
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("cmd", message.getCommand());
|
||||
map.put("service", message.getAppName());
|
||||
return map;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<String, Object> options;
|
||||
private String command;
|
||||
private String requestId;
|
||||
private DeviceType deviceType;
|
||||
private CommandType commandType;
|
||||
private SubCommandType subCommandType;
|
||||
private LinkedHashMap<String, String> parameters;
|
||||
private LinkedHashMap<String, Object> 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<String, Object> getCommandInfo() {
|
||||
return commandInfo;
|
||||
}
|
||||
|
||||
public void setCommandInfo(LinkedHashMap<String, Object> 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<String, Object> options;
|
||||
private String command;
|
||||
private String requestId;
|
||||
private DeviceType deviceType;
|
||||
private CommandType commandType;
|
||||
private SubCommandType subCommandType;
|
||||
private LinkedHashMap<String, String> parameters;
|
||||
private LinkedHashMap<String, Object> 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<String, Object> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
){}
|
|
@ -1,6 +1,7 @@
|
|||
package inc.sdt.blokworks.devicedeployer.domain;
|
||||
|
||||
public enum Status {
|
||||
success,
|
||||
fail
|
||||
}
|
||||
public record Status(
|
||||
int succeed,
|
||||
int statusCode,
|
||||
String errMsg
|
||||
){}
|
|
@ -2,5 +2,6 @@ package inc.sdt.blokworks.devicedeployer.domain;
|
|||
|
||||
public enum SubCommandType {
|
||||
systemd,
|
||||
docker
|
||||
docker,
|
||||
single
|
||||
}
|
||||
|
|
|
@ -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
|
||||
){}
|
||||
}
|
|
@ -10,7 +10,6 @@ public record OutboundMessagePayload(
|
|||
HashMap<String, Object> cmdInfo,
|
||||
CommandType cmdType,
|
||||
SubCommandType subCmdType,
|
||||
DeviceType deviceType,
|
||||
String assetCode,
|
||||
String requestId
|
||||
) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<String> 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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<String, Object> options,
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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}
|
||||
|
|
|
@ -17,7 +17,7 @@ inbound:
|
|||
username: sdt
|
||||
password: 251327
|
||||
topics:
|
||||
- /devicecontrol/result/+/+/+
|
||||
- /device-control/+/result
|
||||
|
||||
stackbase:
|
||||
api:
|
||||
|
|
Loading…
Reference in New Issue