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