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 8d21057b8e..55943c819e 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java @@ -61,6 +61,7 @@ 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.MACOS; 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; @@ -309,15 +310,20 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { doGetTyped("/api/device-connectivity/gateway-launch/" + savedDevice.getId().getId(), new TypeReference<>() { }); - String expectedContainerName = deviceName.replaceAll("[^A-Za-z0-9_.-]", "");; + String expectedContainerName = deviceName.replace(" ", "_").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"); + 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 + " --network=host --add-host=host.docker.internal:host-gateway -e host=host.docker.internal -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 + " -p 6400-6420:6400-6420 -e host=host.docker.internal -e accessToken=" + credentials.getCredentialsId() + " --restart always thingsboard/tb-gateway"); + assertThat(dockerMqttCommands.get(MACOS).asText()).isEqualTo("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 + " -p 6400-6420:6400-6420 -e host=host.docker.internal -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"); + assertThat(dockerMqttsCommands.get(LINUX).asText()).isEqualTo(String.format("curl -f -S -o ~/.tb-gateway/config/ca-root.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "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 + " --network=host --add-host=host.docker.internal:host-gateway -e host=host.docker.internal -e port=8883 -e accessToken=%s -e caCert=/thingsboard_gateway/config/ca-root.pem --restart always thingsboard/tb-gateway", credentials.getCredentialsId())); + assertThat(dockerMqttsCommands.get(WINDOWS).asText()).isEqualTo("curl -f -S -o %HOMEDRIVE%%HOMEPATH%\\tb-gateway\\config\\ca-root.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "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 + " -p 6400-6420:6400-6420 -e host=host.docker.internal -e port=8883 -e accessToken=" + credentials.getCredentialsId() + " -e caCert=/thingsboard_gateway/config/ca-root.pem --restart always thingsboard/tb-gateway"); + assertThat(dockerMqttsCommands.get(MACOS).asText()).isEqualTo("curl -f -S -o ~/.tb-gateway/config/ca-root.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "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 + " -p 6400-6420:6400-6420 -e host=host.docker.internal -e port=8883 -e accessToken=" + credentials.getCredentialsId() + " -e caCert=/thingsboard_gateway/config/ca-root.pem --restart always thingsboard/tb-gateway"); } @Test 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..bc1eeae8e7 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 @@ -60,6 +60,7 @@ 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.MACOS; 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; @@ -302,12 +303,12 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService 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)) + Optional.ofNullable(DeviceConnectivityUtil.getGatewayLaunchCommand(LINUX, deviceName, properties, deviceCredentials, mqttType, baseUrl)) .ifPresent(v -> dockerLaunchCommands.put(LINUX, v)); - Optional.ofNullable(DeviceConnectivityUtil.getGatewayLaunchCommand(WINDOWS, deviceName, mqttHost, mqttPort, deviceCredentials)) + Optional.ofNullable(DeviceConnectivityUtil.getGatewayLaunchCommand(WINDOWS, deviceName, properties, deviceCredentials, mqttType, baseUrl)) .ifPresent(v -> dockerLaunchCommands.put(WINDOWS, v)); + Optional.ofNullable(DeviceConnectivityUtil.getGatewayLaunchCommand(MACOS, deviceName, properties, deviceCredentials, mqttType, baseUrl)) + .ifPresent(v -> dockerLaunchCommands.put(MACOS, v)); return dockerLaunchCommands.isEmpty() ? null : dockerLaunchCommands; } 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 c5708ce34e..4cdc891eac 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,6 @@ */ package org.thingsboard.server.dao.util; -import org.apache.commons.lang3.StringUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; import org.thingsboard.server.common.data.security.DeviceCredentials; @@ -35,11 +34,13 @@ 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 CA_ROOT_GATEWAY_CERT_PEM_PATH = "{gatewayVolumePathPrefix}config{pathSep}" + CA_ROOT_CERT_PEM; 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 "; @@ -93,23 +94,41 @@ public class DeviceConnectivityUtil { return command.toString(); } - public static String getGatewayLaunchCommand(String os, String deviceName, String host, String port, DeviceCredentials deviceCredentials) { + public static String getGatewayLaunchCommand(String os, String deviceName, DeviceConnectivityInfo properties, DeviceCredentials deviceCredentials, String mqttType, String baseUrl) throws URISyntaxException { + String host = getHost(baseUrl, properties, mqttType); + String port = properties.getPort().isEmpty() ? null : properties.getPort(); String gatewayVolumePathPrefix = "~/.tb-gateway/"; + String pathSep = "/"; if (WINDOWS.equals(os)) { gatewayVolumePathPrefix = "%HOMEDRIVE%%HOMEPATH%\\tb-gateway\\"; + pathSep = "\\"; } - String gatewayContainerName = deviceName.replaceAll("[^A-Za-z0-9_.-]", ""); + String gatewayContainerName = deviceName.replace(" ", "_").replaceAll("[^A-Za-z0-9_.-]", ""); - StringBuilder command = new StringBuilder(GATEWAY_DOCKER_RUN); + StringBuilder command = new StringBuilder(); + String caRootGatewayCertPemPath = CA_ROOT_GATEWAY_CERT_PEM_PATH + .replace("{gatewayVolumePathPrefix}", gatewayVolumePathPrefix) + .replace("{pathSep}", pathSep); + if (MQTTS.equals(mqttType)) { + command.append(getCurlPemCertCommand(baseUrl, MQTTS, caRootGatewayCertPemPath)); + command.append(" && "); + } + command.append(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); + if (LINUX.equals(os)) { + command.append(NETWORK_HOST_PARAM); + command.append(isLocalhost(host) ? ADD_DOCKER_INTERNAL_HOST : ""); + } else { + command.append("-p 6400-6420:6400-6420 "); + } + command.append("-e host=").append(isLocalhost(host) ? HOST_DOCKER_INTERNAL : host); + if (port != null && !"1883".equals(port)) { + command.append(" -e port=").append(port); + } switch (deviceCredentials.getCredentialsType()) { case ACCESS_TOKEN: @@ -136,6 +155,10 @@ public class DeviceConnectivityUtil { return null; } + if (MQTTS.equals(mqttType)) { + command.append(" -e caCert=/thingsboard_gateway/config/").append(CA_ROOT_CERT_PEM); + } + command.append(" --restart always"); command.append(" thingsboard/tb-gateway"); @@ -152,7 +175,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 +193,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; }; }