feat: 앱 배포 요청
- 앱 배포 요청 API 작성 - 앱 배포 요청 MQTT 발행 - 배포 완료된 앱 정보 저장 Closed: #SCDD-194
This commit is contained in:
parent
eb2aa72e40
commit
02bb5611f4
|
@ -11,6 +11,10 @@ java {
|
|||
sourceCompatibility = '17'
|
||||
}
|
||||
|
||||
jar {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
@ -20,7 +24,10 @@ dependencies {
|
|||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
implementation("org.springframework.boot:spring-boot-starter-validation")
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
implementation("org.springframework.integration:spring-integration-mqtt")
|
||||
runtimeOnly("org.postgresql:postgresql")
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
package inc.sdt.blokworks.devicedeployer.application;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import inc.sdt.blokworks.devicedeployer.domain.AssetApp;
|
||||
import inc.sdt.blokworks.devicedeployer.domain.DeployMessage;
|
||||
import inc.sdt.blokworks.devicedeployer.domain.OperationType;
|
||||
import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.InboundDeployMessagePayload;
|
||||
import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.OutboundMessagePayload;
|
||||
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.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Service
|
||||
public class DefaultDeployerService implements DeployerService{
|
||||
private final Logger log;
|
||||
private final IMqttClient mqttClient;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final DeployerRepositoryDelegate deployerRepositoryDelegate;
|
||||
|
||||
public DefaultDeployerService(IMqttClient mqttClient,
|
||||
ObjectMapper objectMapper,
|
||||
DeployerRepositoryDelegate deployerRepositoryDelegate) {
|
||||
this.log = LoggerFactory.getLogger(this.getClass());
|
||||
this.mqttClient = mqttClient;
|
||||
this.objectMapper = objectMapper;
|
||||
this.deployerRepositoryDelegate = deployerRepositoryDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publish(DeployMessage deployMessage, String assetCode) {
|
||||
log.info("[publish]");
|
||||
try {
|
||||
OutboundMessagePayload payload = new OutboundMessagePayload(
|
||||
deployMessage.getUrl(),
|
||||
deployMessage.getName(),
|
||||
deployMessage.getPorts(),
|
||||
deployMessage.getEnv(),
|
||||
deployMessage.getCommand(),
|
||||
OperationType.DEPLOY,
|
||||
deployMessage.getRequestId()
|
||||
);
|
||||
|
||||
byte[] bytes = objectMapper.writeValueAsBytes(payload);
|
||||
MqttMessage message = new MqttMessage();
|
||||
message.setPayload(bytes);
|
||||
|
||||
mqttClient.publish("/assets/"+assetCode+"/apps/deploy", message);
|
||||
}catch (JsonProcessingException | MqttException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> apply(InboundDeployMessagePayload inboundDeployMessagePayload) {
|
||||
log.info("[apply] inboundDeployMessagePayload = {}", inboundDeployMessagePayload);
|
||||
// 배포된 앱 정보 저장
|
||||
deployerRepositoryDelegate.save(fromMessage(inboundDeployMessagePayload));
|
||||
return null;
|
||||
}
|
||||
|
||||
private AssetApp fromMessage(InboundDeployMessagePayload payload) {
|
||||
return AssetApp.builder()
|
||||
.assetCode(payload.assetCode())
|
||||
.name(payload.name())
|
||||
.size(payload.size())
|
||||
.releasedAt(payload.releasedAt())
|
||||
.modifiedAt(payload.modifiedAt())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package inc.sdt.blokworks.devicedeployer.application;
|
||||
|
||||
import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.InboundProcessMessagePayload;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Service
|
||||
public class DefaultProcessService implements ProcessService{
|
||||
|
||||
@Override
|
||||
public Mono<Void> apply(InboundProcessMessagePayload inboundProcessMessagePayload) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package inc.sdt.blokworks.devicedeployer.application;
|
||||
|
||||
import inc.sdt.blokworks.devicedeployer.domain.AssetApp;
|
||||
import inc.sdt.blokworks.devicedeployer.domain.DeployMessage;
|
||||
|
||||
public interface DeployerRepositoryDelegate {
|
||||
AssetApp save(AssetApp assetApp);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package inc.sdt.blokworks.devicedeployer.application;
|
||||
|
||||
import inc.sdt.blokworks.devicedeployer.domain.DeployMessage;
|
||||
import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.InboundDeployMessagePayload;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface DeployerService extends Function<InboundDeployMessagePayload, Mono<Void>> {
|
||||
void publish(DeployMessage assetApp, String assetCode);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package inc.sdt.blokworks.devicedeployer.application;
|
||||
|
||||
import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.InboundProcessMessagePayload;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface ProcessService extends Function<InboundProcessMessagePayload, Mono<Void>> {
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package inc.sdt.blokworks.devicedeployer.domain;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
public class AssetApp {
|
||||
private String assetCode;
|
||||
private String name;
|
||||
private Long size;
|
||||
private Long releaseAt;
|
||||
private Long modifiedAt;
|
||||
|
||||
protected AssetApp() {}
|
||||
|
||||
public AssetApp(String assetCode, String name, Long size, Long releaseAt, Long modifiedAt) {
|
||||
this.assetCode = assetCode;
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
this.releaseAt = releaseAt;
|
||||
this.modifiedAt = modifiedAt;
|
||||
}
|
||||
|
||||
public String getAssetCode() {
|
||||
return assetCode;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public Long getReleaseAt() {
|
||||
return releaseAt;
|
||||
}
|
||||
|
||||
public Long getModifiedAt() {
|
||||
return modifiedAt;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private String assetCode;
|
||||
private String name;
|
||||
private Long size;
|
||||
private Long releasedAt;
|
||||
private Long modifiedAt;
|
||||
|
||||
public Builder assetCode(String assetCode) {
|
||||
this.assetCode = assetCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder size(Long size) {
|
||||
this.size = size;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder releasedAt(Long releasedAt) {
|
||||
this.releasedAt = releasedAt;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder modifiedAt(Long modifiedAt) {
|
||||
this.modifiedAt = modifiedAt;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AssetApp build() {
|
||||
AssetApp assetApp = new AssetApp();
|
||||
assetApp.assetCode = this.assetCode;
|
||||
assetApp.name = this.name;
|
||||
assetApp.size = this.size;
|
||||
assetApp.releaseAt = this.releasedAt;
|
||||
assetApp.modifiedAt = this.modifiedAt;
|
||||
return assetApp;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
package inc.sdt.blokworks.devicedeployer.domain;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
public class DeployMessage {
|
||||
private String url;
|
||||
private String name;
|
||||
private Set<Port> ports;
|
||||
private HashMap<String, String> env;
|
||||
private String command;
|
||||
private OperationType operationType;
|
||||
private String requestId;
|
||||
|
||||
protected DeployMessage() {}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Set<Port> getPorts() {
|
||||
return ports;
|
||||
}
|
||||
|
||||
public HashMap<String, String> getEnv() {
|
||||
return env;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public OperationType getOperationType() {
|
||||
return operationType;
|
||||
}
|
||||
|
||||
public void setRequestId(String requestId) {
|
||||
this.requestId = requestId;
|
||||
}
|
||||
|
||||
public String getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AssetApp{" +
|
||||
"url='" + url + '\'' +
|
||||
", name='" + name + '\'' +
|
||||
", ports=" + ports +
|
||||
", env=" + env +
|
||||
", command='" + command + '\'' +
|
||||
", operationType=" + operationType +
|
||||
", requestId='" + requestId + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private String url;
|
||||
private String name;
|
||||
private Set<Port> ports;
|
||||
private HashMap<String, String> env;
|
||||
private String command;
|
||||
private OperationType operationType;
|
||||
private String requestId;
|
||||
|
||||
public Builder url(String url) {
|
||||
this.url = url;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder ports(Set<Port> ports) {
|
||||
this.ports = ports;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder env(HashMap<String, String> env) {
|
||||
this.env = env;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder command(String command) {
|
||||
this.command = command;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder operationType(OperationType operationType) {
|
||||
this.operationType = operationType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder requestId(String requestId) {
|
||||
this.requestId = requestId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DeployMessage build() {
|
||||
DeployMessage deployMessage = new DeployMessage();
|
||||
deployMessage.url = this.url;
|
||||
deployMessage.name = this.name;
|
||||
deployMessage.ports = this.ports;
|
||||
deployMessage.env = this.env;
|
||||
deployMessage.command = this.command;
|
||||
deployMessage.operationType = this.operationType;
|
||||
deployMessage.requestId = this.requestId;
|
||||
return deployMessage;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package inc.sdt.blokworks.devicedeployer.domain;
|
||||
|
||||
public enum OperationType {
|
||||
DEPLOY,
|
||||
START,
|
||||
STOP,
|
||||
DELETE
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package inc.sdt.blokworks.devicedeployer.domain;
|
||||
|
||||
public class Port {
|
||||
private String protocol;
|
||||
private Integer hostPort;
|
||||
private Integer containerPort;
|
||||
|
||||
protected Port() {}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public Integer getHostPort() {
|
||||
return hostPort;
|
||||
}
|
||||
|
||||
public Integer getContainerPort() {
|
||||
return containerPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Port{" +
|
||||
"protocol='" + protocol + '\'' +
|
||||
", hostPort=" + hostPort +
|
||||
", containerPort=" + containerPort +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private String protocol;
|
||||
private Integer hostPort;
|
||||
private Integer containerPort;
|
||||
|
||||
public Builder protocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder hostPort(Integer hostPort) {
|
||||
this.hostPort = hostPort;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder containerPort(Integer containerPort) {
|
||||
this.containerPort = containerPort;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Port build() {
|
||||
Port port = new Port();
|
||||
port.protocol = this.protocol;
|
||||
port.hostPort = this.hostPort;
|
||||
port.containerPort = this.containerPort;
|
||||
return port;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package inc.sdt.blokworks.devicedeployer.domain;
|
||||
|
||||
public enum Status {
|
||||
success,
|
||||
fail
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package inc.sdt.blokworks.devicedeployer.infrastructure.mqtt;
|
||||
|
||||
import inc.sdt.blokworks.devicedeployer.domain.Status;
|
||||
|
||||
public record InboundDeployMessagePayload(
|
||||
Status status,
|
||||
String assetCode,
|
||||
String name,
|
||||
Long size,
|
||||
Long releasedAt,
|
||||
Long modifiedAt
|
||||
) {
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package inc.sdt.blokworks.devicedeployer.infrastructure.mqtt;
|
||||
|
||||
import inc.sdt.blokworks.devicedeployer.domain.Status;
|
||||
|
||||
public record InboundProcessMessagePayload(
|
||||
Status status,
|
||||
String assetCode,
|
||||
Integer pid,
|
||||
String name,
|
||||
Integer cpu,
|
||||
Integer memory,
|
||||
Integer network,
|
||||
Long processedAt
|
||||
) {
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package inc.sdt.blokworks.devicedeployer.infrastructure.mqtt;
|
||||
|
||||
import inc.sdt.blokworks.devicedeployer.domain.OperationType;
|
||||
import inc.sdt.blokworks.devicedeployer.domain.Port;
|
||||
import inc.sdt.blokworks.devicedeployer.presentation.PortResource;
|
||||
import inc.sdt.blokworks.devicedeployer.presentation.PortResourceConverter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
public record OutboundMessagePayload(
|
||||
String url,
|
||||
String name,
|
||||
Set<Port> ports,
|
||||
HashMap<String, String> env,
|
||||
String command,
|
||||
OperationType operationType,
|
||||
String requestId
|
||||
) {
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package inc.sdt.blokworks.devicedeployer.infrastructure.relational;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity(name = "app_process")
|
||||
class AppProcessEntity {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
@Column(name = "id")
|
||||
private String id;
|
||||
@Column(name = "app_id", length = 36)
|
||||
private String appId;
|
||||
@Column(name = "asset_code", length = 255)
|
||||
private String assetCode;
|
||||
@Column(name = "pid")
|
||||
private Integer pid;
|
||||
@Column(name = "cpu")
|
||||
private Integer cpu;
|
||||
@Column(name = "memory")
|
||||
private Integer memory;
|
||||
@Column(name = "network")
|
||||
private Integer network;
|
||||
|
||||
protected AppProcessEntity() {}
|
||||
|
||||
public AppProcessEntity(String id, String appId, String assetCode, Integer pid, Integer cpu, Integer memory, Integer network) {
|
||||
this.id = id;
|
||||
this.appId = appId;
|
||||
this.assetCode = assetCode;
|
||||
this.pid = pid;
|
||||
this.cpu = cpu;
|
||||
this.memory = memory;
|
||||
this.network = network;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
}
|
||||
|
||||
public String getAssetCode() {
|
||||
return assetCode;
|
||||
}
|
||||
|
||||
public Integer getPid() {
|
||||
return pid;
|
||||
}
|
||||
|
||||
public Integer getCpu() {
|
||||
return cpu;
|
||||
}
|
||||
|
||||
public Integer getMemory() {
|
||||
return memory;
|
||||
}
|
||||
|
||||
public Integer getNetwork() {
|
||||
return network;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package inc.sdt.blokworks.devicedeployer.infrastructure.relational;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
@Entity(name = "asset_app")
|
||||
class AssetAppEntity {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
@Column(name = "app_id", length = 36)
|
||||
private String id;
|
||||
@Column(name = "asset_code", length = 255)
|
||||
private String assetCode;
|
||||
@Column(name = "app_name", length = 255)
|
||||
private String name;
|
||||
@Column(name = "size")
|
||||
private Long size;
|
||||
@Column(name = "released_at")
|
||||
private Long releasedAt;
|
||||
@Column(name = "modfied_at")
|
||||
private Long modifiedAt;
|
||||
|
||||
protected AssetAppEntity() {}
|
||||
|
||||
public AssetAppEntity(String id, String assetCode, String name, long size, Long releasedAt, Long modifiedAt) {
|
||||
this.id = id;
|
||||
this.assetCode = assetCode;
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
this.releasedAt = releasedAt;
|
||||
this.modifiedAt = modifiedAt;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getAssetCode() {
|
||||
return assetCode;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public Long getReleasedAt() {
|
||||
return releasedAt;
|
||||
}
|
||||
|
||||
public Long getModifiedAt() {
|
||||
return modifiedAt;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package inc.sdt.blokworks.devicedeployer.infrastructure.relational;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface AssetAppJpaRepository extends JpaRepository<AssetAppEntity, String> {
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
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.DeployMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class AssetAppRelationalRepository implements DeployerRepositoryDelegate {
|
||||
private final Logger log;
|
||||
private final AssetAppJpaRepository assetAppJpaRepository;
|
||||
|
||||
public AssetAppRelationalRepository(AssetAppJpaRepository assetAppJpaRepository) {
|
||||
this.log = LoggerFactory.getLogger(this.getClass());
|
||||
this.assetAppJpaRepository = assetAppJpaRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssetApp save(AssetApp deployMessage) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package inc.sdt.blokworks.devicedeployer.presentation;
|
||||
|
||||
import org.wildfly.common.annotation.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
record AssetAppResource(
|
||||
@NotNull
|
||||
String url,
|
||||
@NotNull
|
||||
String name,
|
||||
Set<PortResource> ports,
|
||||
HashMap<String, String> env,
|
||||
String command
|
||||
) {
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package inc.sdt.blokworks.devicedeployer.presentation;
|
||||
|
||||
import inc.sdt.blokworks.devicedeployer.domain.DeployMessage;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class AssetAppResourceConverter {
|
||||
private final PortResourceConverter portResourceConverter;
|
||||
|
||||
public AssetAppResourceConverter(PortResourceConverter portResourceConverter) {
|
||||
this.portResourceConverter = portResourceConverter;
|
||||
}
|
||||
|
||||
public AssetAppResource toResource(DeployMessage deployMessage) {
|
||||
return new AssetAppResource(
|
||||
deployMessage.getUrl(),
|
||||
deployMessage.getName(),
|
||||
deployMessage.getPorts() != null
|
||||
? deployMessage.getPorts().stream().map(portResourceConverter::toResource).collect(Collectors.toSet())
|
||||
: null,
|
||||
deployMessage.getEnv(),
|
||||
deployMessage.getCommand()
|
||||
);
|
||||
}
|
||||
|
||||
public DeployMessage fromResource(AssetAppResource resource) {
|
||||
return DeployMessage.builder()
|
||||
.url(resource.url())
|
||||
.name(resource.name())
|
||||
.ports(resource.ports() != null
|
||||
? resource.ports().stream().map(portResourceConverter::fromResource).collect(Collectors.toSet())
|
||||
: new HashSet<>())
|
||||
.env(resource.env())
|
||||
.command(resource.command())
|
||||
.build();
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package inc.sdt.blokworks.devicedeployer.presentation;
|
||||
|
||||
import inc.sdt.blokworks.devicedeployer.application.DeployerService;
|
||||
import inc.sdt.blokworks.devicedeployer.domain.DeployMessage;
|
||||
import jakarta.validation.Valid;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
public class DeployerController {
|
||||
private final Logger log;
|
||||
private final DeployerService deployerService;
|
||||
private final AssetAppResourceConverter appResourceConverter;
|
||||
|
||||
public DeployerController(DeployerService deployerService,
|
||||
AssetAppResourceConverter appResourceConverter) {
|
||||
this.log = LoggerFactory.getLogger(this.getClass());
|
||||
this.deployerService = deployerService;
|
||||
this.appResourceConverter = appResourceConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 앱 배포 명령
|
||||
* @param assetCode 자산 코드
|
||||
* @param assetAppResource 배포하려는 앱의 정보
|
||||
*/
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
@PostMapping("/assets/{assetCode}/apps")
|
||||
public void deploy(@PathVariable String assetCode,
|
||||
@Valid @RequestBody AssetAppResource assetAppResource) {
|
||||
log.info("[deploy] assetCode = {}, assetAppResource = {}", assetCode, assetAppResource);
|
||||
DeployMessage deployMessage = appResourceConverter.fromResource(assetAppResource);
|
||||
deployMessage.setRequestId("requestId");
|
||||
deployerService.publish(appResourceConverter.fromResource(assetAppResource), assetCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 배포된 앱 정보 조회
|
||||
* @param assetCode 자산 코드
|
||||
*/
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@GetMapping("/assets/{assetCode}/apps")
|
||||
public void get(@PathVariable String assetCode) {
|
||||
log.info("[get] assetCode = {}", assetCode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package inc.sdt.blokworks.devicedeployer.presentation;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class MqttMessageConverter<T> {
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public MqttMessageConverter(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
public Mono<T> convertFromByte(String payload, Class<T> type) {
|
||||
return Mono.fromFuture(CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
return objectMapper.readValue(payload, type);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package inc.sdt.blokworks.devicedeployer.presentation;
|
||||
|
||||
import inc.sdt.blokworks.devicedeployer.application.DeployerService;
|
||||
import inc.sdt.blokworks.devicedeployer.application.ProcessService;
|
||||
import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.InboundDeployMessagePayload;
|
||||
import inc.sdt.blokworks.devicedeployer.infrastructure.mqtt.InboundProcessMessagePayload;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.integration.annotation.MessageEndpoint;
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
@MessageEndpoint
|
||||
public class MqttMessageHandler {
|
||||
private final Logger log;
|
||||
private final DeployerService deployerService;
|
||||
private final ProcessService processService;
|
||||
private final MqttMessageConverter<InboundDeployMessagePayload> deployMessagePayloadConverter;
|
||||
private final MqttMessageConverter<InboundProcessMessagePayload> processMessagePayloadConverter;
|
||||
|
||||
public MqttMessageHandler(DeployerService deployerService,
|
||||
ProcessService processService,
|
||||
MqttMessageConverter<InboundDeployMessagePayload> deployMessagePayloadConverter,
|
||||
MqttMessageConverter<InboundProcessMessagePayload> processMessagePayloadConverter) {
|
||||
this.log = LoggerFactory.getLogger(this.getClass());
|
||||
this.deployerService = deployerService;
|
||||
this.processService = processService;
|
||||
this.deployMessagePayloadConverter = deployMessagePayloadConverter;
|
||||
this.processMessagePayloadConverter = processMessagePayloadConverter;
|
||||
}
|
||||
|
||||
@ServiceActivator(inputChannel = "mqttInboundChannel")
|
||||
void handleMessage(Message<String> message) {
|
||||
log.debug("[handleMessage] message={}", message);
|
||||
|
||||
if(!message.getPayload().contains("pid")) {
|
||||
deployMessagePayloadConverter.convertFromByte(message.getPayload(), InboundDeployMessagePayload.class)
|
||||
.flatMap(deployerService)
|
||||
.subscribe();
|
||||
}else {
|
||||
processMessagePayloadConverter.convertFromByte(message.getPayload(), InboundProcessMessagePayload.class)
|
||||
.flatMap(processService)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package inc.sdt.blokworks.devicedeployer.presentation;
|
||||
|
||||
public record PortResource(
|
||||
String protocol,
|
||||
Integer hostPort,
|
||||
Integer containerPort
|
||||
) {
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package inc.sdt.blokworks.devicedeployer.presentation;
|
||||
|
||||
import inc.sdt.blokworks.devicedeployer.domain.Port;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class PortResourceConverter {
|
||||
public PortResource toResource(Port port) {
|
||||
return new PortResource(
|
||||
port.getProtocol(),
|
||||
port.getHostPort(),
|
||||
port.getContainerPort()
|
||||
);
|
||||
}
|
||||
|
||||
public Port fromResource(PortResource resource) {
|
||||
return Port.builder()
|
||||
.protocol(resource.protocol())
|
||||
.hostPort(resource.hostPort())
|
||||
.containerPort(resource.containerPort())
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package inc.sdt.blokworks.devicedeployer.presentation.configuration;
|
||||
|
||||
import org.eclipse.paho.client.mqttv3.*;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.core.MessageProducer;
|
||||
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
|
||||
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
|
||||
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(MqttConfigurationProperties.class)
|
||||
public class MqttConfiguration {
|
||||
@Bean(name = "mqttInboundChannel")
|
||||
MessageChannel mqttMessageChannel() {
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
MessageProducer messageChannel(MessageChannel mqttMessageChannel,
|
||||
MqttConfigurationProperties mqttConfigurationProperties) {
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setUserName(mqttConfigurationProperties.getUsername());
|
||||
options.setPassword(mqttConfigurationProperties.getPassword().toCharArray());
|
||||
options.setServerURIs(new String[]{mqttConfigurationProperties.getUrl()});
|
||||
|
||||
DefaultMqttPahoClientFactory clientFactory = new DefaultMqttPahoClientFactory();
|
||||
clientFactory.setConnectionOptions(options);
|
||||
|
||||
MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(
|
||||
mqttConfigurationProperties.getUrl(),
|
||||
MqttAsyncClient.generateClientId(),
|
||||
clientFactory
|
||||
);
|
||||
adapter.setCompletionTimeout(5000);
|
||||
adapter.setConverter(new DefaultPahoMessageConverter());
|
||||
adapter.setQos(1);
|
||||
adapter.addTopic(mqttConfigurationProperties.getTopics());
|
||||
adapter.setOutputChannel(mqttMessageChannel);
|
||||
return adapter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IMqttClient mqttClient(MqttConfigurationProperties mqttConfigurationProperties) throws MqttException {
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setUserName(mqttConfigurationProperties.getUsername());
|
||||
options.setPassword(mqttConfigurationProperties.getPassword().toCharArray());
|
||||
options.setServerURIs(new String[]{mqttConfigurationProperties.getUrl()});
|
||||
|
||||
IMqttClient mqttClient = new MqttClient(mqttConfigurationProperties.getUrl(), MqttClient.generateClientId());
|
||||
mqttClient.connect(options);
|
||||
return mqttClient;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package inc.sdt.blokworks.devicedeployer.presentation.configuration;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@ConfigurationProperties(prefix = "inbound.mqtt")
|
||||
public class MqttConfigurationProperties {
|
||||
private String url;
|
||||
private String username;
|
||||
private String password;
|
||||
private String[] topics;
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String[] getTopics() {
|
||||
return topics;
|
||||
}
|
||||
|
||||
public void setTopics(String[] topics) {
|
||||
this.topics = topics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MqttConfigurationProperties{" +
|
||||
"url='" + url + '\'' +
|
||||
", username='" + username + '\'' +
|
||||
", password='" + password + '\'' +
|
||||
", topics=" + Arrays.toString(topics) +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
spring:
|
||||
datasource:
|
||||
url: jdbc:postgresql://localhost:5432/blokworks
|
||||
username: sdt
|
||||
password: 251327
|
||||
hikari:
|
||||
maximum-pool-size: 3
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
show-sql: true
|
||||
|
||||
inbound:
|
||||
mqtt:
|
||||
url: tcp://localhost:1883
|
||||
username: sdt
|
||||
password: 251327
|
||||
topics:
|
||||
- /assets/+/apps/process
|
||||
- /assets/+/apps/deploy
|
||||
outbound:
|
||||
mqtt:
|
||||
topic:
|
||||
- /assets/+/command-req/+
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
server:
|
||||
port: 8085
|
||||
spring:
|
||||
application:
|
||||
name: device-deployer
|
||||
datasource:
|
||||
driver-class-name: org.postgresql.Driver
|
||||
|
||||
inbound:
|
||||
mqtt:
|
||||
url: tcp://192.168.1.162:32102
|
||||
username: sdt
|
||||
password: 251327
|
||||
topics:
|
||||
- /assets/+/apps/process
|
||||
- /assets/+/apps/deploy
|
||||
outbound:
|
||||
mqtt:
|
||||
topic:
|
||||
- /assets/+/command-req/+
|
Loading…
Reference in New Issue