Merge pull request #9665 from ShvaykaD/fix/version-update-for-nodes-with-valid-config

Force update of version for nodes with valid config and old configuration version
This commit is contained in:
Andrew Shvayka 2023-12-05 12:25:12 +02:00 committed by GitHub
commit 9128c7b7b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 101 additions and 21 deletions

View File

@ -19,7 +19,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNode;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration;
import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode;
@ -405,21 +404,16 @@ public class DefaultTbRuleChainService extends AbstractTbEntityService implement
if (fromVersion < toVersion) {
log.debug("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}",
ruleNodeId, ruleNodeType, fromVersion, toVersion);
try {
TbNodeUpgradeUtils.upgradeConfigurationAndVersion(node, ruleNodeClass);
log.debug("Successfully upgrade rule node with id: {} type: {}, rule chain id: {} fromVersion: {} toVersion: {}",
ruleNodeId, ruleNodeType, ruleChainId, fromVersion, toVersion);
} catch (TbNodeException e) {
log.warn("Failed to upgrade rule node with id: {} type: {} rule chain id: {} fromVersion: {} toVersion: {} due to: ",
ruleNodeId, ruleNodeType, ruleChainId, fromVersion, toVersion, e);
}
TbNodeUpgradeUtils.upgradeConfigurationAndVersion(node, ruleNodeClass);
log.debug("Successfully upgrade rule node with id: {} type: {}, rule chain id: {} fromVersion: {} toVersion: {}",
ruleNodeId, ruleNodeType, ruleChainId, fromVersion, toVersion);
} else {
log.debug("Rule node with id: {} type: {} ruleChainId: {} already set to latest version!",
ruleNodeId, ruleChainId, ruleNodeType);
}
}
} catch (Exception e) {
log.error("Failed to update the rule node with id: {} type: {}, rule chain id: {}",
log.error("Failed to upgrade rule node with id: {} type: {}, rule chain id: {}",
ruleNodeId, ruleNodeType, ruleChainId, e);
}
return node;

View File

@ -16,27 +16,60 @@
package org.thingsboard.server.utils;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.NodeConfiguration;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.common.data.util.TbPair;
import org.thingsboard.server.service.component.RuleNodeClassInfo;
@Slf4j
public class TbNodeUpgradeUtils {
public static void upgradeConfigurationAndVersion(RuleNode node, RuleNodeClassInfo nodeInfo) throws Exception {
public static void upgradeConfigurationAndVersion(RuleNode node, RuleNodeClassInfo nodeInfo) {
JsonNode oldConfiguration = node.getConfiguration();
int configurationVersion = node.getConfigurationVersion();
int currentVersion = nodeInfo.getCurrentVersion();
var configClass = nodeInfo.getAnnotation().configClazz();
if (oldConfiguration == null || !oldConfiguration.isObject()) {
var configClass = nodeInfo.getAnnotation().configClazz();
node.setConfiguration(JacksonUtil.valueToTree(configClass.getDeclaredConstructor().newInstance().defaultConfiguration()));
log.warn("Failed to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}. " +
"Current configuration is null or not a json object. " +
"Going to set default configuration ... ",
node.getId(), node.getType(), configurationVersion, currentVersion);
node.setConfiguration(getDefaultConfig(configClass));
} else {
var tbVersionedNode = (TbNode) nodeInfo.getClazz().getDeclaredConstructor().newInstance();
TbPair<Boolean, JsonNode> upgradeResult = tbVersionedNode.upgrade(node.getConfigurationVersion(), oldConfiguration);
if (upgradeResult.getFirst()) {
node.setConfiguration(upgradeResult.getSecond());
var tbVersionedNode = getTbVersionedNode(nodeInfo);
try {
TbPair<Boolean, JsonNode> upgradeResult = tbVersionedNode.upgrade(configurationVersion, oldConfiguration);
if (upgradeResult.getFirst()) {
node.setConfiguration(upgradeResult.getSecond());
}
} catch (Exception e) {
try {
JacksonUtil.treeToValue(oldConfiguration, configClass);
} catch (Exception ex) {
log.warn("Failed to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}. " +
"Going to set default configuration ... ",
node.getId(), node.getType(), configurationVersion, currentVersion, e);
node.setConfiguration(getDefaultConfig(configClass));
}
}
}
node.setConfigurationVersion(nodeInfo.getCurrentVersion());
node.setConfigurationVersion(currentVersion);
}
@SneakyThrows
private static TbNode getTbVersionedNode(RuleNodeClassInfo nodeInfo) {
return (TbNode) nodeInfo.getClazz().getDeclaredConstructor().newInstance();
}
@SneakyThrows
private static JsonNode getDefaultConfig(Class<? extends NodeConfiguration> configClass) {
return JacksonUtil.valueToTree(configClass.getDeclaredConstructor().newInstance().defaultConfiguration());
}
}

View File

@ -21,6 +21,8 @@ import org.junit.Test;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.metadata.TbGetAttributesNode;
import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration;
import org.thingsboard.rule.engine.metadata.TbGetCustomerAttributeNode;
import org.thingsboard.rule.engine.metadata.TbGetEntityDataNodeConfiguration;
import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.service.component.RuleNodeClassInfo;
@ -38,7 +40,7 @@ public class TbNodeUpgradeUtilsTest {
var annotation = mock(org.thingsboard.rule.engine.api.RuleNode.class);
var defaultConfig = JacksonUtil.valueToTree(nodeConfigClazz.getDeclaredConstructor().newInstance().defaultConfiguration());
when(nodeInfo.getClazz()).thenReturn((Class)TbGetAttributesNode.class);
when(nodeInfo.getClazz()).thenReturn((Class) TbGetAttributesNode.class);
when(nodeInfo.getCurrentVersion()).thenReturn(1);
when(nodeInfo.getAnnotation()).thenReturn(annotation);
when(annotation.configClazz()).thenReturn((Class) nodeConfigClazz);
@ -60,7 +62,7 @@ public class TbNodeUpgradeUtilsTest {
var annotation = mock(org.thingsboard.rule.engine.api.RuleNode.class);
var defaultConfig = JacksonUtil.valueToTree(nodeConfigClazz.getDeclaredConstructor().newInstance().defaultConfiguration());
when(nodeInfo.getClazz()).thenReturn((Class)TbGetAttributesNode.class);
when(nodeInfo.getClazz()).thenReturn((Class) TbGetAttributesNode.class);
when(nodeInfo.getCurrentVersion()).thenReturn(1);
when(nodeInfo.getAnnotation()).thenReturn(annotation);
when(annotation.configClazz()).thenReturn((Class) nodeConfigClazz);
@ -81,7 +83,7 @@ public class TbNodeUpgradeUtilsTest {
var annotation = mock(org.thingsboard.rule.engine.api.RuleNode.class);
var defaultConfig = JacksonUtil.valueToTree(nodeConfigClazz.getDeclaredConstructor().newInstance().defaultConfiguration());
when(nodeInfo.getClazz()).thenReturn((Class)TbGetAttributesNode.class);
when(nodeInfo.getClazz()).thenReturn((Class) TbGetAttributesNode.class);
when(nodeInfo.getCurrentVersion()).thenReturn(1);
when(nodeInfo.getAnnotation()).thenReturn(annotation);
when(annotation.configClazz()).thenReturn((Class) nodeConfigClazz);
@ -102,4 +104,55 @@ public class TbNodeUpgradeUtilsTest {
}
@Test
public void testUpgradeRuleNodeConfigurationWithNewConfigAndOldConfigVersion() throws Exception {
// GIVEN
var node = new RuleNode();
var nodeInfo = mock(RuleNodeClassInfo.class);
var nodeConfigClazz = TbGetEntityDataNodeConfiguration.class;
var annotation = mock(org.thingsboard.rule.engine.api.RuleNode.class);
var defaultConfig = JacksonUtil.valueToTree(nodeConfigClazz.getDeclaredConstructor().newInstance().defaultConfiguration());
when(nodeInfo.getClazz()).thenReturn((Class) TbGetCustomerAttributeNode.class);
when(nodeInfo.getCurrentVersion()).thenReturn(1);
when(nodeInfo.getAnnotation()).thenReturn(annotation);
when(annotation.configClazz()).thenReturn((Class) nodeConfigClazz);
String versionOneDefaultConfig = "{\"fetchTo\":\"METADATA\"," +
"\"dataMapping\":{\"alarmThreshold\":\"threshold\"}," +
"\"dataToFetch\":\"ATTRIBUTES\"}";
node.setConfiguration(JacksonUtil.toJsonNode(versionOneDefaultConfig));
// WHEN
TbNodeUpgradeUtils.upgradeConfigurationAndVersion(node, nodeInfo);
// THEN
Assertions.assertThat(node.getConfiguration()).isEqualTo(defaultConfig);
Assertions.assertThat(node.getConfigurationVersion()).isEqualTo(1);
}
@Test
public void testUpgradeRuleNodeConfigurationWithInvalidConfigAndOldConfigVersion() throws Exception {
// GIVEN
var node = new RuleNode();
var nodeInfo = mock(RuleNodeClassInfo.class);
var nodeConfigClazz = TbGetEntityDataNodeConfiguration.class;
var annotation = mock(org.thingsboard.rule.engine.api.RuleNode.class);
var defaultConfig = JacksonUtil.valueToTree(nodeConfigClazz.getDeclaredConstructor().newInstance().defaultConfiguration());
when(nodeInfo.getClazz()).thenReturn((Class) TbGetCustomerAttributeNode.class);
when(nodeInfo.getCurrentVersion()).thenReturn(1);
when(nodeInfo.getAnnotation()).thenReturn(annotation);
when(annotation.configClazz()).thenReturn((Class) nodeConfigClazz);
// missing telemetry field
String oldConfig = "{\"attrMapping\":{\"alarmThreshold\":\"threshold\"}}";;
node.setConfiguration(JacksonUtil.toJsonNode(oldConfig));
// WHEN
TbNodeUpgradeUtils.upgradeConfigurationAndVersion(node, nodeInfo);
// THEN
Assertions.assertThat(node.getConfiguration()).isEqualTo(defaultConfig);
Assertions.assertThat(node.getConfigurationVersion()).isEqualTo(1);
}
}