Assign multiple distribution sets to a target via mgmt api (#886)
* Add multiassignment to mgmt api target endpoint * Remove single assignment ds to targets offline * Fix tests * Add quota for maxResultingActionsPerManualAssignment * Fix assignment with same target or distribution set multiple times in one request * Log UI error * Add tests * Enable single assignment requests with multiple DSs and types * Remove redundant target to DS assignment methods * Add tests, fix assignment * Fix possible nullpointer during target assignment request * Update api docu * Clean up deployment management code * Enforce MaxActions quota for offline assignment * Fix review findings * Rename property, add migration into * Add builder for DeploymentRequest * Change offline assignment method to accept an assignment list, like online assignment * Fix PR findings Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>
This commit is contained in:
committed by
Stefan Behl
parent
dba972423b
commit
8687510131
@@ -21,7 +21,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -73,7 +72,7 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
|
||||
final DistributionSet set = testdataFactory.createDistributionSet("one");
|
||||
|
||||
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
|
||||
deploymentManagement.assignDistributionSet(set.getId(), Arrays.asList(target.getTargetWithActionType()));
|
||||
assignDistributionSet(set.getId(), target.getControllerId());
|
||||
|
||||
mockMvc.perform(get(DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId()).accept(MediaTypes.HAL_JSON_VALUE))
|
||||
@@ -101,8 +100,8 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
|
||||
final DistributionSet setTwo = testdataFactory.createDistributionSet("two");
|
||||
|
||||
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
|
||||
deploymentManagement.assignDistributionSet(set.getId(), Arrays.asList(target.getTargetWithActionType()));
|
||||
deploymentManagement.assignDistributionSet(setTwo.getId(), Arrays.asList(target.getTargetWithActionType()));
|
||||
assignDistributionSet(set.getId(), target.getControllerId());
|
||||
assignDistributionSet(setTwo.getId(), target.getControllerId());
|
||||
|
||||
mockMvc.perform(get(DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}",
|
||||
tenantAware.getCurrentTenant(), target.getControllerId()).accept(MediaTypes.HAL_JSON_VALUE))
|
||||
@@ -137,8 +136,7 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
|
||||
});
|
||||
|
||||
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
|
||||
final Long actionId = getFirstAssignedActionId(deploymentManagement.assignDistributionSet(set.getId(),
|
||||
Arrays.asList(target.getTargetWithActionType())));
|
||||
final Long actionId = getFirstAssignedActionId(assignDistributionSet(set.getId(), target.getControllerId()));
|
||||
final Action cancelAction = deploymentManagement.cancelAction(actionId);
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -169,8 +167,7 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
|
||||
final DistributionSet set = testdataFactory.createDistributionSet("one");
|
||||
|
||||
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
|
||||
final Long actionId = getFirstAssignedActionId(deploymentManagement.assignDistributionSet(set.getId(),
|
||||
Arrays.asList(target.getTargetWithActionType())));
|
||||
final Long actionId = getFirstAssignedActionId(assignDistributionSet(set.getId(), target.getControllerId()));
|
||||
final Action cancelAction = deploymentManagement.cancelAction(actionId);
|
||||
|
||||
mockMvc.perform(post(
|
||||
@@ -387,8 +384,7 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
|
||||
final DistributionSet set = testdataFactory.createDistributionSet("one");
|
||||
|
||||
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
|
||||
final Long actionId = getFirstAssignedActionId(deploymentManagement.assignDistributionSet(set.getId(),
|
||||
Arrays.asList(target.getTargetWithActionType())));
|
||||
final Long actionId = getFirstAssignedActionId(assignDistributionSet(set.getId(), target.getControllerId()));
|
||||
|
||||
mockMvc.perform(post(DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/"
|
||||
+ DdiRestConstants.DEPLOYMENT_BASE_ACTION + "/{actionId}/feedback", tenantAware.getCurrentTenant(),
|
||||
@@ -434,7 +430,7 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
|
||||
.create(new ArtifactUpload(new ByteArrayInputStream(random), module.getId(), "binaryFile", false, 0));
|
||||
|
||||
final Target target = targetManagement.create(entityFactory.target().create().controllerId(CONTROLLER_ID));
|
||||
deploymentManagement.assignDistributionSet(set.getId(), Arrays.asList(target.getTargetWithActionType()));
|
||||
assignDistributionSet(set.getId(), target.getControllerId());
|
||||
|
||||
mockMvc.perform(
|
||||
get(DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/softwaremodules/{moduleId}/artifacts",
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.eclipse.hawkbit.ddi.rest.resource.DdiApiConfiguration;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.MgmtApiConfiguration;
|
||||
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -169,7 +170,8 @@ public abstract class AbstractApiRestDocumentation extends AbstractRestIntegrati
|
||||
private List<Target> assignWithoutMaintenanceWindow(final DistributionSet distributionSet, final Target savedTarget,
|
||||
final boolean timeforced) {
|
||||
final List<Action> actions = timeforced
|
||||
? assignDistributionSetTimeForced(distributionSet, savedTarget).getAssignedEntity()
|
||||
? assignDistributionSet(distributionSet.getId(), savedTarget.getControllerId(), ActionType.TIMEFORCED)
|
||||
.getAssignedEntity()
|
||||
: assignDistributionSet(distributionSet, savedTarget).getAssignedEntity();
|
||||
return actions.stream().map(Action::getTarget).collect(Collectors.toList());
|
||||
}
|
||||
@@ -178,8 +180,8 @@ public abstract class AbstractApiRestDocumentation extends AbstractRestIntegrati
|
||||
final boolean timeforced, final String maintenanceWindowSchedule, final String maintenanceWindowDuration,
|
||||
final String maintenanceWindowTimeZone) {
|
||||
final List<Action> actions = timeforced
|
||||
? assignDistributionSetWithMaintenanceWindowTimeForced(distributionSet.getId(),
|
||||
savedTarget.getControllerId(), maintenanceWindowSchedule, maintenanceWindowDuration,
|
||||
? assignDistributionSetWithMaintenanceWindow(distributionSet.getId(), savedTarget.getControllerId(),
|
||||
ActionType.TIMEFORCED, maintenanceWindowSchedule, maintenanceWindowDuration,
|
||||
maintenanceWindowTimeZone).getAssignedEntity()
|
||||
: assignDistributionSetWithMaintenanceWindow(distributionSet.getId(), savedTarget.getControllerId(),
|
||||
maintenanceWindowSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone)
|
||||
|
||||
@@ -188,7 +188,7 @@ public final class MgmtApiModelProperties {
|
||||
// request parameter
|
||||
public static final String FORCETIME = "Forcetime in milliseconds.";
|
||||
public static final String FORCE = "Force as boolean.";
|
||||
public static final String FORCETIME_TYPE = "The type of the forcetime.";
|
||||
public static final String ASSIGNMENT_TYPE = "The type of the assignment.";
|
||||
public static final String TARGET_ASSIGNED = "The number of targets that have been assigned as part of this operation.";
|
||||
public static final String TARGET_ASSIGNED_ALREADY = "The number of targets which already had been the assignment.";
|
||||
public static final String TARGET_ASSIGNED_TOTAL = "The total number of targets that are part of this operation.";
|
||||
|
||||
@@ -383,17 +383,20 @@ public class DistributionSetsDocumentationTest extends AbstractApiRestDocumentat
|
||||
parameterWithName("distributionSetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
|
||||
requestParameters(parameterWithName("offline")
|
||||
.description(MgmtApiModelProperties.OFFLINE_UPDATE).optional()),
|
||||
requestFields(requestFieldWithPath("[]forcetime").description(MgmtApiModelProperties.FORCETIME),
|
||||
requestFieldWithPath("[]id").description(ApiModelPropertiesGeneric.ITEM_ID),
|
||||
requestFieldWithPath("[]maintenanceWindow")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW).optional(),
|
||||
requestFieldWithPath("[]maintenanceWindow.schedule")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_SCHEDULE).optional(),
|
||||
requestFieldWithPath("[]maintenanceWindow.duration")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_DURATION).optional(),
|
||||
requestFieldWithPath("[]maintenanceWindow.timezone")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_TIMEZONE).optional(),
|
||||
requestFieldWithPath("[]type").description(MgmtApiModelProperties.FORCETIME_TYPE)
|
||||
requestFields(
|
||||
requestFieldWithPath("[].id").description(ApiModelPropertiesGeneric.ITEM_ID),
|
||||
optionalRequestFieldWithPath("[].forcetime")
|
||||
.description(MgmtApiModelProperties.FORCETIME),
|
||||
optionalRequestFieldWithPath("[].maintenanceWindow")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW),
|
||||
optionalRequestFieldWithPath("[].maintenanceWindow.schedule")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_SCHEDULE),
|
||||
optionalRequestFieldWithPath("[].maintenanceWindow.duration")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_DURATION),
|
||||
optionalRequestFieldWithPath("[].maintenanceWindow.timezone")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_TIMEZONE),
|
||||
optionalRequestFieldWithPath("[].type")
|
||||
.description(MgmtApiModelProperties.ASSIGNMENT_TYPE)
|
||||
.attributes(key("value").value("['soft', 'forced','timeforced', 'downloadonly']"))),
|
||||
responseFields(
|
||||
fieldWithPath("assigned").description(MgmtApiModelProperties.DS_NEW_ASSIGNED_TARGETS),
|
||||
|
||||
@@ -48,6 +48,7 @@ import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.restdocs.payload.FieldDescriptor;
|
||||
import org.springframework.restdocs.payload.JsonFieldType;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
@@ -395,8 +396,8 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
|
||||
public void switchActionToForced() throws Exception {
|
||||
final Target target = testdataFactory.createTarget(targetId);
|
||||
final DistributionSet set = testdataFactory.createDistributionSet();
|
||||
final Long actionId = getFirstAssignedActionId(deploymentManagement.assignDistributionSet(set.getId(),
|
||||
ActionType.SOFT, 0, Collections.singletonList(target.getControllerId())));
|
||||
final Long actionId = getFirstAssignedActionId(
|
||||
assignDistributionSet(set.getId(), target.getControllerId(), ActionType.SOFT));
|
||||
assertThat(deploymentManagement.findAction(actionId).get().getActionType()).isEqualTo(ActionType.SOFT);
|
||||
|
||||
final Map<String, Object> body = new HashMap<>();
|
||||
@@ -485,7 +486,7 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
|
||||
pathParameters(parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
|
||||
getResponseFieldsDistributionSet(false)));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Description("Handles the POST request for assigning a distribution set to a specific target. Required Permission: READ_REPOSITORY and UPDATE_TARGET.")
|
||||
public void postAssignDistributionSetToTarget() throws Exception {
|
||||
@@ -511,30 +512,80 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
|
||||
pathParameters(parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
|
||||
requestParameters(parameterWithName("offline")
|
||||
.description(MgmtApiModelProperties.OFFLINE_UPDATE).optional()),
|
||||
requestFields(requestFieldWithPath("forcetime").description(MgmtApiModelProperties.FORCETIME),
|
||||
requestFields(
|
||||
requestFieldWithPath("id").description(ApiModelPropertiesGeneric.ITEM_ID),
|
||||
requestFieldWithPath("maintenanceWindow")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW).optional(),
|
||||
requestFieldWithPath("maintenanceWindow.schedule")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_SCHEDULE).optional(),
|
||||
requestFieldWithPath("maintenanceWindow.duration")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_DURATION).optional(),
|
||||
requestFieldWithPath("maintenanceWindow.timezone")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_TIMEZONE).optional(),
|
||||
requestFieldWithPath("type").description(MgmtApiModelProperties.FORCETIME_TYPE)
|
||||
optionalRequestFieldWithPath("forcetime").description(MgmtApiModelProperties.FORCETIME),
|
||||
optionalRequestFieldWithPath("maintenanceWindow")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW),
|
||||
optionalRequestFieldWithPath("maintenanceWindow.schedule")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_SCHEDULE),
|
||||
optionalRequestFieldWithPath("maintenanceWindow.duration")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_DURATION),
|
||||
optionalRequestFieldWithPath("maintenanceWindow.timezone")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_TIMEZONE),
|
||||
optionalRequestFieldWithPath("type").description(MgmtApiModelProperties.ASSIGNMENT_TYPE)
|
||||
.attributes(key("value").value("['soft', 'forced','timeforced', 'downloadonly']"))),
|
||||
responseFields(
|
||||
fieldWithPath("assigned").description(MgmtApiModelProperties.DS_NEW_ASSIGNED_TARGETS),
|
||||
fieldWithPath("alreadyAssigned").type(JsonFieldType.NUMBER)
|
||||
.description(MgmtApiModelProperties.DS_ALREADY_ASSIGNED_TARGETS),
|
||||
fieldWithPath("assignedActions").type(JsonFieldType.ARRAY)
|
||||
.description(MgmtApiModelProperties.DS_NEW_ASSIGNED_ACTIONS),
|
||||
fieldWithPath("assignedActions.[].id").type(JsonFieldType.NUMBER)
|
||||
.description(MgmtApiModelProperties.ACTION_ID),
|
||||
fieldWithPath("assignedActions.[]._links.self").type(JsonFieldType.OBJECT)
|
||||
.description(MgmtApiModelProperties.LINK_TO_ACTION),
|
||||
fieldWithPath("total").type(JsonFieldType.NUMBER)
|
||||
.description(MgmtApiModelProperties.DS_TOTAL_ASSIGNED_TARGETS))));
|
||||
responseFields(getDsAssignmentResponseFieldDescriptors())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Handles the POST request for assigning distribution sets to a specific target. Required Permission: READ_REPOSITORY and UPDATE_TARGET.")
|
||||
public void postAssignDistributionSetsToTarget() throws Exception {
|
||||
// create target and ds, and assign ds
|
||||
final List<DistributionSet> sets = testdataFactory.createDistributionSets(2);
|
||||
testdataFactory.createTarget(targetId);
|
||||
|
||||
final long forceTime = System.currentTimeMillis();
|
||||
final JSONArray body = new JSONArray();
|
||||
body.put(new JSONObject().put("id", sets.get(1).getId()).put("type", "timeforced")
|
||||
.put("forcetime", forceTime)
|
||||
.put("maintenanceWindow", new JSONObject().put("schedule", getTestSchedule(100))
|
||||
.put("duration", getTestDuration(10)).put("timezone", getTestTimeZone())))
|
||||
.toString();
|
||||
body.put(new JSONObject().put("id", sets.get(0).getId()).put("type", "forced"));
|
||||
|
||||
enableMultiAssignments();
|
||||
mockMvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/"
|
||||
+ MgmtRestConstants.TARGET_V1_ASSIGNED_DISTRIBUTION_SET, targetId).content(body.toString())
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andDo(this.document.document(
|
||||
pathParameters(parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
|
||||
requestParameters(parameterWithName("offline")
|
||||
.description(MgmtApiModelProperties.OFFLINE_UPDATE).optional()),
|
||||
requestFields(
|
||||
requestFieldWithPath("[].id").description(ApiModelPropertiesGeneric.ITEM_ID),
|
||||
optionalRequestFieldWithPath("[].forcetime")
|
||||
.description(MgmtApiModelProperties.FORCETIME),
|
||||
optionalRequestFieldWithPath("[].maintenanceWindow")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW),
|
||||
optionalRequestFieldWithPath("[].maintenanceWindow.schedule")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_SCHEDULE),
|
||||
optionalRequestFieldWithPath("[].maintenanceWindow.duration")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_DURATION),
|
||||
optionalRequestFieldWithPath("[].maintenanceWindow.timezone")
|
||||
.description(MgmtApiModelProperties.MAINTENANCE_WINDOW_TIMEZONE),
|
||||
optionalRequestFieldWithPath("[].type")
|
||||
.description(MgmtApiModelProperties.ASSIGNMENT_TYPE)
|
||||
.attributes(key("[].value")
|
||||
.value("['soft', 'forced','timeforced', 'downloadonly']"))),
|
||||
responseFields(getDsAssignmentResponseFieldDescriptors())));
|
||||
}
|
||||
|
||||
private static FieldDescriptor[] getDsAssignmentResponseFieldDescriptors() {
|
||||
final FieldDescriptor[] descriptors = {
|
||||
fieldWithPath("assigned").description(MgmtApiModelProperties.DS_NEW_ASSIGNED_TARGETS),
|
||||
fieldWithPath("alreadyAssigned").type(JsonFieldType.NUMBER)
|
||||
.description(MgmtApiModelProperties.DS_ALREADY_ASSIGNED_TARGETS),
|
||||
fieldWithPath("assignedActions").type(JsonFieldType.ARRAY)
|
||||
.description(MgmtApiModelProperties.DS_NEW_ASSIGNED_ACTIONS),
|
||||
fieldWithPath("assignedActions.[].id").type(JsonFieldType.NUMBER)
|
||||
.description(MgmtApiModelProperties.ACTION_ID),
|
||||
fieldWithPath("assignedActions.[]._links.self").type(JsonFieldType.OBJECT)
|
||||
.description(MgmtApiModelProperties.LINK_TO_ACTION),
|
||||
fieldWithPath("total").type(JsonFieldType.NUMBER)
|
||||
.description(MgmtApiModelProperties.DS_TOTAL_ASSIGNED_TARGETS) };
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user