diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java index 06bcf995c..8b95644fd 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java @@ -279,19 +279,26 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl final AbstractDsAssignmentStrategy assignmentStrategy) { final JpaDistributionSet distributionSetEntity = getAndValidateDsById(dsID); - final List targetIds = targetsWithActionType.stream().map(TargetWithActionType::getControllerId) + final List providedTargetIds = targetsWithActionType.stream().map(TargetWithActionType::getControllerId) .distinct().collect(Collectors.toList()); - final List targetEntities = assignmentStrategy.findTargetsForAssignment(targetIds, + final List existingTargetIds = Lists.partition(providedTargetIds, Constants.MAX_ENTRIES_IN_STATEMENT) + .stream().map(targetRepository::filterNonExistingControllerIds).flatMap(List::stream) + .collect(Collectors.toList()); + + final List targetEntities = assignmentStrategy.findTargetsForAssignment(existingTargetIds, distributionSetEntity.getId()); if (targetEntities.isEmpty()) { - return allTargetsAlreadyAssignedResult(distributionSetEntity, targetsWithActionType.size()); + return allTargetsAlreadyAssignedResult(distributionSetEntity, existingTargetIds.size()); } - final List assignedActions = doAssignDistributionSetToTargets(targetsWithActionType, actionMessage, - assignmentStrategy, distributionSetEntity, targetEntities); - return buildAssignmentResult(distributionSetEntity, assignedActions, targetsWithActionType.size()); + final List existingTargetsWithActionType = targetsWithActionType.stream() + .filter(target -> existingTargetIds.contains(target.getControllerId())).collect(Collectors.toList()); + + final List assignedActions = doAssignDistributionSetToTargets(existingTargetsWithActionType, + actionMessage, assignmentStrategy, distributionSetEntity, targetEntities); + return buildAssignmentResult(distributionSetEntity, assignedActions, existingTargetsWithActionType.size()); } private DistributionSetAssignmentResult allTargetsAlreadyAssignedResult( diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetRepository.java index 1f9caf620..59146744e 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetRepository.java @@ -271,4 +271,14 @@ public interface TargetRepository extends BaseEntityRepository, @Transactional @Query("DELETE FROM JpaTarget t WHERE t.tenant = :tenant") void deleteByTenant(@Param("tenant") String tenant); + + /** + * Filters a given list of controllerIds and returns only the existing IDs. + * + * @param controllerIds + * The IDs to be filtered + * @return only the existing controllerIds + */ + @Query("SELECT t.controllerId FROM JpaTarget t WHERE t.controllerId IN ?1") + List filterNonExistingControllerIds(Iterable controllerIds); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java index 3bf0e5446..d92f610be 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DeploymentManagementTest.java @@ -37,11 +37,11 @@ import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdated import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent; +import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedException; import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException; import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException; -import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException; import org.eclipse.hawkbit.repository.jpa.configuration.Constants; import org.eclipse.hawkbit.repository.jpa.model.JpaAction; import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus; @@ -187,7 +187,8 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest { assignDistributionSet(ds1, targets); targets.add(testdataFactory.createTarget("assignmentTest2")); - assertThatExceptionOfType(AssignmentQuotaExceededException.class).isThrownBy(() -> assignDistributionSet(ds2, targets)); + assertThatExceptionOfType(AssignmentQuotaExceededException.class) + .isThrownBy(() -> assignDistributionSet(ds2, targets)); } @Test @@ -647,6 +648,40 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest { deploymentManagement.assignDistributionSets(Arrays.asList(targetToDS0, targetToDS1)))).isEqualTo(2); } + @Test + @Description("Assigning distribution set to the list of targets with a non-existing one leads to successful assignment of valid targets, while not found targets are silently ignored.") + public void assignDistributionSetToNotExistingTarget() { + final String notExistingId = "notExistingTarget"; + + final DistributionSet createdDs = testdataFactory.createDistributionSet(); + + final String[] knownTargetIdsArray = { "1", "2" }; + final List knownTargetIds = Lists.newArrayList(knownTargetIdsArray); + testdataFactory.createTargets(knownTargetIdsArray); + + // add not existing target to targets + knownTargetIds.add(notExistingId); + + final List assignDistributionSetsResults = assignDistributionSetToTargets( + createdDs, knownTargetIds); + + for (final DistributionSetAssignmentResult assignDistributionSetsResult : assignDistributionSetsResults) { + assertThat(assignDistributionSetsResult.getAlreadyAssigned()).isEqualTo(0); + assertThat(assignDistributionSetsResult.getAssigned()).isEqualTo(2); + assertThat(assignDistributionSetsResult.getTotal()).isEqualTo(2); + } + } + + private List assignDistributionSetToTargets(final DistributionSet distributionSet, + final Iterable targetIds) { + final List deploymentRequests = new ArrayList<>(); + for (final String controllerId : targetIds) { + deploymentRequests.add(new DeploymentRequest(controllerId, distributionSet.getId(), ActionType.FORCED, 0, + null, null, null, null)); + } + return deploymentManagement.assignDistributionSets(deploymentRequests); + } + @Test @Description("Duplicate Assignments are removed from a request when multiassignment is disabled, otherwise not") @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java index 389f3f358..54fbaab89 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java @@ -858,6 +858,24 @@ public class TestdataFactory { return targetManagement.create(targets); } + /** + * Creates {@link Target}s in repository and with given targetIds. + * + * @param targetIds + * specifies the IDs of the targets + * + * @return {@link List} of {@link Target} entities + */ + public List createTargets(final String... targetIds) { + + final List targets = new ArrayList<>(); + for (final String targetId : targetIds) { + targets.add(entityFactory.target().create().controllerId(targetId)); + } + + return targetManagement.create(targets); + } + /** * Builds {@link Target} objects with given prefix for * {@link Target#getControllerId()} followed by a number suffix. diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java index 25df64d78..798502a2c 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java @@ -139,11 +139,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr // create Targets final String[] knownTargetIds = new String[] { "1", "2" }; - final JSONArray list = new JSONArray(); - for (final String targetId : knownTargetIds) { - testdataFactory.createTarget(targetId); - list.put(new JSONObject().put("id", Long.valueOf(targetId))); - } + final JSONArray list = createTargetAndJsonArray(null, null, null, null, knownTargetIds); // assign DisSet to target and test assignment assignDistributionSet(disSet.getId(), knownTargetIds[0]); mvc.perform( @@ -257,11 +253,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr // prepare targets final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" }; - final JSONArray list = new JSONArray(); - for (final String targetId : knownTargetIds) { - testdataFactory.createTarget(targetId); - list.put(new JSONObject().put("id", Long.valueOf(targetId))); - } + final JSONArray list = createTargetAndJsonArray(null, null, null, null, knownTargetIds); // assign already one target to DS assignDistributionSet(createdDs.getId(), knownTargetIds[0]); @@ -379,16 +371,10 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr @Description("Assigns multiple targets to distribution set with only maintenance schedule.") public void assignMultipleTargetsToDistributionSetWithMaintenanceWindowStartOnly() throws Exception { // prepare distribution set - final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); - final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); + final DistributionSet createdDs = testdataFactory.createDistributionSet(); // prepare targets final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" }; - final JSONArray list = new JSONArray(); - for (final String targetId : knownTargetIds) { - testdataFactory.createTarget(targetId); - list.put(new JSONObject().put("id", Long.valueOf(targetId)).put("maintenanceWindow", - new JSONObject().put("schedule", getTestSchedule(0)))); - } + final JSONArray list = createTargetAndJsonArray(getTestSchedule(0), null, null, null, knownTargetIds); // assign already one target to DS assignDistributionSet(createdDs.getId(), knownTargetIds[0]); @@ -402,16 +388,10 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr @Description("Assigns multiple targets to distribution set with only maintenance window duration.") public void assignMultipleTargetsToDistributionSetWithMaintenanceWindowEndOnly() throws Exception { // prepare distribution set - final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); - final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); + final DistributionSet createdDs = testdataFactory.createDistributionSet(); // prepare targets final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" }; - final JSONArray list = new JSONArray(); - for (final String targetId : knownTargetIds) { - testdataFactory.createTarget(targetId); - list.put(new JSONObject().put("id", Long.valueOf(targetId)).put("maintenanceWindow", - new JSONObject().put("duration", getTestDuration(10)))); - } + final JSONArray list = createTargetAndJsonArray(null, getTestDuration(10), null, null, knownTargetIds); // assign already one target to DS assignDistributionSet(createdDs.getId(), knownTargetIds[0]); @@ -425,17 +405,11 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr @Description("Assigns multiple targets to distribution set with valid maintenance window.") public void assignMultipleTargetsToDistributionSetWithValidMaintenanceWindow() throws Exception { // prepare distribution set - final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); - final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); + final DistributionSet createdDs = testdataFactory.createDistributionSet(); // prepare targets final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" }; - final JSONArray list = new JSONArray(); - for (final String targetId : knownTargetIds) { - testdataFactory.createTarget(targetId); - list.put(new JSONObject().put("id", Long.valueOf(targetId)).put("maintenanceWindow", - new JSONObject().put("schedule", getTestSchedule(10)).put("duration", getTestDuration(10)) - .put("timezone", getTestTimeZone()))); - } + final JSONArray list = createTargetAndJsonArray(getTestSchedule(10), getTestDuration(10), getTestTimeZone(), + null, knownTargetIds); // assign already one target to DS assignDistributionSet(createdDs.getId(), knownTargetIds[0]); @@ -449,17 +423,11 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr @Description("Assigns multiple targets to distribution set with last maintenance window scheduled before current time.") public void assignMultipleTargetsToDistributionSetWithMaintenanceWindowEndTimeBeforeStartTime() throws Exception { // prepare distribution set - final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); - final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); + final DistributionSet createdDs = testdataFactory.createDistributionSet(); // prepare targets final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" }; - final JSONArray list = new JSONArray(); - for (final String targetId : knownTargetIds) { - testdataFactory.createTarget(targetId); - list.put(new JSONObject().put("id", Long.valueOf(targetId)).put("maintenanceWindow", - new JSONObject().put("schedule", getTestSchedule(-30)).put("duration", getTestDuration(5)) - .put("timezone", getTestTimeZone()))); - } + final JSONArray list = createTargetAndJsonArray(getTestSchedule(-30), getTestDuration(5), getTestTimeZone(), + null, knownTargetIds); // assign already one target to DS assignDistributionSet(createdDs.getId(), knownTargetIds[0]); @@ -473,8 +441,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr @Description("Assigns multiple targets to distribution set with and without maintenance window.") public void assignMultipleTargetsToDistributionSetWithAndWithoutMaintenanceWindow() throws Exception { // prepare distribution set - final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); - final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); + final DistributionSet createdDs = testdataFactory.createDistributionSet(); // prepare targets final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" }; final JSONArray list = new JSONArray(); @@ -497,13 +464,60 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr .andExpect(status().isOk()); } + @Test + @Description("Assigning distribution set to the list of targets with a non-existing one leads to successful assignment of valid targets, while not found targets are silently ignored.") + public void assignNotExistingTargetToDistributionSet() throws Exception { + final DistributionSet createdDs = testdataFactory.createDistributionSet(); + + final String[] knownTargetIds = new String[] { "1", "2", "3" }; + final JSONArray assignTargetJson = createTargetAndJsonArray(null, null, null, "forced", knownTargetIds); + assignDistributionSet(createdDs.getId(), knownTargetIds[0]); + + assignTargetJson.put(new JSONObject().put("id", "notexistingtarget").put("type", "forced")); + + mvc.perform(post( + MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + createdDs.getId() + "/assignedTargets") + .contentType(MediaType.APPLICATION_JSON).content(assignTargetJson.toString())) + .andExpect(status().isOk()).andExpect(jsonPath("$.alreadyAssigned", equalTo(1))) + .andExpect(jsonPath("$.assigned", equalTo(2))).andExpect(jsonPath("$.total", equalTo(3))); + } + + private JSONArray createTargetAndJsonArray(final String schedule, final String duration, final String timezone, + final String type, final String... targetIds) throws Exception { + final JSONArray result = new JSONArray(); + for (final String targetId : targetIds) { + testdataFactory.createTarget(targetId); + + final JSONObject targetJsonObject = new JSONObject(); + result.put(targetJsonObject); + targetJsonObject.put("id", Long.valueOf(targetId)); + if (type != null) { + targetJsonObject.put("type", type); + } + + if (schedule != null || duration != null || timezone != null) { + final JSONObject maintenanceJsonObject = new JSONObject(); + targetJsonObject.put("maintenanceWindow", maintenanceJsonObject); + if (schedule != null) { + maintenanceJsonObject.put("schedule", schedule); + } + if (duration != null) { + maintenanceJsonObject.put("duration", duration); + } + if (timezone != null) { + maintenanceJsonObject.put("timezone", timezone); + } + } + } + return result; + } + @Test @Description("Ensures that assigned targets of DS are returned as reflected by the repository.") public void getAssignedTargetsOfDistributionSet() throws Exception { // prepare distribution set final String knownTargetId = "knownTargetId1"; - final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); - final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); + final DistributionSet createdDs = testdataFactory.createDistributionSet(); testdataFactory.createTarget(knownTargetId); assignDistributionSet(createdDs.getId(), knownTargetId); @@ -516,8 +530,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr @Test @Description("Ensures that assigned targets of DS are returned as persisted in the repository.") public void getAssignedTargetsOfDistributionSetIsEmpty() throws Exception { - final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); - final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); + final DistributionSet createdDs = testdataFactory.createDistributionSet(); mvc.perform(get( MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + createdDs.getId() + "/assignedTargets")) .andExpect(status().isOk()).andExpect(jsonPath("$.size", equalTo(0))) @@ -529,8 +542,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr public void getInstalledTargetsOfDistributionSet() throws Exception { // prepare distribution set final String knownTargetId = "knownTargetId1"; - final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); - final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); + final DistributionSet createdDs = testdataFactory.createDistributionSet(); final Target createTarget = testdataFactory.createTarget(knownTargetId); // create some dummy targets which are not assigned or installed testdataFactory.createTarget("dummy1"); @@ -552,8 +564,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr public void getAutoAssignTargetFiltersOfDistributionSet() throws Exception { // prepare distribution set final String knownFilterName = "a"; - final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); - final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); + final DistributionSet createdDs = testdataFactory.createDistributionSet(); targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name(knownFilterName) .query("name==y").autoAssignDistributionSet(createdDs.getId())); @@ -571,8 +582,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr @Description("Ensures that an error is returned when the query is invalid.") public void getAutoAssignTargetFiltersOfDSWithInvalidFilter() throws Exception { // prepare distribution set - final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); - final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); + final DistributionSet createdDs = testdataFactory.createDistributionSet(); final String invalidQuery = "unknownField=le=42"; mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/" + createdDs.getId() @@ -584,8 +594,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr @Description("Ensures that target filters with auto assign DS are returned according to the query.") public void getMultipleAutoAssignTargetFiltersOfDistributionSet() throws Exception { final String filterNamePrefix = "filter-"; - final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); - final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); + final DistributionSet createdDs = testdataFactory.createDistributionSet(); final String query = "name==" + filterNamePrefix + "*"; prepareTestFilters(filterNamePrefix, createdDs); @@ -601,8 +610,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr @Description("Ensures that no target filters are returned according to the non matching query.") public void getEmptyAutoAssignTargetFiltersOfDistributionSet() throws Exception { final String filterNamePrefix = "filter-"; - final Set createDistributionSetsAlphabetical = createDistributionSetsAlphabetical(1); - final DistributionSet createdDs = createDistributionSetsAlphabetical.iterator().next(); + final DistributionSet createdDs = testdataFactory.createDistributionSet(); final String query = "name==doesNotExist"; prepareTestFilters(filterNamePrefix, createdDs); @@ -1251,11 +1259,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr // prepare targets final String[] knownTargetIds = new String[] { "1", "2", "3", "4", "5" }; - final JSONArray list = new JSONArray(); - for (final String targetId : knownTargetIds) { - testdataFactory.createTarget(targetId); - list.put(new JSONObject().put("id", Long.valueOf(targetId))); - } + final JSONArray list = createTargetAndJsonArray(null, null, null, null, knownTargetIds); // assign already one target to DS assignDistributionSet(createdDs.getId(), knownTargetIds[0], Action.ActionType.DOWNLOAD_ONLY); diff --git a/hawkbit-rest/hawkbit-rest-docs/src/main/asciidoc/distributionsets-api-guide.adoc b/hawkbit-rest/hawkbit-rest-docs/src/main/asciidoc/distributionsets-api-guide.adoc index 5d13ae997..0c1975d07 100644 --- a/hawkbit-rest/hawkbit-rest-docs/src/main/asciidoc/distributionsets-api-guide.adoc +++ b/hawkbit-rest/hawkbit-rest-docs/src/main/asciidoc/distributionsets-api-guide.adoc @@ -440,7 +440,7 @@ include::../errors/429.adoc[] === Implementation Notes -Handles the POST request for assigning multiple targets to a distribution set.The request body must always be a list of target IDs. Required permissions: READ_REPOSITORY and UPDATE_TARGET +Handles the POST request for assigning multiple targets to a distribution set.The request body must always be a list of target IDs. Non-existing targets are silently ignored resulting in a valid response. Required permissions: READ_REPOSITORY and UPDATE_TARGET === Assign targets to a distribution set @@ -482,7 +482,6 @@ include::{snippets}/distributionsets/create-assigned-target/http-response.adoc[] include::../errors/400.adoc[] include::../errors/401.adoc[] include::../errors/403.adoc[] -include::../errors/404.adoc[] include::../errors/405.adoc[] include::../errors/406.adoc[] include::../errors/409.adoc[]