Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for on not found policy in Target REST (un)assignTags #1905

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;

import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Valid;
Expand Down Expand Up @@ -48,16 +49,9 @@

/**
* Management service for {@link Target}s.
*
*/
public interface TargetManagement {

enum OnNotFoundPolicy {
FAIL, // default
TAG_AND_SUCCESS,
TAG_AND_ERROR
}

/**
* Counts number of targets with the given distribution set assigned.
*
Expand Down Expand Up @@ -674,12 +668,12 @@ Slice<Target> findByFilterOrderByLinkedDistributionSet(@NotNull Pageable pageabl
*
* @param controllerIds to assign for
* @param targetTagId to assign
* @param onNotFoundPolicy what to do if there are targets that are not found
* @param notFoundHandler if not all targets found - if null - exception, otherwise tag what found and the handler is called with what's not found
* @return list of assigned targets
* @throws EntityNotFoundException if given targetTagId or at least one of the targets do not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
List<Target> assignTag(@NotEmpty Collection<String> controllerIds, long targetTagId, final OnNotFoundPolicy onNotFoundPolicy);
List<Target> assignTag(@NotEmpty Collection<String> controllerIds, long targetTagId, final Consumer<Collection<String>> notFoundHandler);

/**
* Assign a {@link TargetTag} assignment to given {@link Target}s.
Expand All @@ -691,20 +685,20 @@ Slice<Target> findByFilterOrderByLinkedDistributionSet(@NotNull Pageable pageabl
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
default List<Target> assignTag(@NotEmpty Collection<String> controllerIds, long targetTagId) {
return assignTag(controllerIds, targetTagId, OnNotFoundPolicy.FAIL);
return assignTag(controllerIds, targetTagId, null);
}

/**
* Un-assign a {@link TargetTag} assignment to given {@link Target}s.
*
* @param controllerIds to un-assign for
* @param targetTagId to un-assign
* @param onNotFoundPolicy what to do if there are targets that are not found
* @param notFoundHandler if not all targets found - if null - exception, otherwise un-tag what found and the handler is called with what's not found
* @return list of unassigned targets
* @throws EntityNotFoundException if given targetTagId or at least one of the targets do not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
List<Target> unassignTag(@NotEmpty Collection<String> controllerIds, long targetTagId, final OnNotFoundPolicy onNotFoundPolicy);
List<Target> unassignTag(@NotEmpty Collection<String> controllerIds, long targetTagId, final Consumer<Collection<String>> notFoundHandler);

/**
* Un-assign a {@link TargetTag} assignment to given {@link Target}s.
Expand All @@ -716,7 +710,7 @@ default List<Target> assignTag(@NotEmpty Collection<String> controllerIds, long
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
default List<Target> unassignTag(@NotEmpty Collection<String> controllerIds, long targetTagId) {
return unassignTag(controllerIds, targetTagId, OnNotFoundPolicy.FAIL);
return unassignTag(controllerIds, targetTagId, null);
}

/**
Expand Down Expand Up @@ -1012,7 +1006,7 @@ Page<TargetMetadata> findMetaDataByControllerIdAndRsql(@NotNull Pageable pageabl
/**
* Un-assign a {@link TargetTag} assignment to given {@link Target}.
*
* @deprecated since 0.6.0 - use {@link #unassigнnTag(List, long)} instead
* @deprecated since 0.6.0 - use {@link #unassignTag(Collection, long)} (List, long)} instead
* @param controllerId to un-assign for
* @param targetTagId to un-assign
* @return the unassigned target or <null> if no target is unassigned
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -533,8 +534,8 @@ private List<JpaTarget> findTargetsByInSpecification(final Collection<String> co
@Transactional
@Retryable(include = {
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public List<Target> assignTag(final Collection<String> controllerIds, final long targetTagId, final OnNotFoundPolicy onNotFoundPolicy) {
return updateTag(controllerIds, targetTagId, onNotFoundPolicy, (tag, target) -> {
public List<Target> assignTag(final Collection<String> controllerIds, final long targetTagId, final Consumer<Collection<String>> notFoundHandler) {
return updateTag(controllerIds, targetTagId, notFoundHandler, (tag, target) -> {
if (target.getTags().contains(tag)) {
return target;
} else {
Expand All @@ -547,8 +548,8 @@ public List<Target> assignTag(final Collection<String> controllerIds, final long
@Transactional
@Retryable(include = {
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public List<Target> unassignTag(final Collection<String> controllerIds, final long targetTagId, final OnNotFoundPolicy onNotFoundPolicy) {
return updateTag(controllerIds, targetTagId, onNotFoundPolicy, (tag, target) -> {
public List<Target> unassignTag(final Collection<String> controllerIds, final long targetTagId, final Consumer<Collection<String>> notFoundHandler) {
return updateTag(controllerIds, targetTagId, notFoundHandler, (tag, target) -> {
if (target.getTags().contains(tag)) {
target.removeTag(tag);
return targetRepository.save(target);
Expand All @@ -558,7 +559,7 @@ public List<Target> unassignTag(final Collection<String> controllerIds, final lo
});
}
private List<Target> updateTag(
final Collection<String> controllerIds, final long targetTagId, final OnNotFoundPolicy notFoundPolicy,
final Collection<String> controllerIds, final long targetTagId, final Consumer<Collection<String>> notFoundHandler,
final BiFunction<JpaTargetTag, JpaTarget, Target> updater) {
final JpaTargetTag tag = targetTagRepository.findById(targetTagId)
.orElseThrow(() -> new EntityNotFoundException(TargetTag.class, targetTagId));
Expand All @@ -568,25 +569,20 @@ private List<Target> updateTag(
.orElseGet(Collections::emptyList) :
targetRepository
.findAll(TargetSpecifications.byControllerIdWithTagsInJoin(controllerIds));
final EntityNotFoundException notFoundException;
if (targets.size() < controllerIds.size() && notFoundPolicy != OnNotFoundPolicy.TAG_AND_SUCCESS) {
notFoundException = new EntityNotFoundException(Target.class, notFound(controllerIds, targets));
if (notFoundPolicy == OnNotFoundPolicy.FAIL) {
throw notFoundException;
if (targets.size() < controllerIds.size()) {
final Collection<String> notFound = notFound(controllerIds, targets);
if (notFoundHandler == null) {
throw new EntityNotFoundException(Target.class, notFound);
} else {
notFoundHandler.accept(notFound);
}
} else {
notFoundException = null;
}

targetRepository.getAccessController()
.ifPresent(acm -> acm.assertOperationAllowed(AccessController.Operation.UPDATE, targets));

try {
final List<Target> result = targets.stream().map(target -> updater.apply(tag, target)).toList();
if (notFoundException != null) { // if notFoundPolicy is NotFoundPolicy.TAG_AND_FAIL
throw notFoundException;
} else {
return result; // if all found or notFoundPolicy is NotFoundPolicy.TAG_AND_SUCCESS
}
return targets.stream().map(target -> updater.apply(tag, target)).toList();
} finally {
// No reason to save the tag
entityManager.detach(tag);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@
@Tag(name = "Target Tags", description = "REST API for Target Tag CRUD operations.")
public interface MgmtTargetTagRestApi {

enum OnNotFoundPolicy {
FAIL, // default
ON_WHAT_FOUND_AND_FAIL,
ON_WHAT_FOUND_AND_SUCCESS
}

/**
* Handles the GET request of retrieving all target tags.
*
Expand Down Expand Up @@ -351,6 +357,7 @@ ResponseEntity<Void> assignTarget(
consumes = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE } )
ResponseEntity<Void> assignTargets(
@PathVariable("targetTagId") Long targetTagId,
@RequestParam(value = "onNotFoundPolicy", required = false, defaultValue = "FAIL") OnNotFoundPolicy onNotFoundPolicy,
@Schema(description = "List of controller ids to be assigned", example = "[\"controllerId1\", \"controllerId2\"]")
@RequestBody List<String> controllerIds);

Expand Down Expand Up @@ -410,6 +417,7 @@ ResponseEntity<Void> unassignTarget(
consumes = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<Void> unassignTargets(
@PathVariable("targetTagId") Long targetTagId,
@RequestParam(value = "onNotFoundPolicy", required = false, defaultValue = "FAIL") OnNotFoundPolicy onNotFoundPolicy,
@Schema(description = "List of controller ids to be unassigned", example = "[\"controllerId1\", \"controllerId2\"]")
@RequestBody List<String> controllerId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
*/
package org.eclipse.hawkbit.mgmt.rest.resource;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedTargetRequestBody;
Expand Down Expand Up @@ -186,24 +187,46 @@ public ResponseEntity<Void> assignTarget(final Long targetTagId, final String co
}

@Override
public ResponseEntity<Void> assignTargets(final Long targetTagId, final List<String> controllerIds) {
public ResponseEntity<Void> assignTargets(final Long targetTagId, final OnNotFoundPolicy onNotFoundPolicy, final List<String> controllerIds) {
log.debug("Assign {} targets for target tag {}", controllerIds.size(), targetTagId);
this.targetManagement.assignTag(controllerIds, targetTagId);
if (onNotFoundPolicy == OnNotFoundPolicy.FAIL) {
this.targetManagement.assignTag(controllerIds, targetTagId);
} else {
final AtomicReference<Collection<String>> notFound = new AtomicReference<>();
this.targetManagement.assignTag(controllerIds, targetTagId, notFound::set);
if (notFound.get() != null) {
// has not found
if (onNotFoundPolicy == OnNotFoundPolicy.ON_WHAT_FOUND_AND_FAIL) {
throw new EntityNotFoundException(Target.class, notFound.get());
} // else - success
}
}
return ResponseEntity.ok().build();
}

@Override
public ResponseEntity<Void> unassignTarget(@PathVariable("targetTagId") final Long targetTagId,
public ResponseEntity<Void> unassignTarget(final Long targetTagId,
@PathVariable("controllerId") final String controllerId) {
log.debug("Unassign target {} for target tag {}", controllerId, targetTagId);
this.targetManagement.unassignTag(controllerId, targetTagId);
return ResponseEntity.ok().build();
}

@Override
public ResponseEntity<Void> unassignTargets(final Long targetTagId, final List<String> controllerIds) {
public ResponseEntity<Void> unassignTargets(final Long targetTagId, final OnNotFoundPolicy onNotFoundPolicy, final List<String> controllerIds) {
log.debug("Unassign {} targets for target tag {}", controllerIds.size(), targetTagId);
this.targetManagement.unassignTag(controllerIds, targetTagId);
if (onNotFoundPolicy == OnNotFoundPolicy.FAIL) {
this.targetManagement.unassignTag(controllerIds, targetTagId);
} else {
final AtomicReference<Collection<String>> notFound = new AtomicReference<>();
this.targetManagement.unassignTag(controllerIds, targetTagId, notFound::set);
if (notFound.get() != null) {
// has not found
if (onNotFoundPolicy == OnNotFoundPolicy.ON_WHAT_FOUND_AND_FAIL) {
throw new EntityNotFoundException(Target.class, notFound.get());
} // else - success
}
}
return ResponseEntity.ok().build();
}

Expand Down
Loading
Loading