Add resource collection /rest/v1/actions to Management REST API (#1299)
* Initial commit Signed-off-by: Stefan Behl <stefan.behl@bosch.io> * Added filtering by RSQL Signed-off-by: Stefan Behl <stefan.behl@bosch.io> * Support for filtering actions by distribution set, target, rollout * Added REST docs * Fixed REST docs * Introduce a config property which allows to disable the actions endpoint * Introduce representation mode parameter * Adapt REST docs * Incorporate review findings * Adapt REST docs * Improve unit tests * Minor improvements * Fix REST docs * Fix REST docs * Fix PR review findings Signed-off-by: Stefan Behl <stefan.behl@bosch.io>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRepresentationMode;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.rest.data.ResponseList;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
public final class MgmtActionMapper {
|
||||
|
||||
private MgmtActionMapper() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a response for actions.
|
||||
*
|
||||
* @param actions
|
||||
* list of actions
|
||||
* @param repMode
|
||||
* the representation mode
|
||||
*
|
||||
* @return the response
|
||||
*/
|
||||
public static List<MgmtAction> toResponse(final Collection<Action> actions, final MgmtRepresentationMode repMode) {
|
||||
if (actions == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return new ResponseList<>(actions.stream().map(action -> MgmtActionMapper.toResponse(action, repMode))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
static MgmtAction toResponse(final Action action, final MgmtRepresentationMode repMode) {
|
||||
final String controllerId = action.getTarget().getControllerId();
|
||||
if (repMode == MgmtRepresentationMode.COMPACT) {
|
||||
return MgmtTargetMapper.toResponse(controllerId, action);
|
||||
}
|
||||
return MgmtTargetMapper.toResponseWithLinks(controllerId, action);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtActionRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRepresentationMode;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@ConditionalOnProperty(name = "hawkbit.rest.MgmtActionResource.enabled", matchIfMissing = true)
|
||||
public class MgmtActionResource implements MgmtActionRestApi {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MgmtActionResource.class);
|
||||
|
||||
private final DeploymentManagement deploymentManagement;
|
||||
|
||||
MgmtActionResource(final DeploymentManagement deploymentManagement) {
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtAction>> getActions(final int pagingOffsetParam, final int pagingLimitParam,
|
||||
final String sortParam, final String rsqlParam, final String representationModeParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeActionSortParam(sortParam);
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Slice<Action> actions;
|
||||
final Long totalActionCount;
|
||||
if (rsqlParam != null) {
|
||||
actions = this.deploymentManagement.findActions(rsqlParam, pageable);
|
||||
totalActionCount = this.deploymentManagement.countActions(rsqlParam);
|
||||
} else {
|
||||
actions = this.deploymentManagement.findActionsAll(pageable);
|
||||
totalActionCount = this.deploymentManagement.countActionsAll();
|
||||
}
|
||||
|
||||
final MgmtRepresentationMode repMode = MgmtRepresentationMode.fromValue(representationModeParam)
|
||||
.orElseGet(() -> {
|
||||
// no need for a 400, just apply a safe fallback
|
||||
LOG.warn("Received an invalid representation mode: {}", representationModeParam);
|
||||
return MgmtRepresentationMode.COMPACT;
|
||||
});
|
||||
|
||||
return ResponseEntity
|
||||
.ok(new PagedList<>(MgmtActionMapper.toResponse(actions.getContent(), repMode), totalActionCount));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutSuccessAction;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutSuccessAction.SuccessAction;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroup;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroupResponseBody;
|
||||
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.repository.EntityFactory;
|
||||
@@ -57,11 +58,15 @@ final class MgmtRolloutMapper {
|
||||
}
|
||||
|
||||
static List<MgmtRolloutResponseBody> toResponseRollout(final List<Rollout> rollouts) {
|
||||
return toResponseRollout(rollouts, false);
|
||||
}
|
||||
|
||||
static List<MgmtRolloutResponseBody> toResponseRollout(final List<Rollout> rollouts, final boolean withDetails) {
|
||||
if (rollouts == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return rollouts.stream().map(rollout -> toResponseRollout(rollout, false)).collect(Collectors.toList());
|
||||
return rollouts.stream().map(rollout -> toResponseRollout(rollout, withDetails)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static MgmtRolloutResponseBody toResponseRollout(final Rollout rollout, final boolean withDetails) {
|
||||
@@ -95,6 +100,10 @@ final class MgmtRolloutMapper {
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRolloutGroups(rollout.getId(),
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null)).withRel("groups"));
|
||||
|
||||
final DistributionSet distributionSet = rollout.getDistributionSet();
|
||||
body.add(linkTo(methodOn(MgmtDistributionSetRestApi.class).getDistributionSet(distributionSet.getId()))
|
||||
.withRel("distributionset").withName(distributionSet.getName() + ":" + distributionSet.getVersion()));
|
||||
}
|
||||
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRollout(rollout.getId())).withSelfRel());
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroupResponseBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRepresentationMode;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
@@ -35,6 +36,8 @@ import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
@@ -51,6 +54,9 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
*/
|
||||
@RestController
|
||||
public class MgmtRolloutResource implements MgmtRolloutRestApi {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MgmtRolloutResource.class);
|
||||
|
||||
private final RolloutManagement rolloutManagement;
|
||||
|
||||
private final RolloutGroupManagement rolloutGroupManagement;
|
||||
@@ -76,14 +82,14 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) final int pagingLimitParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) final String sortParam,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam) {
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) final String rsqlParam,
|
||||
final String representationModeParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeRolloutSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Page<Rollout> findRolloutsAll;
|
||||
if (rsqlParam != null) {
|
||||
findRolloutsAll = this.rolloutManagement.findByRsql(pageable, rsqlParam, false);
|
||||
@@ -91,7 +97,15 @@ public class MgmtRolloutResource implements MgmtRolloutRestApi {
|
||||
findRolloutsAll = this.rolloutManagement.findAll(pageable, false);
|
||||
}
|
||||
|
||||
final List<MgmtRolloutResponseBody> rest = MgmtRolloutMapper.toResponseRollout(findRolloutsAll.getContent());
|
||||
final MgmtRepresentationMode repMode = MgmtRepresentationMode.fromValue(representationModeParam)
|
||||
.orElseGet(() -> {
|
||||
// no need for a 400, just apply a safe fallback
|
||||
LOG.warn("Received an invalid representation mode: {}", representationModeParam);
|
||||
return MgmtRepresentationMode.COMPACT;
|
||||
});
|
||||
|
||||
final List<MgmtRolloutResponseBody> rest = MgmtRolloutMapper.toResponseRollout(findRolloutsAll.getContent(),
|
||||
repMode == MgmtRepresentationMode.FULL);
|
||||
return ResponseEntity.ok(new PagedList<>(rest, findRolloutsAll.getTotalElements()));
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.eclipse.hawkbit.repository.builder.TargetCreate;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
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.PollStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
@@ -226,6 +227,8 @@ public final class MgmtTargetMapper {
|
||||
result.setStatus(MgmtAction.ACTION_FINISHED);
|
||||
}
|
||||
|
||||
result.setDetailStatus(action.getStatus().toString().toLowerCase());
|
||||
|
||||
final Rollout rollout = action.getRollout();
|
||||
if (rollout != null) {
|
||||
result.setRollout(rollout.getId());
|
||||
@@ -256,9 +259,13 @@ public final class MgmtTargetMapper {
|
||||
result.add(linkTo(methodOn(MgmtTargetRestApi.class).getAction(controllerId, action.getId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_CANCELED_ACTION));
|
||||
}
|
||||
result.add(linkTo(
|
||||
methodOn(MgmtDistributionSetRestApi.class).getDistributionSet(action.getDistributionSet().getId()))
|
||||
.withRel("distributionset"));
|
||||
|
||||
result.add(linkTo(methodOn(MgmtTargetRestApi.class).getTarget(controllerId)).withRel("target")
|
||||
.withName(action.getTarget().getName()));
|
||||
|
||||
final DistributionSet distributionSet = action.getDistributionSet();
|
||||
result.add(linkTo(methodOn(MgmtDistributionSetRestApi.class).getDistributionSet(distributionSet.getId()))
|
||||
.withRel("distributionset").withName(distributionSet.getName() + ":" + distributionSet.getVersion()));
|
||||
|
||||
result.add(linkTo(methodOn(MgmtTargetRestApi.class).getActionStatusList(controllerId, action.getId(), 0,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE,
|
||||
@@ -268,7 +275,7 @@ public final class MgmtTargetMapper {
|
||||
final Rollout rollout = action.getRollout();
|
||||
if (rollout != null) {
|
||||
result.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRollout(rollout.getId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ROLLOUT));
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ROLLOUT).withName(rollout.getName()));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user