20250828 cleanup (#2639)

* Cleanup

* Refactor artifact management
This commit is contained in:
Avgustin Marinov
2025-09-02 16:08:14 +03:00
committed by GitHub
parent 4f0a8893c7
commit 2a636328a0
305 changed files with 2253 additions and 4566 deletions

View File

@@ -29,6 +29,9 @@ import java.util.stream.StreamSupport;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.ListUtils;
import org.eclipse.hawkbit.artifact.urlresolver.ArtifactUrl;
import org.eclipse.hawkbit.artifact.urlresolver.ArtifactUrlResolver;
import org.eclipse.hawkbit.artifact.urlresolver.ArtifactUrlResolver.DownloadDescriptor;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
@@ -49,23 +52,18 @@ import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.artifact.urlhandler.ApiType;
import org.eclipse.hawkbit.repository.artifact.urlhandler.ArtifactUrl;
import org.eclipse.hawkbit.repository.artifact.urlhandler.ArtifactUrlHandler;
import org.eclipse.hawkbit.repository.artifact.urlhandler.URLPlaceholder;
import org.eclipse.hawkbit.repository.artifact.urlhandler.URLPlaceholder.SoftwareData;
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
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;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.ActionProperties;
import org.eclipse.hawkbit.repository.model.Artifact;
@@ -94,7 +92,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
private static final int MAX_PROCESSING_SIZE = 1000;
private final ArtifactUrlHandler artifactUrlHandler;
private final ArtifactUrlResolver artifactUrlHandler;
private final AmqpMessageSenderService amqpSenderService;
private final SystemSecurityContext systemSecurityContext;
private final SystemManagement systemManagement;
@@ -108,7 +106,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
@SuppressWarnings("java:S107")
protected AmqpMessageDispatcherService(
final RabbitTemplate rabbitTemplate,
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlResolver artifactUrlHandler,
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
final TargetManagement<? extends Target> targetManagement,
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement,
@@ -138,7 +136,7 @@ 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 targetAssignDistributionSetServiceEvent event to be processed
* @param targetAssignDistributionSetServiceEvent event to be processed
*/
@EventListener(classes = TargetAssignDistributionSetServiceEvent.class)
protected void targetAssignDistributionSet(final TargetAssignDistributionSetServiceEvent targetAssignDistributionSetServiceEvent) {
@@ -200,9 +198,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
@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);
final List<Target> eventTargets = partitionedParallelExecution(cancelEvent.getActions().keySet(), targetManagement::findByControllerId);
eventTargets.forEach(target ->
cancelEvent.getActionPropertiesForController(target.getControllerId())
.map(ActionProperties::getId)
@@ -400,7 +396,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
private List<Target> getTargetsWithoutPendingCancellations(final Set<String> controllerIds) {
return partitionedParallelExecution(controllerIds, partition ->
targetManagement.getByControllerId(partition).stream()
targetManagement.findByControllerId(partition).stream()
.filter(target -> {
if (hasPendingCancellations(target.getId())) {
log.debug("Target {} has pending cancellations. Will not send update message to it.",
@@ -450,7 +446,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
? Collections.emptyMap()
: softwareModuleManagement.findMetaDataBySoftwareModuleIdsAndTargetVisible(allSmIds);
targetManagement.getByControllerId(controllerIds).forEach(target ->
targetManagement.findByControllerId(controllerIds).forEach(target ->
sendMultiActionRequestToTarget(
target, controllerIdToActions.get(target.getControllerId()), module -> getSoftwareModuleMetadata.get(module.getId())));
}
@@ -558,14 +554,12 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
localArtifact.getSize(),
localArtifact.getLastModifiedAt(),
artifactUrlHandler
.getUrls(new URLPlaceholder(
tenantMetadata.getTenant(), tenantMetadata.getId(), target.getControllerId(), target.getId(),
new SoftwareData(
localArtifact.getSoftwareModule().getId(), localArtifact.getFilename(), localArtifact.getId(),
localArtifact.getSha1Hash())),
ApiType.DMF)
.getUrls(new DownloadDescriptor(
tenantMetadata.getTenant(), target.getControllerId(),
localArtifact.getSoftwareModule().getId(), localArtifact.getFilename(), localArtifact.getSha1Hash()),
ArtifactUrlResolver.ApiType.DMF)
.stream()
.collect(Collectors.toMap(ArtifactUrl::getProtocol, ArtifactUrl::getRef))
.collect(Collectors.toMap(ArtifactUrl::protocol, ArtifactUrl::ref))
);
}

View File

@@ -18,13 +18,13 @@ import java.util.regex.Pattern;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.artifact.urlhandler.ArtifactUrlHandler;
import org.eclipse.hawkbit.artifact.urlresolver.ArtifactUrlResolver;
import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings;
import org.eclipse.hawkbit.repository.ConfirmationManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
@@ -265,9 +265,10 @@ public class DmfApiConfiguration {
@ConditionalOnMissingBean(AmqpMessageDispatcherService.class)
AmqpMessageDispatcherService amqpMessageDispatcherService(
final RabbitTemplate rabbitTemplate,
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
final AmqpMessageSenderService amqpSenderService, final ArtifactUrlResolver artifactUrlHandler,
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
final TargetManagement<? extends Target> targetManagement, final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
final TargetManagement<? extends Target> targetManagement,
final DistributionSetManagement<? extends DistributionSet> distributionSetManagement,
final SoftwareModuleManagement<? extends SoftwareModule> softwareModuleManagement, final DeploymentManagement deploymentManagement,
final TenantConfigurationManagement tenantConfigurationManagement, final RepositoryProperties repositoryProperties) {
return new AmqpMessageDispatcherService(rabbitTemplate, amqpSenderService, artifactUrlHandler,

View File

@@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException;
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
import org.springframework.amqp.rabbit.listener.FatalExceptionStrategy;
@@ -53,7 +52,7 @@ class RequeueExceptionStrategy implements FatalExceptionStrategy {
// is invalid content, repository exception
ConstraintViolationException.class, InvalidTargetAttributeException.class,
// is invalid content, message exception
InvalidTargetAddressException.class, MessageHandlingException.class
MessageHandlingException.class
));
if (!ObjectUtils.isEmpty(fatalExceptionTypes)) {
// add explicitly configured fatal exception types

View File

@@ -15,7 +15,6 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
@@ -23,28 +22,27 @@ import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.TargetManagement.Create;
import org.eclipse.hawkbit.repository.artifact.ArtifactFilesystem;
import org.eclipse.hawkbit.repository.artifact.model.AbstractDbArtifact;
import org.eclipse.hawkbit.repository.artifact.model.DbArtifactHash;
import org.eclipse.hawkbit.repository.artifact.urlhandler.ArtifactUrl;
import org.eclipse.hawkbit.repository.artifact.urlhandler.ArtifactUrlHandler;
import org.eclipse.hawkbit.artifact.model.ArtifactHashes;
import org.eclipse.hawkbit.artifact.model.StoredArtifactInfo;
import org.eclipse.hawkbit.artifact.urlresolver.ArtifactUrl;
import org.eclipse.hawkbit.artifact.urlresolver.ArtifactUrlResolver;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.DmfActionRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfDownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.DmfSoftwareModule;
import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TargetManagement.Create;
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
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;
import org.eclipse.hawkbit.repository.jpa.JpaRepositoryConfiguration;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Artifact;
@@ -105,7 +103,7 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
senderService = Mockito.mock(DefaultAmqpMessageSenderService.class);
final ArtifactUrlHandler artifactUrlHandlerMock = Mockito.mock(ArtifactUrlHandler.class);
final ArtifactUrlResolver artifactUrlHandlerMock = Mockito.mock(ArtifactUrlResolver.class);
when(artifactUrlHandlerMock.getUrls(any(), any()))
.thenReturn(Collections.singletonList(new ArtifactUrl("http", "download", "http://mockurl")));
@@ -178,24 +176,25 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
void testSendDownloadRequest() {
DistributionSet dsA = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
SoftwareModule module = dsA.getModules().iterator().next();
final List<AbstractDbArtifact> receivedList = new ArrayList<>();
final List<StoredArtifactInfo> receivedList = new ArrayList<>();
for (final Artifact artifact : testdataFactory.createArtifacts(module.getId())) {
receivedList.add(new ArtifactFilesystem(new File("./test"), artifact.getSha1Hash(),
new DbArtifactHash(artifact.getSha1Hash(), null, null), artifact.getSize(), null));
receivedList.add(new StoredArtifactInfo(
null, artifact.getSize(),
new ArtifactHashes(artifact.getSha1Hash(), artifact.getMd5Hash(), artifact.getSha256Hash())));
}
module = softwareModuleManagement.find(module.getId()).get();
dsA = distributionSetManagement.find(dsA.getId()).get();
module = softwareModuleManagement.get(module.getId());
dsA = distributionSetManagement.get(dsA.getId());
final Action action = createAction(dsA);
Mockito.when(rabbitTemplate.convertSendAndReceive(any())).thenReturn(receivedList);
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(action);
final TargetAssignDistributionSetServiceEvent targetAssignDistributionSetServiceEvent = new TargetAssignDistributionSetServiceEvent(targetAssignDistributionSetEvent);
final TargetAssignDistributionSetServiceEvent targetAssignDistributionSetServiceEvent = new TargetAssignDistributionSetServiceEvent(
targetAssignDistributionSetEvent);
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetServiceEvent);
final Message sendMessage = getCaptureAddressEvent(targetAssignDistributionSetEvent);
final DmfDownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage,
action.getId());
final DmfDownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage, action.getId());
assertThat(downloadAndUpdateRequest.getSoftwareModules())
.as("DownloadAndUpdateRequest event should contains 3 software modules")
@@ -231,7 +230,7 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
void sendUpdateAttributesRequest() {
final String amqpUri = "amqp://anyhost";
final TargetAttributesRequestedEvent targetAttributesRequestedEvent = new TargetAttributesRequestedEvent(
TENANT,1L, Target.class, CONTROLLER_ID, amqpUri);
TENANT, 1L, Target.class, CONTROLLER_ID, amqpUri);
final TargetAttributesRequestedServiceEvent targetAttributesRequestedServiceEvent =
new TargetAttributesRequestedServiceEvent(targetAttributesRequestedEvent);
amqpMessageDispatcherService.targetTriggerUpdateAttributes(targetAttributesRequestedServiceEvent);
@@ -314,7 +313,7 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
}
private Message getCaptureAddressEvent(final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent) {
final Target target = targetManagement.getByControllerId(targetAssignDistributionSetEvent.getActions().keySet().iterator().next()).get();
final Target target = targetManagement.getByControllerId(targetAssignDistributionSetEvent.getActions().keySet().iterator().next());
return createArgumentCapture(IpUtil.addressToUri(target.getAddress()));
}

View File

@@ -188,7 +188,7 @@ abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpIntegratio
protected void assertDmfDownloadAndUpdateRequest(
final DmfDownloadAndUpdateRequest request, final Set<SoftwareModule> softwareModules, final String controllerId) {
assertSoftwareModules(softwareModules, request.getSoftwareModules());
final Target updatedTarget = waitUntilIsPresent(() -> targetManagement.getByControllerId(controllerId));
final Target updatedTarget = waitUntilIsPresent(() -> targetManagement.findByControllerId(controllerId));
assertThat(updatedTarget).isNotNull();
assertThat(updatedTarget.getSecurityToken()).isEqualTo(request.getTargetSecurityToken());
}
@@ -266,8 +266,9 @@ abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpIntegratio
protected void registerAndAssertTargetWithExistingTenant(final String controllerId, final String name,
final int existingTargetsAfterCreation, final TargetUpdateStatus expectedTargetStatus,
final String createdBy, final Map<String, String> attributes) {
registerAndAssertTargetWithExistingTenant(controllerId, name, existingTargetsAfterCreation,
expectedTargetStatus, createdBy, attributes, () -> targetManagement.getByControllerId(controllerId));
registerAndAssertTargetWithExistingTenant(
controllerId, name, existingTargetsAfterCreation, expectedTargetStatus, createdBy, attributes,
() -> targetManagement.findByControllerId(controllerId));
}
protected void registerSameTargetAndAssertBasedOnVersion(final String controllerId,
@@ -413,7 +414,7 @@ abstract class AbstractAmqpServiceIntegrationTest extends AbstractAmqpIntegratio
protected void assertConfirmRequest(final DmfConfirmRequest request, final Set<SoftwareModule> softwareModules, final String controllerId) {
assertSoftwareModules(softwareModules, request.getSoftwareModules());
final Target updatedTarget = waitUntilIsPresent(() -> targetManagement.getByControllerId(controllerId));
final Target updatedTarget = waitUntilIsPresent(() -> targetManagement.findByControllerId(controllerId));
assertThat(updatedTarget).isNotNull();
assertThat(updatedTarget.getSecurityToken()).isEqualTo(request.getTargetSecurityToken());
}

View File

@@ -787,9 +787,8 @@ class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpServiceInt
private void waitUntilTargetHasStatus(final String controllerId, final TargetUpdateStatus status) {
waitUntil(() -> {
final Optional<Target> findTargetByControllerID = targetManagement.getByControllerId(controllerId);
return findTargetByControllerID.isPresent()
&& status.equals(findTargetByControllerID.get().getUpdateStatus());
final Optional<Target> findTargetByControllerID = targetManagement.findByControllerId(controllerId);
return findTargetByControllerID.isPresent() && status.equals(findTargetByControllerID.get().getUpdateStatus());
});
}

View File

@@ -950,7 +950,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
amqpMessageHandlerService.setControllerManagement(mockedControllerManagement);
createAndSendThingCreated(controllerId);
verifyOneDeadLetterMessage();
assertThat(targetManagement.getByControllerId(controllerId)).isEmpty();
assertThat(targetManagement.findByControllerId(controllerId)).isEmpty();
}
} finally {
amqpMessageHandlerService.setControllerManagement(controllerManagement);