Optional support for autoclose of deprecated actions (#585)
* Introduce action autoclose into repository. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Extended test. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Fix typo. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Added checkbox to management ui. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Fix Ui allignment. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Fix item ID. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * Fix sonar issues. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com> * readibility. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
@@ -92,7 +92,19 @@ public abstract class AbstractDsAssignmentStrategy {
|
||||
* to cancel actions for
|
||||
* @return {@link Set} of {@link Target#getId()}s
|
||||
*/
|
||||
abstract Set<Long> findTargetIdsToCancel(List<List<Long>> targetIds);
|
||||
abstract Set<Long> cancelActiveActions(List<List<Long>> targetIds);
|
||||
|
||||
/**
|
||||
* Cancels actions that can be canceled (i.e.
|
||||
* {@link DistributionSet#isRequiredMigrationStep() is <code>false</code>})
|
||||
* as a result of the new assignment and returns all {@link Target}s where
|
||||
* such actions existed.
|
||||
*
|
||||
* @param targetIds
|
||||
* to cancel actions for
|
||||
* @return {@link Set} of {@link Target#getId()}s
|
||||
*/
|
||||
abstract void closeActiveActions(List<List<Long>> targetIds);
|
||||
|
||||
/**
|
||||
* Handles event sending related to the assignment.
|
||||
@@ -119,7 +131,7 @@ public abstract class AbstractDsAssignmentStrategy {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes {@link Action}s that are no longer necessary and sends
|
||||
* Cancels {@link Action}s that are no longer necessary and sends
|
||||
* cancellations to the controller.
|
||||
*
|
||||
* @param targetsIds
|
||||
@@ -130,8 +142,8 @@ public abstract class AbstractDsAssignmentStrategy {
|
||||
// Figure out if there are potential target/action combinations that
|
||||
// need to be considered for cancellation
|
||||
final List<JpaAction> activeActions = actionRepository
|
||||
.findByActiveAndTargetIdInAndActionStatusNotEqualToAndDistributionSetRequiredMigrationStep(targetsIds,
|
||||
Action.Status.CANCELING);
|
||||
.findByActiveAndTargetIdInAndActionStatusNotEqualToAndDistributionSetNotRequiredMigrationStep(
|
||||
targetsIds, Action.Status.CANCELING);
|
||||
|
||||
return activeActions.stream().map(action -> {
|
||||
action.setStatus(Status.CANCELING);
|
||||
@@ -148,6 +160,34 @@ public abstract class AbstractDsAssignmentStrategy {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes {@link Action}s that are no longer necessary without sending a
|
||||
* hint to the controller.
|
||||
*
|
||||
* @param targetsIds
|
||||
* to override {@link Action}s
|
||||
*/
|
||||
protected List<Long> closeObsoleteUpdateActions(final Collection<Long> targetsIds) {
|
||||
|
||||
// Figure out if there are potential target/action combinations that
|
||||
// need to be considered for cancellation
|
||||
final List<JpaAction> activeActions = actionRepository
|
||||
.findByActiveAndTargetIdInAndDistributionSetNotRequiredMigrationStep(targetsIds);
|
||||
|
||||
return activeActions.stream().map(action -> {
|
||||
action.setStatus(Status.CANCELED);
|
||||
action.setActive(false);
|
||||
|
||||
// document that the status has been retrieved
|
||||
actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELED, System.currentTimeMillis(),
|
||||
RepositoryConstants.SERVER_MESSAGE_PREFIX + "close obsolete action due to new update"));
|
||||
actionRepository.save(action);
|
||||
|
||||
return action.getTarget().getId();
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the {@link CancelTargetAssignmentEvent} for a specific target to
|
||||
* the eventPublisher.
|
||||
|
||||
@@ -219,9 +219,22 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
*/
|
||||
@EntityGraph(attributePaths = { "target" }, type = EntityGraphType.LOAD)
|
||||
@Query("SELECT a FROM JpaAction a WHERE a.active = true AND a.distributionSet.requiredMigrationStep = false AND a.target IN ?1 AND a.status != ?2")
|
||||
List<JpaAction> findByActiveAndTargetIdInAndActionStatusNotEqualToAndDistributionSetRequiredMigrationStep(
|
||||
List<JpaAction> findByActiveAndTargetIdInAndActionStatusNotEqualToAndDistributionSetNotRequiredMigrationStep(
|
||||
Collection<Long> targetIds, Action.Status notStatus);
|
||||
|
||||
/**
|
||||
*
|
||||
* Retrieves all {@link Action}s which are active and referring to the given
|
||||
* target Ids and distribution set required migration step.
|
||||
*
|
||||
* @param targetIds
|
||||
* the IDs of targets for the actions
|
||||
* @return the found list of {@link Action}s
|
||||
*/
|
||||
@EntityGraph(attributePaths = { "target" }, type = EntityGraphType.LOAD)
|
||||
@Query("SELECT a FROM JpaAction a WHERE a.active = true AND a.distributionSet.requiredMigrationStep = false AND a.target IN ?1")
|
||||
List<JpaAction> findByActiveAndTargetIdInAndDistributionSetNotRequiredMigrationStep(Collection<Long> targetIds);
|
||||
|
||||
/**
|
||||
* Counts all {@link Action}s referring to the given target.
|
||||
*
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.eclipse.hawkbit.repository.ActionFields;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
@@ -57,6 +58,8 @@ import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.model.TargetWithActionType;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -109,13 +112,17 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
private final PlatformTransactionManager txManager;
|
||||
private final OnlineDsAssignmentStrategy onlineDsAssignmentStrategy;
|
||||
private final OfflineDsAssignmentStrategy offlineDsAssignmentStrategy;
|
||||
private final TenantConfigurationManagement tenantConfigurationManagement;
|
||||
private final SystemSecurityContext systemSecurityContext;
|
||||
|
||||
JpaDeploymentManagement(final EntityManager entityManager, final ActionRepository actionRepository,
|
||||
final DistributionSetRepository distributionSetRepository, final TargetRepository targetRepository,
|
||||
final ActionStatusRepository actionStatusRepository, final TargetManagement targetManagement,
|
||||
final AuditorAware<String> auditorProvider, final ApplicationEventPublisher eventPublisher,
|
||||
final ApplicationContext applicationContext, final AfterTransactionCommitExecutor afterCommit,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager) {
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
this.entityManager = entityManager;
|
||||
this.actionRepository = actionRepository;
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
@@ -132,6 +139,8 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
applicationContext, actionRepository, actionStatusRepository);
|
||||
offlineDsAssignmentStrategy = new OfflineDsAssignmentStrategy(targetRepository, afterCommit, eventPublisher,
|
||||
applicationContext, actionRepository, actionStatusRepository);
|
||||
this.tenantConfigurationManagement = tenantConfigurationManagement;
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -254,7 +263,16 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
// need to remember which one we have been switched to canceling state
|
||||
// because for targets which we have changed to canceling we don't want
|
||||
// to publish the new action update event.
|
||||
final Set<Long> targetIdsCancellList = assignmentStrategy.findTargetIdsToCancel(targetIds);
|
||||
final Set<Long> targetIdsCancellList;
|
||||
|
||||
if (systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement
|
||||
.getConfigurationValue(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED, Boolean.class)
|
||||
.getValue())) {
|
||||
targetIdsCancellList = Collections.emptySet();
|
||||
assignmentStrategy.closeActiveActions(targetIds);
|
||||
} else {
|
||||
targetIdsCancellList = assignmentStrategy.cancelActiveActions(targetIds);
|
||||
}
|
||||
|
||||
// cancel all scheduled actions which are in-active, these actions were
|
||||
// not active before and the manual assignment which has been done
|
||||
|
||||
@@ -85,8 +85,9 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final Long targetFilterQueryId) {
|
||||
get(targetFilterQueryId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetFilterQuery.class, targetFilterQueryId));
|
||||
if (!targetFilterQueryRepository.exists(targetFilterQueryId)) {
|
||||
throw new EntityNotFoundException(TargetFilterQuery.class, targetFilterQueryId);
|
||||
}
|
||||
|
||||
targetFilterQueryRepository.delete(targetFilterQueryId);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class JpaTenantStatsManagement implements TenantStatsManagement {
|
||||
|
||||
result.setTargets(targetRepository.count());
|
||||
result.setArtifacts(artifactRepository.countBySoftwareModuleDeleted(false));
|
||||
artifactRepository.getSumOfUndeletedArtifactSize().map(result::setOverallArtifactVolumeInBytes);
|
||||
artifactRepository.getSumOfUndeletedArtifactSize().ifPresent(result::setOverallArtifactVolumeInBytes);
|
||||
result.setActions(actionRepository.count());
|
||||
|
||||
return result;
|
||||
|
||||
@@ -67,10 +67,15 @@ public class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Long> findTargetIdsToCancel(final List<List<Long>> targetIds) {
|
||||
public Set<Long> cancelActiveActions(final List<List<Long>> targetIds) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
void closeActiveActions(final List<List<Long>> targetIds) {
|
||||
// Not supported by offline case
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateTargetStatus(final JpaDistributionSet set, final List<List<Long>> targetIds, final String currentUser) {
|
||||
targetIds.forEach(tIds -> targetRepository.setAssignedAndInstalledDistributionSetAndUpdateStatus(
|
||||
|
||||
@@ -67,11 +67,16 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<Long> findTargetIdsToCancel(final List<List<Long>> targetIds) {
|
||||
Set<Long> cancelActiveActions(final List<List<Long>> targetIds) {
|
||||
return targetIds.stream().map(this::overrideObsoleteUpdateActions).flatMap(Collection::stream)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
void closeActiveActions(final List<List<Long>> targetIds) {
|
||||
targetIds.forEach(this::closeObsoleteUpdateActions);
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateTargetStatus(final JpaDistributionSet set, final List<List<Long>> targetIds, final String currentUser) {
|
||||
targetIds.forEach(tIds -> targetRepository.setAssignedDistributionSetAndUpdateStatus(TargetUpdateStatus.PENDING,
|
||||
|
||||
@@ -531,10 +531,12 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
final TargetManagement targetManagement, final AuditorAware<String> auditorProvider,
|
||||
final ApplicationEventPublisher eventPublisher, final ApplicationContext applicationContext,
|
||||
final AfterTransactionCommitExecutor afterCommit, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final PlatformTransactionManager txManager) {
|
||||
final PlatformTransactionManager txManager,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
return new JpaDeploymentManagement(entityManager, actionRepository, distributionSetRepository, targetRepository,
|
||||
actionStatusRepository, targetManagement, auditorProvider, eventPublisher, applicationContext,
|
||||
afterCommit, virtualPropertyReplacer, txManager);
|
||||
afterCommit, virtualPropertyReplacer, txManager, tenantConfigurationManagement, systemSecurityContext);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -272,7 +272,7 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
|
||||
|
||||
if (allready >= softwareModule.getType().getMaxAssignments()) {
|
||||
modules.stream().filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey()))
|
||||
.findAny().map(modules::remove);
|
||||
.findAny().ifPresent(modules::remove);
|
||||
}
|
||||
|
||||
if (modules.add(softwareModule)) {
|
||||
|
||||
Reference in New Issue
Block a user