Extend access control management (#1493)
* Fix ACM related executions. * Introduce access controller for actions. Resolve some todos and fix distribution set invalidation strategy. * Do only check for access if returned values are access controlled. * Fix review findings. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.com> --------- Signed-off-by: Michael Herdt <Michael.Herdt@bosch.com>
This commit is contained in:
@@ -22,6 +22,9 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
||||
public interface RolloutExecutor {
|
||||
|
||||
/**
|
||||
* This execution should only be triggered by the system as a background job and
|
||||
* not available via API.
|
||||
*
|
||||
* Process rollout based on its current {@link Rollout#getStatus()}.
|
||||
*
|
||||
* For {@link RolloutStatus#CREATING} that means creating the
|
||||
@@ -29,9 +32,9 @@ public interface RolloutExecutor {
|
||||
* {@link RolloutStatus#READY}.
|
||||
*
|
||||
* For {@link RolloutStatus#READY} that means switching to
|
||||
* {@link RolloutStatus#STARTING} if the {@link Rollout#getStartAt()} is set
|
||||
* and time of calling this method is beyond this point in time. This auto
|
||||
* start mechanism is optional. Call {@link #start(Long)} otherwise.
|
||||
* {@link RolloutStatus#STARTING} if the {@link Rollout#getStartAt()} is set and
|
||||
* time of calling this method is beyond this point in time. This auto start
|
||||
* mechanism is optional. Call {@link #start(Long)} otherwise.
|
||||
*
|
||||
* For {@link RolloutStatus#STARTING} that means starting the first
|
||||
* {@link RolloutGroup}s in line and when finished switch to
|
||||
@@ -45,8 +48,7 @@ public interface RolloutExecutor {
|
||||
* rollout was already {@link RolloutStatus#RUNNING} which results in status
|
||||
* change {@link RolloutStatus#DELETED} or hard delete from the persistence
|
||||
* otherwise.
|
||||
*
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.IS_SYSTEM_CODE)
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_ROLLOUT_MANAGEMENT_CREATE)
|
||||
void execute(Rollout rollout);
|
||||
}
|
||||
|
||||
@@ -69,9 +69,11 @@ public interface TargetManagement {
|
||||
/**
|
||||
* Counts number of targets with the given distribution set assigned.
|
||||
*
|
||||
* @param distributionSetId to search for
|
||||
* @param distributionSetId
|
||||
* to search for
|
||||
* @return number of found {@link Target}s.
|
||||
* @throws EntityNotFoundException if distribution set with given ID does not exist
|
||||
* @throws EntityNotFoundException
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
@@ -81,8 +83,8 @@ public interface TargetManagement {
|
||||
* Count {@link Target}s for all the given filter parameters.
|
||||
*
|
||||
* @param filterParams
|
||||
* the filters to apply; only filters are enabled that have
|
||||
* non-null value; filters are AND-gated
|
||||
* the filters to apply; only filters are enabled that have non-null
|
||||
* value; filters are AND-gated
|
||||
*
|
||||
* @return the found number {@link Target}s
|
||||
*
|
||||
@@ -95,21 +97,25 @@ public interface TargetManagement {
|
||||
/**
|
||||
* Get the count of targets with the given distribution set id.
|
||||
*
|
||||
* @param distributionSetId to search for
|
||||
* @param distributionSetId
|
||||
* to search for
|
||||
* @return number of found {@link Target}s.
|
||||
* @throws EntityNotFoundException if distribution set with given ID does not exist
|
||||
* @throws EntityNotFoundException
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
long countByInstalledDistributionSet(long distributionSetId);
|
||||
|
||||
/**
|
||||
* Checks if there is already a {@link Target} that has the given
|
||||
* distribution set Id assigned or installed.
|
||||
* Checks if there is already a {@link Target} that has the given distribution
|
||||
* set Id assigned or installed.
|
||||
*
|
||||
* @param distributionSetId to search for
|
||||
* @param distributionSetId
|
||||
* to search for
|
||||
* @return <code>true</code> if a {@link Target} exists.
|
||||
* @throws EntityNotFoundException if distribution set with given ID does not exist
|
||||
* @throws EntityNotFoundException
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
@@ -126,23 +132,47 @@ public interface TargetManagement {
|
||||
long countByRsql(@NotEmpty String rsqlParam);
|
||||
|
||||
/**
|
||||
* Count all targets for given {@link TargetFilterQuery} and that are
|
||||
* compatible with the passed {@link DistributionSetType}.
|
||||
* Count {@link TargetFilterQuery}s for given target filter query with UPDATE permission.
|
||||
*
|
||||
* @param rsqlParam
|
||||
* filter definition in RSQL syntax
|
||||
* @param distributionSetId
|
||||
* @return the found number of {@link Target}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
long countByRsqlAndUpdatable(@NotEmpty String rsqlParam);
|
||||
|
||||
/**
|
||||
* Count all targets for given {@link TargetFilterQuery} and that are compatible
|
||||
* with the passed {@link DistributionSetType}.
|
||||
*
|
||||
* @param rsqlParam
|
||||
* filter definition in RSQL syntax
|
||||
* @param distributionSetIdTypeId
|
||||
* ID of the {@link DistributionSetType} the targets need to be
|
||||
* compatible with
|
||||
* @return the found number of{@link Target}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
long countByRsqlAndCompatible(@NotEmpty String rsqlParam, @NotNull Long distributionSetId);
|
||||
long countByRsqlAndCompatible(@NotEmpty String rsqlParam, @NotNull Long distributionSetIdTypeId);
|
||||
|
||||
/**
|
||||
* Count all targets with failed actions for specific Rollout
|
||||
* and that are compatible with the passed {@link DistributionSetType}
|
||||
* and created after given timestamp
|
||||
* Count all targets for given {@link TargetFilterQuery} and that are compatible
|
||||
* with the passed {@link DistributionSetType} and UPDATE permission.
|
||||
*
|
||||
* @param rsqlParam
|
||||
* filter definition in RSQL syntax
|
||||
* @param distributionSetIdTypeId
|
||||
* ID of the {@link DistributionSetType} the targets need to be
|
||||
* compatible with
|
||||
* @return the found number of{@link Target}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
long countByRsqlAndCompatibleAndUpdatable(@NotEmpty String rsqlParam, @NotNull Long distributionSetIdTypeId);
|
||||
|
||||
/**
|
||||
* Count all targets with failed actions for specific Rollout and that are
|
||||
* compatible with the passed {@link DistributionSetType} and created after
|
||||
* given timestamp
|
||||
*
|
||||
* @param rolloutId
|
||||
* rolloutId of the rollout to be retried.
|
||||
@@ -185,18 +215,17 @@ public interface TargetManagement {
|
||||
* @throws EntityAlreadyExistsException
|
||||
* given target already exists.
|
||||
* @throws ConstraintViolationException
|
||||
* if fields are not filled as specified. Check
|
||||
* {@link TargetCreate} for field constraints.
|
||||
* if fields are not filled as specified. Check {@link TargetCreate}
|
||||
* for field constraints.
|
||||
*
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET)
|
||||
Target create(@NotNull @Valid TargetCreate create);
|
||||
|
||||
/**
|
||||
* creates multiple {@link Target}s. If the given {@link Target}s
|
||||
* already exists in the DB an {@link EntityAlreadyExistsException} is
|
||||
* thrown. {@link Target}s contain all objects of the parameter targets,
|
||||
* including duplicates.
|
||||
* creates multiple {@link Target}s. If the given {@link Target}s already exists
|
||||
* in the DB an {@link EntityAlreadyExistsException} is thrown. {@link Target}s
|
||||
* contain all objects of the parameter targets, including duplicates.
|
||||
*
|
||||
* @param creates
|
||||
* to be created.
|
||||
@@ -205,8 +234,8 @@ public interface TargetManagement {
|
||||
* @throws EntityAlreadyExistsException
|
||||
* of one of the given targets already exist.
|
||||
* @throws ConstraintViolationException
|
||||
* if fields are not filled as specified. Check
|
||||
* {@link TargetCreate} for field constraints.
|
||||
* if fields are not filled as specified. Check {@link TargetCreate}
|
||||
* for field constraints.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_TARGET)
|
||||
List<Target> create(@NotNull @Valid Collection<TargetCreate> creates);
|
||||
@@ -253,12 +282,12 @@ public interface TargetManagement {
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
Slice<Target> findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(@NotNull Pageable pageRequest,
|
||||
long distributionSetId, @NotNull String rsqlParam);
|
||||
long distributionSetId, @NotNull String rsqlParam);
|
||||
|
||||
/**
|
||||
* Counts all targets for all the given parameter {@link TargetFilterQuery}
|
||||
* and that don't have the specified distribution set in their action
|
||||
* history and are compatible with the passed {@link DistributionSetType}.
|
||||
* Counts all targets for all the given parameter {@link TargetFilterQuery} and
|
||||
* that don't have the specified distribution set in their action history and
|
||||
* are compatible with the passed {@link DistributionSetType}.
|
||||
*
|
||||
* @param distributionSetId
|
||||
* id of the {@link DistributionSet}
|
||||
@@ -273,9 +302,9 @@ public interface TargetManagement {
|
||||
long countByRsqlAndNonDSAndCompatibleAndUpdatable(long distributionSetId, @NotNull String rsqlParam);
|
||||
|
||||
/**
|
||||
* Finds all targets for all the given parameter {@link TargetFilterQuery}
|
||||
* and that are not assigned to one of the {@link RolloutGroup}s and are
|
||||
* compatible with the passed {@link DistributionSetType}.
|
||||
* Finds all targets for all the given parameter {@link TargetFilterQuery} and
|
||||
* that are not assigned to one of the {@link RolloutGroup}s and are compatible
|
||||
* with the passed {@link DistributionSetType}.
|
||||
*
|
||||
* @param pageRequest
|
||||
* the pageRequest to enhance the query for paging and sorting
|
||||
@@ -284,8 +313,8 @@ public interface TargetManagement {
|
||||
* @param rsqlParam
|
||||
* filter definition in RSQL syntax
|
||||
* @param distributionSetType
|
||||
* type of the {@link DistributionSet} the targets must be
|
||||
* compatible withs
|
||||
* type of the {@link DistributionSet} the targets must be compatible
|
||||
* withs
|
||||
* @return a page of the found {@link Target}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
@@ -294,9 +323,9 @@ public interface TargetManagement {
|
||||
@NotNull DistributionSetType distributionSetType);
|
||||
|
||||
/**
|
||||
* Finds all targets with failed actions for specific Rollout
|
||||
* and that are not assigned to one of the retried {@link RolloutGroup}s and are
|
||||
* compatible with the passed {@link DistributionSetType}.
|
||||
* Finds all targets with failed actions for specific Rollout and that are not
|
||||
* assigned to one of the retried {@link RolloutGroup}s and are compatible with
|
||||
* the passed {@link DistributionSetType}.
|
||||
*
|
||||
* @param pageRequest
|
||||
* the pageRequest to enhance the query for paging and sorting
|
||||
@@ -308,12 +337,12 @@ public interface TargetManagement {
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
Slice<Target> findByFailedRolloutAndNotInRolloutGroups(@NotNull Pageable pageRequest,
|
||||
@NotEmpty Collection<Long> groups, @NotNull String rolloutId);
|
||||
@NotEmpty Collection<Long> groups, @NotNull String rolloutId);
|
||||
|
||||
/**
|
||||
* Counts all targets for all the given parameter {@link TargetFilterQuery}
|
||||
* and that are not assigned to one of the {@link RolloutGroup}s and are
|
||||
* compatible with the passed {@link DistributionSetType}.
|
||||
* Counts all targets for all the given parameter {@link TargetFilterQuery} and
|
||||
* that are not assigned to one of the {@link RolloutGroup}s and are compatible
|
||||
* with the passed {@link DistributionSetType}.
|
||||
*
|
||||
* @param groups
|
||||
* the list of {@link RolloutGroup}s
|
||||
@@ -329,9 +358,9 @@ public interface TargetManagement {
|
||||
@NotNull String rsqlParam, @NotNull DistributionSetType distributionSetType);
|
||||
|
||||
/**
|
||||
* Counts all targets with failed actions for specific Rollout
|
||||
* and that are not assigned to one of the {@link RolloutGroup}s and are
|
||||
* compatible with the passed {@link DistributionSetType}.
|
||||
* Counts all targets with failed actions for specific Rollout and that are not
|
||||
* assigned to one of the {@link RolloutGroup}s and are compatible with the
|
||||
* passed {@link DistributionSetType}.
|
||||
*
|
||||
* @param groups
|
||||
* the list of {@link RolloutGroup}s
|
||||
@@ -343,8 +372,8 @@ public interface TargetManagement {
|
||||
long countByFailedRolloutAndNotInRolloutGroups(@NotEmpty Collection<Long> groups, @NotNull String rolloutId);
|
||||
|
||||
/**
|
||||
* Finds all targets of the provided {@link RolloutGroup} that have no
|
||||
* Action for the RolloutGroup.
|
||||
* Finds all targets of the provided {@link RolloutGroup} that have no Action
|
||||
* for the RolloutGroup.
|
||||
*
|
||||
* @param pageRequest
|
||||
* the pageRequest to enhance the query for paging and sorting
|
||||
@@ -376,8 +405,8 @@ public interface TargetManagement {
|
||||
Page<Target> findByAssignedDistributionSet(@NotNull Pageable pageReq, long distributionSetId);
|
||||
|
||||
/**
|
||||
* Retrieves {@link Target}s by the assigned {@link DistributionSet}
|
||||
* possible including additional filtering based on the given {@code spec}.
|
||||
* Retrieves {@link Target}s by the assigned {@link DistributionSet} possible
|
||||
* including additional filtering based on the given {@code spec}.
|
||||
*
|
||||
* @param pageReq
|
||||
* page parameter
|
||||
@@ -420,14 +449,14 @@ public interface TargetManagement {
|
||||
Optional<Target> getByControllerID(@NotEmpty String controllerId);
|
||||
|
||||
/**
|
||||
* Filter {@link Target}s for all the given parameters. If all parameters
|
||||
* except pageable are null, all available {@link Target}s are returned.
|
||||
* Filter {@link Target}s for all the given parameters. If all parameters except
|
||||
* pageable are null, all available {@link Target}s are returned.
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param filterParams
|
||||
* the filters to apply; only filters are enabled that have
|
||||
* non-null value; filters are AND-gated
|
||||
* the filters to apply; only filters are enabled that have non-null
|
||||
* value; filters are AND-gated
|
||||
*
|
||||
* @return the found {@link Target}s
|
||||
*
|
||||
@@ -454,8 +483,8 @@ public interface TargetManagement {
|
||||
Page<Target> findByInstalledDistributionSet(@NotNull Pageable pageReq, long distributionSetId);
|
||||
|
||||
/**
|
||||
* retrieves {@link Target}s by the installed {@link DistributionSet}
|
||||
* including additional filtering based on the given {@code spec}.
|
||||
* retrieves {@link Target}s by the installed {@link DistributionSet} including
|
||||
* additional filtering based on the given {@code spec}.
|
||||
*
|
||||
* @param pageReq
|
||||
* page parameter
|
||||
@@ -480,8 +509,7 @@ public interface TargetManagement {
|
||||
@NotNull String rsqlParam);
|
||||
|
||||
/**
|
||||
* Retrieves the {@link Target} which have a certain
|
||||
* {@link TargetUpdateStatus}.
|
||||
* Retrieves the {@link Target} which have a certain {@link TargetUpdateStatus}.
|
||||
*
|
||||
* @param pageable
|
||||
* page parameter
|
||||
@@ -629,9 +657,9 @@ public interface TargetManagement {
|
||||
|
||||
/**
|
||||
* Initiates {@link TargetType} assignment to given {@link Target}s. If some
|
||||
* targets in the list have the {@link TargetType} not yet assigned, they
|
||||
* will get assigned. If all targets are already of that type, there will be
|
||||
* no un-assignment.
|
||||
* targets in the list have the {@link TargetType} not yet assigned, they will
|
||||
* get assigned. If all targets are already of that type, there will be no
|
||||
* un-assignment.
|
||||
*
|
||||
* @param controllerIds
|
||||
* to set the type to
|
||||
@@ -647,8 +675,8 @@ public interface TargetManagement {
|
||||
TargetTypeAssignmentResult assignType(@NotEmpty Collection<String> controllerIds, @NotNull Long typeId);
|
||||
|
||||
/**
|
||||
* Initiates {@link TargetType} un-assignment to given {@link Target}s. The
|
||||
* type of the targets will be set to {@code null}
|
||||
* Initiates {@link TargetType} un-assignment to given {@link Target}s. The type
|
||||
* of the targets will be set to {@code null}
|
||||
*
|
||||
* @param controllerIds
|
||||
* to remove the type from
|
||||
@@ -710,8 +738,8 @@ public interface TargetManagement {
|
||||
* @throws EntityNotFoundException
|
||||
* if given target does not exist
|
||||
* @throws ConstraintViolationException
|
||||
* if fields are not filled as specified. Check
|
||||
* {@link TargetUpdate} for field constraints.
|
||||
* if fields are not filled as specified. Check {@link TargetUpdate}
|
||||
* for field constraints.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
Target update(@NotNull @Valid TargetUpdate update);
|
||||
@@ -797,30 +825,29 @@ public interface TargetManagement {
|
||||
boolean existsByControllerId(@NotEmpty String controllerId);
|
||||
|
||||
/**
|
||||
* Verify if a target matches a specific target filter query, does not have
|
||||
* a specific DS already assigned and is compatible with it.
|
||||
* Verify if a target matches a specific target filter query, does not have a
|
||||
* specific DS already assigned and is compatible with it.
|
||||
*
|
||||
* @param controllerId
|
||||
* of the {@link org.eclipse.hawkbit.repository.model.Target} to
|
||||
* check
|
||||
* @param distributionSetId
|
||||
* of the
|
||||
* {@link org.eclipse.hawkbit.repository.model.DistributionSet}
|
||||
* to consider
|
||||
* {@link org.eclipse.hawkbit.repository.model.DistributionSet} to
|
||||
* consider
|
||||
* @param targetFilterQuery
|
||||
* to execute
|
||||
* @return true if it matches
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET)
|
||||
boolean isTargetMatchingQueryAndDSNotAssignedAndCompatible(@NotNull String controllerId, long distributionSetId,
|
||||
@NotNull String targetFilterQuery);
|
||||
boolean isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(@NotNull String controllerId,
|
||||
long distributionSetId, @NotNull String targetFilterQuery);
|
||||
|
||||
/**
|
||||
* Creates a list of target meta data entries.
|
||||
*
|
||||
* @param controllerId
|
||||
* {@link Target} controller id the metadata has to be created
|
||||
* for
|
||||
* {@link Target} controller id the metadata has to be created for
|
||||
* @param metadata
|
||||
* the meta data entries to create or update
|
||||
* @return the updated or created target metadata entries
|
||||
@@ -829,12 +856,12 @@ public interface TargetManagement {
|
||||
* if given target does not exist
|
||||
*
|
||||
* @throws EntityAlreadyExistsException
|
||||
* in case one of the metadata entry already exists for the
|
||||
* specific key
|
||||
* in case one of the metadata entry already exists for the specific
|
||||
* key
|
||||
*
|
||||
* @throws AssignmentQuotaExceededException
|
||||
* if the maximum number of {@link MetaData} entries is exceeded
|
||||
* for the addressed {@link Target}
|
||||
* if the maximum number of {@link MetaData} entries is exceeded for
|
||||
* the addressed {@link Target}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
List<TargetMetadata> createMetaData(@NotEmpty String controllerId, @NotEmpty Collection<MetaData> metadata);
|
||||
@@ -928,15 +955,13 @@ public interface TargetManagement {
|
||||
* Updates a target meta data value if corresponding entry exists.
|
||||
*
|
||||
* @param controllerId
|
||||
* {@link Target} controller id of the metadata entry to be
|
||||
* updated
|
||||
* {@link Target} controller id of the metadata entry to be updated
|
||||
* @param metadata
|
||||
* meta data entry to be updated
|
||||
* @return the updated meta data entry
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* in case the metadata entry does not exist and cannot be
|
||||
* updated
|
||||
* in case the metadata entry does not exist and cannot be updated
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
TargetMetadata updateMetadata(@NotEmpty String controllerId, @NotNull MetaData metadata);
|
||||
|
||||
@@ -15,7 +15,10 @@ import java.util.Optional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaTenantAwareBaseEntity;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.BaseEntityRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.NoCountSliceRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -26,6 +29,7 @@ import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -54,6 +58,9 @@ public final class JpaManagementHelper {
|
||||
}
|
||||
|
||||
public static <J> Specification<J> combineWithAnd(final List<Specification<J>> specList) {
|
||||
if (ObjectUtils.isEmpty(specList)) {
|
||||
return Specification.where(null);
|
||||
}
|
||||
return specList.size() == 1 ? specList.get(0) : SpecificationsBuilder.combineWithAnd(specList);
|
||||
}
|
||||
|
||||
|
||||
@@ -520,10 +520,10 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
||||
|
||||
final String baseFilter = RolloutHelper.getTargetFilterQuery(rollout);
|
||||
final String groupTargetFilter;
|
||||
if (StringUtils.isEmpty(group.getTargetFilterQuery())) {
|
||||
groupTargetFilter = baseFilter;
|
||||
} else {
|
||||
if (StringUtils.hasText(group.getTargetFilterQuery())) {
|
||||
groupTargetFilter = baseFilter + ";" + group.getTargetFilterQuery();
|
||||
} else {
|
||||
groupTargetFilter = baseFilter;
|
||||
}
|
||||
|
||||
final List<Long> readyGroups = RolloutHelper.getGroupsByStatusIncludingGroup(rollout.getRolloutGroups(),
|
||||
|
||||
@@ -101,6 +101,7 @@ import org.eclipse.hawkbit.repository.jpa.management.JpaTargetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTenantStatsManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
@@ -1038,13 +1039,12 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
final DistributionSetManagement distributionSetManagement, final RolloutManagement rolloutManagement,
|
||||
final DeploymentManagement deploymentManagement,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement, final ActionRepository actionRepository,
|
||||
final PlatformTransactionManager txManager,
|
||||
final RepositoryProperties repositoryProperties, final TenantAware tenantAware,
|
||||
final LockRegistry lockRegistry) {
|
||||
final PlatformTransactionManager txManager, final RepositoryProperties repositoryProperties,
|
||||
final TenantAware tenantAware, final LockRegistry lockRegistry,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
return new JpaDistributionSetInvalidationManagement(distributionSetManagement, rolloutManagement,
|
||||
deploymentManagement, targetFilterQueryManagement, actionRepository,
|
||||
txManager, repositoryProperties, tenantAware,
|
||||
lockRegistry);
|
||||
deploymentManagement, targetFilterQueryManagement, actionRepository, txManager, repositoryProperties,
|
||||
tenantAware, lockRegistry, systemSecurityContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1080,10 +1080,12 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
@Autowired(required = false) final AccessController<JpaDistributionSetType> distributionSetTypeAccessController,
|
||||
@Autowired(required = false) final AccessController<JpaDistributionSet> distributionSetAccessController,
|
||||
@Autowired(required = false) final AccessController<JpaTargetType> targetTypeAccessControlManager,
|
||||
@Autowired(required = false) final AccessController<JpaTarget> targetAccessControlManager) {
|
||||
@Autowired(required = false) final AccessController<JpaTarget> targetAccessControlManager,
|
||||
@Autowired(required = false) final AccessController<JpaAction> actionAccessController) {
|
||||
return new BeanPostProcessor() {
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(@NonNull final Object bean, @NonNull final String beanName) throws BeansException {
|
||||
public Object postProcessAfterInitialization(@NonNull final Object bean, @NonNull final String beanName)
|
||||
throws BeansException {
|
||||
if (bean instanceof LocalArtifactRepository repo) {
|
||||
return repo.withACM(artifactAccessController);
|
||||
} else if (bean instanceof SoftwareModuleTypeRepository repo) {
|
||||
@@ -1098,6 +1100,8 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
return repo.withACM(targetTypeAccessControlManager);
|
||||
} else if (bean instanceof TargetRepository repo) {
|
||||
return repo.withACM(targetAccessControlManager);
|
||||
} else if (bean instanceof ActionRepository repo) {
|
||||
return repo.withACM(actionAccessController);
|
||||
}
|
||||
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ public class AutoAssignChecker extends AbstractAutoAssignExecutor {
|
||||
LOGGER.debug("Auto assign check call for tenant {} and target filter query id {} for device {} started",
|
||||
getContextAware().getCurrentTenant(), targetFilterQuery.getId(), controllerId);
|
||||
try {
|
||||
final boolean controllerIdMatches = targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(
|
||||
final boolean controllerIdMatches = targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(
|
||||
controllerId, targetFilterQuery.getAutoAssignDistributionSet().getId(),
|
||||
targetFilterQuery.getQuery());
|
||||
|
||||
|
||||
@@ -308,7 +308,6 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||
throwExceptionIfSoftwareModuleDoesNotExist(moduleId);
|
||||
|
||||
// TODO AC - REVIEW
|
||||
// it used to perform 3-table join query
|
||||
// @Query("Select a from JpaAction a join a.distributionSet ds join ds.modules modul where a.target.controllerId = :target and modul.id = :module order by a.id desc")
|
||||
// final List<Action> actions = actionRepository.findActionByTargetAndSoftwareModule(controllerId, moduleId);
|
||||
|
||||
@@ -158,14 +158,14 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
private final RetryTemplate retryTemplate;
|
||||
|
||||
public JpaDeploymentManagement(final EntityManager entityManager, final ActionRepository actionRepository,
|
||||
final DistributionSetManagement distributionSetManagement,
|
||||
final DistributionSetRepository distributionSetRepository, final TargetRepository targetRepository,
|
||||
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
|
||||
final EventPublisherHolder eventPublisherHolder, final AfterTransactionCommitExecutor afterCommit,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final Database database,
|
||||
final RepositoryProperties repositoryProperties) {
|
||||
final DistributionSetManagement distributionSetManagement,
|
||||
final DistributionSetRepository distributionSetRepository, final TargetRepository targetRepository,
|
||||
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
|
||||
final EventPublisherHolder eventPublisherHolder, final AfterTransactionCommitExecutor afterCommit,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final Database database,
|
||||
final RepositoryProperties repositoryProperties) {
|
||||
super(actionRepository, actionStatusRepository, quotaManagement, repositoryProperties);
|
||||
this.entityManager = entityManager;
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
@@ -240,10 +240,10 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
deploymentRequests = deploymentRequests.stream().distinct().toList();
|
||||
checkForMultiAssignment(deploymentRequests);
|
||||
checkQuotaForAssignment(deploymentRequests);
|
||||
// validates READ access to deployment sets, throws exception if deployment set is not accessible
|
||||
// validates READ access to deployment sets, throws exception if deployment set
|
||||
// is not accessible
|
||||
checkForTargetTypeCompatibility(deploymentRequests);
|
||||
// filters only targets that are updatable
|
||||
// TODO - should assignments that contain non-existing/allowed devices be allowed anyway?
|
||||
return filterByTargetUpdatable(deploymentRequests);
|
||||
}
|
||||
|
||||
@@ -313,16 +313,12 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
}
|
||||
|
||||
private List<DeploymentRequest> filterByTargetUpdatable(final List<DeploymentRequest> deploymentRequests) {
|
||||
final List<String> controllerIds =
|
||||
deploymentRequests.stream()
|
||||
.map(DeploymentRequest::getControllerId)
|
||||
.distinct()
|
||||
.toList();
|
||||
final List<String> controllerIds = deploymentRequests.stream().map(DeploymentRequest::getControllerId)
|
||||
.distinct().toList();
|
||||
|
||||
final List<String> found = targetRepository.findAll(
|
||||
AccessController.Operation.UPDATE,
|
||||
TargetSpecifications.hasControllerIdIn(controllerIds)
|
||||
).stream().map(JpaTarget::getControllerId).toList();
|
||||
final List<String> found = targetRepository
|
||||
.findAll(AccessController.Operation.UPDATE, TargetSpecifications.hasControllerIdIn(controllerIds))
|
||||
.stream().map(JpaTarget::getControllerId).toList();
|
||||
if (found.size() != controllerIds.size()) {
|
||||
return deploymentRequests.stream()
|
||||
.filter(deploymentRequest -> found.contains(deploymentRequest.getControllerId())).toList();
|
||||
@@ -384,8 +380,8 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
|
||||
final List<String> existingTargetIds = Lists.partition(providedTargetIds, Constants.MAX_ENTRIES_IN_STATEMENT)
|
||||
.stream()
|
||||
.map(ids -> targetRepository.findAll(
|
||||
AccessController.Operation.UPDATE, TargetSpecifications.hasControllerIdIn(ids)))
|
||||
.map(ids -> targetRepository.findAll(AccessController.Operation.UPDATE,
|
||||
TargetSpecifications.hasControllerIdIn(ids)))
|
||||
.flatMap(List::stream).map(JpaTarget::getControllerId).toList();
|
||||
|
||||
final List<JpaTarget> targetEntities = assignmentStrategy.findTargetsForAssignment(existingTargetIds,
|
||||
@@ -490,9 +486,10 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
public void cancelInactiveScheduledActionsForTargets(final List<Long> targetIds) {
|
||||
if (!isMultiAssignmentsEnabled()) {
|
||||
targetRepository.getAccessController().ifPresent(v -> {
|
||||
if (targetRepository.count(AccessController.Operation.UPDATE, TargetSpecifications.hasIdIn(targetIds)) != targetIds.size()) {
|
||||
throw new EntityNotFoundException(Target.class, targetIds);
|
||||
}
|
||||
if (targetRepository.count(AccessController.Operation.UPDATE,
|
||||
TargetSpecifications.hasIdIn(targetIds)) != targetIds.size()) {
|
||||
throw new EntityNotFoundException(Target.class, targetIds);
|
||||
}
|
||||
});
|
||||
actionRepository.switchStatus(Status.CANCELED, targetIds, false, Status.SCHEDULED);
|
||||
} else {
|
||||
@@ -776,24 +773,21 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
|
||||
@Override
|
||||
public Optional<Action> findAction(final long actionId) {
|
||||
return actionRepository
|
||||
.findById(actionId)
|
||||
return actionRepository.findById(actionId)
|
||||
.filter(action -> targetRepository.exists(TargetSpecifications.hasId(action.getTarget().getId())))
|
||||
.map(JpaAction.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Action> findActionWithDetails(final long actionId) {
|
||||
return actionRepository
|
||||
.findWithDetailsById(actionId)
|
||||
return actionRepository.findWithDetailsById(actionId)
|
||||
.filter(action -> targetRepository.exists(TargetSpecifications.hasId(action.getTarget().getId())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Action> findActionsByTarget(final String controllerId, final Pageable pageable) {
|
||||
assertTargetReadAllowed(controllerId);
|
||||
return actionRepository
|
||||
.findAll(ActionSpecifications.byTargetControllerId(controllerId), pageable)
|
||||
return actionRepository.findAll(ActionSpecifications.byTargetControllerId(controllerId), pageable)
|
||||
.map(Action.class::cast);
|
||||
}
|
||||
|
||||
@@ -853,8 +847,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Action forceTargetAction(final long actionId) {
|
||||
final JpaAction action = actionRepository.findById(actionId)
|
||||
.map(this::assertTargetUpdateAllowed)
|
||||
final JpaAction action = actionRepository.findById(actionId).map(this::assertTargetUpdateAllowed)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
||||
|
||||
if (!action.isForcedOrTimeForced()) {
|
||||
@@ -878,7 +871,8 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
return actionStatusRepository.countByActionId(actionId);
|
||||
}
|
||||
|
||||
// action is already got and there are checked read permissions - do not check permissions
|
||||
// action is already got and there are checked read permissions - do not check
|
||||
// permissions
|
||||
// and UI which is to be removed
|
||||
@Override
|
||||
public Page<String> findMessagesByActionStatusId(final Pageable pageable, final long actionStatusId) {
|
||||
@@ -921,15 +915,11 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
return JpaManagementHelper.countBySpec(actionRepository, specList);
|
||||
}
|
||||
|
||||
// TODO - return via Mgmt API all actions (event for targets the use has no access - check if should and could
|
||||
// be limited
|
||||
@Override
|
||||
public Slice<Action> findActionsAll(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(actionRepository, pageable, null);
|
||||
}
|
||||
|
||||
// TODO - return via Mgmt API all actions (event for targets the use has no access - check if should and could
|
||||
// be limited
|
||||
@Override
|
||||
public Slice<Action> findActions(final String rsqlParam, final Pageable pageable) {
|
||||
final List<Specification<JpaAction>> specList = List.of(
|
||||
@@ -983,8 +973,8 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
public boolean hasPendingCancellations(final Long targetId) {
|
||||
// target access checked in assertTargetReadAllowed
|
||||
assertTargetReadAllowed(targetId);
|
||||
return actionRepository.exists(
|
||||
ActionSpecifications.byTargetIdAndIsActiveAndStatus(targetId, Action.Status.CANCELING));
|
||||
return actionRepository
|
||||
.exists(ActionSpecifications.byTargetIdAndIsActiveAndStatus(targetId, Action.Status.CANCELING));
|
||||
}
|
||||
|
||||
private static String getQueryForDeleteActionsByStatusAndLastModifiedBeforeString(final Database database) {
|
||||
@@ -1039,29 +1029,33 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void cancelActionsForDistributionSet(
|
||||
final CancelationType cancelationType, final DistributionSet distributionSet) {
|
||||
actionRepository
|
||||
.findAll(ActionSpecifications.byDistributionSetIdAndActiveAndStatusIsNot(distributionSet.getId(), Status.CANCELING))
|
||||
public void cancelActionsForDistributionSet(final CancelationType cancelationType,
|
||||
final DistributionSet distributionSet) {
|
||||
actionRepository.findAll(ActionSpecifications
|
||||
.byDistributionSetIdAndActiveAndStatusIsNot(distributionSet.getId(), Status.CANCELING))
|
||||
.forEach(action -> {
|
||||
try {
|
||||
assertTargetUpdateAllowed(action);
|
||||
cancelAction(action.getId());
|
||||
LOG.debug("Action {} canceled", action.getId());
|
||||
} catch (final InsufficientPermissionException e) {
|
||||
// no access - skip it
|
||||
LOG.trace("Could not cancel action {} due to insufficient permissions.", action.getId(), e);
|
||||
} catch (final EntityNotFoundException e) {
|
||||
LOG.trace("Could not cancel action {} due to entity not found exception.", action.getId(), e);
|
||||
}
|
||||
});
|
||||
if (cancelationType == CancelationType.FORCE) {
|
||||
actionRepository
|
||||
.findAll(ActionSpecifications.byDistributionSetIdAndActive(distributionSet.getId()))
|
||||
actionRepository.findAll(ActionSpecifications.byDistributionSetIdAndActive(distributionSet.getId()))
|
||||
.forEach(action -> {
|
||||
try {
|
||||
assertTargetUpdateAllowed(action);
|
||||
forceQuitAction(action.getId());
|
||||
LOG.debug("Action {} force canceled", action.getId());
|
||||
} catch (final InsufficientPermissionException e) {
|
||||
// no access - skip it
|
||||
LOG.trace("Could not cancel action {} due to insufficient permissions.", action.getId(), e);
|
||||
} catch (final EntityNotFoundException e) {
|
||||
LOG.trace("Could not cancel action {} due to entity not found exception.", action.getId(),
|
||||
e);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1080,9 +1074,12 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
}
|
||||
|
||||
private JpaAction assertTargetUpdateAllowed(final JpaAction action) {
|
||||
if (!targetRepository.exists(TargetSpecifications.hasId(action.getTarget().getId()))) {
|
||||
targetRepository.findOne(TargetSpecifications.hasId(action.getTarget().getId())).ifPresentOrElse(target -> {
|
||||
targetRepository.getAccessController()
|
||||
.ifPresent(acm -> acm.assertOperationAllowed(AccessController.Operation.UPDATE, target));
|
||||
}, () -> {
|
||||
throw new EntityNotFoundException(Action.class, action);
|
||||
}
|
||||
});
|
||||
return action;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation.CancelationType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidationCount;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -50,13 +51,14 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet
|
||||
private final RepositoryProperties repositoryProperties;
|
||||
private final TenantAware tenantAware;
|
||||
private final LockRegistry lockRegistry;
|
||||
private final SystemSecurityContext systemSecurityContext;
|
||||
|
||||
public JpaDistributionSetInvalidationManagement(final DistributionSetManagement distributionSetManagement,
|
||||
final RolloutManagement rolloutManagement, final DeploymentManagement deploymentManagement,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement, final ActionRepository actionRepository,
|
||||
final PlatformTransactionManager txManager,
|
||||
final RepositoryProperties repositoryProperties, final TenantAware tenantAware,
|
||||
final LockRegistry lockRegistry) {
|
||||
final PlatformTransactionManager txManager, final RepositoryProperties repositoryProperties,
|
||||
final TenantAware tenantAware, final LockRegistry lockRegistry,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.rolloutManagement = rolloutManagement;
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
@@ -66,13 +68,13 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet
|
||||
this.repositoryProperties = repositoryProperties;
|
||||
this.tenantAware = tenantAware;
|
||||
this.lockRegistry = lockRegistry;
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateDistributionSet(final DistributionSetInvalidation distributionSetInvalidation) {
|
||||
LOG.debug("Invalidate distribution sets {}", distributionSetInvalidation.getDistributionSetIds());
|
||||
final String tenant = tenantAware.getCurrentTenant();
|
||||
|
||||
if (shouldRolloutsBeCanceled(distributionSetInvalidation.getCancelationType(),
|
||||
distributionSetInvalidation.isCancelRollouts())) {
|
||||
final String handlerId = JpaRolloutManagement.createRolloutLockKey(tenant);
|
||||
@@ -95,6 +97,7 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet
|
||||
// no lock is needed as no rollout will be stopped
|
||||
invalidateDistributionSetsInTransaction(distributionSetInvalidation, tenant);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void invalidateDistributionSetsInTransaction(final DistributionSetInvalidation distributionSetInvalidation,
|
||||
@@ -110,17 +113,25 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet
|
||||
final boolean cancelRollouts) {
|
||||
final DistributionSet set = distributionSetManagement.getValidAndComplete(setId);
|
||||
distributionSetManagement.invalidate(set);
|
||||
LOG.debug("Distribution set {} set to invalid", setId);
|
||||
LOG.debug("Distribution set {} marked as invalid.", setId);
|
||||
|
||||
// rollout cancellation should only be permitted with UPDATE_ROLLOUT permission
|
||||
if (shouldRolloutsBeCanceled(cancelationType, cancelRollouts)) {
|
||||
LOG.debug("Cancel rollouts after ds invalidation. ID: {}", setId);
|
||||
rolloutManagement.cancelRolloutsForDistributionSet(set);
|
||||
}
|
||||
|
||||
if (cancelationType != CancelationType.NONE) {
|
||||
deploymentManagement.cancelActionsForDistributionSet(cancelationType, set);
|
||||
}
|
||||
// Do run as system to ensure all actions (even invisible) are canceled due to invalidation.
|
||||
systemSecurityContext.runAsSystem(() -> {
|
||||
if (cancelationType != CancelationType.NONE) {
|
||||
LOG.debug("Cancel actions after ds invalidation. ID: {}", setId);
|
||||
deploymentManagement.cancelActionsForDistributionSet(cancelationType, set);
|
||||
}
|
||||
|
||||
targetFilterQueryManagement.cancelAutoAssignmentForDistributionSet(setId);
|
||||
LOG.debug("Cancel auto assignments after ds invalidation. ID: {}", setId);
|
||||
targetFilterQueryManagement.cancelAutoAssignmentForDistributionSet(setId);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean shouldRolloutsBeCanceled(final CancelationType cancelationType,
|
||||
@@ -131,13 +142,16 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet
|
||||
@Override
|
||||
public DistributionSetInvalidationCount countEntitiesForInvalidation(
|
||||
final DistributionSetInvalidation distributionSetInvalidation) {
|
||||
final Collection<Long> setIds = distributionSetInvalidation.getDistributionSetIds();
|
||||
final long rolloutsCount = shouldRolloutsBeCanceled(distributionSetInvalidation.getCancelationType(),
|
||||
distributionSetInvalidation.isCancelRollouts()) ? countRolloutsForInvalidation(setIds) : 0;
|
||||
final long autoAssignmentsCount = countAutoAssignmentsForInvalidation(setIds);
|
||||
final long actionsCount = countActionsForInvalidation(setIds, distributionSetInvalidation.getCancelationType());
|
||||
return systemSecurityContext.runAsSystem(() -> {
|
||||
final Collection<Long> setIds = distributionSetInvalidation.getDistributionSetIds();
|
||||
final long rolloutsCount = shouldRolloutsBeCanceled(distributionSetInvalidation.getCancelationType(),
|
||||
distributionSetInvalidation.isCancelRollouts()) ? countRolloutsForInvalidation(setIds) : 0;
|
||||
final long autoAssignmentsCount = countAutoAssignmentsForInvalidation(setIds);
|
||||
final long actionsCount = countActionsForInvalidation(setIds,
|
||||
distributionSetInvalidation.getCancelationType());
|
||||
|
||||
return new DistributionSetInvalidationCount(rolloutsCount, autoAssignmentsCount, actionsCount);
|
||||
return new DistributionSetInvalidationCount(rolloutsCount, autoAssignmentsCount, actionsCount);
|
||||
});
|
||||
}
|
||||
|
||||
private long countRolloutsForInvalidation(final Collection<Long> setIds) {
|
||||
@@ -163,7 +177,9 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet
|
||||
}
|
||||
|
||||
private long countActionsForSoftInvalidation(final Collection<Long> setIds) {
|
||||
return setIds.stream().mapToLong(distributionSet -> actionRepository
|
||||
.countByDistributionSetIdAndActiveIsTrueAndStatusIsNot(distributionSet, Status.CANCELING)).sum();
|
||||
return setIds.stream()
|
||||
.mapToLong(distributionSet -> actionRepository
|
||||
.countByDistributionSetIdAndActiveIsTrueAndStatusIsNot(distributionSet, Status.CANCELING))
|
||||
.sum();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -786,7 +786,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
public void invalidate(final DistributionSet distributionSet) {
|
||||
final JpaDistributionSet jpaSet = (JpaDistributionSet) distributionSet;
|
||||
jpaSet.invalidate();
|
||||
distributionSetRepository.save(AccessController.Operation.DELETE, jpaSet);
|
||||
distributionSetRepository.save(jpaSet);
|
||||
}
|
||||
|
||||
private JpaDistributionSet getById(final long id) {
|
||||
|
||||
@@ -96,6 +96,8 @@ import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import static org.eclipse.hawkbit.repository.jpa.JpaManagementHelper.combineWithAnd;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link TargetManagement}.
|
||||
*
|
||||
@@ -130,7 +132,6 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
private final Database database;
|
||||
|
||||
|
||||
public JpaTargetManagement(final EntityManager entityManager,
|
||||
final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
|
||||
final TargetRepository targetRepository, final TargetTypeRepository targetTypeRepository,
|
||||
@@ -138,8 +139,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
final RolloutGroupRepository rolloutGroupRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
final TargetTagRepository targetTagRepository, final EventPublisherHolder eventPublisherHolder,
|
||||
final TenantAware tenantAware,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database) {
|
||||
final TenantAware tenantAware, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final Database database) {
|
||||
this.entityManager = entityManager;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.quotaManagement = quotaManagement;
|
||||
@@ -161,8 +162,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
}
|
||||
|
||||
private JpaTarget getByControllerIdAndThrowIfNotFound(final String controllerId) {
|
||||
return targetRepository
|
||||
.findOne(TargetSpecifications.hasControllerId(controllerId))
|
||||
return targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId))
|
||||
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
||||
}
|
||||
|
||||
@@ -255,6 +255,9 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
final JpaTarget target = JpaManagementHelper.touch(entityManager, targetRepository,
|
||||
getByControllerIdAndThrowIfNotFound(controllerId));
|
||||
|
||||
targetRepository.getAccessController()
|
||||
.ifPresent(acm -> acm.assertOperationAllowed(AccessController.Operation.UPDATE, target));
|
||||
|
||||
targetMetadataRepository.deleteById(metadata.getId());
|
||||
// target update event is set to ignore "lastModifiedAt" field, so it is
|
||||
// not send automatically within the touch() method
|
||||
@@ -312,17 +315,14 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetFilterQuery.class, targetFilterQueryId));
|
||||
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(targetRepository, pageable,
|
||||
List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery.getQuery(), TargetFields.class,
|
||||
virtualPropertyReplacer, database)));
|
||||
List.of(RSQLUtility.buildRsqlSpecification(targetFilterQuery.getQuery(), TargetFields.class,
|
||||
virtualPropertyReplacer, database)));
|
||||
}
|
||||
|
||||
@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
|
||||
@@ -481,7 +481,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
final TargetTag tag = targetTagRepository.findByNameEquals(tagName)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetTag.class, tagName));
|
||||
final List<JpaTarget> allTargets = targetRepository
|
||||
.findAll(AccessController.Operation.UPDATE, TargetSpecifications.byControllerIdWithTagsInJoin(controllerIds));
|
||||
.findAll(TargetSpecifications.byControllerIdWithTagsInJoin(controllerIds));
|
||||
if (allTargets.size() < controllerIds.size()) {
|
||||
throw new EntityNotFoundException(Target.class, controllerIds,
|
||||
allTargets.stream().map(Target::getControllerId).toList());
|
||||
@@ -492,6 +492,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
// all are already assigned -> unassign
|
||||
if (alreadyAssignedTargets.size() == allTargets.size()) {
|
||||
|
||||
alreadyAssignedTargets.forEach(target -> target.removeTag(tag));
|
||||
return new TargetTagAssignmentResult(0, Collections.emptyList(),
|
||||
Collections.unmodifiableList(alreadyAssignedTargets), tag);
|
||||
@@ -501,9 +502,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
// some or none are assigned -> assign
|
||||
allTargets.forEach(target -> target.addTag(tag));
|
||||
final TargetTagAssignmentResult result = new TargetTagAssignmentResult(alreadyAssignedTargets.size(),
|
||||
Collections
|
||||
.unmodifiableList(allTargets.stream().map(targetRepository::save).collect(Collectors.toList())),
|
||||
Collections.emptyList(), tag);
|
||||
targetRepository.saveAll(allTargets), Collections.emptyList(), tag);
|
||||
|
||||
// no reason to persist the tag
|
||||
entityManager.detach(tag);
|
||||
@@ -528,7 +527,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
targetsWithoutSameType.forEach(target -> target.setTargetType(type));
|
||||
|
||||
final TargetTypeAssignmentResult result = new TargetTypeAssignmentResult(targetsWithSameType.size(),
|
||||
targetsWithoutSameType.stream().map(targetRepository::save).toList(), Collections.emptyList(), type);
|
||||
targetRepository.saveAll(targetsWithoutSameType), Collections.emptyList(), type);
|
||||
|
||||
// no reason to persist the type
|
||||
entityManager.detach(type);
|
||||
@@ -566,12 +565,15 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<Target> assignTag(final Collection<String> controllerIds, final long tagId) {
|
||||
final List<JpaTarget> allTargets = targetRepository
|
||||
.findAll(AccessController.Operation.UPDATE, TargetSpecifications.byControllerIdWithTagsInJoin(controllerIds));
|
||||
.findAll(TargetSpecifications.byControllerIdWithTagsInJoin(controllerIds));
|
||||
if (allTargets.size() < controllerIds.size()) {
|
||||
throw new EntityNotFoundException(Target.class, controllerIds,
|
||||
allTargets.stream().map(Target::getControllerId).toList());
|
||||
}
|
||||
|
||||
targetRepository.getAccessController()
|
||||
.ifPresent(acm -> acm.assertOperationAllowed(AccessController.Operation.UPDATE, allTargets));
|
||||
|
||||
final JpaTargetTag tag = targetTagRepository.findById(tagId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetTag.class, tagId));
|
||||
|
||||
@@ -619,6 +621,11 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Target assignType(final String controllerId, final Long targetTypeId) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId);
|
||||
|
||||
targetRepository.getAccessController().ifPresent(acm -> {
|
||||
acm.assertOperationAllowed(AccessController.Operation.UPDATE, target);
|
||||
});
|
||||
|
||||
final JpaTargetType targetType = getTargetTypeByIdAndThrowIfNotFound(targetTypeId);
|
||||
target.setTargetType(targetType);
|
||||
return targetRepository.save(target);
|
||||
@@ -626,7 +633,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByFilterOrderByLinkedDistributionSet(final Pageable pageable,
|
||||
final long orderByDistributionSetId, final FilterParams filterParams) {
|
||||
final long orderByDistributionSetId, final FilterParams filterParams) {
|
||||
// remove default sort from pageable to not overwrite sorted spec
|
||||
final OffsetBasedPageRequest unsortedPage = new OffsetBasedPageRequest(pageable.getOffset(),
|
||||
pageable.getPageSize(), Sort.unsorted());
|
||||
@@ -661,41 +668,42 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(final Pageable pageRequest,
|
||||
final long distributionSetId, final String targetFilterQuery) {
|
||||
final long distributionSetId, final String targetFilterQuery) {
|
||||
final DistributionSet jpaDistributionSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
final Long distSetTypeId = jpaDistributionSet.getType().getId();
|
||||
|
||||
return targetRepository.findAllWithoutCount(
|
||||
AccessController.Operation.UPDATE,
|
||||
JpaManagementHelper.combineWithAnd(List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))),
|
||||
pageRequest).map(Target.class::cast);
|
||||
return targetRepository
|
||||
.findAllWithoutCount(AccessController.Operation.UPDATE,
|
||||
combineWithAnd(List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class,
|
||||
virtualPropertyReplacer, database),
|
||||
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))),
|
||||
pageRequest)
|
||||
.map(Target.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByTargetFilterQueryAndNotInRolloutGroupsAndCompatibleAndUpdatable(
|
||||
final Pageable pageRequest, final Collection<Long> groups, final String targetFilterQuery,
|
||||
final DistributionSetType dsType) {
|
||||
return targetRepository.findAllWithoutCount(
|
||||
AccessController.Operation.UPDATE,
|
||||
JpaManagementHelper.combineWithAnd(List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))),
|
||||
pageRequest).map(Target.class::cast);
|
||||
return targetRepository
|
||||
.findAllWithoutCount(AccessController.Operation.UPDATE,
|
||||
combineWithAnd(List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class,
|
||||
virtualPropertyReplacer, database),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))),
|
||||
pageRequest)
|
||||
.map(Target.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByFailedRolloutAndNotInRolloutGroups(Pageable pageRequest, Collection<Long> groups,
|
||||
String rolloutId) {
|
||||
String rolloutId) {
|
||||
final List<Specification<JpaTarget>> specList = Arrays.asList(
|
||||
TargetSpecifications.failedActionsForRollout(rolloutId),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups)
|
||||
);
|
||||
TargetSpecifications.failedActionsForRollout(rolloutId),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups));
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, pageRequest, specList);
|
||||
}
|
||||
@@ -712,34 +720,34 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public long countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(final Collection<Long> groups,
|
||||
final String targetFilterQuery, final DistributionSetType dsType) {
|
||||
return targetRepository.count(AccessController.Operation.UPDATE, JpaManagementHelper.combineWithAnd(
|
||||
List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))));
|
||||
final String targetFilterQuery, final DistributionSetType dsType) {
|
||||
return targetRepository.count(AccessController.Operation.UPDATE,
|
||||
combineWithAnd(List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class,
|
||||
virtualPropertyReplacer, database),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByFailedRolloutAndNotInRolloutGroups(Collection<Long> groups, String rolloutId) {
|
||||
final List<Specification<JpaTarget>> specList = Arrays.asList(
|
||||
TargetSpecifications.failedActionsForRollout(rolloutId),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups));
|
||||
TargetSpecifications.failedActionsForRollout(rolloutId),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups));
|
||||
|
||||
return JpaManagementHelper.countBySpec(targetRepository, specList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByRsqlAndNonDSAndCompatibleAndUpdatable(final long distributionSetId,
|
||||
final String targetFilterQuery) {
|
||||
final String targetFilterQuery) {
|
||||
final DistributionSet jpaDistributionSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
final Long distSetTypeId = jpaDistributionSet.getType().getId();
|
||||
|
||||
return targetRepository.count(AccessController.Operation.UPDATE, JpaManagementHelper.combineWithAnd(
|
||||
List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
return targetRepository.count(AccessController.Operation.UPDATE,
|
||||
combineWithAnd(List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class,
|
||||
virtualPropertyReplacer, database),
|
||||
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))));
|
||||
}
|
||||
@@ -798,27 +806,38 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@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 countByRsqlAndCompatible(final String targetFilterQuery, final Long distributionSetId) {
|
||||
final List<Specification<JpaTarget>> specList = List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetId));
|
||||
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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByRsqlAndCompatible(final String targetFilterQuery, final Long distributionSetIdTypeId) {
|
||||
final List<Specification<JpaTarget>> specList = List.of(RSQLUtility.buildRsqlSpecification(targetFilterQuery,
|
||||
TargetFields.class, virtualPropertyReplacer, database),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetIdTypeId));
|
||||
|
||||
return JpaManagementHelper.countBySpec(targetRepository, specList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByRsqlAndCompatibleAndUpdatable(String targetFilterQuery, Long distributionSetIdTypeId) {
|
||||
final List<Specification<JpaTarget>> specList = List.of(RSQLUtility.buildRsqlSpecification(targetFilterQuery,
|
||||
TargetFields.class, virtualPropertyReplacer, database),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetIdTypeId));
|
||||
return targetRepository.count(AccessController.Operation.UPDATE, combineWithAnd(specList));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByFailedInRollout(final String rolloutId, final Long dsTypeId) {
|
||||
final List<Specification<JpaTarget>> specList = List.of(
|
||||
TargetSpecifications.failedActionsForRollout(rolloutId));
|
||||
final List<Specification<JpaTarget>> specList = List
|
||||
.of(TargetSpecifications.failedActionsForRollout(rolloutId));
|
||||
|
||||
return JpaManagementHelper.countBySpec(targetRepository, specList);
|
||||
}
|
||||
@@ -856,6 +875,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Override
|
||||
public void requestControllerAttributes(final String controllerId) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId);
|
||||
targetRepository.getAccessController()
|
||||
.ifPresent(acm -> acm.assertOperationAllowed(AccessController.Operation.UPDATE, target));
|
||||
target.setRequestControllerAttributes(true);
|
||||
eventPublisherHolder.getEventPublisher()
|
||||
.publishEvent(new TargetAttributesRequestedEvent(tenantAware.getCurrentTenant(), target.getId(),
|
||||
@@ -876,7 +897,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTargetMatchingQueryAndDSNotAssignedAndCompatible(final String controllerId,
|
||||
public boolean isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(final String controllerId,
|
||||
final long distributionSetId, final String targetFilterQuery) {
|
||||
RSQLUtility.validateRsqlFor(targetFilterQuery, TargetFields.class);
|
||||
final DistributionSet ds = distributionSetManagement.get(distributionSetId)
|
||||
@@ -891,7 +912,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
final Specification<JpaTarget> combinedSpecification = Objects
|
||||
.requireNonNull(SpecificationsBuilder.combineWithAnd(specList));
|
||||
return targetRepository.exists(combinedSpecification);
|
||||
return targetRepository.exists(AccessController.Operation.UPDATE, combinedSpecification);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,7 +27,6 @@ import javax.transaction.Transactional;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -70,13 +69,18 @@ public class BaseEntityRepositoryACM<T extends AbstractJpaTenantAwareBaseEntity>
|
||||
if (method.getName().startsWith("find") || method.getName().startsWith("get")) {
|
||||
final Object result = method.invoke(repository, args);
|
||||
if (Iterable.class.isAssignableFrom(method.getReturnType())) {
|
||||
for (final T e : ((Iterable<T>) result)) {
|
||||
accessController.assertOperationAllowed(AccessController.Operation.READ, e);
|
||||
for (final Object e : (Iterable<?>) result) {
|
||||
if (repository.getDomainClass().isAssignableFrom(e.getClass())) {
|
||||
accessController.assertOperationAllowed(AccessController.Operation.READ, (T) e);
|
||||
}
|
||||
}
|
||||
} else if (Optional.class.isAssignableFrom(method.getReturnType())) {
|
||||
return ((Optional<T>)result).filter(t -> isOperationAllowed(AccessController.Operation.READ, t, accessController));
|
||||
} else if (Optional.class.isAssignableFrom(method.getReturnType()) && ((Optional<?>) result)
|
||||
.filter(value -> repository.getDomainClass().isAssignableFrom(value.getClass()))
|
||||
.isPresent()) {
|
||||
return ((Optional<T>) result).filter(
|
||||
t -> isOperationAllowed(AccessController.Operation.READ, t, accessController));
|
||||
} else if (repository.getDomainClass().isAssignableFrom(method.getReturnType())) {
|
||||
accessController.assertOperationAllowed(AccessController.Operation.READ, (T)result);
|
||||
accessController.assertOperationAllowed(AccessController.Operation.READ, (T) result);
|
||||
}
|
||||
return result;
|
||||
} else if ("toString".equals(method.getName()) && method.getParameterCount() == 0) {
|
||||
|
||||
@@ -74,9 +74,9 @@ class AutoAssignCheckerTest {
|
||||
when(targetFilterQueryManagement.findWithAutoAssignDS(any()))
|
||||
.thenReturn(new SliceImpl<>(Arrays.asList(notMatching, matching)));
|
||||
|
||||
when(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target, ds, matching.getQuery()))
|
||||
when(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(target, ds, matching.getQuery()))
|
||||
.thenReturn(true);
|
||||
when(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target, ds, notMatching.getQuery()))
|
||||
when(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(target, ds, notMatching.getQuery()))
|
||||
.thenReturn(false);
|
||||
|
||||
sut.checkSingleTarget(target);
|
||||
|
||||
@@ -203,18 +203,18 @@ class DistributionSetInvalidationManagementTest extends AbstractJpaIntegrationTe
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify that a user that has authority READ_REPOSITORY and UPDATE_REPOSITORY is not allowed to invalidate a distribution set")
|
||||
@Description("Verify that a user that has authority READ_REPOSITORY and UPDATE_REPOSITORY is allowed to invalidate a distribution set")
|
||||
@WithUser(authorities = { "READ_REPOSITORY", "UPDATE_REPOSITORY" })
|
||||
void verifyInvalidateWithReadAndUpdateRepoAuthority() {
|
||||
final InvalidationTestData invalidationTestData = systemSecurityContext
|
||||
.runAsSystem(() -> createInvalidationTestData("verifyInvalidateWithUpdateRepoAuthority"));
|
||||
|
||||
assertThatExceptionOfType(InsufficientPermissionException.class)
|
||||
.as("Insufficient permission exception expected")
|
||||
.isThrownBy(() -> distributionSetInvalidationManagement
|
||||
.invalidateDistributionSet(new DistributionSetInvalidation(
|
||||
Collections.singletonList(invalidationTestData.getDistributionSet().getId()),
|
||||
CancelationType.NONE, false)));
|
||||
distributionSetInvalidationManagement.invalidateDistributionSet(new DistributionSetInvalidation(
|
||||
Collections.singletonList(invalidationTestData.getDistributionSet().getId()), CancelationType.NONE,
|
||||
false));
|
||||
assertThat(
|
||||
distributionSetRepository.findById(invalidationTestData.getDistributionSet().getId()).get().isValid())
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1267,7 +1267,7 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
final String filter = "metadata.key1==target1-value1";
|
||||
|
||||
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target.getControllerId(),
|
||||
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(target.getControllerId(),
|
||||
ds.getId(), filter)).isTrue();
|
||||
}
|
||||
|
||||
@@ -1278,7 +1278,7 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
final String filter = "metadata.key==not_existing";
|
||||
|
||||
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target.getControllerId(),
|
||||
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(target.getControllerId(),
|
||||
ds.getId(), filter)).isFalse();
|
||||
}
|
||||
|
||||
@@ -1292,7 +1292,7 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
assignDistributionSet(ds2, target);
|
||||
final String filter = "name==*";
|
||||
|
||||
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target.getControllerId(),
|
||||
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(target.getControllerId(),
|
||||
ds1.getId(), filter)).isFalse();
|
||||
}
|
||||
|
||||
@@ -1303,7 +1303,7 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
final Target target = testdataFactory.createTarget("target", "target", type.getId());
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
|
||||
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target.getControllerId(),
|
||||
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(target.getControllerId(),
|
||||
ds.getId(), "name==*")).isFalse();
|
||||
}
|
||||
|
||||
@@ -1314,9 +1314,9 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
final Long ds = testdataFactory.createDistributionSet().getId();
|
||||
|
||||
assertThatExceptionOfType(RSQLParameterSyntaxException.class).isThrownBy(() -> targetManagement
|
||||
.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target, ds, "invalid_syntax"));
|
||||
.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(target, ds, "invalid_syntax"));
|
||||
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class).isThrownBy(() -> targetManagement
|
||||
.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target, ds, "invalid_field==1"));
|
||||
.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(target, ds, "invalid_field==1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1324,7 +1324,7 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
void matchesFilterTargetNotExists() {
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
|
||||
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible("notExisting", ds.getId(),
|
||||
assertThat(targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable("notExisting", ds.getId(),
|
||||
"name==*")).isFalse();
|
||||
}
|
||||
|
||||
@@ -1334,7 +1334,7 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
final String target = testdataFactory.createTarget().getControllerId();
|
||||
|
||||
assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
|
||||
() -> targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(target, 123, "name==*"));
|
||||
() -> targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(target, 123, "name==*"));
|
||||
}
|
||||
|
||||
private void validateFoundTargetsByRsql(final String rsqlFilter, final String... controllerIds) {
|
||||
|
||||
@@ -134,14 +134,13 @@ public class AddRolloutWindowLayout extends AbstractRolloutWindowLayout {
|
||||
}
|
||||
|
||||
private Long getTotalTargets(final String filterQuery, final Long distSetTypeId) {
|
||||
// TODO AC - Check for updatable targets only
|
||||
if (StringUtils.isEmpty(filterQuery)) {
|
||||
return null;
|
||||
}
|
||||
if (distSetTypeId == null) {
|
||||
return targetManagement.countByRsql(filterQuery);
|
||||
return targetManagement.countByRsqlAndUpdatable(filterQuery);
|
||||
}
|
||||
return targetManagement.countByRsqlAndCompatible(filterQuery, distSetTypeId);
|
||||
return targetManagement.countByRsqlAndCompatibleAndUpdatable(filterQuery, distSetTypeId);
|
||||
}
|
||||
|
||||
private boolean isSimpleGroupsTabSelected() {
|
||||
|
||||
Reference in New Issue
Block a user