ManagementApi: Action does not have property containing rollout name (#1116)

* Mgmt Rest API: Enhance Action payload with rollout properties

Signed-off-by: Stefan Behl <stefan.behl@bosch.io>

* Enhance Mgmt REST API docs

Signed-off-by: Stefan Behl <stefan.behl@bosch.io>

* Minor changes

Signed-off-by: Stefan Behl <stefan.behl@bosch.io>
This commit is contained in:
Stefan Behl
2021-05-18 13:50:05 +02:00
committed by GitHub
parent efa21469cd
commit 069d717be1
7 changed files with 150 additions and 18 deletions

View File

@@ -65,6 +65,12 @@ public class MgmtAction extends MgmtBaseEntity {
@JsonProperty
private MgmtMaintenanceWindow maintenanceWindow;
@JsonProperty
private Long rollout;
@JsonProperty
private String rolloutName;
public MgmtMaintenanceWindow getMaintenanceWindow() {
return maintenanceWindow;
@@ -121,4 +127,21 @@ public class MgmtAction extends MgmtBaseEntity {
public void setType(final String type) {
this.type = type;
}
public Long getRollout() {
return rollout;
}
public void setRollout(Long rollout) {
this.rollout = rollout;
}
public String getRolloutName() {
return rolloutName;
}
public void setRolloutName(String rolloutName) {
this.rolloutName = rolloutName;
}
}

View File

@@ -84,6 +84,10 @@ public final class MgmtRestConstants {
* The target URL mapping, href link for canceled actions.
*/
public static final String TARGET_V1_ACTION_STATUS = "status";
/**
* The target URL mapping, href link for a rollout.
*/
public static final String TARGET_V1_ROLLOUT = "rollout";
/**
* The target URL mapping rest resource.

View File

@@ -28,6 +28,7 @@ import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetRestApi;
import org.eclipse.hawkbit.repository.ActionFields;
import org.eclipse.hawkbit.repository.ActionStatusFields;
@@ -39,6 +40,7 @@ import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.eclipse.hawkbit.repository.model.PollStatus;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetMetadata;
import org.eclipse.hawkbit.rest.data.ResponseList;
@@ -215,6 +217,12 @@ public final class MgmtTargetMapper {
result.setStatus(MgmtAction.ACTION_FINISHED);
}
Rollout rollout = action.getRollout();
if (rollout != null) {
result.setRollout(rollout.getId());
result.setRolloutName(rollout.getName());
}
if (action.hasMaintenanceSchedule()) {
final MgmtMaintenanceWindow maintenanceWindow = new MgmtMaintenanceWindow();
maintenanceWindow.setSchedule(action.getMaintenanceWindowSchedule());
@@ -248,6 +256,12 @@ public final class MgmtTargetMapper {
ActionStatusFields.ID.getFieldName() + ":" + SortDirection.DESC))
.withRel(MgmtRestConstants.TARGET_V1_ACTION_STATUS));
final Rollout rollout = action.getRollout();
if (rollout != null) {
result.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRollout(rollout.getId()))
.withRel(MgmtRestConstants.TARGET_V1_ROLLOUT));
}
return result;
}

View File

@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasItem;
@@ -51,6 +52,7 @@ import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetMetadata;
@@ -2039,5 +2041,38 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
}
}
@Test
@Description("An action provides information of the rollout it was created for (if any).")
public void getActionWithRolloutInfo() throws Exception {
// setup
final int amountTargets = 10;
final List<Target> targets = testdataFactory.createTargets(amountTargets, "trg", "trg");
final DistributionSet ds = testdataFactory.createDistributionSet("");
final Rollout rollout = testdataFactory.createRolloutByVariables("My Rollout", "My Rollout Description", 1,
"name==trg*", ds, "50", "5");
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
// get all actions for the first target
final Target target = targets.get(0);
mvc.perform(get("/rest/v1/targets/{targetId}/actions", target.getControllerId())).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(jsonPath("content.[0].rollout", equalTo(rollout.getId().intValue())))
.andExpect(jsonPath("content.[0].rolloutName", equalTo(rollout.getName())));
// get the first action for the first target;
// verify that also the rollout link is present
final Slice<Action> action = deploymentManagement.findActionsByTarget(target.getControllerId(),
PageRequest.of(0, 100));
assertThat(action.getContent()).hasSize(1);
mvc.perform(get("/rest/v1/targets/{targetId}/actions/{actionId}", target.getControllerId(),
action.getContent().get(0).getId())).andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andExpect(jsonPath("$.rollout", equalTo(rollout.getId().intValue())))
.andExpect(jsonPath("$.rolloutName", equalTo(rollout.getName()))).andExpect(jsonPath(
"$._links.rollout.href", containsString("/rest/v1/rollouts/" + rollout.getId().intValue())));
}
}

View File

@@ -19,6 +19,7 @@ import static org.springframework.restdocs.snippet.Attributes.key;
import java.io.ByteArrayInputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@@ -33,6 +34,7 @@ import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
import org.eclipse.hawkbit.repository.model.DeploymentRequestBuilder;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.test.TestConfiguration;
@@ -161,28 +163,52 @@ public abstract class AbstractApiRestDocumentation extends AbstractRestIntegrati
protected Target createTargetByGivenNameWithAttributes(final String name, final boolean inSync,
final boolean timeforced, final DistributionSet distributionSet) {
return createTargetByGivenNameWithAttributes(name, inSync, timeforced, distributionSet, null, null, null);
return createTargetByGivenNameWithAttributes(name, inSync, timeforced, distributionSet, null, null, null, false);
}
protected Target createTargetByGivenNameWithAttributes(final String name, final boolean inSync,
final boolean timeforced, final DistributionSet distributionSet, final boolean createRollout) {
return createTargetByGivenNameWithAttributes(name, inSync, timeforced, distributionSet, null, null, null, createRollout);
}
protected Target createTargetByGivenNameWithAttributes(final String name, final boolean inSync,
final boolean timeforced, final DistributionSet distributionSet, final String maintenanceWindowSchedule,
final String maintenanceWindowDuration, final String maintenanceWindowTimeZone) {
final String maintenanceWindowDuration, final String maintenanceWindowTimeZone, final boolean createRollout) {
final Target savedTarget = targetManagement.create(entityFactory.target().create().controllerId(name)
.status(TargetUpdateStatus.UNKNOWN).address("http://192.168.0.1").description("My name is " + name)
.lastTargetQuery(System.currentTimeMillis()));
final DeploymentRequestBuilder deploymentRequestBuilder = DeploymentManagement
.deploymentRequest(savedTarget.getControllerId(), distributionSet.getId())
.setMaintenance(maintenanceWindowSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone);
if (timeforced) {
deploymentRequestBuilder.setActionType(ActionType.TIMEFORCED);
}
if (isMultiAssignmentsEnabled()) {
deploymentRequestBuilder.setWeight(600);
}
final List<Target> updatedTargets = makeAssignment(deploymentRequestBuilder.build()).getAssignedEntity()
.stream().map(Action::getTarget).collect(Collectors.toList());
final List<Target> updatedTargets;
if (createRollout) {
final Rollout rollout = testdataFactory.createRolloutByVariables("rollout", "rollout desc", 1,
"name==" + name, distributionSet, "50", "5", timeforced ? ActionType.TIMEFORCED : ActionType.FORCED,
isMultiAssignmentsEnabled() ? 600 : null);
// start the rollout and handle it
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
updatedTargets = Collections.singletonList(savedTarget);
} else {
final DeploymentRequestBuilder deploymentRequestBuilder = DeploymentManagement
.deploymentRequest(savedTarget.getControllerId(), distributionSet.getId())
.setMaintenance(maintenanceWindowSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone);
if (timeforced) {
deploymentRequestBuilder.setActionType(ActionType.TIMEFORCED);
}
if (isMultiAssignmentsEnabled()) {
deploymentRequestBuilder.setWeight(600);
}
updatedTargets = makeAssignment(deploymentRequestBuilder.build()).getAssignedEntity().stream()
.map(Action::getTarget).collect(Collectors.toList());
}
if (inSync) {
feedbackToByInSync(distributionSet);
}

View File

@@ -31,6 +31,7 @@ public final class MgmtApiModelProperties {
public static final String LINK_TO_METADATA = "The link to the metadata.";
public static final String LINK_TO_MANDATORY_SMT = "Link to mandatory software modules types in this distribution set type.";
public static final String LINK_TO_OPTIONAL_SMT = "Link to optional software modules types in this distribution set type.";
public static final String LINK_TO_ROLLOUT = "The link to the rollout.";
// software module types
public static final String SMT_TYPE = "The type of the software module identified by its key.";
@@ -143,6 +144,10 @@ public final class MgmtApiModelProperties {
public static final String ACTION_WEIGHT = "Weight of the action showing the importance of the update.";
public static final String ACTION_ROLLOUT = "The ID of the rollout this action was created for.";
public static final String ACTION_ROLLOUT_NAME = "The name of the rollout this action was created for.";
public static final String IP_ADDRESS = "Last known IP address of the target. Only presented if IP address of the target itself is known (connected directly through DDI API).";
public static final String ADDRESS = "The last known address URI of the target. Includes information of the target is connected either directly (DDI) through HTTP or indirectly (DMF) through amqp.";

View File

@@ -201,7 +201,7 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Description("Handles the GET request of retrieving the full action history of a specific target. Required Permission: READ_TARGET.")
public void getActionsFromTarget() throws Exception {
enableMultiAssignments();
generateActionForTarget(targetId);
generateRolloutActionForTarget(targetId);
mockMvc.perform(
get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/" + MgmtRestConstants.TARGET_V1_ACTIONS,
@@ -228,7 +228,10 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
.attributes(key("value").value("['finished', 'pending']")),
fieldWithPath("content[]._links").description(MgmtApiModelProperties.LINK_TO_ACTION),
fieldWithPath("content[].id").description(MgmtApiModelProperties.ACTION_ID),
fieldWithPath("content[].weight").description(MgmtApiModelProperties.ACTION_WEIGHT))));
fieldWithPath("content[].weight").description(MgmtApiModelProperties.ACTION_WEIGHT),
fieldWithPath("content[].rollout").description(MgmtApiModelProperties.ACTION_ROLLOUT),
fieldWithPath("content[].rolloutName")
.description(MgmtApiModelProperties.ACTION_ROLLOUT_NAME))));
}
@Test
@@ -323,7 +326,7 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Description("Handles the GET request of retrieving a specific action on a specific target. Required Permission: READ_TARGET.")
public void getActionFromTarget() throws Exception {
enableMultiAssignments();
final Action action = generateActionForTarget(targetId, true, true);
final Action action = generateRolloutActionForTarget(targetId, true, true);
assertThat(deploymentManagement.findAction(action.getId()).get().getActionType())
.isEqualTo(ActionType.TIMEFORCED);
@@ -349,10 +352,15 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
.type("String"),
fieldWithPath("status").description(MgmtApiModelProperties.ACTION_EXECUTION_STATUS)
.attributes(key("value").value("['finished', 'pending']")),
fieldWithPath("rollout").description(MgmtApiModelProperties.ACTION_ROLLOUT),
fieldWithPath("rolloutName")
.description(MgmtApiModelProperties.ACTION_ROLLOUT_NAME),
fieldWithPath("_links.self").ignored(),
fieldWithPath("_links.distributionset").description(MgmtApiModelProperties.LINK_TO_DS),
fieldWithPath("_links.status")
.description(MgmtApiModelProperties.LINKS_ACTION_STATUSES))));
.description(MgmtApiModelProperties.LINKS_ACTION_STATUSES),
fieldWithPath("_links.rollout")
.description(MgmtApiModelProperties.LINK_TO_ROLLOUT))));
}
@Test
@@ -820,10 +828,19 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
return generateActionForTarget(knownControllerId, true, false, null, null, null);
}
private Action generateRolloutActionForTarget(final String knownControllerId) throws Exception {
return generateActionForTarget(knownControllerId, true, false, null, null, null, true);
}
private Action generateActionForTarget(final String knownControllerId, final boolean inSync) throws Exception {
return generateActionForTarget(knownControllerId, inSync, false, null, null, null);
}
private Action generateRolloutActionForTarget(final String knownControllerId, final boolean inSync,
final boolean timeforced) throws Exception {
return generateActionForTarget(knownControllerId, inSync, timeforced, null, null, null, true);
}
private Action generateActionForTarget(final String knownControllerId, final boolean inSync,
final boolean timeforced) throws Exception {
return generateActionForTarget(knownControllerId, inSync, timeforced, null, null, null);
@@ -832,14 +849,22 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
private Action generateActionForTarget(final String knownControllerId, final boolean inSync,
final boolean timeforced, final String maintenanceWindowSchedule, final String maintenanceWindowDuration,
final String maintenanceWindowTimeZone) throws Exception {
return generateActionForTarget(knownControllerId, inSync, timeforced, maintenanceWindowSchedule,
maintenanceWindowDuration, maintenanceWindowTimeZone, false);
}
private Action generateActionForTarget(final String knownControllerId, final boolean inSync,
final boolean timeforced, final String maintenanceWindowSchedule, final String maintenanceWindowDuration,
final String maintenanceWindowTimeZone, final boolean createRollout) throws Exception {
final PageRequest pageRequest = PageRequest.of(0, 1, Direction.ASC, ActionStatusFields.ID.getFieldName());
createTargetByGivenNameWithAttributes(knownControllerId, inSync, timeforced, createDistributionSet(),
maintenanceWindowSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone);
maintenanceWindowSchedule, maintenanceWindowDuration, maintenanceWindowTimeZone, createRollout);
final List<Action> actions = deploymentManagement.findActionsAll(pageRequest).getContent();
assertThat(actions).hasSize(1);
return actions.get(0);
}
}