Fix dynamic rollouts when there are finished actions from previous rollouts (#2434)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-06-06 16:13:21 +03:00
committed by GitHub
parent d166dd6224
commit 0e0b5ed6ff
6 changed files with 151 additions and 209 deletions

View File

@@ -647,7 +647,7 @@ public class JpaRolloutExecutor implements RolloutExecutor {
rollout.getRolloutGroups(), RolloutGroupStatus.READY, group);
final Slice<Target> targets;
if (!RolloutHelper.isRolloutRetried(rollout.getTargetFilterQuery())) {
targets = targetManagement.findByTargetFilterQueryAndNotInRolloutGroupsAndCompatibleAndUpdatable(
targets = targetManagement.findByTargetFilterQueryAndNotInRolloutAndCompatibleAndUpdatable(
pageRequest, readyGroups, targetFilter, rollout.getDistributionSet().getType());
} else {
targets = targetManagement.findByFailedRolloutAndNotInRolloutGroups(
@@ -771,7 +771,7 @@ public class JpaRolloutExecutor implements RolloutExecutor {
final String targetFilter, final long limit) {
return DeploymentHelper.runInNewTransaction(txManager, "createActionsForRolloutDynamicGroup", status -> {
final PageRequest pageRequest = PageRequest.of(0, Math.toIntExact(limit));
final Slice<Target> targets = targetManagement.findByNotInGEGroupAndNotInActiveActionGEWeightOrInRolloutAndTargetFilterQueryAndCompatibleAndUpdatable(
final Slice<Target> targets = targetManagement.findByTargetFilterQueryAndNoOverridingActionsAndNotInRolloutAndCompatibleAndUpdatable(
pageRequest,
rollout.getId(), rollout.getWeight().orElse(1000), // Dynamic rollouts shall always have weight!
rolloutGroupRepository.findByRolloutOrderByIdAsc(rollout).get(0).getId(),

View File

@@ -12,7 +12,6 @@ package org.eclipse.hawkbit.repository.jpa.management;
import static org.eclipse.hawkbit.repository.jpa.JpaManagementHelper.combineWithAnd;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -135,7 +134,6 @@ public class JpaTargetManagement implements TargetManagement {
@Override
public long countByAssignedDistributionSet(final long distributionSetId) {
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException((distributionSetId));
return targetRepository.count(TargetSpecifications.hasAssignedDistributionSet(validDistSet.getId()));
}
@@ -148,29 +146,29 @@ public class JpaTargetManagement implements TargetManagement {
@Override
public long countByInstalledDistributionSet(final long distributionSetId) {
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException((distributionSetId));
return targetRepository.count(TargetSpecifications.hasInstalledDistributionSet(validDistSet.getId()));
}
@Override
public boolean existsByInstalledOrAssignedDistributionSet(final long distributionSetId) {
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException((distributionSetId));
return targetRepository
.exists(TargetSpecifications.hasInstalledOrAssignedDistributionSet(validDistSet.getId()));
return targetRepository.exists(TargetSpecifications.hasInstalledOrAssignedDistributionSet(validDistSet.getId()));
}
@Override
public long countByRsql(final String targetFilterQuery) {
return JpaManagementHelper.countBySpec(targetRepository, List.of(RSQLUtility
.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database)));
return JpaManagementHelper.countBySpec(
targetRepository,
List.of(RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database)));
}
@Override
public long countByRsqlAndUpdatable(String targetFilterQuery) {
final List<Specification<JpaTarget>> specList = List.of(RSQLUtility.buildRsqlSpecification(targetFilterQuery,
TargetFields.class, virtualPropertyReplacer, database));
return targetRepository.count(AccessController.Operation.UPDATE, combineWithAnd(specList));
final List<Specification<JpaTarget>> specList = List.of(
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database));
return targetRepository.count(
AccessController.Operation.UPDATE,
combineWithAnd(specList));
}
@Override
@@ -197,7 +195,8 @@ public class JpaTargetManagement implements TargetManagement {
@Override
public long countByTargetFilterQuery(final long targetFilterQueryId) {
final TargetFilterQuery targetFilterQuery = targetFilterQueryRepository.findById(targetFilterQueryId)
final TargetFilterQuery targetFilterQuery = targetFilterQueryRepository
.findById(targetFilterQueryId)
.orElseThrow(() -> new EntityNotFoundException(TargetFilterQuery.class, targetFilterQueryId));
return countByRsql(targetFilterQuery.getQuery());
}
@@ -221,8 +220,7 @@ public class JpaTargetManagement implements TargetManagement {
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public List<Target> create(final Collection<TargetCreate> targets) {
final List<JpaTarget> targetList = targets.stream().map(JpaTargetCreate.class::cast).map(JpaTargetCreate::build)
.toList();
final List<JpaTarget> targetList = targets.stream().map(JpaTargetCreate.class::cast).map(JpaTargetCreate::build).toList();
return Collections.unmodifiableList(targetRepository.saveAll(AccessController.Operation.CREATE, targetList));
}
@@ -236,7 +234,6 @@ public class JpaTargetManagement implements TargetManagement {
throw new EntityNotFoundException(Target.class, ids,
targets.stream().map(Target::getId).filter(id -> !ids.contains(id)).toList());
}
targetRepository.deleteAll(targets);
}
@@ -255,10 +252,10 @@ public class JpaTargetManagement implements TargetManagement {
final Long distSetTypeId = jpaDistributionSet.getType().getId();
return targetRepository
.findAllWithoutCount(AccessController.Operation.UPDATE,
.findAllWithoutCount(
AccessController.Operation.UPDATE,
combineWithAnd(List.of(
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class,
virtualPropertyReplacer, database),
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database),
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))),
pageRequest)
@@ -266,8 +263,7 @@ public class JpaTargetManagement implements TargetManagement {
}
@Override
public long countByRsqlAndNonDSAndCompatibleAndUpdatable(final long distributionSetId,
final String targetFilterQuery) {
public long countByRsqlAndNonDSAndCompatibleAndUpdatable(final long distributionSetId, final String targetFilterQuery) {
final DistributionSet jpaDistributionSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
final Long distSetTypeId = jpaDistributionSet.getType().getId();
@@ -281,14 +277,12 @@ public class JpaTargetManagement implements TargetManagement {
}
@Override
public Slice<Target> findByTargetFilterQueryAndNotInRolloutGroupsAndCompatibleAndUpdatable(
final Pageable pageRequest, final Collection<Long> groups, final String targetFilterQuery,
final DistributionSetType dsType) {
public Slice<Target> findByTargetFilterQueryAndNotInRolloutAndCompatibleAndUpdatable(
final Pageable pageRequest, final Collection<Long> groups, final String targetFilterQuery, final DistributionSetType dsType) {
return targetRepository
.findAllWithoutCount(AccessController.Operation.UPDATE,
combineWithAnd(List.of(
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class,
virtualPropertyReplacer, database),
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database),
TargetSpecifications.isNotInRolloutGroups(groups),
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))),
pageRequest)
@@ -296,16 +290,14 @@ public class JpaTargetManagement implements TargetManagement {
}
@Override
public Slice<Target> findByNotInGEGroupAndNotInActiveActionGEWeightOrInRolloutAndTargetFilterQueryAndCompatibleAndUpdatable(
public Slice<Target> findByTargetFilterQueryAndNoOverridingActionsAndNotInRolloutAndCompatibleAndUpdatable(
final Pageable pageRequest, final long rolloutId, final int weight, final long firstGroupId, final String targetFilterQuery,
final DistributionSetType distributionSetType) {
return targetRepository
.findAllWithoutCount(AccessController.Operation.UPDATE,
combineWithAnd(List.of(
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class,
virtualPropertyReplacer, database),
TargetSpecifications.isNotInGERolloutGroup(firstGroupId),
TargetSpecifications.hasNoActiveActionWithGEWeightOrInRollout(weight, rolloutId),
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database),
TargetSpecifications.hasNoOverridingActionsAndNotInRollout(weight, rolloutId),
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetType.getId()))),
pageRequest)
.map(Target.class::cast);
@@ -319,7 +311,7 @@ public class JpaTargetManagement implements TargetManagement {
@Override
public Slice<Target> findByFailedRolloutAndNotInRolloutGroups(Pageable pageRequest, Collection<Long> groups,
String rolloutId) {
final List<Specification<JpaTarget>> specList = Arrays.asList(
final List<Specification<JpaTarget>> specList = List.of(
TargetSpecifications.failedActionsForRollout(rolloutId),
TargetSpecifications.isNotInRolloutGroups(groups));
@@ -327,22 +319,20 @@ public class JpaTargetManagement implements TargetManagement {
}
@Override
public long countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(final String targetFilterQuery, final Collection<Long> groups,
final DistributionSetType dsType) {
public long countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(
final String targetFilterQuery, final Collection<Long> groups, final DistributionSetType dsType) {
return targetRepository.count(AccessController.Operation.UPDATE,
combineWithAnd(List.of(
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class,
virtualPropertyReplacer, database),
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database),
TargetSpecifications.isNotInRolloutGroups(groups),
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))));
}
@Override
public long countByFailedRolloutAndNotInRolloutGroups(String rolloutId, Collection<Long> groups) {
final List<Specification<JpaTarget>> specList = Arrays.asList(
final List<Specification<JpaTarget>> specList = List.of(
TargetSpecifications.failedActionsForRollout(rolloutId),
TargetSpecifications.isNotInRolloutGroups(groups));
return JpaManagementHelper.countBySpec(targetRepository, specList);
}
@@ -352,22 +342,21 @@ public class JpaTargetManagement implements TargetManagement {
throw new EntityNotFoundException(RolloutGroup.class, group);
}
return JpaManagementHelper.findAllWithoutCountBySpec(targetRepository, pageRequest,
List.of(TargetSpecifications.hasNoActionInRolloutGroup(group)));
return JpaManagementHelper.findAllWithoutCountBySpec(
targetRepository, pageRequest, List.of(TargetSpecifications.hasNoActionInRolloutGroup(group)));
}
@Override
public Page<Target> findByAssignedDistributionSet(final Pageable pageReq, final long distributionSetId) {
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
return JpaManagementHelper.findAllWithCountBySpec(targetRepository,
List.of(TargetSpecifications.hasAssignedDistributionSet(validDistSet.getId())), pageReq
);
return JpaManagementHelper.findAllWithCountBySpec(
targetRepository,
List.of(TargetSpecifications.hasAssignedDistributionSet(validDistSet.getId())), pageReq);
}
@Override
public Page<Target> findByAssignedDistributionSetAndRsql(final Pageable pageReq, final long distributionSetId,
final String rsqlParam) {
public Page<Target> findByAssignedDistributionSetAndRsql(final Pageable pageReq, final long distributionSetId, final String rsqlParam) {
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
final List<Specification<JpaTarget>> specList = List.of(
@@ -379,8 +368,7 @@ public class JpaTargetManagement implements TargetManagement {
@Override
public List<Target> getByControllerID(final Collection<String> controllerIDs) {
return Collections.unmodifiableList(
targetRepository.findAll(TargetSpecifications.byControllerIdWithAssignedDsInJoin(controllerIDs)));
return Collections.unmodifiableList(targetRepository.findAll(TargetSpecifications.byControllerIdWithAssignedDsInJoin(controllerIDs)));
}
@Override
@@ -403,14 +391,12 @@ public class JpaTargetManagement implements TargetManagement {
public Page<Target> findByInstalledDistributionSet(final Pageable pageReq, final long distributionSetId) {
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
return JpaManagementHelper.findAllWithCountBySpec(targetRepository,
List.of(TargetSpecifications.hasInstalledDistributionSet(validDistSet.getId())), pageReq
);
return JpaManagementHelper.findAllWithCountBySpec(
targetRepository, List.of(TargetSpecifications.hasInstalledDistributionSet(validDistSet.getId())), pageReq);
}
@Override
public Page<Target> findByInstalledDistributionSetAndRsql(final Pageable pageable, final long distributionSetId,
final String rsqlParam) {
public Page<Target> findByInstalledDistributionSetAndRsql(final Pageable pageable, final long distributionSetId, final String rsqlParam) {
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
final List<Specification<JpaTarget>> specList = List.of(
@@ -422,9 +408,8 @@ public class JpaTargetManagement implements TargetManagement {
@Override
public Page<Target> findByUpdateStatus(final Pageable pageable, final TargetUpdateStatus status) {
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, List.of(TargetSpecifications.hasTargetUpdateStatus(status)),
pageable
);
return JpaManagementHelper.findAllWithCountBySpec(
targetRepository, List.of(TargetSpecifications.hasTargetUpdateStatus(status)), pageable);
}
@Override
@@ -434,8 +419,9 @@ public class JpaTargetManagement implements TargetManagement {
@Override
public Slice<Target> findByRsql(final Pageable pageable, final String targetFilterQuery) {
return JpaManagementHelper.findAllWithoutCountBySpec(targetRepository, pageable, List.of(RSQLUtility
.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database)));
return JpaManagementHelper.findAllWithoutCountBySpec(
targetRepository, pageable,
List.of(RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database)));
}
@Override
@@ -443,24 +429,23 @@ public class JpaTargetManagement implements TargetManagement {
final TargetFilterQuery targetFilterQuery = targetFilterQueryRepository.findById(targetFilterQueryId)
.orElseThrow(() -> new EntityNotFoundException(TargetFilterQuery.class, targetFilterQueryId));
return JpaManagementHelper.findAllWithoutCountBySpec(targetRepository, pageable,
List.of(RSQLUtility.buildRsqlSpecification(targetFilterQuery.getQuery(), TargetFields.class,
virtualPropertyReplacer, database)));
return JpaManagementHelper.findAllWithoutCountBySpec(
targetRepository, pageable,
List.of(RSQLUtility.buildRsqlSpecification(
targetFilterQuery.getQuery(), TargetFields.class, virtualPropertyReplacer, database)));
}
@Override
public Page<Target> findByTag(final Pageable pageable, final long tagId) {
throwEntityNotFoundExceptionIfTagDoesNotExist(tagId);
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, List.of(TargetSpecifications.hasTag(tagId)), pageable
);
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, List.of(TargetSpecifications.hasTag(tagId)), pageable);
}
@Override
public Page<Target> findByRsqlAndTag(final Pageable pageable, final String rsqlParam, final long tagId) {
throwEntityNotFoundExceptionIfTagDoesNotExist(tagId);
final List<Specification<JpaTarget>> specList = Arrays.asList(
final List<Specification<JpaTarget>> specList = List.of(
RSQLUtility.buildRsqlSpecification(rsqlParam, TargetFields.class, virtualPropertyReplacer, database),
TargetSpecifications.hasTag(tagId));
@@ -472,20 +457,19 @@ public class JpaTargetManagement implements TargetManagement {
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public TargetTypeAssignmentResult assignType(final Collection<String> controllerIds, final Long typeId) {
final JpaTargetType type = targetTypeRepository.findById(typeId)
final JpaTargetType type = targetTypeRepository
.findById(typeId)
.orElseThrow(() -> new EntityNotFoundException(TargetType.class, typeId));
final List<JpaTarget> targetsWithSameType = findTargetsByInSpecification(controllerIds,
TargetSpecifications.hasTargetType(typeId));
final List<JpaTarget> targetsWithoutSameType = findTargetsByInSpecification(controllerIds,
TargetSpecifications.hasTargetTypeNot(typeId));
final List<JpaTarget> targetsWithSameType = findTargetsByInSpecification(controllerIds, TargetSpecifications.hasTargetType(typeId));
final List<JpaTarget> targetsWithoutSameType =
findTargetsByInSpecification(controllerIds, TargetSpecifications.hasTargetTypeNot(typeId));
// set new target type to all targets without that type
targetsWithoutSameType.forEach(target -> target.setTargetType(type));
final TargetTypeAssignmentResult result = new TargetTypeAssignmentResult(targetsWithSameType.size(),
targetRepository.saveAll(targetsWithoutSameType), Collections.emptyList(), type);
final TargetTypeAssignmentResult result = new TargetTypeAssignmentResult(
targetsWithSameType.size(), targetRepository.saveAll(targetsWithoutSameType), Collections.emptyList(), type);
// no reason to persist the type
entityManager.detach(type);
@@ -500,8 +484,7 @@ public class JpaTargetManagement implements TargetManagement {
final List<JpaTarget> allTargets = findTargetsByInSpecification(controllerIds, null);
if (allTargets.size() < controllerIds.size()) {
throw new EntityNotFoundException(Target.class, controllerIds,
allTargets.stream().map(Target::getControllerId).toList());
throw new EntityNotFoundException(Target.class, controllerIds, allTargets.stream().map(Target::getControllerId).toList());
}
// set new target type to null for all targets
@@ -514,8 +497,8 @@ public class JpaTargetManagement implements TargetManagement {
@Transactional
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public List<Target> assignTag(final Collection<String> controllerIds, final long targetTagId,
final Consumer<Collection<String>> notFoundHandler) {
public List<Target> assignTag(
final Collection<String> controllerIds, final long targetTagId, final Consumer<Collection<String>> notFoundHandler) {
return assignTag0(controllerIds, targetTagId, notFoundHandler);
}
@@ -527,8 +510,8 @@ public class JpaTargetManagement implements TargetManagement {
return assignTag0(controllerIds, targetTagId, null);
}
private List<Target> assignTag0(final Collection<String> controllerIds, final long targetTagId,
final Consumer<Collection<String>> notFoundHandler) {
private List<Target> assignTag0(
final Collection<String> controllerIds, final long targetTagId, final Consumer<Collection<String>> notFoundHandler) {
return updateTag(controllerIds, targetTagId, notFoundHandler, (tag, target) -> {
if (target.getTags().contains(tag)) {
return target;
@@ -543,8 +526,8 @@ public class JpaTargetManagement implements TargetManagement {
@Transactional
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public List<Target> unassignTag(final Collection<String> controllerIds, final long targetTagId,
final Consumer<Collection<String>> notFoundHandler) {
public List<Target> unassignTag(
final Collection<String> controllerIds, final long targetTagId, final Consumer<Collection<String>> notFoundHandler) {
return unassignTag0(controllerIds, targetTagId, notFoundHandler);
}
@@ -556,8 +539,8 @@ public class JpaTargetManagement implements TargetManagement {
return unassignTag0(controllerIds, targetTagId, null);
}
private List<Target> unassignTag0(final Collection<String> controllerIds, final long targetTagId,
final Consumer<Collection<String>> notFoundHandler) {
private List<Target> unassignTag0(
final Collection<String> controllerIds, final long targetTagId, final Consumer<Collection<String>> notFoundHandler) {
return updateTag(controllerIds, targetTagId, notFoundHandler, (tag, target) -> {
if (target.getTags().contains(tag)) {
target.removeTag(tag);
@@ -630,13 +613,13 @@ public class JpaTargetManagement implements TargetManagement {
}
@Override
public boolean isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(final String controllerId,
final long distributionSetId, final String targetFilterQuery) {
public boolean isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(
final String controllerId, final long distributionSetId, final String targetFilterQuery) {
RSQLUtility.validateRsqlFor(targetFilterQuery, TargetFields.class, JpaTarget.class, virtualPropertyReplacer, entityManager);
final DistributionSet ds = distributionSetManagement.get(distributionSetId)
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, distributionSetId));
final Long distSetTypeId = ds.getType().getId();
final List<Specification<JpaTarget>> specList = Arrays.asList(
final List<Specification<JpaTarget>> specList = List.of(
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database),
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId),
@@ -830,8 +813,7 @@ public class JpaTargetManagement implements TargetManagement {
return specList;
}
private List<JpaTarget> findTargetsByInSpecification(final Collection<String> controllerIds,
final Specification<JpaTarget> specification) {
private List<JpaTarget> findTargetsByInSpecification(final Collection<String> controllerIds, final Specification<JpaTarget> specification) {
return ListUtils.partition(new ArrayList<>(controllerIds), Constants.MAX_ENTRIES_IN_STATEMENT).stream()
.map(ids -> targetRepository.findAll(TargetSpecifications.hasControllerIdIn(ids).and(specification)))
.flatMap(List::stream).toList();
@@ -873,4 +855,4 @@ public class JpaTargetManagement implements TargetManagement {
throw new EntityNotFoundException(TargetTag.class, tagId);
}
}
}
}

View File

@@ -119,15 +119,13 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link JpaTarget}s including
* {@link JpaTarget#getAssignedDistributionSet()}.
* {@link Specification} for retrieving {@link JpaTarget}s including {@link JpaTarget#getAssignedDistributionSet()}.
*
* @param controllerIDs to search for
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> byControllerIdWithAssignedDsInJoin(final Collection<String> controllerIDs) {
return (targetRoot, query, cb) -> {
final Predicate predicate = targetRoot.get(JpaTarget_.controllerId).in(controllerIDs);
targetRoot.fetch(JpaTarget_.assignedDistributionSet, JoinType.LEFT);
return predicate;
@@ -135,8 +133,7 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s by "equal to any
* given {@link TargetUpdateStatus}".
* {@link Specification} for retrieving {@link Target}s by "equal to any given {@link TargetUpdateStatus}".
*
* @param updateStatus to be filtered on
* @return the {@link Target} {@link Specification}
@@ -146,8 +143,7 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s by "equal to given
* {@link TargetUpdateStatus}".
* {@link Specification} for retrieving {@link Target}s by "equal to given {@link TargetUpdateStatus}".
*
* @param updateStatus to be filtered on
* @return the {@link Target} {@link Specification}
@@ -157,8 +153,7 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s by "not equal to
* given {@link TargetUpdateStatus}".
* {@link Specification} for retrieving {@link Target}s by "not equal to given {@link TargetUpdateStatus}".
*
* @param updateStatus to be filtered on
* @return the {@link Target} {@link Specification}
@@ -168,17 +163,13 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s that are overdue. A
* target is overdue if it did not respond during the configured
* {@link Specification} for retrieving {@link Target}s that are overdue. A target is overdue if it did not respond during the configured
* intervals:<br>
* <em>poll_itvl + overdue_itvl</em>
*
* @param overdueTimestamp the calculated timestamp to compare with the last respond of a
* target (lastTargetQuery).<br>
* The <code>overdueTimestamp</code> has to be calculated with
* the following expression:<br>
* <em>overdueTimestamp = nowTimestamp - poll_itvl -
* overdue_itvl</em>
* @param overdueTimestamp the calculated timestamp to compare with the last response of a target (lastTargetQuery).<br>
* The <code>overdueTimestamp</code> has to be calculated with the following expression:<br>
* <em>overdueTimestamp = nowTimestamp - poll_itvl - overdue_itvl</em>
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> isOverdue(final long overdueTimestamp) {
@@ -187,8 +178,7 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s by "like
* controllerId or like name".
* {@link Specification} for retrieving {@link Target}s by "like controllerId or like name".
*
* @param searchText to be filtered on
* @return the {@link Target} {@link Specification}
@@ -202,8 +192,7 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s by "like
* controllerId".
* {@link Specification} for retrieving {@link Target}s by "like controllerId".
*
* @param distributionId to be filtered on
* @return the {@link Target} {@link Specification}
@@ -228,8 +217,7 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s based on a
* {@link TargetTag} name.
* {@link Specification} for retrieving {@link Target}s based on a {@link TargetTag} name.
*
* @param tagName to search for
* @return the {@link Target} {@link Specification}
@@ -242,8 +230,7 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s by "has no tag
* names"or "has at least on of the given tag names".
* {@link Specification} for retrieving {@link Target}s by "has no tag names"or "has at least on of the given tag names".
*
* @param tagNames to be filtered on
* @param selectTargetWithNoTag flag to get targets with no tag assigned
@@ -258,8 +245,7 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s by assigned
* distribution set.
* {@link Specification} for retrieving {@link Target}s by assigned distribution set.
*
* @param distributionSetId the ID of the distribution set which must be assigned
* @return the {@link Target} {@link Specification}
@@ -270,8 +256,7 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s that don't have the
* given distribution set in their action history
* {@link Specification} for retrieving {@link Target}s that don't have the given distribution set in their action history
*
* @param distributionSetId the ID of the distribution set which must not be assigned
* @return the {@link Target} {@link Specification}
@@ -285,10 +270,9 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s that are compatible
* with given {@link DistributionSetType}. Compatibility is evaluated by
* checking the {@link TargetType} of a target. Targets that don't have a
* {@link TargetType} are compatible with all {@link DistributionSetType}
* {@link Specification} for retrieving {@link Target}s that are compatible with given {@link DistributionSetType}. Compatibility is
* evaluated by checking the {@link TargetType} of a target. Targets that don't have a {@link TargetType} are compatible with all
* {@link DistributionSetType}
*
* @param distributionSetTypeId the ID of the distribution set type which must be compatible
* @return the {@link Target} {@link Specification}
@@ -302,10 +286,8 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s that are NOT
* compatible with given {@link DistributionSetType}. Compatibility is
* evaluated by checking the {@link TargetType} of a target. Targets that
* don't have a {@link TargetType} are compatible with all
* {@link Specification} for retrieving {@link Target}s that are NOT compatible with given {@link DistributionSetType}. Compatibility is
* evaluated by checking the {@link TargetType} of a target. Targets that don't have a {@link TargetType} are compatible with all
* {@link DistributionSetType}
*
* @param distributionSetTypeId the ID of the distribution set type which must be incompatible
@@ -329,23 +311,20 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s that are in a given
* {@link RolloutGroup}
* {@link Specification} for retrieving {@link Target}s that are in a given {@link RolloutGroup}
*
* @param group the {@link RolloutGroup}
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> isInRolloutGroup(final Long group) {
return (targetRoot, query, cb) -> {
final ListJoin<JpaTarget, RolloutTargetGroup> targetGroupJoin = targetRoot
.join(JpaTarget_.rolloutTargetGroup);
final ListJoin<JpaTarget, RolloutTargetGroup> targetGroupJoin = targetRoot.join(JpaTarget_.rolloutTargetGroup);
return cb.equal(targetGroupJoin.get(RolloutTargetGroup_.rolloutGroup).get(AbstractJpaBaseEntity_.id), group);
};
}
/**
* {@link Specification} for retrieving {@link Target}s that are in an
* action for a given {@link RolloutGroup}
* {@link Specification} for retrieving {@link Target}s that are in an action for a given {@link RolloutGroup}
*
* @param group the {@link RolloutGroup}
* @return the {@link Target} {@link Specification}
@@ -358,41 +337,21 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s that are not in the
* given {@link RolloutGroup}s
* {@link Specification} for retrieving {@link Target}s that are not in the given {@link RolloutGroup}s
*
* @param groups the {@link RolloutGroup}s
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> isNotInRolloutGroups(final Collection<Long> groups) {
return (targetRoot, query, cb) -> {
final ListJoin<JpaTarget, RolloutTargetGroup> rolloutTargetJoin = targetRoot
.join(JpaTarget_.rolloutTargetGroup, JoinType.LEFT);
rolloutTargetJoin.on(rolloutTargetJoin.get(RolloutTargetGroup_.rolloutGroup)
.get(AbstractJpaBaseEntity_.id).in(groups));
final ListJoin<JpaTarget, RolloutTargetGroup> rolloutTargetJoin = targetRoot.join(JpaTarget_.rolloutTargetGroup, JoinType.LEFT);
rolloutTargetJoin.on(rolloutTargetJoin.get(RolloutTargetGroup_.rolloutGroup).get(AbstractJpaBaseEntity_.id).in(groups));
return cb.isNull(rolloutTargetJoin.get(RolloutTargetGroup_.target));
};
}
/**
* {@link Specification} for retrieving {@link Target}s that are not in
* any {@link RolloutGroup}s
*
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> isNotInGERolloutGroup(final long groupId) {
return (targetRoot, query, cb) -> {
final ListJoin<JpaTarget, RolloutTargetGroup> rolloutTargetJoin = targetRoot
.join(JpaTarget_.rolloutTargetGroup, JoinType.LEFT);
rolloutTargetJoin.on(cb.ge(rolloutTargetJoin.get(RolloutTargetGroup_.rolloutGroup)
.get(AbstractJpaBaseEntity_.id), groupId));
return cb.isNull(rolloutTargetJoin.get(RolloutTargetGroup_.target));
};
}
/**
* {@link Specification} for retrieving {@link Target}s that have no Action
* of the {@link RolloutGroup}.
* {@link Specification} for retrieving {@link Target}s that have no Action of the {@link RolloutGroup}.
*
* @param group the {@link RolloutGroup}
* @return the {@link Target} {@link Specification}
@@ -412,8 +371,7 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s by assigned
* distribution set.
* {@link Specification} for retrieving {@link Target}s by assigned distribution set.
*
* @param distributionSetId the ID of the distribution set which must be assigned
* @return the {@link Target} {@link Specification}
@@ -448,8 +406,7 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s by target type id is
* equal to null
* {@link Specification} for retrieving {@link Target}s by target type id is equal to null
*
* @return the {@link Target} {@link Specification}
*/
@@ -458,8 +415,7 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s that don't have
* target type assigned
* {@link Specification} for retrieving {@link Target}s that don't have target type assigned
*
* @param typeId the id of the target type
* @return the {@link Target} {@link Specification}
@@ -471,9 +427,7 @@ public final class TargetSpecifications {
public static Specification<JpaTarget> failedActionsForRollout(final String rolloutId) {
return (targetRoot, query, cb) -> {
Join<JpaTarget, Action> targetActions =
targetRoot.join("actions");
final Join<JpaTarget, Action> targetActions = targetRoot.join("actions");
return cb.and(
cb.equal(targetActions.get("rollout").get("id"), rolloutId),
cb.equal(targetActions.get("status"), Action.Status.ERROR));
@@ -481,34 +435,31 @@ public final class TargetSpecifications {
}
/**
* {@link Specification} for retrieving {@link Target}s that have no active (non-finished) action
* with great or equal weight (GEWeight.
* {@link Specification} for retrieving {@link Target}s that have:
* <ul>
* <li>no active (non-finished) actions with greater weight in the older rollouts</li>
* <li>or have actions in the current rollout</li>
* <li>or have actions with great or equal weight in the newer rollouts</li>
* </ul>
*
* @param weight the referent weight
* @return the {@link Target} {@link Specification}
*/
public static Specification<JpaTarget> hasNoActiveActionWithGEWeightOrInRollout(final int weight, final long rolloutId) {
public static Specification<JpaTarget> hasNoOverridingActionsAndNotInRollout(final int weight, final long rolloutId) {
return (targetRoot, query, cb) -> {
final ListJoin<JpaTarget, JpaAction> actionsJoin = targetRoot.join(JpaTarget_.actions, JoinType.LEFT);
actionsJoin.on(
cb.or(
cb.gt(actionsJoin.get(JpaAction_.weight), weight),
cb.and(
cb.equal(actionsJoin.get(JpaAction_.weight), weight),
cb.ge(actionsJoin.get(JpaAction_.ROLLOUT).get(AbstractJpaBaseEntity_.ID), rolloutId))));
// another, but probably heavier variant
// actionsJoin.on(
// cb.or(
// // in rollout
// cb.equal(actionsJoin.get(JpaAction_.ROLLOUT).get(AbstractJpaBaseEntity_.ID), rolloutId),
// // or, in newer rollout with greater or equal weight
// cb.and(
// cb.gt(actionsJoin.get(JpaAction_.ROLLOUT).get(AbstractJpaBaseEntity_.ID), rolloutId),
// cb.ge(actionsJoin.get(JpaAction_.weight), weight)),
// // or, in older with greater status
// cb.and(
// cb.lt(actionsJoin.get(JpaAction_.ROLLOUT).get(AbstractJpaBaseEntity_.ID), rolloutId),
// cb.gt(actionsJoin.get(JpaAction_.weight), weight))));
cb.and(
cb.lt(actionsJoin.get(JpaAction_.rollout).get(AbstractJpaBaseEntity_.id), rolloutId),
cb.gt(actionsJoin.get(JpaAction_.weight), weight)),
cb.or(
cb.equal(actionsJoin.get(JpaAction_.active), true),
cb.equal(actionsJoin.get(JpaAction_.status), Action.Status.SCHEDULED))),
cb.and(
cb.ge(actionsJoin.get(JpaAction_.rollout).get(AbstractJpaBaseEntity_.id), rolloutId),
cb.ge(actionsJoin.get(JpaAction_.weight), weight))));
return cb.isNull(actionsJoin.get(AbstractJpaBaseEntity_.id));
};
}