diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java index dca113621c..d93dc0cc6d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java @@ -51,6 +51,7 @@ import static org.thingsboard.server.controller.ControllerConstants.PROTOCOL; import static org.thingsboard.server.controller.ControllerConstants.PROTOCOL_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.CA_ROOT_CERT_PEM; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.DOCKER_COMPOSE_YML; @RestController @TbCoreComponent @@ -89,36 +90,6 @@ public class DeviceConnectivityController extends BaseController { return deviceConnectivityService.findDevicePublishTelemetryCommands(baseUrl, device); } - @ApiOperation(value = "Get commands to launch gateway (getGatewayLaunchCommands)", - notes = "Fetch the list of commands for different operation systems to launch a gateway using docker." + - TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) - @ApiResponses(value = { - @ApiResponse(code = 200, message = "OK", - examples = @io.swagger.annotations.Example( - value = { - @io.swagger.annotations.ExampleProperty( - mediaType = "application/json", - value = "{\"mqtt\": {\n" + - " \"linux\": \"docker run --rm -it -v ~/.tb-gateway/logs:/thingsboard_gateway/logs -v ~/.tb-gateway/extensions:/thingsboard_gateway/extensions -v ~/.tb-gateway/config:/thingsboard_gateway/config --name tbGateway127001 -e host=localhost -e port=1883 -e accessToken=qTe5oDBHPJf0KCSKO8J3 --restart always thingsboard/tb-gateway\",\n" + - " \"windows\": \"docker run --rm -it -v %HOMEPATH%/tb-gateway/logs:/thingsboard_gateway/logs -v %HOMEPATH%/tb-gateway/extensions:/thingsboard_gateway/extensions -v %HOMEPATH%/tb-gateway/config:/thingsboard_gateway/config --name tbGateway127001 -e host=localhost -e port=1883 -e accessToken=qTe5oDBHPJf0KCSKO8J3 --restart always thingsboard/tb-gateway\"}\n" + - "}")}))}) - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/device-connectivity/gateway-launch/{deviceId}", method = RequestMethod.GET) - @ResponseBody - public JsonNode getGatewayLaunchCommands(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) - @PathVariable(DEVICE_ID) String strDeviceId, HttpServletRequest request) throws ThingsboardException, URISyntaxException { - checkParameter(DEVICE_ID, strDeviceId); - DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); - Device device = checkDeviceId(deviceId, Operation.READ_CREDENTIALS); - - if (!checkIsGateway(device)) { - throw new ThingsboardException("The device must be a gateway!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); - } - - String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request); - return deviceConnectivityService.findGatewayLaunchCommands(baseUrl, device); - } - @ApiOperation(value = "Download server certificate using file path defined in device.connectivity properties (downloadServerCertificate)", notes = "Download server certificate.") @RequestMapping(value = "/device-connectivity/{protocol}/certificate/download", method = RequestMethod.GET) @ResponseBody @@ -136,6 +107,30 @@ public class DeviceConnectivityController extends BaseController { .body(pemCert); } + @ApiOperation(value = "Download generated docker-compose.yml file for gateway (downloadGatewayDockerCompose)", notes = "Download generated docker-compose.yml for gateway.") + @RequestMapping(value = "/device-connectivity/gateway-launch/{deviceId}/docker-compose/download", method = RequestMethod.GET) + @ResponseBody + public ResponseEntity downloadGatewayDockerCompose(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) + @PathVariable(DEVICE_ID) String strDeviceId, HttpServletRequest request) throws ThingsboardException, URISyntaxException, IOException { + checkParameter(DEVICE_ID, strDeviceId); + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); + Device device = checkDeviceId(deviceId, Operation.READ_CREDENTIALS); + + if (!checkIsGateway(device)) { + throw new ThingsboardException("The device must be a gateway!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); + } + + String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request); + var dockerCompose = checkNotNull(deviceConnectivityService.createGatewayDockerComposeFile(baseUrl, device), "Failed to create docker-compose.yml file!"); + + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + DOCKER_COMPOSE_YML) + .header("x-filename", DOCKER_COMPOSE_YML) + .contentLength(dockerCompose.contentLength()) + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .body(dockerCompose); + } + private static boolean checkIsGateway(Device device) { return device.getAdditionalInfo().has(DataConstants.GATEWAY_PARAMETER) && device.getAdditionalInfo().get(DataConstants.GATEWAY_PARAMETER).asBoolean(); diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java index 57ae38f096..ba307529ed 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java @@ -54,10 +54,8 @@ import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAPS; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.DOCKER; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.LINUX; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.WINDOWS; @TestPropertySource(properties = { "device.connectivity.mqtts.pem_cert_file=/tmp/" + CA_ROOT_CERT_PEM @@ -278,7 +276,7 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { } @Test - public void testFetchGatewayLaunchCommands() throws Exception { + public void testFetchGatewayDockerComposeFile() throws Exception { String deviceName = "My device"; Device device = new Device(); device.setName(deviceName); @@ -290,19 +288,50 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { DeviceCredentials credentials = doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); - JsonNode commands = - doGetTyped("/api/device-connectivity/gateway-launch/" + savedDevice.getId().getId(), new TypeReference<>() { - }); - - String expectedContainerName = deviceName.replaceAll("[^A-Za-z0-9_.-]", ""); - - JsonNode dockerMqttCommands = commands.get(MQTT); - assertThat(dockerMqttCommands.get(LINUX).asText()).isEqualTo(String.format("docker run -it -v ~/.tb-gateway/logs:/thingsboard_gateway/logs -v ~/.tb-gateway/extensions:/thingsboard_gateway/extensions -v ~/.tb-gateway/config:/thingsboard_gateway/config --name " + expectedContainerName + " --add-host=host.docker.internal:host-gateway -p 60000-61000:60000-61000 -e host=host.docker.internal -e port=1883 -e accessToken=%s --restart always thingsboard/tb-gateway", credentials.getCredentialsId())); - assertThat(dockerMqttCommands.get(WINDOWS).asText()).isEqualTo("docker run -it -v %HOMEDRIVE%%HOMEPATH%\\tb-gateway\\logs:/thingsboard_gateway/logs -v %HOMEDRIVE%%HOMEPATH%\\tb-gateway\\extensions:/thingsboard_gateway/extensions -v %HOMEDRIVE%%HOMEPATH%\\tb-gateway\\config:/thingsboard_gateway/config --name " + expectedContainerName + " --add-host=host.docker.internal:host-gateway -p 60000-61000:60000-61000 -e host=host.docker.internal -e port=1883 -e accessToken=" + credentials.getCredentialsId() + " --restart always thingsboard/tb-gateway"); - - JsonNode dockerMqttsCommands = commands.get(MQTTS); - assertThat(dockerMqttsCommands.get(LINUX).asText()).isEqualTo(String.format("docker run -it -v ~/.tb-gateway/logs:/thingsboard_gateway/logs -v ~/.tb-gateway/extensions:/thingsboard_gateway/extensions -v ~/.tb-gateway/config:/thingsboard_gateway/config --name " + expectedContainerName + " --add-host=host.docker.internal:host-gateway -p 60000-61000:60000-61000 -e host=host.docker.internal -e port=8883 -e accessToken=%s --restart always thingsboard/tb-gateway", credentials.getCredentialsId())); - assertThat(dockerMqttsCommands.get(WINDOWS).asText()).isEqualTo("docker run -it -v %HOMEDRIVE%%HOMEPATH%\\tb-gateway\\logs:/thingsboard_gateway/logs -v %HOMEDRIVE%%HOMEPATH%\\tb-gateway\\extensions:/thingsboard_gateway/extensions -v %HOMEDRIVE%%HOMEPATH%\\tb-gateway\\config:/thingsboard_gateway/config --name " + expectedContainerName + " --add-host=host.docker.internal:host-gateway -p 60000-61000:60000-61000 -e host=host.docker.internal -e port=8883 -e accessToken=" + credentials.getCredentialsId() + " --restart always thingsboard/tb-gateway"); + String commands = + doGet("/api/device-connectivity/gateway-launch/" + savedDevice.getId().getId() + "/docker-compose/download", String.class); + + assertThat(commands).isEqualTo(String.format("version: '3.4'\n" + + "services:\n" + + " # ThingsBoard IoT Gateway Service Configuration\n" + + " tb-gateway:\n" + + " image: thingsboard/tb-gateway\n" + + " container_name: tb-gateway\n" + + " restart: always\n" + + "\n" + + " # Ports bindings - required by some connectors\n" + + " ports:\n" + + " - \"5000:5000\" # Comment if you don't use REST connector and change if you use another port\n" + + " # Uncomment and modify the following ports based on connector usage:\n" + + "# - \"1052:1052\" # BACnet connector\n" + + "# - \"5026:5026\" # Modbus TCP connector (Modbus Slave)\n" + + "# - \"50000:50000/tcp\" # Socket connector with type TCP\n" + + "# - \"50000:50000/udp\" # Socket connector with type UDP\n" + + "\n" + + " # Necessary mapping for Linux\n" + + " extra_hosts:\n" + + " - \"host.docker.internal:host-gateway\"\n" + + "\n" + + " # Environment variables\n" + + " environment:\n" + + " - host=host.docker.internal\n" + + " - port=1883\n" + + " - accessToken=" + credentials.getCredentialsId() + "\n" + + "\n" + + " # Volumes bind\n" + + " volumes:\n" + + " - tb-gw-config:/thingsboard_gateway/config\n" + + " - tb-gw-logs:/thingsboard_gateway/logs\n" + + " - tb-gw-extensions:/thingsboard_gateway/extensions\n" + + "\n" + + "# Volumes declaration for configurations, extensions and configuration\n" + + "volumes:\n" + + " tb-gw-config:\n" + + " name: tb-gw-config\n" + + " tb-gw-logs:\n" + + " name: tb-gw-logs\n" + + " tb-gw-extensions:\n" + + " name: tb-gw-extensions\n")); } @Test diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java index 4f2d9a1aee..97e69c5ec7 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java @@ -25,7 +25,7 @@ public interface DeviceConnectivityService { JsonNode findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException; - JsonNode findGatewayLaunchCommands(String baseUrl, Device device) throws URISyntaxException; - Resource getPemCertFile(String protocol); + + Resource createGatewayDockerComposeFile(String baseUrl, Device device) throws URISyntaxException; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java index 50396c6ebc..cd872dce22 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java @@ -59,10 +59,8 @@ import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAPS; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.DOCKER; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.LINUX; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.WINDOWS; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.getHost; @Service("DeviceConnectivityDaoService") @@ -130,27 +128,6 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService return commands; } - @Override - public JsonNode findGatewayLaunchCommands(String baseUrl, Device device) throws URISyntaxException { - DeviceId deviceId = device.getId(); - log.trace("Executing findDevicePublishTelemetryCommands [{}]", deviceId); - validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); - - DeviceCredentials creds = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), deviceId); - String deviceName = device.getName(); - - ObjectNode commands = JacksonUtil.newObjectNode(); - if (isEnabled(MQTT)) { - Optional.ofNullable(getGatewayDockerCommands(baseUrl, deviceName, creds, MQTT)) - .ifPresent(v -> commands.set(MQTT, v)); - } - if (isEnabled(MQTTS)) { - Optional.ofNullable(getGatewayDockerCommands(baseUrl, deviceName, creds, MQTTS)) - .ifPresent(v -> commands.set(MQTTS, v)); - } - return commands; - } - @Override public Resource getPemCertFile(String protocol) { return certs.computeIfAbsent(protocol, key -> { @@ -174,6 +151,14 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService }); } + @Override + public Resource createGatewayDockerComposeFile(String baseUrl, Device device) throws URISyntaxException { + String mqttType = isEnabled(MQTTS) ? MQTTS : MQTT; + DeviceConnectivityInfo properties = getConnectivity(mqttType); + DeviceCredentials creds = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), device.getId()); + return DeviceConnectivityUtil.getGatewayDockerComposeFile(baseUrl, properties, creds, mqttType); + } + private DeviceConnectivityInfo getConnectivity(String protocol) { AdminSettings connectivitySettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "connectivity"); JsonNode connectivity; @@ -299,18 +284,6 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService return null; } - private JsonNode getGatewayDockerCommands(String baseUrl, String deviceName, DeviceCredentials deviceCredentials, String mqttType) throws URISyntaxException { - ObjectNode dockerLaunchCommands = JacksonUtil.newObjectNode(); - DeviceConnectivityInfo properties = getConnectivity(mqttType); - String mqttHost = getHost(baseUrl, properties, mqttType); - String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); - Optional.ofNullable(DeviceConnectivityUtil.getGatewayLaunchCommand(LINUX, deviceName, mqttHost, mqttPort, deviceCredentials)) - .ifPresent(v -> dockerLaunchCommands.put(LINUX, v)); - Optional.ofNullable(DeviceConnectivityUtil.getGatewayLaunchCommand(WINDOWS, deviceName, mqttHost, mqttPort, deviceCredentials)) - .ifPresent(v -> dockerLaunchCommands.put(WINDOWS, v)); - return dockerLaunchCommands.isEmpty() ? null : dockerLaunchCommands; - } - private String getDockerMqttPublishCommand(String protocol, String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException { DeviceConnectivityInfo properties = getConnectivity(protocol); String mqttHost = getHost(baseUrl, properties, protocol); diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java b/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java index 63ddba1c14..e6e805f4f7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java @@ -15,7 +15,8 @@ */ package org.thingsboard.server.dao.util; -import org.apache.commons.lang3.StringUtils; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; import org.thingsboard.server.common.data.security.DeviceCredentials; @@ -26,6 +27,7 @@ import java.net.InetAddress; import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; +import java.nio.charset.StandardCharsets; import java.util.regex.Pattern; public class DeviceConnectivityUtil { @@ -35,17 +37,16 @@ public class DeviceConnectivityUtil { public static final String MQTT = "mqtt"; public static final String LINUX = "linux"; public static final String WINDOWS = "windows"; + public static final String MACOS = "macos"; public static final String DOCKER = "docker"; public static final String MQTTS = "mqtts"; public static final String COAP = "coap"; public static final String COAPS = "coaps"; public static final String CA_ROOT_CERT_PEM = "ca-root.pem"; + public static final String DOCKER_COMPOSE_YML = "docker-compose.yml"; public static final String CHECK_DOCUMENTATION = "Check documentation"; public static final String JSON_EXAMPLE_PAYLOAD = "\"{temperature:25}\""; public static final String DOCKER_RUN = "docker run --rm -it "; - public static final String GATEWAY_DOCKER_RUN = "docker run -it "; - - public static final String NETWORK_HOST_PARAM = "--network=host "; public static final String HOST_DOCKER_INTERNAL = "host.docker.internal"; public static final String ADD_DOCKER_INTERNAL_HOST = "--add-host=" + HOST_DOCKER_INTERNAL + ":host-gateway "; public static final String MQTT_IMAGE = "thingsboard/mosquitto-clients "; @@ -93,53 +94,74 @@ public class DeviceConnectivityUtil { return command.toString(); } - public static String getGatewayLaunchCommand(String os, String deviceName, String host, String port, DeviceCredentials deviceCredentials) { - String gatewayVolumePathPrefix = "~/.tb-gateway/"; - if (WINDOWS.equals(os)) { - gatewayVolumePathPrefix = "%HOMEDRIVE%%HOMEPATH%\\tb-gateway\\"; + public static Resource getGatewayDockerComposeFile(String baseUrl, DeviceConnectivityInfo properties, DeviceCredentials deviceCredentials, String mqttType) throws URISyntaxException { + String host = getHost(baseUrl, properties, mqttType); + + StringBuilder dockerComposeBuilder = new StringBuilder(); + dockerComposeBuilder.append("version: '3.4'\n"); + dockerComposeBuilder.append("services:\n"); + dockerComposeBuilder.append(" # ThingsBoard IoT Gateway Service Configuration\n"); + dockerComposeBuilder.append(" tb-gateway:\n"); + dockerComposeBuilder.append(" image: thingsboard/tb-gateway\n"); + dockerComposeBuilder.append(" container_name: tb-gateway\n"); + dockerComposeBuilder.append(" restart: always\n"); + dockerComposeBuilder.append("\n"); + dockerComposeBuilder.append(" # Ports bindings - required by some connectors\n"); + dockerComposeBuilder.append(" ports:\n"); + dockerComposeBuilder.append(" - \"5000:5000\" # Comment if you don't use REST connector and change if you use another port\n"); + dockerComposeBuilder.append(" # Uncomment and modify the following ports based on connector usage:\n"); + dockerComposeBuilder.append("# - \"1052:1052\" # BACnet connector\n"); + dockerComposeBuilder.append("# - \"5026:5026\" # Modbus TCP connector (Modbus Slave)\n"); + dockerComposeBuilder.append("# - \"50000:50000/tcp\" # Socket connector with type TCP\n"); + dockerComposeBuilder.append("# - \"50000:50000/udp\" # Socket connector with type UDP\n"); + if (isLocalhost(host)) { + dockerComposeBuilder.append("\n"); + dockerComposeBuilder.append(" # Necessary mapping for Linux\n"); + dockerComposeBuilder.append(" extra_hosts:\n"); + dockerComposeBuilder.append(" - \"host.docker.internal:host-gateway\"\n"); } - - String gatewayContainerName = deviceName.replaceAll("[^A-Za-z0-9_.-]", ""); - - StringBuilder command = new StringBuilder(GATEWAY_DOCKER_RUN); - command.append("-v {gatewayVolumePathPrefix}logs:/thingsboard_gateway/logs ".replace("{gatewayVolumePathPrefix}", gatewayVolumePathPrefix)); - command.append("-v {gatewayVolumePathPrefix}extensions:/thingsboard_gateway/extensions ".replace("{gatewayVolumePathPrefix}", gatewayVolumePathPrefix)); - command.append("-v {gatewayVolumePathPrefix}config:/thingsboard_gateway/config ".replace("{gatewayVolumePathPrefix}", gatewayVolumePathPrefix)); - command.append("--name ").append(gatewayContainerName).append(" "); - command.append(isLocalhost(host) ? ADD_DOCKER_INTERNAL_HOST : ""); - command.append("-p 60000-61000:60000-61000 "); - command.append("-e host=").append(isLocalhost(host) ? HOST_DOCKER_INTERNAL : host).append(" "); - command.append("-e port=").append(port); - + dockerComposeBuilder.append("\n"); + dockerComposeBuilder.append(" # Environment variables\n"); + dockerComposeBuilder.append(" environment:\n"); + dockerComposeBuilder.append(" - host=").append(isLocalhost(host) ? HOST_DOCKER_INTERNAL : host).append("\n"); + dockerComposeBuilder.append(" - port=1883\n"); switch (deviceCredentials.getCredentialsType()) { case ACCESS_TOKEN: - command.append(" -e accessToken=").append(deviceCredentials.getCredentialsId()); + dockerComposeBuilder.append(" - accessToken=").append(deviceCredentials.getCredentialsId()).append("\n"); break; case MQTT_BASIC: BasicMqttCredentials credentials = JacksonUtil.fromString(deviceCredentials.getCredentialsValue(), BasicMqttCredentials.class); if (credentials != null) { if (credentials.getClientId() != null) { - command.append(" -e clientId=").append(credentials.getClientId()); + dockerComposeBuilder.append(" - clientId=").append(credentials.getClientId()).append("\n"); } if (credentials.getUserName() != null) { - command.append(" -e username=").append(credentials.getUserName()); + dockerComposeBuilder.append(" - username=").append(credentials.getUserName()).append("\n"); } if (credentials.getPassword() != null) { - command.append(" -e password=").append(credentials.getPassword()); + dockerComposeBuilder.append(" - password=").append(credentials.getPassword()).append("\n"); } - } else { - return null; } break; - default: - return null; } - - command.append(" --restart always"); - command.append(" thingsboard/tb-gateway"); - - return command.toString(); + dockerComposeBuilder.append("\n"); + dockerComposeBuilder.append(" # Volumes bind\n"); + dockerComposeBuilder.append(" volumes:\n"); + dockerComposeBuilder.append(" - tb-gw-config:/thingsboard_gateway/config\n"); + dockerComposeBuilder.append(" - tb-gw-logs:/thingsboard_gateway/logs\n"); + dockerComposeBuilder.append(" - tb-gw-extensions:/thingsboard_gateway/extensions\n"); + dockerComposeBuilder.append("\n"); + dockerComposeBuilder.append("# Volumes declaration for configurations, extensions and configuration\n"); + dockerComposeBuilder.append("volumes:\n"); + dockerComposeBuilder.append(" tb-gw-config:\n"); + dockerComposeBuilder.append(" name: tb-gw-config\n"); + dockerComposeBuilder.append(" tb-gw-logs:\n"); + dockerComposeBuilder.append(" name: tb-gw-logs\n"); + dockerComposeBuilder.append(" tb-gw-extensions:\n"); + dockerComposeBuilder.append(" name: tb-gw-extensions\n"); + + return new ByteArrayResource(dockerComposeBuilder.toString().getBytes(StandardCharsets.UTF_8)); } public static String getDockerMqttPublishCommand(String protocol, String baseUrl, String host, String port, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { @@ -152,7 +174,7 @@ public class DeviceConnectivityUtil { StringBuilder mqttDockerCommand = new StringBuilder(); mqttDockerCommand.append(DOCKER_RUN).append(isLocalhost(host) ? ADD_DOCKER_INTERNAL_HOST : "").append(MQTT_IMAGE); - if (isLocalhost(host)){ + if (isLocalhost(host)) { mqttCommand = mqttCommand.replace(host, HOST_DOCKER_INTERNAL); } @@ -170,7 +192,11 @@ public class DeviceConnectivityUtil { } public static String getCurlPemCertCommand(String baseUrl, String protocol) { - return String.format("curl -f -S -o %s %s/api/device-connectivity/%s/certificate/download", CA_ROOT_CERT_PEM, baseUrl, protocol); + return getCurlPemCertCommand(baseUrl, protocol, CA_ROOT_CERT_PEM); + } + + public static String getCurlPemCertCommand(String baseUrl, String protocol, String caCertFilePath) { + return String.format("curl -f -S -o %s %s/api/device-connectivity/%s/certificate/download", caCertFilePath, baseUrl, protocol); } public static String getCoapPublishCommand(String protocol, String host, String port, DeviceCredentials deviceCredentials) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.html index 2d7a604852..084eb49245 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.html @@ -52,7 +52,7 @@ + *ngTemplateOutlet="commandsExample; context: {command: commands?.mqtt?.macos }"> diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index fd277b52fb..64cd6a1909 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -869,6 +869,7 @@ export interface PublishLaunchCommand { mqtt: { linux: string; windows: string; + macos: string; }; }