diff --git a/application/src/main/data/json/edge/install_instructions/centos/instructions.md b/application/src/main/data/json/edge/instructions/install/centos/instructions.md
similarity index 98%
rename from application/src/main/data/json/edge/install_instructions/centos/instructions.md
rename to application/src/main/data/json/edge/instructions/install/centos/instructions.md
index 126c79b641..9ad882c387 100644
--- a/application/src/main/data/json/edge/install_instructions/centos/instructions.md
+++ b/application/src/main/data/json/edge/instructions/install/centos/instructions.md
@@ -1,4 +1,4 @@
-Here is the list of commands, that can be used to quickly install ThingsBoard Edge on RHEL/CentOS 7/8 and connect to the cloud.
+Here is the list of commands, that can be used to quickly install ThingsBoard Edge on RHEL/CentOS 7/8 and connect to the server.
#### Prerequisites
Before continue to installation execute the following commands in order to install necessary tools:
diff --git a/application/src/main/data/json/edge/install_instructions/docker/instructions.md b/application/src/main/data/json/edge/instructions/install/docker/instructions.md
similarity index 98%
rename from application/src/main/data/json/edge/install_instructions/docker/instructions.md
rename to application/src/main/data/json/edge/instructions/install/docker/instructions.md
index e308a38076..cbfe5f8c4c 100644
--- a/application/src/main/data/json/edge/install_instructions/docker/instructions.md
+++ b/application/src/main/data/json/edge/instructions/install/docker/instructions.md
@@ -1,4 +1,4 @@
-Here is the list of commands, that can be used to quickly install ThingsBoard Edge using docker compose and connect to the cloud.
+Here is the list of commands, that can be used to quickly install ThingsBoard Edge using docker compose and connect to the server.
#### Prerequisites
diff --git a/application/src/main/data/json/edge/install_instructions/docker/localhost_warning.md b/application/src/main/data/json/edge/instructions/install/docker/localhost_warning.md
similarity index 100%
rename from application/src/main/data/json/edge/install_instructions/docker/localhost_warning.md
rename to application/src/main/data/json/edge/instructions/install/docker/localhost_warning.md
diff --git a/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md b/application/src/main/data/json/edge/instructions/install/ubuntu/instructions.md
similarity index 98%
rename from application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md
rename to application/src/main/data/json/edge/instructions/install/ubuntu/instructions.md
index 425c08662b..2a6d9c0bc3 100644
--- a/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md
+++ b/application/src/main/data/json/edge/instructions/install/ubuntu/instructions.md
@@ -1,4 +1,4 @@
-Here is the list of commands, that can be used to quickly install ThingsBoard Edge on Ubuntu Server and connect to the cloud.
+Here is the list of commands, that can be used to quickly install ThingsBoard Edge on Ubuntu Server and connect to the server.
#### Install Java 11 (OpenJDK)
ThingsBoard service is running on Java 11. Follow these instructions to install OpenJDK 11:
diff --git a/application/src/main/data/json/edge/instructions/upgrade/centos/instructions.md b/application/src/main/data/json/edge/instructions/upgrade/centos/instructions.md
new file mode 100644
index 0000000000..d0b2a1895d
--- /dev/null
+++ b/application/src/main/data/json/edge/instructions/upgrade/centos/instructions.md
@@ -0,0 +1,30 @@
+#### Upgrading to ${TB_EDGE_VERSION_TITLE}
+**NOTE**:These steps are applicable for ThingsBoard Edge ${CURRENT_TB_EDGE_VERSION} version.
+
+**ThingsBoard Edge package download**
+```bash
+wget https://github.com/thingsboard/thingsboard-edge/releases/download/v${TB_EDGE_TAG}/tb-edge-${TB_EDGE_TAG}.rpm
+{:copy-code}
+```
+
+#### ThingsBoard Edge service upgrade
+
+Stop ThingsBoard Edge service if it is running:
+
+```bash
+sudo service tb-edge stop
+{:copy-code}
+```
+
+```bash
+sudo rpm -Uvh tb-edge-${TB_EDGE_TAG}.rpm
+{:copy-code}
+```
+
+${UPGRADE_DB}
+
+Start the service
+```bash
+sudo service tb-edge start
+{:copy-code}
+```
diff --git a/application/src/main/data/json/edge/instructions/upgrade/docker/instructions.md b/application/src/main/data/json/edge/instructions/upgrade/docker/instructions.md
new file mode 100644
index 0000000000..ad7f4b2c46
--- /dev/null
+++ b/application/src/main/data/json/edge/instructions/upgrade/docker/instructions.md
@@ -0,0 +1,15 @@
+#### Upgrading to ${TB_EDGE_VERSION}
+
+**NOTE**:These steps are applicable for ThingsBoard Edge ${CURRENT_TB_EDGE_VERSION} version.
+Execute the following command to pull **${TB_EDGE_VERSION}** image:
+
+```bash
+docker pull thingsboard/tb-edge:${TB_EDGE_VERSION}
+{:copy-code}
+```
+
+${STOP_SERVICE}
+
+${UPGRADE_DB}
+
+Make sure your image is the set to tb-edge-${TB_EDGE_VERSION}.
diff --git a/application/src/main/data/json/edge/instructions/upgrade/docker/start_service.md b/application/src/main/data/json/edge/instructions/upgrade/docker/start_service.md
new file mode 100644
index 0000000000..cfdd9a66f2
--- /dev/null
+++ b/application/src/main/data/json/edge/instructions/upgrade/docker/start_service.md
@@ -0,0 +1,7 @@
+Execute the following commands to up this docker compose directly:
+
+```bash
+docker compose up -d
+docker compose logs -f mytbedge
+{:copy-code}
+```
diff --git a/application/src/main/data/json/edge/instructions/upgrade/docker/stop_service.md b/application/src/main/data/json/edge/instructions/upgrade/docker/stop_service.md
new file mode 100644
index 0000000000..8f4aedb117
--- /dev/null
+++ b/application/src/main/data/json/edge/instructions/upgrade/docker/stop_service.md
@@ -0,0 +1,11 @@
+Set the terminal in the directory which contains the `docker-compose.yml` file and execute the following command to stop
+and remove currently running TB Edge container (if it’s still running):
+
+```bash
+make docker-compose.yml
+
+```bash
+docker compose stop
+docker compose rm mytbedge
+{:copy-code}
+```
diff --git a/application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_db.md b/application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_db.md
new file mode 100644
index 0000000000..ae6181bf08
--- /dev/null
+++ b/application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_db.md
@@ -0,0 +1,53 @@
+Create docker compose file for ThingsBoard Edge upgrade process:
+
+```bash
+nano docker-compose-upgrade.yml
+{:copy-code}
+```
+
+Add the following lines to the yml file:
+
+```bash
+version: '3.0'
+services:
+ mytbedge:
+ restart: on-failure
+ image: "thingsboard/tb-edge:${TB_EDGE_VERSION}"
+ environment:
+ SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/tb-edge
+ volumes:
+ - ~/.mytb-edge-data:/data
+ - ~/.mytb-edge-logs:/var/log/tb-edge
+ entrypoint: upgrade-tb-edge.sh
+ postgres:
+ restart: always
+ image: "postgres:12"
+ ports:
+ - "5432"
+ environment:
+ POSTGRES_DB: tb-edge
+ POSTGRES_PASSWORD: postgres
+ volumes:
+ - ~/.mytb-edge-data/db:/var/lib/postgresql/data
+{:copy-code}
+```
+
+Execute the following command to start upgrade process:
+
+```bash
+docker compose -f docker-compose-upgrade.yml up
+{:copy-code}
+```
+
+Once upgrade process successfully completed, exit from the docker-compose shell by this combination:
+
+```text
+Ctrl + C
+```
+
+Execute the following command to stop TB Edge upgrade container:
+
+```bash
+docker compose -f docker-compose-upgrade.yml stop
+{:copy-code}
+```
diff --git a/application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_preparing.md b/application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_preparing.md
new file mode 100644
index 0000000000..c82daaee26
--- /dev/null
+++ b/application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_preparing.md
@@ -0,0 +1,26 @@
+Here is the list of commands, that can be used to quickly upgrade ThingsBoard Edge on Docker (Linux or MacOS).
+
+#### Prepare for upgrading ThingsBoard Edge
+Set the terminal in the directory which contains the `docker-compose.yml` file and execute the following command
+to stop and remove currently running TB Edge container:
+
+```bash
+docker compose stop
+docker compose rm mytbedge
+{:copy-code}
+```
+
+If you still rely on Docker Compose as docker-compose (with a hyphen) here is the list of the above commands:
+docker-compose stop
+docker-compose rm mytbedge
+
+#### Backup Database
+Make a copy of the database folder before upgrading:
+
+```bash
+sudo cp -r ~/.mytb-edge-data/db ~/.mytb-edge-db-BACKUP
+{:copy-code}
+```
+
+```bash
+make docker-compose.yml
diff --git a/application/src/main/data/json/edge/instructions/upgrade/start_service.md b/application/src/main/data/json/edge/instructions/upgrade/start_service.md
new file mode 100644
index 0000000000..0ce6a0b222
--- /dev/null
+++ b/application/src/main/data/json/edge/instructions/upgrade/start_service.md
@@ -0,0 +1,6 @@
+Start the service
+
+```bash
+sudo service tb-edge start
+{:copy-code}
+```
diff --git a/application/src/main/data/json/edge/instructions/upgrade/stop_service.md b/application/src/main/data/json/edge/instructions/upgrade/stop_service.md
new file mode 100644
index 0000000000..615d0f8a40
--- /dev/null
+++ b/application/src/main/data/json/edge/instructions/upgrade/stop_service.md
@@ -0,0 +1,6 @@
+Stop ThingsBoard Edge service if it is running:
+
+```bash
+sudo service tb-edge stop
+{:copy-code}
+```
diff --git a/application/src/main/data/json/edge/instructions/upgrade/ubuntu/instructions.md b/application/src/main/data/json/edge/instructions/upgrade/ubuntu/instructions.md
new file mode 100644
index 0000000000..5824875f47
--- /dev/null
+++ b/application/src/main/data/json/edge/instructions/upgrade/ubuntu/instructions.md
@@ -0,0 +1,19 @@
+#### Upgrading to ${TB_EDGE_VERSION}
+**NOTE**:These steps are applicable for ThingsBoard Edge ${CURRENT_TB_EDGE_VERSION} version.
+
+**ThingsBoard Edge package download**
+```bash
+wget https://github.com/thingsboard/thingsboard-edge/releases/download/v${TB_EDGE_TAG}/tb-edge-${TB_EDGE_TAG}.deb
+{:copy-code}
+```
+
+#### ThingsBoard Edge service upgrade
+
+${STOP_SERVICE}
+
+```bash
+sudo dpkg -i tb-edge-${TB_EDGE_TAG}.deb
+{:copy-code}
+```
+
+${UPGRADE_DB}
diff --git a/application/src/main/data/json/edge/instructions/upgrade/upgrade_db.md b/application/src/main/data/json/edge/instructions/upgrade/upgrade_db.md
new file mode 100644
index 0000000000..d3a28fb20b
--- /dev/null
+++ b/application/src/main/data/json/edge/instructions/upgrade/upgrade_db.md
@@ -0,0 +1,8 @@
+**NOTE**: Package installer may ask you to merge your tb-edge configuration. It is preferred to use **merge option** to make sure that all your previous parameters will not be overwritten.
+
+Execute regular upgrade script:
+
+```bash
+sudo /usr/share/tb-edge/bin/install/upgrade.sh --fromVersion=${CURRENT_TB_EDGE_VERSION}
+{:copy-code}
+```
diff --git a/application/src/main/data/json/edge/instructions/upgrade/upgrade_preparing.md b/application/src/main/data/json/edge/instructions/upgrade/upgrade_preparing.md
new file mode 100644
index 0000000000..105a94b778
--- /dev/null
+++ b/application/src/main/data/json/edge/instructions/upgrade/upgrade_preparing.md
@@ -0,0 +1,37 @@
+Here is the list of commands, that can be used to quickly upgrade ThingsBoard Edge on RHEL/CentOS 7/8.
+
+#### Prepare for upgrading ThingsBoard Edge
+
+Stop ThingsBoard Edge service:
+
+```bash
+sudo systemctl stop tb-edge
+{:copy-code}
+```
+
+#### Backup Database
+Make a backup of the database before upgrading.
+**Make sure you have enough space to place a backup of the database.**
+
+Check database size:
+
+```bash
+sudo -u postgres psql -c "SELECT pg_size_pretty( pg_database_size('tb_edge') );"
+{:copy-code}
+```
+
+Check free space:
+
+```bash
+df -h /
+{:copy-code}
+```
+
+If there is enough free space - make a backup:
+
+```bash
+sudo -Hiu postgres pg_dump tb_edge > tb_edge.sql.bak
+{:copy-code}
+```
+
+Check backup file created successfully.
diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java
index fa16fbff81..c621dc777f 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java
@@ -39,7 +39,7 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeInfo;
-import org.thingsboard.server.common.data.edge.EdgeInstallInstructions;
+import org.thingsboard.server.common.data.edge.EdgeInstructions;
import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
@@ -60,6 +60,7 @@ import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.EdgeBulkImportService;
import org.thingsboard.server.service.edge.instructions.EdgeInstallService;
+import org.thingsboard.server.service.edge.instructions.EdgeUpgradeService;
import org.thingsboard.server.service.edge.rpc.EdgeRpcService;
import org.thingsboard.server.service.entitiy.edge.TbEdgeService;
import org.thingsboard.server.service.security.model.SecurityUser;
@@ -102,6 +103,7 @@ public class EdgeController extends BaseController {
private final TbEdgeService tbEdgeService;
private final Optional edgeRpcServiceOpt;
private final Optional edgeInstallServiceOpt;
+ private final Optional edgeUpgradeServiceOpt;
public static final String EDGE_ID = "edgeId";
public static final String EDGE_SECURITY_CHECK = "If the user has the authority of 'Tenant Administrator', the server checks that the edge is owned by the same tenant. " +
@@ -553,16 +555,16 @@ public class EdgeController extends BaseController {
return edgeBulkImportService.processBulkImport(request, user);
}
- @ApiOperation(value = "Get Edge Docker Install Instructions (getEdgeDockerInstallInstructions)",
+ @ApiOperation(value = "Get Edge Install Instructions (getEdgeInstallInstructions)",
notes = "Get a docker install instructions for provided edge id." + TENANT_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
- @RequestMapping(value = "/edge/instructions/{edgeId}/{method}", method = RequestMethod.GET)
+ @RequestMapping(value = "/edge/instructions/install/{edgeId}/{method}", method = RequestMethod.GET)
@ResponseBody
- public EdgeInstallInstructions getEdgeDockerInstallInstructions(
+ public EdgeInstructions getEdgeInstallInstructions(
@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("edgeId") String strEdgeId,
- @ApiParam(value = "Installation method ('docker', 'ubuntu' or 'centos')")
+ @ApiParam(value = "Installation method ('docker', 'ubuntu' or 'centos')", allowableValues = "docker,ubuntu,centos")
@PathVariable("method") String installationMethod,
HttpServletRequest request) throws ThingsboardException {
if (isEdgesEnabled() && edgeInstallServiceOpt.isPresent()) {
@@ -574,4 +576,27 @@ public class EdgeController extends BaseController {
throw new ThingsboardException("Edges support disabled", ThingsboardErrorCode.GENERAL);
}
}
+
+ @ApiOperation(value = "Get Edge Upgrade Instructions (getEdgeUpgradeInstructions)",
+ notes = "Get a docker install instructions for provided edge id." + TENANT_AUTHORITY_PARAGRAPH,
+ produces = MediaType.APPLICATION_JSON_VALUE)
+ @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
+ @RequestMapping(value = "/edge/instructions/upgrade/{edgeId}/{edgeVersion}/{method}", method = RequestMethod.GET)
+ @ResponseBody
+ public EdgeInstructions getEdgeUpgradeInstructions(
+ @ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
+ @PathVariable("edgeId") String strEdgeId,
+ @ApiParam(value = "Edge version", required = true)
+ @PathVariable("edgeVersion") String edgeVersion,
+ @ApiParam(value = "Installation method ('docker', 'ubuntu' or 'centos')", allowableValues = "docker,ubuntu,centos")
+ @PathVariable("method") String method) throws Exception {
+ if (isEdgesEnabled() && edgeUpgradeServiceOpt.isPresent()) {
+ EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
+ edgeId = checkNotNull(edgeId);
+ Edge edge = checkEdgeId(edgeId, Operation.READ);
+ return checkNotNull(edgeUpgradeServiceOpt.get().getUpgradeInstructions(getTenantId(), edge, edgeVersion, method));
+ } else {
+ throw new ThingsboardException("Edges support disabled", ThingsboardErrorCode.GENERAL);
+ }
+ }
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java b/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java
index dd17f83317..24340f7a97 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java
@@ -21,7 +21,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.edge.Edge;
-import org.thingsboard.server.common.data.edge.EdgeInstallInstructions;
+import org.thingsboard.server.common.data.edge.EdgeInstructions;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.install.InstallScripts;
@@ -40,8 +40,8 @@ import java.nio.file.Paths;
public class DefaultEdgeInstallService implements EdgeInstallService {
private static final String EDGE_DIR = "edge";
-
- private static final String EDGE_INSTALL_INSTRUCTIONS_DIR = "install_instructions";
+ private static final String INSTRUCTIONS_DIR = "instructions";
+ private static final String INSTALL_DIR = "install";
private final InstallScripts installScripts;
@@ -55,7 +55,7 @@ public class DefaultEdgeInstallService implements EdgeInstallService {
private String appVersion;
@Override
- public EdgeInstallInstructions getInstallInstructions(TenantId tenantId, Edge edge, String installationMethod, HttpServletRequest request) {
+ public EdgeInstructions getInstallInstructions(TenantId tenantId, Edge edge, String installationMethod, HttpServletRequest request) {
switch (installationMethod.toLowerCase()) {
case "docker":
return getDockerInstallInstructions(edge, request);
@@ -68,7 +68,7 @@ public class DefaultEdgeInstallService implements EdgeInstallService {
}
}
- private EdgeInstallInstructions getDockerInstallInstructions(Edge edge, HttpServletRequest request) {
+ private EdgeInstructions getDockerInstallInstructions(Edge edge, HttpServletRequest request) {
String dockerInstallInstructions = readFile(resolveFile("docker", "instructions.md"));
String baseUrl = request.getServerName();
if (baseUrl.contains("localhost") || baseUrl.contains("127.0.0.1")) {
@@ -83,26 +83,26 @@ public class DefaultEdgeInstallService implements EdgeInstallService {
edgeVersion = edgeVersion.replace("-SNAPSHOT", "");
dockerInstallInstructions = dockerInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion);
dockerInstallInstructions = replacePlaceholders(dockerInstallInstructions, edge);
- return new EdgeInstallInstructions(dockerInstallInstructions);
+ return new EdgeInstructions(dockerInstallInstructions);
}
- private EdgeInstallInstructions getUbuntuInstallInstructions(Edge edge, HttpServletRequest request) {
+ private EdgeInstructions getUbuntuInstallInstructions(Edge edge, HttpServletRequest request) {
String ubuntuInstallInstructions = readFile(resolveFile("ubuntu", "instructions.md"));
ubuntuInstallInstructions = replacePlaceholders(ubuntuInstallInstructions, edge);
ubuntuInstallInstructions = ubuntuInstallInstructions.replace("${BASE_URL}", request.getServerName());
String edgeVersion = appVersion.replace("-SNAPSHOT", "");
ubuntuInstallInstructions = ubuntuInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion);
- return new EdgeInstallInstructions(ubuntuInstallInstructions);
+ return new EdgeInstructions(ubuntuInstallInstructions);
}
- private EdgeInstallInstructions getCentosInstallInstructions(Edge edge, HttpServletRequest request) {
+ private EdgeInstructions getCentosInstallInstructions(Edge edge, HttpServletRequest request) {
String centosInstallInstructions = readFile(resolveFile("centos", "instructions.md"));
centosInstallInstructions = replacePlaceholders(centosInstallInstructions, edge);
centosInstallInstructions = centosInstallInstructions.replace("${BASE_URL}", request.getServerName());
String edgeVersion = appVersion.replace("-SNAPSHOT", "");
centosInstallInstructions = centosInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion);
- return new EdgeInstallInstructions(centosInstallInstructions);
+ return new EdgeInstructions(centosInstallInstructions);
}
private String replacePlaceholders(String instructions, Edge edge) {
@@ -127,6 +127,6 @@ public class DefaultEdgeInstallService implements EdgeInstallService {
}
private Path getEdgeInstallInstructionsDir() {
- return Paths.get(installScripts.getDataDir(), InstallScripts.JSON_DIR, EDGE_DIR, EDGE_INSTALL_INSTRUCTIONS_DIR);
+ return Paths.get(installScripts.getDataDir(), InstallScripts.JSON_DIR, EDGE_DIR, INSTRUCTIONS_DIR, INSTALL_DIR);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeUpgradeService.java
new file mode 100644
index 0000000000..a1d737757d
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeUpgradeService.java
@@ -0,0 +1,190 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.edge.instructions;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Service;
+import org.thingsboard.server.common.data.DataConstants;
+import org.thingsboard.server.common.data.edge.Edge;
+import org.thingsboard.server.common.data.edge.EdgeInstructions;
+import org.thingsboard.server.common.data.id.EdgeId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.kv.AttributeKvEntry;
+import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
+import org.thingsboard.server.common.data.kv.StringDataEntry;
+import org.thingsboard.server.dao.attributes.AttributesService;
+import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.install.InstallScripts;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+
+@Service
+@Slf4j
+@RequiredArgsConstructor
+@ConditionalOnProperty(prefix = "edges", value = "enabled", havingValue = "true")
+@TbCoreComponent
+public class DefaultEdgeUpgradeService implements EdgeUpgradeService {
+
+ private static final HashMap upgradeVersionHashMap;
+
+ static {
+ upgradeVersionHashMap = new HashMap<>();
+ upgradeVersionHashMap.put("3.6.0", new UpgradeInfo(true, "3.6.1"));
+ upgradeVersionHashMap.put("3.6.1", new UpgradeInfo(true, "3.6.2"));
+ upgradeVersionHashMap.put("3.6.2", new UpgradeInfo(true, null));
+ }
+
+ private static final String EDGE_DIR = "edge";
+ private static final String INSTRUCTIONS_DIR = "instructions";
+ private static final String UPGRADE_DIR = "upgrade";
+
+ private final InstallScripts installScripts;
+ private final AttributesService attributesService;
+
+ @Value("${app.version:unknown}")
+ private String appVersion;
+
+ @Override
+ public EdgeInstructions getUpgradeInstructions(TenantId tenantId, Edge edge, String edgeVersion, String upgradeMethod) {
+ String tbVersion = appVersion.replace("-SNAPSHOT", "");
+ String currentEdgeVersion = convertEdgeVersionToDocsFormat(edgeVersion);
+ switch (upgradeMethod.toLowerCase()) {
+ case "docker":
+ return getDockerUpgradeInstructions(tenantId, edge.getId(), tbVersion, currentEdgeVersion);
+ case "ubuntu":
+ case "centos":
+ return getLinuxUpgradeInstructions(tenantId, edge.getId(), tbVersion, currentEdgeVersion, upgradeMethod.toLowerCase());
+ default:
+ throw new IllegalArgumentException("Unsupported upgrade method for Edge: " + upgradeMethod);
+ }
+ }
+
+ private EdgeInstructions getDockerUpgradeInstructions(TenantId tenantId, EdgeId edgeId, String tbVersion, String currentEdgeVersion) {
+ UpgradeInfo upgradeInfo = upgradeVersionHashMap.get(currentEdgeVersion);
+ if (upgradeInfo.getNextVersion() == null || tbVersion.equals(currentEdgeVersion)) {
+ return null;
+ }
+ boolean stoppedService = false;
+ StringBuilder result = new StringBuilder(readFile(resolveFile("docker", "upgrade_preparing.md")));
+ while (upgradeInfo.getNextVersion() != null || !tbVersion.equals(currentEdgeVersion)) {
+ String edgeVersion = upgradeInfo.getNextVersion();
+ String ubuntuUpgradeInstructions = readFile(resolveFile("docker", "instructions.md"));
+ if (upgradeInfo.isUpgradeDb()) {
+ String upgradeDb = readFile(resolveFile("docker", "upgrade_db.md"));
+ ubuntuUpgradeInstructions = ubuntuUpgradeInstructions.replace("${UPGRADE_DB}", upgradeDb);
+ }
+ if (!stoppedService) {
+ stoppedService = true;
+ String stopService = readFile(resolveFile("docker", "stop_service.md"));
+ ubuntuUpgradeInstructions = ubuntuUpgradeInstructions.replace("${STOP_SERVICE}", stopService);
+ } else {
+ ubuntuUpgradeInstructions = ubuntuUpgradeInstructions.replace("${STOP_SERVICE}", "");
+ }
+ ubuntuUpgradeInstructions = ubuntuUpgradeInstructions.replace("${TB_EDGE_VERSION}", edgeVersion + "EDGE");
+ ubuntuUpgradeInstructions = ubuntuUpgradeInstructions.replace("${CURRENT_TB_EDGE_VERSION}", currentEdgeVersion + "EDGE");
+ currentEdgeVersion = edgeVersion;
+ upgradeInfo = upgradeVersionHashMap.get(upgradeInfo.getNextVersion());
+ result.append(ubuntuUpgradeInstructions);
+ }
+ String startService = readFile(resolveFile("docker", "start_service.md"));
+ result.append(startService);
+ AttributeKvEntry attributeKvEntry = new BaseAttributeKvEntry(new StringDataEntry("edgeVersion", currentEdgeVersion), System.currentTimeMillis());
+ attributesService.save(tenantId, edgeId, DataConstants.SERVER_SCOPE, attributeKvEntry);
+ return new EdgeInstructions(result.toString());
+ }
+
+ private EdgeInstructions getLinuxUpgradeInstructions(TenantId tenantId, EdgeId edgeId, String tbVersion, String currentEdgeVersion, String os) {
+ UpgradeInfo upgradeInfo = upgradeVersionHashMap.get(currentEdgeVersion);
+ if (upgradeInfo.getNextVersion() == null || tbVersion.equals(currentEdgeVersion)) {
+ return null;
+ }
+ boolean stoppedService = false;
+ StringBuilder result = new StringBuilder(readFile(resolveFile("upgrade_preparing.md")));
+ while (upgradeInfo.getNextVersion() != null || !tbVersion.equals(currentEdgeVersion)) {
+ String edgeVersion = upgradeInfo.getNextVersion();
+ String ubuntuUpgradeInstructions = readFile(resolveFile(os, "instructions.md"));
+ if (upgradeInfo.isUpgradeDb()) {
+ String upgradeDb = readFile(resolveFile("upgrade_db.md"));
+ ubuntuUpgradeInstructions = ubuntuUpgradeInstructions.replace("${UPGRADE_DB}", upgradeDb);
+ }
+ if (!stoppedService) {
+ stoppedService = true;
+ String stopService = readFile(resolveFile("stop_service.md"));
+ ubuntuUpgradeInstructions = ubuntuUpgradeInstructions.replace("${STOP_SERVICE}", stopService);
+ } else {
+ ubuntuUpgradeInstructions = ubuntuUpgradeInstructions.replace("${STOP_SERVICE}", "");
+ }
+ ubuntuUpgradeInstructions = ubuntuUpgradeInstructions.replace("${TB_EDGE_TAG}", getTagVersion(edgeVersion));
+ ubuntuUpgradeInstructions = ubuntuUpgradeInstructions.replace("${CURRENT_TB_EDGE_TAG}", getTagVersion(currentEdgeVersion));
+ ubuntuUpgradeInstructions = ubuntuUpgradeInstructions.replace("${TB_EDGE_VERSION}", edgeVersion);
+ ubuntuUpgradeInstructions = ubuntuUpgradeInstructions.replace("${CURRENT_TB_EDGE_VERSION}", currentEdgeVersion);
+ ubuntuUpgradeInstructions = ubuntuUpgradeInstructions.replace("${TB_EDGE_VERSION_TITLE}", edgeVersion + "EDGE");
+ currentEdgeVersion = edgeVersion;
+ upgradeInfo = upgradeVersionHashMap.get(upgradeInfo.getNextVersion());
+ result.append(ubuntuUpgradeInstructions);
+ }
+ String startService = readFile(resolveFile("start_service.md"));
+ result.append(startService);
+ AttributeKvEntry attributeKvEntry = new BaseAttributeKvEntry(new StringDataEntry("edgeVersion", convertDocsFormatToEdgeVersion(currentEdgeVersion)), System.currentTimeMillis());
+ attributesService.save(tenantId, edgeId, DataConstants.SERVER_SCOPE, attributeKvEntry);
+ return new EdgeInstructions(result.toString());
+ }
+
+ private String getTagVersion(String version) {
+ return version.endsWith(".0") ? version.substring(0, version.length() - 2) : version;
+ }
+
+ private String convertEdgeVersionToDocsFormat(String edgeVersion) {
+ return edgeVersion.replace("_", ".").substring(2);
+ }
+
+ private String convertDocsFormatToEdgeVersion(String edgeVersion) {
+ return "V_" + edgeVersion.replace(".", "_");
+ }
+
+ private String readFile(Path file) {
+ try {
+ return Files.readString(file);
+ } catch (IOException e) {
+ log.warn("Failed to read file: {}", file, e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Path resolveFile(String subDir, String... subDirs) {
+ return getEdgeInstallInstructionsDir().resolve(Paths.get(subDir, subDirs));
+ }
+
+ private Path getEdgeInstallInstructionsDir() {
+ return Paths.get(installScripts.getDataDir(), InstallScripts.JSON_DIR, EDGE_DIR, INSTRUCTIONS_DIR, UPGRADE_DIR);
+ }
+
+ @AllArgsConstructor
+ @Data
+ public static class UpgradeInfo {
+ private boolean upgradeDb;
+ private String nextVersion;
+ }
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallService.java b/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallService.java
index 20cac25e33..cba8703920 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallService.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallService.java
@@ -16,12 +16,12 @@
package org.thingsboard.server.service.edge.instructions;
import org.thingsboard.server.common.data.edge.Edge;
-import org.thingsboard.server.common.data.edge.EdgeInstallInstructions;
+import org.thingsboard.server.common.data.edge.EdgeInstructions;
import org.thingsboard.server.common.data.id.TenantId;
import javax.servlet.http.HttpServletRequest;
public interface EdgeInstallService {
- EdgeInstallInstructions getInstallInstructions(TenantId tenantId, Edge edge, String installationMethod, HttpServletRequest request);
+ EdgeInstructions getInstallInstructions(TenantId tenantId, Edge edge, String installationMethod, HttpServletRequest request);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeUpgradeService.java
new file mode 100644
index 0000000000..0f4394ace9
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeUpgradeService.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright © 2016-2023 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.edge.instructions;
+
+import org.thingsboard.server.common.data.edge.Edge;
+import org.thingsboard.server.common.data.edge.EdgeInstructions;
+import org.thingsboard.server.common.data.id.TenantId;
+
+public interface EdgeUpgradeService {
+
+ EdgeInstructions getUpgradeInstructions(TenantId tenantId, Edge edge, String edgeVersion, String upgradeMethod) throws Exception;
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
index 7318b1eb24..32d648c045 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
@@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry;
+import org.thingsboard.server.common.data.kv.StringDataEntry;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.SortOrder;
@@ -774,7 +775,7 @@ public final class EdgeGrpcSession implements Closeable {
try {
if (edge.getSecret().equals(request.getEdgeSecret())) {
sessionOpenListener.accept(edge.getId(), this);
- this.edgeVersion = request.getEdgeVersion();
+ this.edgeVersion = processGetAndSaveEdgeVersion(request.getEdgeVersion());
return ConnectResponseMsg.newBuilder()
.setResponseCode(ConnectResponseCode.ACCEPTED)
.setErrorMsg("")
@@ -800,6 +801,12 @@ public final class EdgeGrpcSession implements Closeable {
.setConfiguration(EdgeConfiguration.getDefaultInstance()).build();
}
+ private EdgeVersion processGetAndSaveEdgeVersion(EdgeVersion edgeVersion) {
+ AttributeKvEntry attributeKvEntry = new BaseAttributeKvEntry(new StringDataEntry("edgeVersion", edgeVersion.name()), System.currentTimeMillis());
+ ctx.getAttributesService().save(this.tenantId, this.edge.getId(), DataConstants.SERVER_SCOPE, attributeKvEntry);
+ return edgeVersion;
+ }
+
@Override
public void close() {
log.debug("[{}][{}] Closing session", this.tenantId, sessionId);
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeInstallInstructions.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeInstructions.java
similarity index 90%
rename from common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeInstallInstructions.java
rename to common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeInstructions.java
index 8343058250..2c3a66c002 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeInstallInstructions.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeInstructions.java
@@ -25,8 +25,8 @@ import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
-public class EdgeInstallInstructions {
+public class EdgeInstructions {
- @ApiModelProperty(position = 1, value = "Markdown with install instructions")
- private String installInstructions;
+ @ApiModelProperty(position = 1, value = "Markdown with install/upgrade instructions")
+ private String instructions;
}
diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java
index fb878a33b6..d90a58fde8 100644
--- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java
+++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java
@@ -84,7 +84,7 @@ import org.thingsboard.server.common.data.device.DeviceSearchQuery;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeInfo;
-import org.thingsboard.server.common.data.edge.EdgeInstallInstructions;
+import org.thingsboard.server.common.data.edge.EdgeInstructions;
import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
import org.thingsboard.server.common.data.id.AlarmCommentId;
@@ -3241,9 +3241,9 @@ public class RestClient implements Closeable {
}).getBody();
}
- public Optional getEdgeDockerInstallInstructions(EdgeId edgeId) {
- ResponseEntity edgeInstallInstructionsResult =
- restTemplate.getForEntity(baseURL + "/api/edge/instructions/{edgeId}", EdgeInstallInstructions.class, edgeId.getId());
+ public Optional getEdgeDockerInstallInstructions(EdgeId edgeId, String method) {
+ ResponseEntity edgeInstallInstructionsResult =
+ restTemplate.getForEntity(baseURL + "/api/edge/instructions/install/{edgeId}/{method}", EdgeInstructions.class, edgeId.getId(), method);
return Optional.ofNullable(edgeInstallInstructionsResult.getBody());
}