Remote Events migrated from Spring Bus to Spring Cloud Stream (#2563)

* Remote Events migrated from Spring Bus to Spring Cloud Stream

---------

Co-authored-by: vasilchev <vasil.ilchev@bosch.com>
This commit is contained in:
Vasil Ilchev
2025-07-30 16:58:00 +03:00
committed by GitHub
parent 10da0288d9
commit 4a8e60764f
49 changed files with 1147 additions and 461 deletions

View File

@@ -55,7 +55,14 @@ import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.MultiActionAssignServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.MultiActionCancelServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetAssignDistributionSetServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetDeletedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
@@ -73,8 +80,6 @@ import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.cloud.bus.ServiceMatcher;
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.data.domain.PageRequest;
import org.springframework.security.core.context.SecurityContext;
@@ -96,7 +101,6 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
private final SystemSecurityContext systemSecurityContext;
private final SystemManagement systemManagement;
private final TargetManagement targetManagement;
private final ServiceMatcher serviceMatcher;
private final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement;
private final DistributionSetManagement<? extends DistributionSet> distributionSetManagement;
private final DeploymentManagement deploymentManagement;
@@ -111,7 +115,6 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
* @param systemSecurityContext for execution with system permissions
* @param systemManagement the systemManagement
* @param targetManagement to access target information
* @param serviceMatcher to check in cluster case if the message is from the same cluster node
* @param distributionSetManagement to retrieve modules
* @param tenantConfigurationManagement to access tenant configuration
*/
@@ -120,7 +123,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
final RabbitTemplate rabbitTemplate,
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
final TargetManagement targetManagement, final ServiceMatcher serviceMatcher,
final TargetManagement targetManagement,
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement, final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
final DeploymentManagement deploymentManagement,
final TenantConfigurationManagement tenantConfigurationManagement) {
@@ -130,7 +133,6 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
this.systemSecurityContext = systemSecurityContext;
this.systemManagement = systemManagement;
this.targetManagement = targetManagement;
this.serviceMatcher = serviceMatcher;
this.softwareModuleManagement = softwareModuleManagement;
this.distributionSetManagement = distributionSetManagement;
this.deploymentManagement = deploymentManagement;
@@ -146,14 +148,11 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
/**
* Method to send a message to a RabbitMQ Exchange after the Distribution set has been assign to a Target.
*
* @param assignedEvent the object to be sent.
* @param targetAssignDistributionSetServiceEvent event to be processed
*/
@EventListener(classes = TargetAssignDistributionSetEvent.class)
protected void targetAssignDistributionSet(final TargetAssignDistributionSetEvent assignedEvent) {
if (shouldSkip(assignedEvent)) {
return;
}
@EventListener(classes = TargetAssignDistributionSetServiceEvent.class)
protected void targetAssignDistributionSet(final TargetAssignDistributionSetServiceEvent targetAssignDistributionSetServiceEvent) {
final TargetAssignDistributionSetEvent assignedEvent = targetAssignDistributionSetServiceEvent.getRemoteEvent();
final List<Target> filteredTargetList = getTargetsWithoutPendingCancellations(assignedEvent.getActions().keySet());
if (!filteredTargetList.isEmpty()) {
@@ -165,16 +164,25 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
/**
* Listener for Multi-Action events.
*
* @param multiActionEvent the Multi-Action event to be processed
* @param multiActionAssignServiceEvent the Multi-Action event to be processed
*/
@EventListener(classes = MultiActionEvent.class)
protected void onMultiAction(final MultiActionEvent multiActionEvent) {
if (shouldSkip(multiActionEvent)) {
return;
}
@EventListener(classes = MultiActionAssignServiceEvent.class)
protected void onMultiActionAssign(final MultiActionAssignServiceEvent multiActionAssignServiceEvent) {
final MultiActionAssignEvent multiActionAssignEvent = multiActionAssignServiceEvent.getRemoteEvent();
log.debug("MultiActionAssignEvent received for {}", multiActionAssignEvent.getControllerIds());
sendMultiActionRequestMessages(multiActionAssignEvent.getControllerIds());
}
log.debug("MultiActionEvent received for {}", multiActionEvent.getControllerIds());
sendMultiActionRequestMessages(multiActionEvent.getControllerIds());
/**
* Listener for Multi-Action events.
*
* @param multiActionCancelServiceEvent the Multi-Action event to be processed
*/
@EventListener(classes = MultiActionCancelServiceEvent.class)
protected void onMultiActionCancel(final MultiActionCancelServiceEvent multiActionCancelServiceEvent) {
final MultiActionCancelEvent multiActionCancelEvent = multiActionCancelServiceEvent.getRemoteEvent();
log.debug("MultiActionCancelEvent received for {}", multiActionCancelEvent.getControllerIds());
sendMultiActionRequestMessages(multiActionCancelEvent.getControllerIds());
}
protected void sendUpdateMessageToTarget(
@@ -198,14 +206,11 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
* Method to send a message to a RabbitMQ Exchange after the assignment of
* the Distribution set to a Target has been canceled.
*
* @param cancelEvent that is to be converted to a DMF message
* @param cancelTargetAssignmentServiceEvent that is to be converted to a DMF message
*/
@EventListener(classes = CancelTargetAssignmentEvent.class)
protected void targetCancelAssignmentToDistributionSet(final CancelTargetAssignmentEvent cancelEvent) {
if (shouldSkip(cancelEvent)) {
return;
}
@EventListener(classes = CancelTargetAssignmentServiceEvent.class)
protected void targetCancelAssignmentToDistributionSet(final CancelTargetAssignmentServiceEvent cancelTargetAssignmentServiceEvent) {
final CancelTargetAssignmentEvent cancelEvent = cancelTargetAssignmentServiceEvent.getRemoteEvent();
final List<Target> eventTargets = partitionedParallelExecution(
cancelEvent.getActions().keySet(), targetManagement::getByControllerID);
@@ -221,19 +226,17 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
/**
* Method to send a message to a RabbitMQ Exchange after a Target was deleted.
*
* @param deleteEvent the TargetDeletedEvent which holds the necessary data for sending a target delete message.
* @param serviceTargetDeleteEvent the TargetDeletedEvent which holds the necessary data for sending a target delete message.
*/
@EventListener(classes = TargetDeletedEvent.class)
protected void targetDelete(final TargetDeletedEvent deleteEvent) {
if (shouldSkip(deleteEvent)) {
return;
}
@EventListener(classes = TargetDeletedServiceEvent.class)
protected void targetDelete(final TargetDeletedServiceEvent serviceTargetDeleteEvent) {
final TargetDeletedEvent deleteEvent = serviceTargetDeleteEvent.getRemoteEvent();
sendDeleteMessage(deleteEvent.getTenant(), deleteEvent.getControllerId(), deleteEvent.getTargetAddress());
}
@EventListener(classes = TargetAttributesRequestedEvent.class)
protected void targetTriggerUpdateAttributes(final TargetAttributesRequestedEvent updateAttributesEvent) {
@EventListener(classes = TargetAttributesRequestedServiceEvent.class)
protected void targetTriggerUpdateAttributes(final TargetAttributesRequestedServiceEvent serviceTargetUpdateAttributesEvent) {
final TargetAttributesRequestedEvent updateAttributesEvent = serviceTargetUpdateAttributesEvent.getRemoteEvent();
sendUpdateAttributesMessageToTarget(
updateAttributesEvent.getTenant(), updateAttributesEvent.getControllerId(),
updateAttributesEvent.getTargetAddress());
@@ -252,10 +255,6 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
IpUtil.createAmqpUri(virtualHost, ping.getMessageProperties().getReplyTo()));
}
protected boolean shouldSkip(final RemoteApplicationEvent event) {
return !isFromSelf(event);
}
protected void sendCancelMessageToTarget(final String tenant, final String controllerId, final Long actionId, final URI address) {
if (!IpUtil.isAmqpUri(address)) {
return;
@@ -515,10 +514,6 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
return targetAddress == null || !IpUtil.isAmqpUri(URI.create(targetAddress));
}
private boolean isFromSelf(final RemoteApplicationEvent event) {
return serviceMatcher == null || serviceMatcher.isFromSelf(event);
}
private boolean hasPendingCancellations(final Long targetId) {
return deploymentManagement.hasPendingCancellations(targetId);
}

View File

@@ -45,13 +45,11 @@ import org.springframework.amqp.rabbit.listener.FatalExceptionStrategy;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.bus.ServiceMatcher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
@@ -73,8 +71,6 @@ public class DmfApiConfiguration {
private final AmqpDeadletterProperties amqpDeadletterProperties;
private final ConnectionFactory rabbitConnectionFactory;
private ServiceMatcher serviceMatcher;
public DmfApiConfiguration(
final AmqpProperties amqpProperties, final AmqpDeadletterProperties amqpDeadletterProperties,
final ConnectionFactory rabbitConnectionFactory) {
@@ -83,11 +79,6 @@ public class DmfApiConfiguration {
this.rabbitConnectionFactory = rabbitConnectionFactory;
}
@Autowired(required = false) // spring setter injection
public void setServiceMatcher(final ServiceMatcher serviceMatcher) {
this.serviceMatcher = serviceMatcher;
}
@Bean
public FatalExceptionStrategy sqlFatalSQLExceptionStrategy(final AmqpProperties amqpProperties) {
return new SqlFatalExceptionStrategy(amqpProperties.getFatalSqlExceptionPolicy());
@@ -281,7 +272,7 @@ public class DmfApiConfiguration {
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement, final DeploymentManagement deploymentManagement,
final TenantConfigurationManagement tenantConfigurationManagement) {
return new AmqpMessageDispatcherService(rabbitTemplate, amqpSenderService, artifactUrlHandler,
systemSecurityContext, systemManagement, targetManagement, serviceMatcher, softwareModuleManagement, distributionSetManagement,
systemSecurityContext, systemManagement, targetManagement, softwareModuleManagement, distributionSetManagement,
deploymentManagement, tenantConfigurationManagement);
}

View File

@@ -36,6 +36,10 @@ import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.event.remote.service.CancelTargetAssignmentServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetAssignDistributionSetServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetAttributesRequestedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.service.TargetDeletedServiceEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
@@ -69,8 +73,8 @@ import org.springframework.test.context.TestPropertySource;
@ActiveProfiles({ "test" })
@SpringBootTest(classes = { JpaRepositoryConfiguration.class }, webEnvironment = SpringBootTest.WebEnvironment.NONE)
@TestPropertySource(properties = {
"spring.main.allow-bean-definition-overriding=true",
"spring.cloud.bus.enabled=true" })
"org.eclipse.hawkbit.events.remote-enabled=false",
"spring.main.allow-bean-definition-overriding=true" })
class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
private static final String TENANT = "DEFAULT";
@@ -108,7 +112,7 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
when(systemManagement.getTenantMetadataWithoutDetails()).thenReturn(tenantMetaData);
amqpMessageDispatcherService = new AmqpMessageDispatcherService(rabbitTemplate, senderService,
artifactUrlHandlerMock, systemSecurityContext, systemManagement, targetManagement, serviceMatcher,
artifactUrlHandlerMock, systemSecurityContext, systemManagement, targetManagement,
softwareModuleManagement, distributionSetManagement, deploymentManagement, tenantConfigurationManagement);
}
@@ -131,7 +135,9 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
final Action action = createAction(createDistributionSet);
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(action);
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
final TargetAssignDistributionSetServiceEvent targetAssignDistributionSetServiceEvent =
new TargetAssignDistributionSetServiceEvent(targetAssignDistributionSetEvent);
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetServiceEvent);
final Message sendMessage = getCaptureAddressEvent(targetAssignDistributionSetEvent);
final DmfDownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage,
action.getId());
@@ -179,7 +185,8 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
Mockito.when(rabbitTemplate.convertSendAndReceive(any())).thenReturn(receivedList);
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(action);
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
final TargetAssignDistributionSetServiceEvent targetAssignDistributionSetServiceEvent = new TargetAssignDistributionSetServiceEvent(targetAssignDistributionSetEvent);
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetServiceEvent);
final Message sendMessage = getCaptureAddressEvent(targetAssignDistributionSetEvent);
final DmfDownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage,
action.getId());
@@ -219,8 +226,9 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
final String amqpUri = "amqp://anyhost";
final TargetAttributesRequestedEvent targetAttributesRequestedEvent = new TargetAttributesRequestedEvent(
TENANT,1L, Target.class, CONTROLLER_ID, amqpUri);
amqpMessageDispatcherService.targetTriggerUpdateAttributes(targetAttributesRequestedEvent);
final TargetAttributesRequestedServiceEvent targetAttributesRequestedServiceEvent =
new TargetAttributesRequestedServiceEvent(targetAttributesRequestedEvent);
amqpMessageDispatcherService.targetTriggerUpdateAttributes(targetAttributesRequestedServiceEvent);
final Message sendMessage = createArgumentCapture(URI.create(amqpUri));
assertUpdateAttributesMessage(sendMessage);
@@ -236,7 +244,9 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
when(action.getTenant()).thenReturn(TENANT);
when(action.getTarget()).thenReturn(testTarget);
final CancelTargetAssignmentEvent cancelTargetAssignmentDistributionSetEvent = new CancelTargetAssignmentEvent(action);
amqpMessageDispatcherService.targetCancelAssignmentToDistributionSet(cancelTargetAssignmentDistributionSetEvent);
final CancelTargetAssignmentServiceEvent serviceCancelTargetAssignmentDistributionSetEvent =
new CancelTargetAssignmentServiceEvent(cancelTargetAssignmentDistributionSetEvent);
amqpMessageDispatcherService.targetCancelAssignmentToDistributionSet(serviceCancelTargetAssignmentDistributionSetEvent);
final Message sendMessage = createArgumentCapture(AMQP_URI);
assertCancelMessage(sendMessage);
@@ -251,9 +261,10 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
// setup
final String amqpUri = "amqp://anyhost";
final TargetDeletedEvent targetDeletedEvent = new TargetDeletedEvent(TENANT, 1L, Target.class, CONTROLLER_ID, amqpUri);
final TargetDeletedServiceEvent targetDeletedServiceEvent = new TargetDeletedServiceEvent(targetDeletedEvent);
// test
amqpMessageDispatcherService.targetDelete(targetDeletedEvent);
amqpMessageDispatcherService.targetDelete(targetDeletedServiceEvent);
// verify
final Message sendMessage = createArgumentCapture(URI.create(amqpUri));
@@ -269,9 +280,10 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
// setup
final String noAmqpUri = "http://anyhost";
final TargetDeletedEvent targetDeletedEvent = new TargetDeletedEvent(TENANT, 1L, Target.class, CONTROLLER_ID, noAmqpUri);
final TargetDeletedServiceEvent targetDeletedServiceEvent = new TargetDeletedServiceEvent(targetDeletedEvent);
// test
amqpMessageDispatcherService.targetDelete(targetDeletedEvent);
amqpMessageDispatcherService.targetDelete(targetDeletedServiceEvent);
// verify
Mockito.verifyNoInteractions(senderService);
@@ -286,9 +298,10 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
// setup
final String noAmqpUri = null;
final TargetDeletedEvent targetDeletedEvent = new TargetDeletedEvent(TENANT, 1L, Target.class, CONTROLLER_ID, noAmqpUri);
final TargetDeletedServiceEvent targetDeletedServiceEvent = new TargetDeletedServiceEvent(targetDeletedEvent);
// test
amqpMessageDispatcherService.targetDelete(targetDeletedEvent);
amqpMessageDispatcherService.targetDelete(targetDeletedServiceEvent);
// verify
Mockito.verifyNoInteractions(senderService);

View File

@@ -128,7 +128,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@Test
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 2) })
void registerTargetWithName() {
final String controllerId = TARGET_PREFIX + "registerTargetWithName";
@@ -148,7 +148,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@Test
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = TargetPollEvent.class, count = 2) })
void registerTargetWithAttributes() {
final String controllerId = TARGET_PREFIX + "registerTargetWithAttributes";
@@ -171,7 +171,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@Test
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 3),
@Expect(type = TargetUpdatedEvent.class, count = 3),
@Expect(type = TargetPollEvent.class, count = 2) })
void registerTargetWithNameAndAttributes() {
final String controllerId = TARGET_PREFIX + "registerTargetWithAttributes";
@@ -404,14 +404,14 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 9), // implicit lock
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = TargetPollEvent.class, count = 1) })
void finishActionStatus() {
final String controllerId = TARGET_PREFIX + "finishActionStatus";
@@ -425,7 +425,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class),
@Expect(type = ActionUpdatedEvent.class),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@@ -445,7 +445,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class),
@Expect(type = ActionUpdatedEvent.class),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@@ -484,7 +484,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@@ -663,7 +663,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 3), // implicit lock
@Expect(type = CancelTargetAssignmentEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 2) })
void receiveCancelUpdateMessageAfterAssignmentWasCanceled() {
@@ -691,14 +691,14 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 9), // implicit lock
@Expect(type = CancelTargetAssignmentEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1),
@Expect(type = TargetPollEvent.class, count = 1) })
void actionNotExists() {
final String controllerId = TARGET_PREFIX + "actionNotExists";
@@ -738,7 +738,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = CancelTargetAssignmentEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 2),
@Expect(type = ActionUpdatedEvent.class, count = 2),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@@ -766,7 +766,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@Test
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 4),
@Expect(type = TargetUpdatedEvent.class, count = 4),
@Expect(type = TargetPollEvent.class, count = 1) })
void updateAttributesWithDifferentUpdateModes() {
final String controllerId = TARGET_PREFIX + "updateAttributes";
@@ -794,7 +794,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@Test
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class),
@Expect(type = TargetUpdatedEvent.class),
@Expect(type = TargetPollEvent.class, count = 1) })
void updateAttributesWithNoThingId() {
final String controllerId = TARGET_PREFIX + "updateAttributesWithNoThingId";
@@ -822,7 +822,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@Test
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class),
@Expect(type = TargetUpdatedEvent.class),
@Expect(type = TargetPollEvent.class, count = 1) })
void updateAttributesWithWrongBody() {
// setup
@@ -857,14 +857,14 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 1),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 9), // implicit lock
@Expect(type = TargetAttributesRequestedEvent.class, count = 1),
@Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 2),
@Expect(type = TargetPollEvent.class, count = 1) })
void downloadOnlyAssignmentFinishesActionWhenTargetReportsDownloaded() throws IOException {
// create target
@@ -893,14 +893,14 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class, count = 2),
@Expect(type = ActionUpdatedEvent.class, count = 2),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1), // implicit lock
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 9), // implicit lock
@Expect(type = TargetAttributesRequestedEvent.class, count = 2),
@Expect(type = TargetUpdatedEvent.class, count = 3),
@Expect(type = TargetUpdatedEvent.class, count = 3),
@Expect(type = TargetPollEvent.class, count = 1) })
void downloadOnlyAssignmentAllowsActionStatusUpdatesWhenTargetReportsFinishedAndUpdatesInstalledDS()
throws IOException {
@@ -1098,7 +1098,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
@ExpectEvents({
@Expect(type = TargetCreatedEvent.class, count = 1),
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
@Expect(type = ActionUpdatedEvent.class),
@Expect(type = ActionUpdatedEvent.class),
@Expect(type = ActionCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3),

View File

@@ -38,8 +38,8 @@ import org.springframework.test.context.TestPropertySource;
// Dirty context is necessary to create a new vhost and recreate all necessary beans after every test class.
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
@TestPropertySource(properties = {
"spring.main.allow-bean-definition-overriding=true",
"spring.cloud.bus.enabled=true" })
"org.eclipse.hawkbit.events.remote-enabled=false",
"spring.main.allow-bean-definition-overriding=true" })
@SuppressWarnings("java:S6813") // constructor injects are not possible for test classes
public abstract class AbstractAmqpIntegrationTest extends AbstractIntegrationTest {

View File

@@ -14,34 +14,6 @@ Or:
```bash
run org.eclipse.hawkbit.app.dmf.DMFStart
```
### Clustering (Experimental)
The micro-service instances are configured to communicate via Spring Cloud Bus. You could run multiple instances of any
micro-service but hawkbit-mgmt-server. Management server run some schedulers which shall not run simultaneously - e.g.
auto assignment checker and rollouts executor. To run multiple management server instances you shall do some extensions
of hawkbit to ensure that they wont run schedulers simultaneously or you shall configure all instances but one to do not
run schedulers!
## Optional Protostuff for Spring cloud bus
The micro-service instances are configured to communicate via Spring Cloud Bus. Optionally, you could
use [Protostuff](https://github.com/protostuff/protostuff) based message payload serialization for improved performance.
**Note**: If Protostuff is enabled it shall be enabled on all microservices!
Add/Uncomment to/in your `application.properties` :
```properties
spring.cloud.stream.bindings.springCloudBusInput.content-type=application/binary+protostuff
spring.cloud.stream.bindings.springCloudBusOutput.content-type=application/binary+protostuff
```
Add to your `pom.xml` :
```xml
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
</dependency>
```
# Clustering (Experimental!!!)
## Remote Events between micro-services
[See more information](../../site/content/guides/clustering.md)

View File

@@ -13,7 +13,6 @@ spring.application.name=dmf-server
spring.main.allow-bean-definition-overriding=true
# Logging configuration
logging.level.org.eclipse.hawkbit.eventbus.DeadEventListener=WARN
logging.level.org.springframework.boot.actuate.audit.listener.AuditListener=WARN
logging.level.org.hibernate.validator.internal.util.Version=WARN
# security Log with hints on potential attacks
@@ -35,12 +34,8 @@ hawkbit.lock=inMemory
# Disable discovery client of spring-cloud-commons
spring.cloud.discovery.enabled=false
# Configure communication between services
endpoints.spring.cloud.bus.refresh.enabled=false
endpoints.spring.cloud.bus.env.enabled=false
spring.cloud.stream.bindings.springCloudBusInput.group=dmf-server
# To use protostuff (for instance fot improved performance) you shall uncomment
# the following two lines and add io.protostuff:protostuff-core and io.protostuff:protostuff-runtime to dependencies
#spring.cloud.stream.bindings.springCloudBusInput.content-type=application/binary+protostuff
#spring.cloud.stream.bindings.springCloudBusOutput.content-type=application/binary+protostuff
# remote events configuration
spring.config.import=classpath:/hawkbit-events-defaults.properties
# Optional: Use protostuff (if enabled)
# spring.cloud.stream.default.content-type=application/binary+protostuff