Browse Source

Merge pull request #9873 from AndriiLandiak/fix/edge-instructions

Edge - fix instructions upgrade
pull/9885/head
Andrew Shvayka 2 years ago
committed by GitHub
parent
commit
82fc774ead
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  2. 39
      application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeUpgradeInstructionsService.java
  3. 4
      application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeUpgradeInstructionsService.java
  4. 2
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
  5. 5
      application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java
  6. 38
      application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java
  7. 1
      common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java
  8. 4
      ui-ngx/src/app/core/http/edge.service.ts
  9. 34
      ui-ngx/src/app/modules/home/pages/edge/edge.component.ts

18
application/src/main/java/org/thingsboard/server/controller/EdgeController.java

@ -594,4 +594,22 @@ public class EdgeController extends BaseController {
throw new ThingsboardException("Edges support disabled", ThingsboardErrorCode.GENERAL);
}
}
@ApiOperation(value = "Is edge upgrade enabled (isEdgeUpgradeAvailable)",
notes = "Returns 'true' if upgrade available for connected edge, 'false' - otherwise.")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/upgrade/available", method = RequestMethod.GET)
@ResponseBody
public boolean isEdgeUpgradeAvailable(
@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("edgeId") String strEdgeId) throws Exception {
if (isEdgesEnabled() && edgeUpgradeServiceOpt.isPresent()) {
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
edgeId = checkNotNull(edgeId);
Edge edge = checkEdgeId(edgeId, Operation.READ);
return edgeUpgradeServiceOpt.get().isUpgradeAvailable(edge.getTenantId(), edge.getId());
} else {
throw new ThingsboardException("Edges support disabled", ThingsboardErrorCode.GENERAL);
}
}
}

39
application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeUpgradeInstructionsService.java

@ -21,8 +21,13 @@ 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.EdgeUpgradeInfo;
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.dao.attributes.AttributesService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.install.InstallScripts;
@ -32,6 +37,7 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@Service
@Slf4j
@ -47,6 +53,7 @@ public class DefaultEdgeUpgradeInstructionsService implements EdgeUpgradeInstruc
private static final String UPGRADE_DIR = "upgrade";
private final InstallScripts installScripts;
private final AttributesService attributesService;
@Value("${app.version:unknown}")
@Setter
@ -74,13 +81,41 @@ public class DefaultEdgeUpgradeInstructionsService implements EdgeUpgradeInstruc
}
}
@Override
public boolean isUpgradeAvailable(TenantId tenantId, EdgeId edgeId) throws Exception {
Optional<AttributeKvEntry> attributeKvEntryOpt = attributesService.find(tenantId, edgeId, DataConstants.SERVER_SCOPE, DataConstants.EDGE_VERSION_ATTR_KEY).get();
if (attributeKvEntryOpt.isPresent()) {
String edgeVersionFormatted = convertEdgeVersionToDocsFormat(attributeKvEntryOpt.get().getValueAsString());
return isVersionGreaterOrEqualsThan(edgeVersionFormatted, "3.6.0") && !isVersionGreaterOrEqualsThan(edgeVersionFormatted, appVersion);
}
return false;
}
private boolean isVersionGreaterOrEqualsThan(String version1, String version2) {
String[] v1 = version1.split("\\.");
String[] v2 = version2.split("\\.");
int length = Math.max(v1.length, v2.length);
for (int i = 0; i < length; i++) {
int num1 = i < v1.length ? Integer.parseInt(v1[i]) : 0;
int num2 = i < v2.length ? Integer.parseInt(v2[i]) : 0;
if (num1 < num2) {
return false;
} else if (num1 > num2) {
return true;
}
}
return true;
}
private EdgeInstructions getDockerUpgradeInstructions(String tbVersion, String currentEdgeVersion) {
EdgeUpgradeInfo edgeUpgradeInfo = upgradeVersionHashMap.get(currentEdgeVersion);
if (edgeUpgradeInfo == null || edgeUpgradeInfo.getNextEdgeVersion() == null || tbVersion.equals(currentEdgeVersion)) {
return new EdgeInstructions("Edge upgrade instruction for " + currentEdgeVersion + "EDGE is not available.");
}
StringBuilder result = new StringBuilder(readFile(resolveFile("docker", "upgrade_preparing.md")));
while (edgeUpgradeInfo.getNextEdgeVersion() != null || !tbVersion.equals(currentEdgeVersion)) {
while (edgeUpgradeInfo.getNextEdgeVersion() != null && !tbVersion.equals(currentEdgeVersion)) {
String edgeVersion = edgeUpgradeInfo.getNextEdgeVersion();
String dockerUpgradeInstructions = readFile(resolveFile("docker", "instructions.md"));
if (edgeUpgradeInfo.isRequiresUpdateDb()) {
@ -109,7 +144,7 @@ public class DefaultEdgeUpgradeInstructionsService implements EdgeUpgradeInstruc
String upgrade_preparing = readFile(resolveFile("upgrade_preparing.md"));
upgrade_preparing = upgrade_preparing.replace("${OS}", os.equals("centos") ? "RHEL/CentOS 7/8" : "Ubuntu");
StringBuilder result = new StringBuilder(upgrade_preparing);
while (edgeUpgradeInfo.getNextEdgeVersion() != null || !tbVersion.equals(currentEdgeVersion)) {
while (edgeUpgradeInfo.getNextEdgeVersion() != null && !tbVersion.equals(currentEdgeVersion)) {
String edgeVersion = edgeUpgradeInfo.getNextEdgeVersion();
String linuxUpgradeInstructions = readFile(resolveFile(os, "instructions.md"));
if (edgeUpgradeInfo.isRequiresUpdateDb()) {

4
application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeUpgradeInstructionsService.java

@ -17,6 +17,8 @@ package org.thingsboard.server.service.edge.instructions;
import org.thingsboard.server.common.data.EdgeUpgradeInfo;
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 java.util.Map;
@ -27,4 +29,6 @@ public interface EdgeUpgradeInstructionsService {
void updateInstructionMap(Map<String, EdgeUpgradeInfo> upgradeVersions);
void setAppVersion(String version);
boolean isUpgradeAvailable(TenantId tenantId, EdgeId edgeId) throws Exception;
}

2
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java

@ -822,7 +822,7 @@ public final class EdgeGrpcSession implements Closeable {
}
private void processSaveEdgeVersionAsAttribute(String edgeVersion) {
AttributeKvEntry attributeKvEntry = new BaseAttributeKvEntry(new StringDataEntry("edgeVersion", edgeVersion), System.currentTimeMillis());
AttributeKvEntry attributeKvEntry = new BaseAttributeKvEntry(new StringDataEntry(DataConstants.EDGE_VERSION_ATTR_KEY, edgeVersion), System.currentTimeMillis());
ctx.getAttributesService().save(this.tenantId, this.edge.getId(), DataConstants.SERVER_SCOPE, attributeKvEntry);
}

5
application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java

@ -41,7 +41,6 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@ -81,8 +80,6 @@ public class DefaultUpdateService implements UpdateService {
private final RestTemplate restClient = new RestTemplate();
private UpdateMessage updateMessage;
private EdgeUpgradeMessage edgeUpgradeMessage;
private String edgeInstallVersion;
private String platform;
private String version;
@ -94,7 +91,6 @@ public class DefaultUpdateService implements UpdateService {
updateMessage = new UpdateMessage(false, version, "", "",
"https://thingsboard.io/docs/reference/releases",
"https://thingsboard.io/docs/reference/releases");
edgeUpgradeMessage = new EdgeUpgradeMessage(new HashMap<>());
if (updatesEnabled) {
try {
platform = System.getProperty("platform", "unknown");
@ -173,5 +169,4 @@ public class DefaultUpdateService implements UpdateService {
public UpdateMessage checkUpdates() {
return updateMessage;
}
}

38
application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java

@ -44,11 +44,11 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EdgeUpgradeInfo;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.EdgeUpgradeInfo;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetProfile;
@ -1200,4 +1200,40 @@ public class EdgeControllerTest extends AbstractControllerTest {
Assert.assertTrue(upgradeInstructions.contains("Upgrading to 3.6.1EDGE"));
Assert.assertTrue(upgradeInstructions.contains("Upgrading to 3.6.2EDGE"));
}
@Test
public void testIsEdgeUpgradeAvailable() throws Exception {
Edge edge = constructEdge("Edge Upgrade Available", "default");
Edge savedEdge = doPost("/api/edge", edge, Edge.class);
// Test 3.5.0 Edge - upgrade not available
String body = "{\"edgeVersion\": \"V_3_5_0\"}";
doPostAsync("/api/plugins/telemetry/EDGE/" + savedEdge.getId().getId() + "/attributes/SERVER_SCOPE", body, String.class, status().isOk());
edgeUpgradeInstructionsService.setAppVersion("3.6.0");
Assert.assertFalse(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId()));
edgeUpgradeInstructionsService.setAppVersion("3.6.2");
Assert.assertFalse(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId()));
edgeUpgradeInstructionsService.setAppVersion("3.6.2.7");
Assert.assertFalse(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId()));
// Test 3.6.0 Edge - upgrade available
body = "{\"edgeVersion\": \"V_3_6_0\"}";
doPostAsync("/api/plugins/telemetry/EDGE/" + savedEdge.getId().getId() + "/attributes/SERVER_SCOPE", body, String.class, status().isOk());
edgeUpgradeInstructionsService.setAppVersion("3.6.0");
Assert.assertFalse(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId()));
edgeUpgradeInstructionsService.setAppVersion("3.6.1.5");
Assert.assertTrue(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId()));
edgeUpgradeInstructionsService.setAppVersion("3.6.2");
Assert.assertTrue(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId()));
// Test 3.6.1 Edge - upgrade available
body = "{\"edgeVersion\": \"V_3_6_1\"}";
doPostAsync("/api/plugins/telemetry/EDGE/" + savedEdge.getId().getId() + "/attributes/SERVER_SCOPE", body, String.class, status().isOk());
edgeUpgradeInstructionsService.setAppVersion("3.6.1");
Assert.assertFalse(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId()));
edgeUpgradeInstructionsService.setAppVersion("3.6.2");
Assert.assertTrue(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId()));
edgeUpgradeInstructionsService.setAppVersion("3.6.2.6");
Assert.assertTrue(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId()));
}
}

1
common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java

@ -124,6 +124,7 @@ public class DataConstants {
public static final String PASSWORD = "password";
public static final String EDGE_MSG_SOURCE = "edge";
public static final String MSG_SOURCE_KEY = "source";
public static final String EDGE_VERSION_ATTR_KEY = "edgeVersion";
public static final String LAST_CONNECTED_GATEWAY = "lastConnectedGateway";

4
ui-ngx/src/app/core/http/edge.service.ts

@ -121,4 +121,8 @@ export class EdgeService {
public getEdgeUpgradeInstructions(edgeVersion: string, method: string = 'ubuntu', config?: RequestConfig): Observable<EdgeInstructions> {
return this.http.get<EdgeInstructions>(`/api/edge/instructions/upgrade/${edgeVersion}/${method}`, defaultHttpOptionsFromConfig(config));
}
public isEdgeUpgradeAvailable(edgeId: string, config?: RequestConfig): Observable<boolean> {
return this.http.get<boolean>(`/api/edge/${edgeId}/upgrade/available`, defaultHttpOptionsFromConfig(config));
}
}

34
ui-ngx/src/app/modules/home/pages/edge/edge.component.ts

@ -20,15 +20,13 @@ import { AppState } from '@core/core.state';
import { EntityComponent } from '@home/components/entity/entity.component';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { EntityType } from '@shared/models/entity-type.models';
import { EdgeInfo, edgeVersionAttributeKey } from '@shared/models/edge.models';
import { EdgeInfo } from '@shared/models/edge.models';
import { TranslateService } from '@ngx-translate/core';
import { NULL_UUID } from '@shared/models/id/has-uuid';
import { ActionNotificationShow } from '@core/notification/notification.actions';
import { generateSecret, guid } from '@core/utils';
import { EntityTableConfig } from '@home/models/entity/entities-table-config.models';
import { environment as env } from '@env/environment';
import { AttributeService } from '@core/http/attribute.service';
import { AttributeScope } from '@shared/models/telemetry/telemetry.models';
import {EdgeService} from "@core/http/edge.service";
@Component({
selector: 'tb-edge',
@ -44,7 +42,7 @@ export class EdgeComponent extends EntityComponent<EdgeInfo> {
constructor(protected store: Store<AppState>,
protected translate: TranslateService,
private attributeService: AttributeService,
private edgeService: EdgeService,
@Inject('entity') protected entityValue: EdgeInfo,
@Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<EdgeInfo>,
public fb: UntypedFormBuilder,
@ -100,7 +98,10 @@ export class EdgeComponent extends EntityComponent<EdgeInfo> {
}
});
this.generateRoutingKeyAndSecret(entity, this.entityForm);
this.checkEdgeVersion();
this.edgeService.isEdgeUpgradeAvailable(this.entity.id.id)
.subscribe(isUpgradeAvailable => {
this.upgradeAvailable = isUpgradeAvailable;
});
}
updateFormState() {
@ -139,25 +140,4 @@ export class EdgeComponent extends EntityComponent<EdgeInfo> {
form.get('secret').patchValue(generateSecret(20), {emitEvent: false});
}
}
checkEdgeVersion() {
this.attributeService.getEntityAttributes(this.entity.id, AttributeScope.SERVER_SCOPE, [edgeVersionAttributeKey])
.subscribe(attributes => {
if (attributes?.length) {
const edgeVersion = attributes[0].value;
const tbVersion = 'V_' + env.tbVersion.replaceAll('.', '_');
this.upgradeAvailable = this.versionUpgradeSupported(edgeVersion) && (edgeVersion !== tbVersion);
} else {
this.upgradeAvailable = false;
}
}
);
}
private versionUpgradeSupported(edgeVersion: string): boolean {
const edgeVersionArray = edgeVersion.split('_');
const major = parseInt(edgeVersionArray[1]);
const minor = parseInt(edgeVersionArray[2]);
return major >= 3 && minor >= 6;
}
}

Loading…
Cancel
Save