Browse Source

Initial implementation of the ClusterVersionControlService

pull/6591/head
Andrii Shvaika 4 years ago
parent
commit
4472bd7f7c
  1. 2
      application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
  2. 2
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceProfileMsgConstructor.java
  3. 3
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
  4. 13
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java
  5. 3
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java
  6. 2
      application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java
  7. 63
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java
  8. 79
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java
  9. 5
      application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java
  10. 9
      application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java
  11. 1
      application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java
  12. 29
      application/src/main/java/org/thingsboard/server/service/sync/vc/VoidGitRequest.java
  13. 2
      application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java
  14. 2
      application/src/main/resources/thingsboard.yml
  15. 24
      common/cluster-api/src/main/proto/queue.proto
  16. 7
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntitiesVersionControlSettings.java
  17. 4
      common/queue/pom.xml
  18. 13
      common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java
  19. 2
      common/queue/src/main/java/org/thingsboard/server/queue/util/DataDecodingEncodingService.java
  20. 3
      common/queue/src/main/java/org/thingsboard/server/queue/util/ProtoWithFSTService.java
  21. 5
      common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/ProtoTransportEntityService.java
  22. 4
      common/transport/transport-api/pom.xml
  23. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportDeviceProfileCache.java
  24. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportResourceCache.java
  25. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java
  26. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportTenantProfileCache.java
  27. 12
      common/version-control/pom.xml
  28. 22
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/ClusterVersionControlService.java
  29. 219
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java
  30. 52
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlService.java
  31. 49
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/VersionControlRequestCtx.java

2
application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java

@ -48,7 +48,7 @@ import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.common.msg.tools.TbRateLimits;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.audit.AuditLogService;

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

@ -20,7 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent;

3
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java

@ -53,7 +53,7 @@ import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.FromDeviceRPCResponseProto;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
@ -140,6 +140,7 @@ public class DefaultTbClusterService implements TbClusterService {
TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_VC_EXECUTOR, tenantId, tenantId);
log.trace("PUSHING msg: {} to:{}", msg, tpi);
producerProvider.getTbVersionControlMsgProducer().send(tpi, new TbProtoQueueMsg<>(tenantId.getId(), msg), callback);
//TODO: ashvayka
toCoreMsgs.incrementAndGet();
}

13
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java

@ -36,7 +36,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
import org.thingsboard.server.common.stats.StatsFactory;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.DeviceStateServiceMsgProto;
@ -74,6 +74,8 @@ import org.thingsboard.server.service.state.DeviceStateService;
import org.thingsboard.server.service.subscription.SubscriptionManagerService;
import org.thingsboard.server.service.subscription.TbLocalSubscriptionService;
import org.thingsboard.server.service.subscription.TbSubscriptionUtils;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import org.thingsboard.server.service.sync.vc.GitVersionControlQueueService;
import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
import javax.annotation.PostConstruct;
@ -116,6 +118,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
private final TbCoreDeviceRpcService tbCoreDeviceRpcService;
private final EdgeNotificationService edgeNotificationService;
private final OtaPackageStateService firmwareStateService;
private final GitVersionControlQueueService vcQueueService;
private final TbCoreConsumerStats stats;
protected final TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> usageStatsConsumer;
private final TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> firmwareStatesConsumer;
@ -137,7 +140,9 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
TbTenantProfileCache tenantProfileCache,
TbApiUsageStateService apiUsageStateService,
EdgeNotificationService edgeNotificationService,
OtaPackageStateService firmwareStateService, PartitionService partitionService) {
OtaPackageStateService firmwareStateService,
GitVersionControlQueueService vcQueueService,
PartitionService partitionService) {
super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, apiUsageStateService, partitionService, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer());
this.mainConsumer = tbCoreQueueFactory.createToCoreMsgConsumer();
this.usageStatsConsumer = tbCoreQueueFactory.createToUsageStatsServiceMsgConsumer();
@ -150,6 +155,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
this.stats = new TbCoreConsumerStats(statsFactory);
this.statsService = statsService;
this.firmwareStateService = firmwareStateService;
this.vcQueueService = vcQueueService;
}
@PostConstruct
@ -322,6 +328,9 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
TransportProtos.QueueDeleteMsg queue = toCoreNotification.getQueueDeleteMsg();
partitionService.removeQueue(queue);
callback.onSuccess();
} else if (toCoreNotification.hasVcResponseMsg()) {
vcQueueService.processResponse(toCoreNotification.getVcResponseMsg());
callback.onSuccess();
}
if (statsEnabled) {
stats.log(toCoreNotification);

3
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java

@ -36,7 +36,7 @@ import org.thingsboard.server.common.msg.queue.TbMsgCallback;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
import org.thingsboard.server.common.stats.StatsFactory;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.gen.transport.TransportProtos;
@ -75,7 +75,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

2
application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java

@ -37,7 +37,7 @@ import org.thingsboard.server.queue.TbQueueConsumer;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.discovery.TbApplicationEventListener;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
import org.thingsboard.server.service.profile.TbDeviceProfileCache;

63
application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java

@ -36,30 +36,34 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.vc.*;
import org.thingsboard.server.common.data.sync.vc.request.load.EntityTypeVersionLoadConfig;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.sync.ie.EntitiesExportImportService;
import org.thingsboard.server.service.sync.ie.exporting.ExportableEntitiesService;
import org.thingsboard.server.common.data.sync.ThrowingRunnable;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.sync.ie.EntityExportSettings;
import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.common.data.sync.ie.EntityImportSettings;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.common.data.sync.vc.VersionControlAuthMethod;
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.common.data.sync.vc.VersionLoadResult;
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.common.data.sync.vc.request.create.ComplexVersionCreateRequest;
import org.thingsboard.server.common.data.sync.vc.request.create.SingleEntityVersionCreateRequest;
import org.thingsboard.server.common.data.sync.vc.request.create.SyncStrategy;
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateConfig;
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import org.thingsboard.server.common.data.sync.vc.request.load.EntityTypeVersionLoadConfig;
import org.thingsboard.server.common.data.sync.vc.request.load.EntityTypeVersionLoadRequest;
import org.thingsboard.server.common.data.sync.vc.request.load.SingleEntityVersionLoadRequest;
import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadConfig;
import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadRequest;
import org.thingsboard.server.common.data.sync.ThrowingRunnable;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.sync.ie.EntitiesExportImportService;
import org.thingsboard.server.service.sync.ie.exporting.ExportableEntitiesService;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@ -330,35 +334,34 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
} catch (Exception e) {
throw new RuntimeException("Failed to load version control settings!", e);
}
//TODO: ashvayka
// try {
// gitService.clearRepository(tenantId);
// gitService.initRepository(tenantId, savedVersionControlSettings);
// } catch (Exception e) {
// throw new RuntimeException("Failed to init repository!", e);
// }
try {
//TODO: ashvayka: replace future.get with deferred result. Don't forget to call when tenant is deleted.
gitServiceQueue.initRepository(tenantId, versionControlSettings).get();
} catch (Exception e) {
throw new RuntimeException("Failed to init repository!", e);
}
return savedVersionControlSettings;
}
@Override
public void deleteVersionControlSettings(TenantId tenantId) {
//TODO: ashvayka
// if (adminSettingsService.deleteAdminSettings(tenantId, SETTINGS_KEY)) {
// gitService.clearRepository(tenantId);
// }
public void deleteVersionControlSettings(TenantId tenantId) throws Exception {
if (adminSettingsService.deleteAdminSettings(tenantId, SETTINGS_KEY)) {
//TODO: ashvayka: replace future.get with deferred result. Don't forget to call when tenant is deleted.
gitServiceQueue.clearRepository(tenantId).get();
}
}
@Override
public void checkVersionControlAccess(TenantId tenantId, EntitiesVersionControlSettings settings) throws ThingsboardException {
EntitiesVersionControlSettings storedSettings = getVersionControlSettings(tenantId);
settings = this.restoreCredentials(settings, storedSettings);
//TODO: ashvayka
// try {
// gitService.testRepository(tenantId, settings);
// } catch (Exception e) {
// throw new ThingsboardException(String.format("Unable to access repository: %s", e.getMessage()),
// ThingsboardErrorCode.GENERAL);
// }
try {
//TODO: ashvayka: replace future.get with deferred result.
gitServiceQueue.testRepository(tenantId, settings).get();
} catch (Exception e) {
throw new ThingsboardException(String.format("Unable to access repository: %s", e.getMessage()),
ThingsboardErrorCode.GENERAL);
}
}
private EntitiesVersionControlSettings restoreCredentials(EntitiesVersionControlSettings settings, EntitiesVersionControlSettings storedSettings) {

79
application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java

@ -21,26 +21,30 @@ import com.fasterxml.jackson.databind.SerializationFeature;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.CommitRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.EntitiesContentRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.EntityContentRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.GenericRepositoryRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ListEntitiesRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ListVersionsRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.EntityContentRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.EntitiesContentRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.PrepareMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.VersionControlResponseMsg;
import org.thingsboard.server.queue.TbQueueCallback;
import org.thingsboard.server.queue.TbQueueMsgMetadata;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
@ -56,6 +60,7 @@ import java.util.function.Function;
@TbCoreComponent
@Service
@RequiredArgsConstructor
@Slf4j
public class DefaultGitVersionControlQueueService implements GitVersionControlQueueService {
private final ObjectWriter jsonWriter = new ObjectMapper().writer(SerializationFeature.INDENT_OUTPUT);
@ -188,15 +193,6 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
return request.getFuture();
}
private <T> void registerAndSend(PendingGitRequest<T> request, Function<ToVersionControlServiceMsg.Builder, ToVersionControlServiceMsg> enrichFunction, TbQueueCallback callback) {
if (!request.getFuture().isDone()) {
pendingRequestMap.putIfAbsent(request.getRequestId(), request);
clusterService.pushMsgToVersionControl(request.getTenantId(), enrichFunction.apply(newRequestProto(request)), callback);
} else {
throw new RuntimeException("Future is already done!");
}
}
@Override
public ListenableFuture<EntityExportData> getEntity(TenantId tenantId, String versionId, EntityId entityId) {
EntityContentGitRequest request = new EntityContentGitRequest(tenantId, versionId, entityId);
@ -218,6 +214,15 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
// }
}
private <T> void registerAndSend(PendingGitRequest<T> request, Function<ToVersionControlServiceMsg.Builder, ToVersionControlServiceMsg> enrichFunction, TbQueueCallback callback) {
if (!request.getFuture().isDone()) {
pendingRequestMap.putIfAbsent(request.getRequestId(), request);
clusterService.pushMsgToVersionControl(request.getTenantId(), enrichFunction.apply(newRequestProto(request)), callback);
} else {
throw new RuntimeException("Future is already done!");
}
}
@Override
public ListenableFuture<List<EntityExportData>> getEntities(TenantId tenantId, String versionId, EntityType entityType, int offset, int limit) {
EntitiesContentGitRequest request = new EntitiesContentGitRequest(tenantId, versionId, entityType);
@ -233,6 +238,56 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
return request.getFuture();
}
@Override
public ListenableFuture<Void> initRepository(TenantId tenantId, EntitiesVersionControlSettings settings) {
VoidGitRequest request = new VoidGitRequest(tenantId);
registerAndSend(request, builder -> builder.setInitRepositoryRequest(GenericRepositoryRequestMsg.newBuilder().build()).build()
, wrap(request.getFuture()));
return request.getFuture();
}
@Override
public ListenableFuture<Void> testRepository(TenantId tenantId, EntitiesVersionControlSettings settings) {
VoidGitRequest request = new VoidGitRequest(tenantId);
registerAndSend(request, builder -> builder.setTestRepositoryRequest(GenericRepositoryRequestMsg.newBuilder().build()).build()
, wrap(request.getFuture()));
return request.getFuture();
}
@Override
public ListenableFuture<Void> clearRepository(TenantId tenantId) {
VoidGitRequest request = new VoidGitRequest(tenantId);
registerAndSend(request, builder -> builder.setClearRepositoryRequest(GenericRepositoryRequestMsg.newBuilder().build()).build()
, wrap(request.getFuture()));
return request.getFuture();
}
@Override
public void processResponse(VersionControlResponseMsg vcResponseMsg) {
UUID requestId = new UUID(vcResponseMsg.getRequestIdMSB(), vcResponseMsg.getRequestIdLSB());
PendingGitRequest<?> request = pendingRequestMap.get(requestId);
if (request == null) {
log.debug("[{}] received stale response: {}", requestId, vcResponseMsg);
return;
} else {
log.debug("[{}] processing response: {}", requestId, vcResponseMsg);
}
var future = request.getFuture();
if (!StringUtils.isEmpty(vcResponseMsg.getError())) {
future.setException(new RuntimeException(vcResponseMsg.getError()));
} else {
if (vcResponseMsg.hasGenericResponse()) {
future.set(null);
}
}
}
private static <T> TbQueueCallback wrap(SettableFuture<T> future) {
return new TbQueueCallback() {
@Override

5
application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java

@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadReques
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import java.util.List;
import java.util.concurrent.ExecutionException;
public interface EntitiesVersionControlService {
@ -57,8 +58,8 @@ public interface EntitiesVersionControlService {
EntitiesVersionControlSettings saveVersionControlSettings(TenantId tenantId, EntitiesVersionControlSettings versionControlSettings);
void deleteVersionControlSettings(TenantId tenantId);
void deleteVersionControlSettings(TenantId tenantId) throws Exception;
void checkVersionControlAccess(TenantId tenantId, EntitiesVersionControlSettings settings) throws ThingsboardException;
void checkVersionControlAccess(TenantId tenantId, EntitiesVersionControlSettings settings) throws Exception;
}

9
application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java

@ -21,10 +21,12 @@ import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import org.thingsboard.server.gen.transport.TransportProtos.VersionControlResponseMsg;
import java.util.List;
@ -54,4 +56,11 @@ public interface GitVersionControlQueueService {
ListenableFuture<List<EntityExportData>> getEntities(TenantId tenantId, String versionId, EntityType entityType, int offset, int limit);
ListenableFuture<Void> initRepository(TenantId tenantId, EntitiesVersionControlSettings settings);
ListenableFuture<Void> testRepository(TenantId tenantId, EntitiesVersionControlSettings settings);
ListenableFuture<Void> clearRepository(TenantId tenantId);
void processResponse(VersionControlResponseMsg vcResponseMsg);
}

1
application/src/main/java/org/thingsboard/server/service/sync/vc/PendingGitRequest.java

@ -17,7 +17,6 @@ package org.thingsboard.server.service.sync.vc;
import com.google.common.util.concurrent.SettableFuture;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.thingsboard.server.common.data.id.TenantId;
import java.util.UUID;

29
application/src/main/java/org/thingsboard/server/service/sync/vc/VoidGitRequest.java

@ -0,0 +1,29 @@
/**
* Copyright © 2016-2022 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.sync.vc;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import java.util.List;
public class VoidGitRequest extends PendingGitRequest<Void> {
public VoidGitRequest(TenantId tenantId) {
super(tenantId);
}
}

2
application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java

@ -65,7 +65,7 @@ import org.thingsboard.server.common.msg.EncryptionUtil;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceProvisionService;
import org.thingsboard.server.dao.device.DeviceService;

2
application/src/main/resources/thingsboard.yml

@ -1024,6 +1024,8 @@ queue:
vc:
topic: "${TB_QUEUE_VC_TOPIC:tb_version_control}"
partitions: "${TB_QUEUE_VC_PARTITIONS:10}"
poll-interval: "${TB_QUEUE_VC_INTERVAL_MS:25}"
pack-processing-timeout: "${TB_QUEUE_VC_PACK_PROCESSING_TIMEOUT_MS:2000}"
js:
# JS Eval request topic
request_topic: "${REMOTE_JS_EVAL_REQUEST_TOPIC:js_eval.requests}"

24
common/cluster-api/src/main/proto/queue.proto

@ -745,24 +745,34 @@ message EntitiesContentRequestMsg {
int32 limit = 4;
}
message GenericRepositoryRequestMsg {}
message GenericRepositoryResponseMsg {}
message ToVersionControlServiceMsg {
string nodeId = 1;
int64 tenantIdMSB = 2;
int64 tenantIdLSB = 3;
int64 requestIdMSB = 4;
int64 requestIdLSB = 5;
CommitRequestMsg commitRequest = 6;
ListVersionsRequestMsg listVersionRequest = 7;
ListEntitiesRequestMsg listEntitiesRequest = 8;
ListBranchesRequestMsg listBranchesRequest = 9;
EntityContentRequestMsg entityContentRequest = 10;
EntitiesContentRequestMsg entitiesContentRequest = 11;
bytes vcSettings = 6;
GenericRepositoryRequestMsg initRepositoryRequest = 7;
GenericRepositoryRequestMsg testRepositoryRequest = 8;
GenericRepositoryRequestMsg clearRepositoryRequest = 9;
CommitRequestMsg commitRequest = 10;
ListVersionsRequestMsg listVersionRequest = 11;
ListEntitiesRequestMsg listEntitiesRequest = 12;
ListBranchesRequestMsg listBranchesRequest = 13;
EntityContentRequestMsg entityContentRequest = 14;
EntitiesContentRequestMsg entitiesContentRequest = 15;
}
message VersionControlResponseMsg {
int64 requestIdMSB = 1;
int64 requestIdLSB = 2;
CommitResponseMsg commitResponse = 3;
string error = 3;
GenericRepositoryResponseMsg genericResponse = 4;
CommitResponseMsg commitResponse = 5;
}
/**

7
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntitiesVersionControlSettings.java

@ -16,8 +16,13 @@
package org.thingsboard.server.common.data.sync.vc;
import lombok.Data;
import java.io.Serializable;
@Data
public class EntitiesVersionControlSettings {
public class EntitiesVersionControlSettings implements Serializable {
private static final long serialVersionUID = -3211552851889198721L;
private String repositoryUri;
private VersionControlAuthMethod authMethod;
private String username;

4
common/queue/pom.xml

@ -120,6 +120,10 @@
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
</dependency>
<dependency>
<groupId>de.ruedigermoeller</groupId>
<artifactId>fst</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>

13
common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java

@ -5,7 +5,7 @@
* 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
* 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,
@ -37,28 +37,32 @@ import org.thingsboard.server.queue.settings.TbQueueCoreSettings;
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings;
import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings;
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings;
import org.thingsboard.server.queue.settings.TbQueueVersionControlSettings;
@Slf4j
@Component
@ConditionalOnExpression("'${queue.type:null}'=='in-memory' && '${service.type:null}'=='monolith'")
public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory {
public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory, TbVersionControlQueueFactory {
private final NotificationsTopicService notificationsTopicService;
private final TbQueueCoreSettings coreSettings;
private final TbServiceInfoProvider serviceInfoProvider;
private final TbQueueRuleEngineSettings ruleEngineSettings;
private final TbQueueVersionControlSettings vcSettings;
private final TbQueueTransportApiSettings transportApiSettings;
private final TbQueueTransportNotificationSettings transportNotificationSettings;
private final InMemoryStorage storage;
public InMemoryMonolithQueueFactory(NotificationsTopicService notificationsTopicService, TbQueueCoreSettings coreSettings,
TbQueueRuleEngineSettings ruleEngineSettings,
TbQueueVersionControlSettings vcSettings,
TbServiceInfoProvider serviceInfoProvider,
TbQueueTransportApiSettings transportApiSettings,
TbQueueTransportNotificationSettings transportNotificationSettings,
InMemoryStorage storage) {
this.notificationsTopicService = notificationsTopicService;
this.coreSettings = coreSettings;
this.vcSettings = vcSettings;
this.serviceInfoProvider = serviceInfoProvider;
this.ruleEngineSettings = ruleEngineSettings;
this.transportApiSettings = transportApiSettings;
@ -91,6 +95,11 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE
return new InMemoryTbQueueProducer<>(storage, coreSettings.getTopic());
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToVersionControlServiceMsg>> createToVersionControlMsgConsumer() {
return new InMemoryTbQueueConsumer<>(storage, vcSettings.getTopic());
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToRuleEngineMsg>> createToRuleEngineMsgConsumer(Queue configuration) {
return new InMemoryTbQueueConsumer<>(storage, configuration.getTopic());

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/DataDecodingEncodingService.java → common/queue/src/main/java/org/thingsboard/server/queue/util/DataDecodingEncodingService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.transport.util;
package org.thingsboard.server.queue.util;
import java.util.Optional;

3
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/ProtoWithFSTService.java → common/queue/src/main/java/org/thingsboard/server/queue/util/ProtoWithFSTService.java

@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.transport.util;
package org.thingsboard.server.queue.util;
import lombok.extern.slf4j.Slf4j;
import org.nustaq.serialization.FSTConfiguration;
import org.springframework.stereotype.Service;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import java.util.Optional;

5
common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/ProtoTransportEntityService.java

@ -24,14 +24,11 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbSnmpTransportComponent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@TbSnmpTransportComponent
@Service

4
common/transport/transport-api/pom.xml

@ -64,10 +64,6 @@
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>de.ruedigermoeller</groupId>
<artifactId>fst</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportDeviceProfileCache.java

@ -25,7 +25,7 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.transport.TransportDeviceProfileCache;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbTransportComponent;

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportResourceCache.java

@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.transport.TransportResourceCache;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbTransportComponent;

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java

@ -69,7 +69,7 @@ import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGateway
import org.thingsboard.server.common.transport.auth.TransportDeviceInfo;
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.common.transport.limits.TransportRateLimitService;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.common.transport.util.JsonUtils;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportTenantProfileCache.java

@ -29,7 +29,7 @@ import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.TransportTenantProfileCache;
import org.thingsboard.server.common.transport.limits.TransportRateLimitService;
import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbTransportComponent;

12
common/version-control/pom.xml

@ -36,6 +36,14 @@
</properties>
<dependencies>
<dependency>
<groupId>org.thingsboard.common</groupId>
<artifactId>data</artifactId>
</dependency>
<dependency>
<groupId>org.thingsboard.common</groupId>
<artifactId>queue</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
@ -105,10 +113,6 @@
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.thingsboard.common</groupId>
<artifactId>data</artifactId>
</dependency>
</dependencies>
<distributionManagement>

22
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/ClusterVersionControlService.java

@ -0,0 +1,22 @@
/**
* Copyright © 2016-2022 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.sync.vc;
import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
import org.springframework.context.ApplicationListener;
public interface ClusterVersionControlService extends ApplicationListener<PartitionChangeEvent> {
}

219
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java

@ -0,0 +1,219 @@
/**
* Copyright © 2016-2022 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.sync.vc;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg;
import org.thingsboard.server.queue.TbQueueCallback;
import org.thingsboard.server.queue.TbQueueConsumer;
import org.thingsboard.server.queue.TbQueueMsgMetadata;
import org.thingsboard.server.queue.TbQueueProducer;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.discovery.NotificationsTopicService;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.TbApplicationEventListener;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
import org.thingsboard.server.queue.provider.TbVersionControlQueueFactory;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.TbVersionControlComponent;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Slf4j
@TbVersionControlComponent
@Service
@RequiredArgsConstructor
public class DefaultClusterVersionControlService extends TbApplicationEventListener<PartitionChangeEvent> implements ClusterVersionControlService {
private final TbServiceInfoProvider serviceInfoProvider;
private final TbVersionControlQueueFactory queueFactory;
private final DataDecodingEncodingService encodingService;
private final GitRepositoryService vcService;
private final NotificationsTopicService notificationsTopicService;
private volatile ExecutorService consumerExecutor;
private volatile TbQueueConsumer<TbProtoQueueMsg<ToVersionControlServiceMsg>> consumer;
private volatile TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> producer;
private volatile boolean stopped = false;
@Value("${queue.vc.poll-interval:25}")
private long pollDuration;
@Value("${queue.vc.pack-processing-timeout:60000}")
private long packProcessingTimeout;
@PostConstruct
public void init() {
consumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("vc-consumer"));
producer = queueFactory.createTbCoreNotificationsMsgProducer();
consumer = queueFactory.createToVersionControlMsgConsumer();
}
@PreDestroy
public void stop() {
stopped = true;
if (consumer != null) {
consumer.unsubscribe();
}
if (consumerExecutor != null) {
consumerExecutor.shutdownNow();
}
}
@Override
protected void onTbApplicationEvent(PartitionChangeEvent event) {
//TODO: cleanup repositories that we no longer manage in this node.
consumer.subscribe(event.getPartitions());
}
@EventListener(ApplicationReadyEvent.class)
@Order(value = 2)
public void onApplicationEvent(ApplicationReadyEvent event) {
consumerExecutor.execute(() -> consumerLoop(consumer));
}
void consumerLoop(TbQueueConsumer<TbProtoQueueMsg<ToVersionControlServiceMsg>> consumer) {
while (!stopped && !consumer.isStopped()) {
try {
List<TbProtoQueueMsg<ToVersionControlServiceMsg>> msgs = consumer.poll(pollDuration);
if (msgs.isEmpty()) {
continue;
}
for (TbProtoQueueMsg<ToVersionControlServiceMsg> msgWrapper : msgs) {
ToVersionControlServiceMsg msg = msgWrapper.getValue();
if (msg.hasClearRepositoryRequest()) {
handleClearRepositoryCommand(new VersionControlRequestCtx(msg, null));
} else {
VersionControlRequestCtx ctx = new VersionControlRequestCtx(msg, getEntitiesVersionControlSettings(msg));
if (msg.hasTestRepositoryRequest()) {
handleTestRepositoryCommand(ctx);
} else if (msg.hasInitRepositoryRequest()) {
handleInitRepositoryCommand(ctx);
}
}
}
// ConcurrentMap<UUID, TbProtoQueueMsg<ToIntegrationExecutorDownlinkMsg>> pendingMap = msgs.stream().collect(
// Collectors.toConcurrentMap(s -> UUID.randomUUID(), Function.identity()));
// CountDownLatch processingTimeoutLatch = new CountDownLatch(1);
// TbPackProcessingContext<TbProtoQueueMsg<ToIntegrationExecutorDownlinkMsg>> ctx = new TbPackProcessingContext<>(
// processingTimeoutLatch, pendingMap, new ConcurrentHashMap<>());
// pendingMap.forEach((id, msg) -> {
// log.trace("[{}] Creating downlink callback for message: {}", id, msg.getValue());
// TbCallback callback = new TbPackCallback<>(id, ctx);
// try {
// handleDownlink(id, msg, callback);
// } catch (Throwable e) {
// log.warn("[{}] Failed to process notification: {}", id, msg, e);
// callback.onFailure(e);
// }
// });
// if (!processingTimeoutLatch.await(processingTimeout, TimeUnit.MILLISECONDS)) {
// ctx.getAckMap().forEach((id, msg) -> log.warn("[{}] Timeout to process downlink: {}", id, msg.getValue()));
// ctx.getFailedMap().forEach((id, msg) -> log.warn("[{}] Failed to process downlink: {}", id, msg.getValue()));
// }
consumer.commit();
} catch (Exception e) {
if (!stopped) {
log.warn("Failed to obtain version control requests from queue.", e);
try {
Thread.sleep(pollDuration);
} catch (InterruptedException e2) {
log.trace("Failed to wait until the server has capacity to handle new version control messages", e2);
}
}
}
}
log.info("TB Version Control request consumer stopped.");
}
private void handleClearRepositoryCommand(VersionControlRequestCtx ctx) {
try {
vcService.clearRepository(ctx.getTenantId());
reply(ctx, Optional.empty());
} catch (Exception e) {
log.debug("[{}] Failed to connect to the repository: ", ctx, e);
reply(ctx, Optional.of(e));
}
}
private void handleInitRepositoryCommand(VersionControlRequestCtx ctx) {
try {
vcService.initRepository(ctx.getTenantId(), ctx.getSettings());
reply(ctx, Optional.empty());
} catch (Exception e) {
log.debug("[{}] Failed to connect to the repository: ", ctx, e);
reply(ctx, Optional.of(e));
}
}
private void handleTestRepositoryCommand(VersionControlRequestCtx ctx) {
try {
vcService.testRepository(ctx.getTenantId(), ctx.getSettings());
reply(ctx, Optional.empty());
} catch (Exception e) {
log.debug("[{}] Failed to connect to the repository: ", ctx, e);
reply(ctx, Optional.of(e));
}
}
private void reply(VersionControlRequestCtx ctx, Optional<Exception> e) {
TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, ctx.getNodeId());
TransportProtos.VersionControlResponseMsg.Builder builder = TransportProtos.VersionControlResponseMsg.newBuilder()
.setRequestIdMSB(ctx.getRequestId().getMostSignificantBits())
.setRequestIdLSB(ctx.getRequestId().getLeastSignificantBits());
if (e.isPresent()) {
builder.setError(e.get().getMessage());
} else {
builder.setGenericResponse(TransportProtos.GenericRepositoryResponseMsg.newBuilder().build());
}
ToCoreNotificationMsg msg = ToCoreNotificationMsg.newBuilder().setVcResponseMsg(builder).build();
log.trace("PUSHING msg: {} to: {}", msg, tpi);
producer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), msg), null);
}
private EntitiesVersionControlSettings getEntitiesVersionControlSettings(ToVersionControlServiceMsg msg) {
Optional<EntitiesVersionControlSettings> settingsOpt = encodingService.decode(msg.getVcSettings().toByteArray());
if (settingsOpt.isPresent()) {
return settingsOpt.get();
} else {
log.warn("Failed to parse VC settings: {}", msg.getVcSettings());
throw new RuntimeException("Failed to parse vc settings!");
}
}
}

52
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlService.java

@ -1,52 +0,0 @@
/**
* Copyright © 2016-2022 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.sync.vc;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import java.util.List;
public interface GitVersionControlService {
void testRepository(TenantId tenantId, EntitiesVersionControlSettings settings);
void initRepository(TenantId tenantId, EntitiesVersionControlSettings settings);
void clearRepository(TenantId tenantId);
List<EntityVersion> listVersions(TenantId tenantId, String branch);
List<EntityVersion> listVersions(TenantId tenantId, String branch, EntityType entityType);
List<EntityVersion> listVersions(TenantId tenantId, String branch, EntityId entityId);
List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType);
List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId);
List<String> listBranches(TenantId tenantId);
EntityExportData<?> getEntity(TenantId tenantId, String versionId, EntityId entityId);
List<EntityExportData<?>> getEntities(TenantId tenantId, String branch, String versionId, EntityType entityType, int offset, int limit);
}

49
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/VersionControlRequestCtx.java

@ -0,0 +1,49 @@
/**
* Copyright © 2016-2022 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.sync.vc;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.vc.EntitiesVersionControlSettings;
import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg;
import java.util.UUID;
@RequiredArgsConstructor
@Data
public class VersionControlRequestCtx {
private final String nodeId;
private final UUID requestId;
private final TenantId tenantId;
private final EntitiesVersionControlSettings settings;
public VersionControlRequestCtx(ToVersionControlServiceMsg msg, EntitiesVersionControlSettings settings) {
this.nodeId = msg.getNodeId();
this.requestId = new UUID(msg.getRequestIdMSB(), msg.getRequestIdLSB());
this.tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB()));
this.settings = settings;
}
@Override
public String toString() {
return "VersionControlRequestCtx{" +
"nodeId='" + nodeId + '\'' +
", requestId=" + requestId +
", tenantId=" + tenantId +
'}';
}
}
Loading…
Cancel
Save