Feature target metadata (#757)

* Defined the model for target matadata and the corresponding repository layer/management
* Added target metadata quotas incl enforcement
* Extended Target Mgmt REST API to allow for metadata CRUD operations
* Added migration scripts for each database
* Added back reference to target metadata in JpaTarget
* Added tests for target management, Mgmt REST API, target metadata RSQL, and REST documentation
* Updated asciidocs for target rest documentation
* Fix Allure imports and annotations
* Fix review findings

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch-si.com>
Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>
This commit is contained in:
Bondar Bogdan
2018-10-29 11:28:34 +01:00
committed by Stefan Behl
parent 1cbde47370
commit 0cf4f8e8b9
37 changed files with 1886 additions and 216 deletions

View File

@@ -10,6 +10,8 @@ package org.eclipse.hawkbit.mgmt.rest.api;
import java.util.List;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadataBodyPut;
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction;
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtActionRequestBodyPut;
@@ -37,13 +39,13 @@ public interface MgmtTargetRestApi {
/**
* Handles the GET request of retrieving a single target.
*
* @param controllerId
* @param targetId
* the ID of the target to retrieve
* @return a single target with status OK.
*/
@RequestMapping(method = RequestMethod.GET, value = "/{controllerId}", produces = { MediaTypes.HAL_JSON_VALUE,
@RequestMapping(method = RequestMethod.GET, value = "/{targetId}", produces = { MediaTypes.HAL_JSON_VALUE,
MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<MgmtTarget> getTarget(@PathVariable("controllerId") String controllerId);
ResponseEntity<MgmtTarget> getTarget(@PathVariable("targetId") String targetId);
/**
* Handles the GET request of retrieving all targets.
@@ -94,7 +96,7 @@ public interface MgmtTargetRestApi {
* path of the request. A given ID in the request body is ignored. It's not
* possible to set fields to {@code null} values.
*
* @param controllerId
* @param targetId
* the path parameter which contains the ID of the target
* @param targetRest
* the request body which contains the fields which should be
@@ -103,40 +105,40 @@ public interface MgmtTargetRestApi {
* @return the updated target response which contains all fields also fields
* which have not updated
*/
@RequestMapping(method = RequestMethod.PUT, value = "/{controllerId}", consumes = { MediaTypes.HAL_JSON_VALUE,
@RequestMapping(method = RequestMethod.PUT, value = "/{targetId}", consumes = { MediaTypes.HAL_JSON_VALUE,
MediaType.APPLICATION_JSON_VALUE }, produces = { MediaTypes.HAL_JSON_VALUE,
MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<MgmtTarget> updateTarget(@PathVariable("controllerId") String controllerId,
ResponseEntity<MgmtTarget> updateTarget(@PathVariable("targetId") String targetId,
MgmtTargetRequestBody targetRest);
/**
* Handles the DELETE request of deleting a target.
*
* @param controllerId
* @param targetId
* the ID of the target to be deleted
* @return If the given controllerId could exists and could be deleted Http
* OK. In any failure the JsonResponseExceptionHandler is handling
* the response.
* @return If the given targetId could exists and could be deleted Http OK.
* In any failure the JsonResponseExceptionHandler is handling the
* response.
*/
@RequestMapping(method = RequestMethod.DELETE, value = "/{controllerId}")
ResponseEntity<Void> deleteTarget(@PathVariable("controllerId") String controllerId);
@RequestMapping(method = RequestMethod.DELETE, value = "/{targetId}")
ResponseEntity<Void> deleteTarget(@PathVariable("targetId") String targetId);
/**
* Handles the GET request of retrieving the attributes of a specific
* target.
*
* @param controllerId
* @param targetId
* the ID of the target to retrieve the attributes.
* @return the target attributes as map response with status OK
*/
@RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/attributes", produces = {
@RequestMapping(method = RequestMethod.GET, value = "/{targetId}/attributes", produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<MgmtTargetAttributes> getAttributes(@PathVariable("controllerId") String controllerId);
ResponseEntity<MgmtTargetAttributes> getAttributes(@PathVariable("targetId") String targetId);
/**
* Handles the GET request of retrieving the Actions of a specific target.
*
* @param controllerId
* @param targetId
* to load actions for
* @param pagingOffsetParam
* the offset of list of targets for pagination, might not be
@@ -154,9 +156,9 @@ public interface MgmtTargetRestApi {
* status OK. The response is always paged. In any failure the
* JsonResponseExceptionHandler is handling the response.
*/
@RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/actions", produces = {
@RequestMapping(method = RequestMethod.GET, value = "/{targetId}/actions", produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<PagedList<MgmtAction>> getActionHistory(@PathVariable("controllerId") String controllerId,
ResponseEntity<PagedList<MgmtAction>> getActionHistory(@PathVariable("targetId") String targetId,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) int pagingOffsetParam,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) int pagingLimitParam,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) String sortParam,
@@ -166,22 +168,22 @@ public interface MgmtTargetRestApi {
* Handles the GET request of retrieving a specific Actions of a specific
* Target.
*
* @param controllerId
* @param targetId
* to load the action for
* @param actionId
* to load
* @return the action
*/
@RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/actions/{actionId}", produces = {
@RequestMapping(method = RequestMethod.GET, value = "/{targetId}/actions/{actionId}", produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<MgmtAction> getAction(@PathVariable("controllerId") String controllerId,
ResponseEntity<MgmtAction> getAction(@PathVariable("targetId") String targetId,
@PathVariable("actionId") Long actionId);
/**
* Handles the DELETE request of canceling an specific Actions of a specific
* Target.
*
* @param controllerId
* @param targetId
* the ID of the target in the URL path parameter
* @param actionId
* the ID of the action in the URL path parameter
@@ -189,15 +191,15 @@ public interface MgmtTargetRestApi {
* optional parameter, which indicates a force cancel
* @return status no content in case cancellation was successful
*/
@RequestMapping(method = RequestMethod.DELETE, value = "/{controllerId}/actions/{actionId}")
ResponseEntity<Void> cancelAction(@PathVariable("controllerId") String controllerId,
@RequestMapping(method = RequestMethod.DELETE, value = "/{targetId}/actions/{actionId}")
ResponseEntity<Void> cancelAction(@PathVariable("targetId") String targetId,
@PathVariable("actionId") Long actionId,
@RequestParam(value = "force", required = false, defaultValue = "false") boolean force);
/**
* Handles the PUT update request to switch an action from soft to forced.
*
* @param controllerId
* @param targetId
* the ID of the target in the URL path parameter
* @param actionId
* the ID of the action in the URL path parameter
@@ -205,17 +207,17 @@ public interface MgmtTargetRestApi {
* to update the action
* @return status no content in case cancellation was successful
*/
@RequestMapping(method = RequestMethod.PUT, value = "/{controllerId}/actions/{actionId}", consumes = {
@RequestMapping(method = RequestMethod.PUT, value = "/{targetId}/actions/{actionId}", consumes = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = { MediaTypes.HAL_JSON_VALUE,
MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<MgmtAction> updateAction(@PathVariable("controllerId") String controllerId,
ResponseEntity<MgmtAction> updateAction(@PathVariable("targetId") String targetId,
@PathVariable("actionId") Long actionId, MgmtActionRequestBodyPut actionUpdate);
/**
* Handles the GET request of retrieving the ActionStatus of a specific
* target and action.
*
* @param controllerId
* @param targetId
* of the the action
* @param actionId
* of the status we are intend to load
@@ -232,9 +234,9 @@ public interface MgmtTargetRestApi {
* with status OK. The response is always paged. In any failure the
* JsonResponseExceptionHandler is handling the response.
*/
@RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/actions/{actionId}/status", produces = {
@RequestMapping(method = RequestMethod.GET, value = "/{targetId}/actions/{actionId}/status", produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<PagedList<MgmtActionStatus>> getActionStatusList(@PathVariable("controllerId") String controllerId,
ResponseEntity<PagedList<MgmtActionStatus>> getActionStatusList(@PathVariable("targetId") String targetId,
@PathVariable("actionId") Long actionId,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) int pagingOffsetParam,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) int pagingLimitParam,
@@ -244,20 +246,20 @@ public interface MgmtTargetRestApi {
* Handles the GET request of retrieving the assigned distribution set of an
* specific target.
*
* @param controllerId
* @param targetId
* the ID of the target to retrieve the assigned distribution
*
* @return the assigned distribution set with status OK, if none is assigned
* than {@code null} content (e.g. "{}")
*/
@RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/assignedDS", produces = {
@RequestMapping(method = RequestMethod.GET, value = "/{targetId}/assignedDS", produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<MgmtDistributionSet> getAssignedDistributionSet(@PathVariable("controllerId") String controllerId);
ResponseEntity<MgmtDistributionSet> getAssignedDistributionSet(@PathVariable("targetId") String targetId);
/**
* Changes the assigned distribution set of a target.
*
* @param controllerId
* @param targetId
* of the target to change
* @param dsId
* of the distributionset that is to be assigned
@@ -269,24 +271,113 @@ public interface MgmtTargetRestApi {
* complex return body which contains information about the assigned
* targets and the already assigned targets counters
*/
@RequestMapping(method = RequestMethod.POST, value = "/{controllerId}/assignedDS", consumes = {
@RequestMapping(method = RequestMethod.POST, value = "/{targetId}/assignedDS", consumes = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = { MediaTypes.HAL_JSON_VALUE,
MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<MgmtTargetAssignmentResponseBody> postAssignedDistributionSet(
@PathVariable("controllerId") String controllerId, MgmtDistributionSetAssignment dsId,
@PathVariable("targetId") String targetId, MgmtDistributionSetAssignment dsId,
@RequestParam(value = "offline", required = false) boolean offline);
/**
* Handles the GET request of retrieving the installed distribution set of
* an specific target.
*
* @param controllerId
* @param targetId
* the ID of the target to retrieve
* @return the assigned installed set with status OK, if none is installed
* than {@code null} content (e.g. "{}")
*/
@RequestMapping(method = RequestMethod.GET, value = "/{controllerId}/installedDS", produces = {
@RequestMapping(method = RequestMethod.GET, value = "/{targetId}/installedDS", produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<MgmtDistributionSet> getInstalledDistributionSet(@PathVariable("controllerId") String controllerId);
ResponseEntity<MgmtDistributionSet> getInstalledDistributionSet(@PathVariable("targetId") String targetId);
/**
* Gets a paged list of meta data for a target.
*
* @param targetId
* the ID of the target for the meta data
* @param pagingOffsetParam
* the offset of list of targets for pagination, might not be
* present in the rest request then default value will be applied
* @param pagingLimitParam
* the limit of the paged request, might not be present in the
* rest request then default value will be applied
* @param sortParam
* the sorting parameter in the request URL, syntax
* {@code field:direction, field:direction}
* @param rsqlParam
* the search parameter in the request URL, syntax
* {@code q=key==abc}
* @return status OK if get request is successful with the paged list of
* meta data
*/
@RequestMapping(method = RequestMethod.GET, value = "/{targetId}/metadata", produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<PagedList<MgmtMetadata>> getMetadata(@PathVariable("targetId") String targetId,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) int pagingOffsetParam,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT) int pagingLimitParam,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SORTING, required = false) String sortParam,
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_SEARCH, required = false) String rsqlParam);
/**
* Gets a single meta data value for a specific key of a target.
*
* @param targetId
* the ID of the target to get the meta data from
* @param metadataKey
* the key of the meta data entry to retrieve the value from
* @return status OK if get request is successful with the value of the meta
* data
*/
@RequestMapping(method = RequestMethod.GET, value = "/{targetId}/metadata/{metadataKey}", produces = {
MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<MgmtMetadata> getMetadataValue(@PathVariable("targetId") String targetId,
@PathVariable("metadataKey") String metadataKey);
/**
* Updates a single meta data value of a target.
*
* @param targetId
* the ID of the target to update the meta data entry
* @param metadataKey
* the key of the meta data to update the value
* @param metadata
* update body
* @return status OK if the update request is successful and the updated
* meta data result
*/
@RequestMapping(method = RequestMethod.PUT, value = "/{targetId}/metadata/{metadataKey}", produces = {
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<MgmtMetadata> updateMetadata(@PathVariable("targetId") String targetId,
@PathVariable("metadataKey") String metadataKey, MgmtMetadataBodyPut metadata);
/**
* Deletes a single meta data entry from the target.
*
* @param targetId
* the ID of the target to delete the meta data entry
* @param metadataKey
* the key of the meta data to delete
* @return status OK if the delete request is successful
*/
@RequestMapping(method = RequestMethod.DELETE, value = "/{targetId}/metadata/{metadataKey}")
ResponseEntity<Void> deleteMetadata(@PathVariable("targetId") String targetId,
@PathVariable("metadataKey") String metadataKey);
/**
* Creates a list of meta data for a specific target.
*
* @param targetId
* the ID of the targetId to create meta data for
* @param metadataRest
* the list of meta data entries to create
* @return status created if post request is successful with the value of
* the created meta data
*/
@RequestMapping(method = RequestMethod.POST, value = "/{targetId}/metadata", consumes = {
MediaType.APPLICATION_JSON_VALUE,
MediaTypes.HAL_JSON_VALUE }, produces = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<List<MgmtMetadata>> createMetadata(@PathVariable("targetId") String targetId,
List<MgmtMetadata> metadataRest);
}

View File

@@ -93,7 +93,7 @@ public final class MgmtDistributionSetMapper {
}
return metadata.stream()
.map(metadataRest -> entityFactory.generateMetadata(metadataRest.getKey(), metadataRest.getValue()))
.map(metadataRest -> entityFactory.generateDsMetadata(metadataRest.getKey(), metadataRest.getValue()))
.collect(Collectors.toList());
}

View File

@@ -321,7 +321,7 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
// check if distribution set exists otherwise throw exception
// immediately
final DistributionSetMetadata updated = distributionSetManagement.updateMetaData(distributionSetId,
entityFactory.generateMetadata(metadataKey, metadata.getValue()));
entityFactory.generateDsMetadata(metadataKey, metadata.getValue()));
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponseDsMetadata(updated));
}

View File

@@ -20,6 +20,7 @@ import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindow;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
import org.eclipse.hawkbit.mgmt.json.model.MgmtPollStatus;
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction;
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtActionStatus;
@@ -36,8 +37,10 @@ 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.MetaData;
import org.eclipse.hawkbit.repository.model.PollStatus;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetMetadata;
import org.eclipse.hawkbit.rest.data.ResponseList;
import org.eclipse.hawkbit.rest.data.SortDirection;
import org.eclipse.hawkbit.util.IpUtil;
@@ -71,6 +74,9 @@ public final class MgmtTargetMapper {
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE,
ActionFields.ID.getFieldName() + ":" + SortDirection.DESC, null))
.withRel(MgmtRestConstants.TARGET_V1_ACTIONS).expand());
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getMetadata(response.getControllerId(),
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null)).withRel("metadata"));
}
static void addPollStatus(final Target target, final MgmtTarget targetRest) {
@@ -167,6 +173,17 @@ public final class MgmtTargetMapper {
.address(targetRest.getAddress());
}
static List<MetaData> fromRequestTargetMetadata(final List<MgmtMetadata> metadata,
final EntityFactory entityFactory) {
if (metadata == null) {
return Collections.emptyList();
}
return metadata.stream().map(
metadataRest -> entityFactory.generateTargetMetadata(metadataRest.getKey(), metadataRest.getValue()))
.collect(Collectors.toList());
}
static List<MgmtActionStatus> toActionStatusRestResponse(final Collection<ActionStatus> actionStatus,
final DeploymentManagement deploymentManagement) {
if (actionStatus == null) {
@@ -261,4 +278,15 @@ public final class MgmtTargetMapper {
return result;
}
static MgmtMetadata toResponseTargetMetadata(final TargetMetadata metadata) {
final MgmtMetadata metadataRest = new MgmtMetadata();
metadataRest.setKey(metadata.getKey());
metadataRest.setValue(metadata.getValue());
return metadataRest;
}
static List<MgmtMetadata> toResponseTargetMetadata(final List<TargetMetadata> metadata) {
return metadata.stream().map(MgmtTargetMapper::toResponseTargetMetadata).collect(Collectors.toList());
}
}

View File

@@ -16,6 +16,8 @@ import java.util.Map;
import javax.validation.ValidationException;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindowRequestBody;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadataBodyPut;
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction;
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtActionRequestBodyPut;
@@ -38,6 +40,7 @@ import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetMetadata;
import org.eclipse.hawkbit.repository.model.TargetWithActionType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -70,8 +73,8 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
private EntityFactory entityFactory;
@Override
public ResponseEntity<MgmtTarget> getTarget(@PathVariable("controllerId") final String controllerId) {
final Target findTarget = findTargetWithExceptionIfNotFound(controllerId);
public ResponseEntity<MgmtTarget> getTarget(@PathVariable("targetId") final String targetId) {
final Target findTarget = findTargetWithExceptionIfNotFound(targetId);
// to single response include poll status
final MgmtTarget response = MgmtTargetMapper.toResponse(findTarget);
MgmtTargetMapper.addPollStatus(findTarget, response);
@@ -117,22 +120,21 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
}
@Override
public ResponseEntity<MgmtTarget> updateTarget(@PathVariable("controllerId") final String controllerId,
public ResponseEntity<MgmtTarget> updateTarget(@PathVariable("targetId") final String targetId,
@RequestBody final MgmtTargetRequestBody targetRest) {
if (targetRest.isRequestAttributes() != null) {
if (targetRest.isRequestAttributes()) {
targetManagement.requestControllerAttributes(controllerId);
targetManagement.requestControllerAttributes(targetId);
} else {
return ResponseEntity.badRequest().build();
}
}
final Target updateTarget = this.targetManagement.update(entityFactory.target().update(controllerId)
final Target updateTarget = this.targetManagement.update(entityFactory.target().update(targetId)
.name(targetRest.getName()).description(targetRest.getDescription()).address(targetRest.getAddress())
.securityToken(targetRest.getSecurityToken()).requestAttributes(targetRest.isRequestAttributes()));
final MgmtTarget response = MgmtTargetMapper.toResponse(updateTarget);
MgmtTargetMapper.addPollStatus(updateTarget, response);
MgmtTargetMapper.addTargetLinks(response);
@@ -141,15 +143,15 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
}
@Override
public ResponseEntity<Void> deleteTarget(@PathVariable("controllerId") final String controllerId) {
this.targetManagement.deleteByControllerID(controllerId);
LOG.debug("{} target deleted, return status {}", controllerId, HttpStatus.OK);
public ResponseEntity<Void> deleteTarget(@PathVariable("targetId") final String targetId) {
this.targetManagement.deleteByControllerID(targetId);
LOG.debug("{} target deleted, return status {}", targetId, HttpStatus.OK);
return ResponseEntity.ok().build();
}
@Override
public ResponseEntity<MgmtTargetAttributes> getAttributes(@PathVariable("controllerId") final String controllerId) {
final Map<String, String> controllerAttributes = targetManagement.getControllerAttributes(controllerId);
public ResponseEntity<MgmtTargetAttributes> getAttributes(@PathVariable("targetId") final String targetId) {
final Map<String, String> controllerAttributes = targetManagement.getControllerAttributes(targetId);
if (controllerAttributes.isEmpty()) {
return ResponseEntity.noContent().build();
}
@@ -162,13 +164,13 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
@Override
public ResponseEntity<PagedList<MgmtAction>> getActionHistory(
@PathVariable("controllerId") final String controllerId,
@PathVariable("targetId") final String targetId,
@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) {
findTargetWithExceptionIfNotFound(controllerId);
findTargetWithExceptionIfNotFound(targetId);
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
@@ -178,40 +180,41 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
final Slice<Action> activeActions;
final Long totalActionCount;
if (rsqlParam != null) {
activeActions = this.deploymentManagement.findActionsByTarget(rsqlParam, controllerId, pageable);
totalActionCount = this.deploymentManagement.countActionsByTarget(rsqlParam, controllerId);
activeActions = this.deploymentManagement.findActionsByTarget(rsqlParam, targetId, pageable);
totalActionCount = this.deploymentManagement.countActionsByTarget(rsqlParam, targetId);
} else {
activeActions = this.deploymentManagement.findActionsByTarget(controllerId, pageable);
totalActionCount = this.deploymentManagement.countActionsByTarget(controllerId);
activeActions = this.deploymentManagement.findActionsByTarget(targetId, pageable);
totalActionCount = this.deploymentManagement.countActionsByTarget(targetId);
}
return ResponseEntity.ok(new PagedList<>(MgmtTargetMapper.toResponse(controllerId, activeActions.getContent()),
return ResponseEntity.ok(
new PagedList<>(MgmtTargetMapper.toResponse(targetId, activeActions.getContent()),
totalActionCount));
}
@Override
public ResponseEntity<MgmtAction> getAction(@PathVariable("controllerId") final String controllerId,
public ResponseEntity<MgmtAction> getAction(@PathVariable("targetId") final String targetId,
@PathVariable("actionId") final Long actionId) {
final Action action = deploymentManagement.findAction(actionId)
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
if (!action.getTarget().getControllerId().equals(controllerId)) {
LOG.warn("given action ({}) is not assigned to given target ({}).", action.getId(), controllerId);
if (!action.getTarget().getControllerId().equals(targetId)) {
LOG.warn("given action ({}) is not assigned to given target ({}).", action.getId(), targetId);
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(MgmtTargetMapper.toResponseWithLinks(controllerId, action));
return ResponseEntity.ok(MgmtTargetMapper.toResponseWithLinks(targetId, action));
}
@Override
public ResponseEntity<Void> cancelAction(@PathVariable("controllerId") final String controllerId,
public ResponseEntity<Void> cancelAction(@PathVariable("targetId") final String targetId,
@PathVariable("actionId") final Long actionId,
@RequestParam(value = "force", required = false, defaultValue = "false") final boolean force) {
final Action action = deploymentManagement.findAction(actionId)
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
if (!action.getTarget().getControllerId().equals(controllerId)) {
LOG.warn("given action ({}) is not assigned to given target ({}).", actionId, controllerId);
if (!action.getTarget().getControllerId().equals(targetId)) {
LOG.warn("given action ({}) is not assigned to given target ({}).", actionId, targetId);
return ResponseEntity.notFound().build();
}
@@ -228,12 +231,12 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
@Override
public ResponseEntity<PagedList<MgmtActionStatus>> getActionStatusList(
@PathVariable("controllerId") final String controllerId, @PathVariable("actionId") final Long actionId,
@PathVariable("targetId") final String targetId, @PathVariable("actionId") final Long actionId,
@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) {
final Target target = findTargetWithExceptionIfNotFound(controllerId);
final Target target = findTargetWithExceptionIfNotFound(targetId);
final Action action = deploymentManagement.findAction(actionId)
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
@@ -258,8 +261,8 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
@Override
public ResponseEntity<MgmtDistributionSet> getAssignedDistributionSet(
@PathVariable("controllerId") final String controllerId) {
final MgmtDistributionSet distributionSetRest = deploymentManagement.getAssignedDistributionSet(controllerId)
@PathVariable("targetId") final String targetId) {
final MgmtDistributionSet distributionSetRest = deploymentManagement.getAssignedDistributionSet(targetId)
.map(ds -> {
final MgmtDistributionSet response = MgmtDistributionSetMapper.toResponse(ds);
MgmtDistributionSetMapper.addLinks(ds, response);
@@ -275,21 +278,21 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
@Override
public ResponseEntity<MgmtTargetAssignmentResponseBody> postAssignedDistributionSet(
@PathVariable("controllerId") final String controllerId,
@PathVariable("targetId") final String targetId,
@RequestBody final MgmtDistributionSetAssignment dsId,
@RequestParam(value = "offline", required = false) final boolean offline) {
if (offline) {
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponse(
deploymentManagement.offlineAssignedDistributionSet(dsId.getId(), Arrays.asList(controllerId))));
deploymentManagement.offlineAssignedDistributionSet(dsId.getId(), Arrays.asList(targetId))));
}
findTargetWithExceptionIfNotFound(controllerId);
findTargetWithExceptionIfNotFound(targetId);
final MgmtMaintenanceWindowRequestBody maintenanceWindow = dsId.getMaintenanceWindow();
if (maintenanceWindow == null) {
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponse(this.deploymentManagement
.assignDistributionSet(dsId.getId(), Arrays.asList(new TargetWithActionType(controllerId,
.assignDistributionSet(dsId.getId(), Arrays.asList(new TargetWithActionType(targetId,
MgmtRestModelMapper.convertActionType(dsId.getType()), dsId.getForcetime())))));
}
@@ -301,7 +304,7 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
return ResponseEntity
.ok(MgmtDistributionSetMapper.toResponse(this.deploymentManagement.assignDistributionSet(dsId.getId(),
Arrays.asList(new TargetWithActionType(controllerId,
Arrays.asList(new TargetWithActionType(targetId,
MgmtRestModelMapper.convertActionType(dsId.getType()), dsId.getForcetime(),
cronSchedule, duration, timezone)))));
@@ -309,8 +312,8 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
@Override
public ResponseEntity<MgmtDistributionSet> getInstalledDistributionSet(
@PathVariable("controllerId") final String controllerId) {
final MgmtDistributionSet distributionSetRest = deploymentManagement.getInstalledDistributionSet(controllerId)
@PathVariable("targetId") final String targetId) {
final MgmtDistributionSet distributionSetRest = deploymentManagement.getInstalledDistributionSet(targetId)
.map(set -> {
final MgmtDistributionSet response = MgmtDistributionSetMapper.toResponse(set);
MgmtDistributionSetMapper.addLinks(set, response);
@@ -325,19 +328,19 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
return ResponseEntity.ok(distributionSetRest);
}
private Target findTargetWithExceptionIfNotFound(final String controllerId) {
return targetManagement.getByControllerID(controllerId)
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
private Target findTargetWithExceptionIfNotFound(final String targetId) {
return targetManagement.getByControllerID(targetId)
.orElseThrow(() -> new EntityNotFoundException(Target.class, targetId));
}
@Override
public ResponseEntity<MgmtAction> updateAction(@PathVariable("controllerId") final String controllerId,
public ResponseEntity<MgmtAction> updateAction(@PathVariable("targetId") final String targetId,
@PathVariable("actionId") final Long actionId, @RequestBody final MgmtActionRequestBodyPut actionUpdate) {
Action action = deploymentManagement.findAction(actionId)
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
if (!action.getTarget().getControllerId().equals(controllerId)) {
LOG.warn("given action ({}) is not assigned to given target ({}).", action.getId(), controllerId);
if (!action.getTarget().getControllerId().equals(targetId)) {
LOG.warn("given action ({}) is not assigned to given target ({}).", action.getId(), targetId);
return ResponseEntity.notFound().build();
}
@@ -347,7 +350,62 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
action = deploymentManagement.forceTargetAction(actionId);
return ResponseEntity.ok(MgmtTargetMapper.toResponseWithLinks(controllerId, action));
return ResponseEntity.ok(MgmtTargetMapper.toResponseWithLinks(targetId, action));
}
@Override
public ResponseEntity<PagedList<MgmtMetadata>> getMetadata(@PathVariable("targetId") final String targetId,
@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) {
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
final Sort sorting = PagingUtility.sanitizeDistributionSetMetadataSortParam(sortParam);
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
final Page<TargetMetadata> metaDataPage;
if (rsqlParam != null) {
metaDataPage = targetManagement.findMetaDataByControllerIdAndRsql(pageable, targetId, rsqlParam);
} else {
metaDataPage = targetManagement.findMetaDataByControllerId(pageable, targetId);
}
return ResponseEntity.ok(new PagedList<>(MgmtTargetMapper.toResponseTargetMetadata(metaDataPage.getContent()),
metaDataPage.getTotalElements()));
}
@Override
public ResponseEntity<MgmtMetadata> getMetadataValue(@PathVariable("targetId") final String targetId,
@PathVariable("metadataKey") final String metadataKey) {
final TargetMetadata findOne = targetManagement.getMetaDataByControllerId(targetId, metadataKey)
.orElseThrow(() -> new EntityNotFoundException(TargetMetadata.class, targetId, metadataKey));
return ResponseEntity.ok(MgmtTargetMapper.toResponseTargetMetadata(findOne));
}
@Override
public ResponseEntity<MgmtMetadata> updateMetadata(@PathVariable("targetId") final String targetId,
@PathVariable("metadataKey") final String metadataKey, @RequestBody final MgmtMetadataBodyPut metadata) {
final TargetMetadata updated = targetManagement.updateMetaData(targetId,
entityFactory.generateTargetMetadata(metadataKey, metadata.getValue()));
return ResponseEntity.ok(MgmtTargetMapper.toResponseTargetMetadata(updated));
}
@Override
public ResponseEntity<Void> deleteMetadata(@PathVariable("targetId") final String targetId,
@PathVariable("metadataKey") final String metadataKey) {
targetManagement.deleteMetaData(targetId, metadataKey);
return ResponseEntity.ok().build();
}
@Override
public ResponseEntity<List<MgmtMetadata>> createMetadata(@PathVariable("targetId") final String targetId,
@RequestBody final List<MgmtMetadata> metadataRest) {
final List<TargetMetadata> created = targetManagement.createMetaData(targetId,
MgmtTargetMapper.fromRequestTargetMetadata(metadataRest, entityFactory));
return new ResponseEntity<>(MgmtTargetMapper.toResponseTargetMetadata(created), HttpStatus.CREATED);
}
}

View File

@@ -1036,7 +1036,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
final String updateValue = "valueForUpdate";
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
createDistributionSetMetadata(testDS.getId(), entityFactory.generateMetadata(knownKey, knownValue));
createDistributionSetMetadata(testDS.getId(), entityFactory.generateDsMetadata(knownKey, knownValue));
final JSONObject jsonObject = new JSONObject().put("key", knownKey).put("value", updateValue);
@@ -1060,7 +1060,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
final String knownValue = "knownValue";
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
createDistributionSetMetadata(testDS.getId(), entityFactory.generateMetadata(knownKey, knownValue));
createDistributionSetMetadata(testDS.getId(), entityFactory.generateDsMetadata(knownKey, knownValue));
mvc.perform(delete("/rest/v1/distributionsets/{dsId}/metadata/{key}", testDS.getId(), knownKey))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
@@ -1076,7 +1076,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
final String knownValue = "knownValue";
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
createDistributionSetMetadata(testDS.getId(), entityFactory.generateMetadata(knownKey, knownValue));
createDistributionSetMetadata(testDS.getId(), entityFactory.generateDsMetadata(knownKey, knownValue));
mvc.perform(delete("/rest/v1/distributionsets/{dsId}/metadata/XXX", testDS.getId(), knownKey))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
@@ -1094,7 +1094,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
final String knownKey = "knownKey";
final String knownValue = "knownValue";
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
createDistributionSetMetadata(testDS.getId(), entityFactory.generateMetadata(knownKey, knownValue));
createDistributionSetMetadata(testDS.getId(), entityFactory.generateDsMetadata(knownKey, knownValue));
mvc.perform(get("/rest/v1/distributionsets/{dsId}/metadata/{key}", testDS.getId(), knownKey))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
@@ -1113,7 +1113,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
for (int index = 0; index < totalMetadata; index++) {
createDistributionSetMetadata(testDS.getId(),
entityFactory.generateMetadata(knownKeyPrefix + index, knownValuePrefix + index));
entityFactory.generateDsMetadata(knownKeyPrefix + index, knownValuePrefix + index));
}
mvc.perform(get("/rest/v1/distributionsets/{dsId}/metadata?offset=" + offsetParam + "&limit=" + limitParam,
@@ -1189,7 +1189,7 @@ public class MgmtDistributionSetResourceTest extends AbstractManagementApiIntegr
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
for (int index = 0; index < totalMetadata; index++) {
createDistributionSetMetadata(testDS.getId(),
entityFactory.generateMetadata(knownKeyPrefix + index, knownValuePrefix + index));
entityFactory.generateDsMetadata(knownKeyPrefix + index, knownValuePrefix + index));
}
final String rsqlSearchValue1 = "value==knownValue1";

View File

@@ -26,8 +26,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -45,8 +47,10 @@ import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.Action.Status;
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.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetMetadata;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.rest.exception.MessageNotReadableException;
@@ -54,6 +58,7 @@ import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.eclipse.hawkbit.util.IpUtil;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Test;
import org.springframework.data.domain.PageRequest;
@@ -1564,8 +1569,8 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
final String body = new JSONObject().put("requestAttributes", true).toString();
mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId).content(body)
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(targetManagement.isControllerAttributesRequested(knownTargetId)).isTrue();
}
@@ -1575,8 +1580,8 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
final String body = new JSONObject().put("description", "verify attribute can be missing").toString();
mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId).content(body)
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
}
@Step
@@ -1584,8 +1589,8 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
final String body = new JSONObject().put("requestAttributes", false).toString();
mvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId).content(body)
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
assertThat(targetManagement.isControllerAttributesRequested(knownTargetId)).isTrue();
}
@@ -1649,4 +1654,193 @@ public class MgmtTargetResourceTest extends AbstractManagementApiIntegrationTest
assertThat(actionsByTarget.getContent()).hasSize(1);
return targetManagement.getByControllerID(tA.getControllerId()).get();
}
@Test
@Description("Ensures that the metadata creation through API is reflected by the repository.")
public void createMetadata() throws Exception {
final String knownControllerId = "targetIdWithMetadata";
testdataFactory.createTarget(knownControllerId);
final String knownKey1 = "knownKey1";
final String knownKey2 = "knownKey2";
final String knownValue1 = "knownValue1";
final String knownValue2 = "knownValue2";
final JSONArray metaData1 = new JSONArray();
metaData1.put(new JSONObject().put("key", knownKey1).put("value", knownValue1));
metaData1.put(new JSONObject().put("key", knownKey2).put("value", knownValue2));
mvc.perform(
post("/rest/v1/targets/{targetId}/metadata", knownControllerId).accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).content(metaData1.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0]key", equalTo(knownKey1))).andExpect(jsonPath("[0]value", equalTo(knownValue1)))
.andExpect(jsonPath("[1]key", equalTo(knownKey2)))
.andExpect(jsonPath("[1]value", equalTo(knownValue2)));
final TargetMetadata metaKey1 = targetManagement.getMetaDataByControllerId(knownControllerId, knownKey1).get();
final TargetMetadata metaKey2 = targetManagement.getMetaDataByControllerId(knownControllerId, knownKey2).get();
assertThat(metaKey1.getValue()).isEqualTo(knownValue1);
assertThat(metaKey2.getValue()).isEqualTo(knownValue2);
// verify quota enforcement
final int maxMetaData = quotaManagement.getMaxMetaDataEntriesPerTarget();
final JSONArray metaData2 = new JSONArray();
for (int i = 0; i < maxMetaData - metaData1.length() + 1; ++i) {
metaData2.put(new JSONObject().put("key", knownKey1 + i).put("value", knownValue1 + i));
}
mvc.perform(
post("/rest/v1/targets/{targetId}/metadata", knownControllerId).accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON).content(metaData2.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden());
// verify that the number of meta data entries has not changed
// (we cannot use the PAGE constant here as it tries to sort by ID)
assertThat(targetManagement.findMetaDataByControllerId(new PageRequest(0, Integer.MAX_VALUE), knownControllerId)
.getTotalElements()).isEqualTo(metaData1.length());
}
@Test
@Description("Ensures that a metadata update through API is reflected by the repository.")
public void updateMetadata() throws Exception {
final String knownControllerId = "targetIdWithMetadata";
// prepare and create metadata for update
final String knownKey = "knownKey";
final String knownValue = "knownValue";
final String updateValue = "valueForUpdate";
setupTargetWithMetadata(knownControllerId, knownKey, knownValue);
final JSONObject jsonObject = new JSONObject().put("key", knownKey).put("value", updateValue);
mvc.perform(put("/rest/v1/targets/{targetId}/metadata/{key}", knownControllerId, knownKey)
.accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON)
.content(jsonObject.toString())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("key", equalTo(knownKey))).andExpect(jsonPath("value", equalTo(updateValue)));
final TargetMetadata updatedTargetMetadata = targetManagement
.getMetaDataByControllerId(knownControllerId, knownKey).get();
assertThat(updatedTargetMetadata.getValue()).isEqualTo(updateValue);
}
private void setupTargetWithMetadata(final String knownControllerId, final String knownKey,
final String knownValue) {
testdataFactory.createTarget(knownControllerId);
targetManagement.createMetaData(knownControllerId,
Collections.singletonList(entityFactory.generateTargetMetadata(knownKey, knownValue)));
}
@Test
@Description("Ensures that a metadata entry deletion through API is reflected by the repository.")
public void deleteMetadata() throws Exception {
final String knownControllerId = "targetIdWithMetadata";
// prepare and create metadata for deletion
final String knownKey = "knownKey";
final String knownValue = "knownValue";
setupTargetWithMetadata(knownControllerId, knownKey, knownValue);
mvc.perform(delete("/rest/v1/targets/{targetId}/metadata/{key}", knownControllerId, knownKey))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(targetManagement.getMetaDataByControllerId(knownControllerId, knownKey)).isNotPresent();
}
@Test
@Description("Ensures that target metadata deletion request to API on an entity that does not exist results in NOT_FOUND.")
public void deleteMetadataThatDoesNotExistLeadsToNotFound() throws Exception {
final String knownControllerId = "targetIdWithMetadata";
// prepare and create metadata for deletion
final String knownKey = "knownKey";
final String knownValue = "knownValue";
setupTargetWithMetadata(knownControllerId, knownKey, knownValue);
mvc.perform(delete("/rest/v1/targets/{targetId}/metadata/XXX", knownControllerId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
mvc.perform(delete("/rest/v1/targets/1234/metadata/{key}", knownKey)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
assertThat(targetManagement.getMetaDataByControllerId(knownControllerId, knownKey)).isPresent();
}
@Test
@Description("Ensures that a metadata entry selection through API reflectes the repository content.")
public void getSingleMetadata() throws Exception {
final String knownControllerId = "targetIdWithMetadata";
// prepare and create metadata for deletion
final String knownKey = "knownKey";
final String knownValue = "knownValue";
setupTargetWithMetadata(knownControllerId, knownKey, knownValue);
mvc.perform(get("/rest/v1/targets/{targetId}/metadata/{key}", knownControllerId, knownKey))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("key", equalTo(knownKey))).andExpect(jsonPath("value", equalTo(knownValue)));
}
@Test
@Description("Ensures that a metadata entry paged list selection through API reflectes the repository content.")
public void getPagedListOfMetadata() throws Exception {
final String knownControllerId = "targetIdWithMetadata";
final int totalMetadata = 10;
final int limitParam = 5;
final String offsetParam = "0";
final String knownKeyPrefix = "knownKey";
final String knownValuePrefix = "knownValue";
setupTargetWithMetadata(knownControllerId, knownKeyPrefix, knownValuePrefix, totalMetadata);
mvc.perform(get("/rest/v1/targets/{targetId}/metadata?offset=" + offsetParam + "&limit=" + limitParam,
knownControllerId)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("size", equalTo(limitParam))).andExpect(jsonPath("total", equalTo(totalMetadata)))
.andExpect(jsonPath("content[0].key", equalTo("knownKey0")))
.andExpect(jsonPath("content[0].value", equalTo("knownValue0")));
}
private void setupTargetWithMetadata(final String knownControllerId, final String knownKeyPrefix,
final String knownValuePrefix, final int totalMetadata) {
testdataFactory.createTarget(knownControllerId);
final List<MetaData> targetMetadataEntries = new LinkedList<>();
for (int index = 0; index < totalMetadata; index++) {
targetMetadataEntries
.add(entityFactory.generateTargetMetadata(knownKeyPrefix + index, knownValuePrefix + index));
}
targetManagement.createMetaData(knownControllerId, targetMetadataEntries);
}
@Test
@Description("Ensures that a target metadata filtered query with value==knownValue1 parameter returns only the metadata entries with that value.")
public void searchDistributionSetMetadataRsql() throws Exception {
final String knownControllerId = "targetIdWithMetadata";
final int totalMetadata = 10;
final String knownKeyPrefix = "knownKey";
final String knownValuePrefix = "knownValue";
setupTargetWithMetadata(knownControllerId, knownKeyPrefix, knownValuePrefix, totalMetadata);
final String rsqlSearchValue1 = "value==knownValue1";
mvc.perform(get("/rest/v1/targets/{targetId}/metadata?q=" + rsqlSearchValue1, knownControllerId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("size", equalTo(1)))
.andExpect(jsonPath("total", equalTo(1))).andExpect(jsonPath("content[0].key", equalTo("knownKey1")))
.andExpect(jsonPath("content[0].value", equalTo("knownValue1")));
}
}

View File

@@ -683,6 +683,241 @@ include::../errors/406.adoc[]
include::../errors/429.adoc[]
|===
== GET /rest/v1/targets/{targetId}/metadata
=== Implementation Notes
Get a paged list of meta data for a target. Required permission: READ_REPOSITORY
=== Get a paged list of meta data
==== Curl
include::{snippets}/targets/get-metadata/curl-request.adoc[]
==== Request URL
include::{snippets}/targets/get-metadata/http-request.adoc[]
==== Request path parameter
include::{snippets}/targets/get-metadata/path-parameters.adoc[]
==== Request query parameter
include::{snippets}/targets/get-metadata-with-parameters/request-parameters.adoc[]
==== Request parameter example
include::{snippets}/targets/get-metadata-with-parameters/http-request.adoc[]
=== Response (Status 200)
==== Response fields
include::{snippets}/targets/get-metadata/response-fields.adoc[]
==== Response example
include::{snippets}/targets/get-metadata/http-response.adoc[]
=== Error responses
|===
| HTTP Status Code | Reason | Response Model
include::../errors/400.adoc[]
include::../errors/401.adoc[]
include::../errors/403.adoc[]
include::../errors/405.adoc[]
include::../errors/406.adoc[]
include::../errors/429.adoc[]
|===
== POST /rest/v1/targets/{targetId}/metadata
=== Implementation Notes
Create a list of meta data entries Required permissions: READ_REPOSITORY and UPDATE_TARGET
=== Create a list of meta data entries
==== CURL
include::{snippets}/targets/create-metadata/curl-request.adoc[]
==== Request URL
include::{snippets}/targets/create-metadata/http-request.adoc[]
==== Request path parameter
include::{snippets}/targets/create-metadata/path-parameters.adoc[]
==== Request fields
include::{snippets}/targets/create-metadata/request-fields.adoc[]
=== Response (Status 200)
==== Response example
include::{snippets}/targets/create-metadata/http-response.adoc[]
=== Error responses
|===
| HTTP Status Code | Reason | Response Model
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[]
include::../errors/415.adoc[]
include::../errors/429.adoc[]
|===
== DELETE /rest/v1/targets/{targetId}/metadata/{metadataKey}
=== Implementation Notes
Delete a single meta data. Required permission: UPDATE_REPOSITORY
=== Delete a single meta data
==== CURL
include::{snippets}/targets/delete-metadata/curl-request.adoc[]
==== Request URL
include::{snippets}/targets/delete-metadata/http-request.adoc[]
==== Request path parameter
include::{snippets}/targets/delete-metadata/path-parameters.adoc[]
=== Response (Status 200)
==== Response example
include::{snippets}/targets/delete-metadata/http-response.adoc[]
=== Error responses
|===
| HTTP Status Code | Reason | Response Model
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/429.adoc[]
|===
== GET /rest/v1/targets/{targetId}/metadata/{metadataKey}
=== Implementation Notes
Get a single meta data value for a meta data key. Required permission: READ_REPOSITORY
=== Get a single meta data value
==== Curl
include::{snippets}/targets/get-metadata-value/curl-request.adoc[]
==== Request URL
include::{snippets}/targets/get-metadata-value/http-request.adoc[]
==== Request path parameter
include::{snippets}/targets/get-metadata-value/path-parameters.adoc[]
=== Response (Status 200)
==== Response fields
include::{snippets}/targets/get-metadata-value/response-fields.adoc[]
==== Response example
include::{snippets}/targets/get-metadata-value/http-response.adoc[]
=== Error responses
|===
| HTTP Status Code | Reason | Response Model
include::../errors/400.adoc[]
include::../errors/401.adoc[]
include::../errors/403.adoc[]
include::../errors/405.adoc[]
include::../errors/406.adoc[]
include::../errors/429.adoc[]
|===
== PUT /rest/v1/targets/{targetId}/metadata/{metadataKey}
=== Implementation Notes
Update a single meta data value for speficic key. Required permission: UPDATE_REPOSITORY
=== Update a single meta data value
==== Curl
include::{snippets}/targets/update-metadata/curl-request.adoc[]
==== Request URL
include::{snippets}/targets/update-metadata/http-request.adoc[]
==== Request path parameter
include::{snippets}/targets/update-metadata/path-parameters.adoc[]
==== Request fields
include::{snippets}/targets/update-metadata/request-fields.adoc[]
=== Response (Status 200)
==== Response fields
include::{snippets}/targets/update-metadata/response-fields.adoc[]
==== Response example
include::{snippets}/targets/update-metadata/http-response.adoc[]
=== Error responses
|===
| HTTP Status Code | Reason | Response Model
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[]
include::../errors/415.adoc[]
include::../errors/429.adoc[]
|===
== Additional content

View File

@@ -248,7 +248,9 @@ public abstract class AbstractApiRestDocumentation extends AbstractRestIntegrati
fieldWithPath(fieldArrayPrefix + "_links.attributes")
.description(MgmtApiModelProperties.LINKS_ATTRIBUTES),
fieldWithPath(fieldArrayPrefix + "_links.actions")
.description(MgmtApiModelProperties.LINKS_ACTIONS)));
.description(MgmtApiModelProperties.LINKS_ACTIONS),
fieldWithPath(fieldArrayPrefix + "_links.metadata").description(MgmtApiModelProperties.META_DATA)));
}
fields.addAll(Arrays.asList(descriptors));

View File

@@ -504,7 +504,7 @@ public class DistributionSetsDocumentationTest extends AbstractApiRestDocumentat
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
for (int index = 0; index < totalMetadata; index++) {
distributionSetManagement.createMetaData(testDS.getId(), Lists
.newArrayList(entityFactory.generateMetadata(knownKeyPrefix + index, knownValuePrefix + index)));
.newArrayList(entityFactory.generateDsMetadata(knownKeyPrefix + index, knownValuePrefix + index)));
}
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/metadata",
@@ -532,7 +532,7 @@ public class DistributionSetsDocumentationTest extends AbstractApiRestDocumentat
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
for (int index = 0; index < totalMetadata; index++) {
distributionSetManagement.createMetaData(testDS.getId(), Lists
.newArrayList(entityFactory.generateMetadata(knownKeyPrefix + index, knownValuePrefix + index)));
.newArrayList(entityFactory.generateDsMetadata(knownKeyPrefix + index, knownValuePrefix + index)));
}
mockMvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{dsId}/metadata", testDS.getId())
@@ -564,7 +564,7 @@ public class DistributionSetsDocumentationTest extends AbstractApiRestDocumentat
final String knownValue = "knownValue";
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
distributionSetManagement.createMetaData(testDS.getId(),
Arrays.asList(entityFactory.generateMetadata(knownKey, knownValue)));
Arrays.asList(entityFactory.generateDsMetadata(knownKey, knownValue)));
mockMvc.perform(get(
MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/metadata/{metadatakey}",
@@ -588,7 +588,7 @@ public class DistributionSetsDocumentationTest extends AbstractApiRestDocumentat
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
distributionSetManagement.createMetaData(testDS.getId(),
Arrays.asList(entityFactory.generateMetadata(knownKey, knownValue)));
Arrays.asList(entityFactory.generateDsMetadata(knownKey, knownValue)));
final JSONObject jsonObject = new JSONObject().put("key", knownKey).put("value", updateValue);
@@ -616,7 +616,7 @@ public class DistributionSetsDocumentationTest extends AbstractApiRestDocumentat
final DistributionSet testDS = testdataFactory.createDistributionSet("one");
distributionSetManagement.createMetaData(testDS.getId(),
Arrays.asList(entityFactory.generateMetadata(knownKey, knownValue)));
Arrays.asList(entityFactory.generateDsMetadata(knownKey, knownValue)));
mockMvc.perform(
delete(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/{distributionSetId}/metadata/{key}",

View File

@@ -20,6 +20,7 @@ import static org.springframework.restdocs.request.RequestDocumentation.paramete
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.restdocs.snippet.Attributes.key;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -28,6 +29,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.ActionStatusFields;
import org.eclipse.hawkbit.repository.model.Action;
@@ -38,6 +40,7 @@ import org.eclipse.hawkbit.rest.documentation.AbstractApiRestDocumentation;
import org.eclipse.hawkbit.rest.documentation.ApiModelPropertiesGeneric;
import org.eclipse.hawkbit.rest.documentation.MgmtApiModelProperties;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
@@ -47,6 +50,7 @@ import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.JsonFieldType;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.collect.Lists;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
@@ -60,7 +64,7 @@ import io.qameta.allure.Story;
@Story("Target Resource")
public class TargetResourceDocumentationTest extends AbstractApiRestDocumentation {
private final String controllerId = "137";
private final String targetId = "137";
@Override
@Before
@@ -72,7 +76,7 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Test
@Description("Handles the GET request of retrieving all targets within SP. Required Permission: READ_TARGET.")
public void getTargets() throws Exception {
createTargetByGivenNameWithAttributes(controllerId, createDistributionSet());
createTargetByGivenNameWithAttributes(targetId, createDistributionSet());
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING)).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
@@ -90,7 +94,8 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
.type("enum").attributes(
key("value").value("['error', 'in_sync', 'pending', 'registered', 'unknown']")),
fieldWithPath("content[].securityToken").description(MgmtApiModelProperties.SECURITY_TOKEN),
fieldWithPath("content[].requestAttributes").description(MgmtApiModelProperties.REQUEST_ATTRIBUTES),
fieldWithPath("content[].requestAttributes")
.description(MgmtApiModelProperties.REQUEST_ATTRIBUTES),
fieldWithPath("content[].installedAt").description(MgmtApiModelProperties.INSTALLED_AT),
fieldWithPath("content[].lastModifiedAt")
.description(ApiModelPropertiesGeneric.LAST_MODIFIED_AT).type("Number"),
@@ -142,67 +147,71 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
.attributes(key("value")
.value("['error', 'in_sync', 'pending', 'registered', 'unknown']")),
fieldWithPath("[]securityToken").description(MgmtApiModelProperties.SECURITY_TOKEN),
fieldWithPath("[]requestAttributes").description(MgmtApiModelProperties.REQUEST_ATTRIBUTES),
fieldWithPath("[]requestAttributes")
.description(MgmtApiModelProperties.REQUEST_ATTRIBUTES),
fieldWithPath("[]_links.self").ignored())));
}
@Test
@Description("Handles the DELETE request of deleting a single target within SP. Required Permission: DELETE_TARGET.")
public void deleteTarget() throws Exception {
final Target target = testdataFactory.createTarget(controllerId);
final Target target = testdataFactory.createTarget(targetId);
mockMvc.perform(
delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}", target.getControllerId()))
delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}", target.getControllerId()))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print()).andDo(this.document.document(
pathParameters(parameterWithName("controllerId").description(ApiModelPropertiesGeneric.NAME))));
pathParameters(parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving a single target within SP. Required Permission: READ_TARGET.")
public void getTarget() throws Exception {
final Target target = createTargetByGivenNameWithAttributes(controllerId, createDistributionSet());
final Target target = createTargetByGivenNameWithAttributes(targetId, createDistributionSet());
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}", target.getControllerId()))
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}", target.getControllerId()))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
getResponseFieldTarget(false)));
}
@Test
@Description("Handles the PUT request of updating a target within SP. Required Permission: UPDATE_TARGET.")
public void putTarget() throws Exception {
final Target target = createTargetByGivenNameWithAttributes(controllerId, createDistributionSet());
final String targetAsJson = createJsonTarget(controllerId, "newTargetName", "I've been updated");
final Target target = createTargetByGivenNameWithAttributes(targetId, createDistributionSet());
final String targetAsJson = createJsonTarget(targetId, "newTargetName", "I've been updated");
mockMvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}", target.getControllerId())
mockMvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}", target.getControllerId())
.contentType(MediaType.APPLICATION_JSON_UTF8).content(targetAsJson)).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(optionalRequestFieldWithPath("name").description(ApiModelPropertiesGeneric.NAME),
optionalRequestFieldWithPath("description").description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
optionalRequestFieldWithPath("description")
.description(ApiModelPropertiesGeneric.DESCRPTION),
optionalRequestFieldWithPath("controllerId")
.description(ApiModelPropertiesGeneric.ITEM_ID),
optionalRequestFieldWithPath("address").description(MgmtApiModelProperties.ADDRESS),
optionalRequestFieldWithPath("securityToken")
.description(MgmtApiModelProperties.SECURITY_TOKEN),
optionalRequestFieldWithPath("requestAttributes").description(MgmtApiModelProperties.REQUEST_ATTRIBUTES)),
optionalRequestFieldWithPath("requestAttributes")
.description(MgmtApiModelProperties.REQUEST_ATTRIBUTES)),
getResponseFieldTarget(false)));
}
@Test
@Description("Handles the GET request of retrieving the full action history of a specific target. Required Permission: READ_TARGET.")
public void getActionsFromTarget() throws Exception {
generateActionForTarget(controllerId);
generateActionForTarget(targetId);
mockMvc.perform(get(
MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/" + MgmtRestConstants.TARGET_V1_ACTIONS,
controllerId)).andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/" + MgmtRestConstants.TARGET_V1_ACTIONS,
targetId)).andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
@@ -227,14 +236,14 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Test
@Description("Handles the GET request of retrieving the full action history of a specific target with maintenance window. Required Permission: READ_TARGET.")
public void getActionsFromTargetWithMaintenanceWindow() throws Exception {
generateActionForTarget(controllerId, true, false, getTestSchedule(2), getTestDuration(1), getTestTimeZone());
generateActionForTarget(targetId, true, false, getTestSchedule(2), getTestDuration(1), getTestTimeZone());
mockMvc.perform(get(
MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/" + MgmtRestConstants.TARGET_V1_ACTIONS,
controllerId)).andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/" + MgmtRestConstants.TARGET_V1_ACTIONS,
targetId)).andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
@@ -269,9 +278,9 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Test
@Description("Handles the GET request of retrieving all targets within SP based by parameter. Required Permission: READ_TARGET.")
public void getActionsFromTargetWithParameters() throws Exception {
generateActionForTarget(controllerId);
generateActionForTarget(targetId);
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + controllerId + "/"
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + targetId + "/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "?limit=10&sort=id:ASC&offset=0&q=status==pending"))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(requestParameters(
@@ -285,22 +294,22 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Test
@Description("Cancels an active action, only active actions can be deleted. Required Permission: UPDATE_TARGET.")
public void deleteActionFromTarget() throws Exception {
final Action actions = generateActionForTarget(controllerId, false);
final Action actions = generateActionForTarget(targetId, false);
mockMvc.perform(delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/{actionId}", controllerId, actions.getId()))
mockMvc.perform(delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/{actionId}", targetId, actions.getId()))
.andExpect(status().isNoContent()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
pathParameters(parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("actionId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving all targets within SP based by parameter. Required Permission: READ_TARGET.")
public void deleteActionsFromTargetWithParameters() throws Exception {
generateActionForTarget(controllerId);
generateActionForTarget(targetId);
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + controllerId + "/"
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + targetId + "/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "?force=true")).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print()).andDo(this.document.document(
requestParameters(parameterWithName("force").description(MgmtApiModelProperties.FORCE))));
@@ -309,15 +318,15 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Test
@Description("Handles the GET request of retrieving a specific action on a specific target. Required Permission: READ_TARGET.")
public void getActionFromTarget() throws Exception {
final Action action = generateActionForTarget(controllerId, true, true);
final Action action = generateActionForTarget(targetId, true, true);
assertThat(deploymentManagement.findAction(action.getId()).get().getActionType())
.isEqualTo(ActionType.TIMEFORCED);
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/{actionId}", controllerId, action.getId()))
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/{actionId}", targetId, action.getId()))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
pathParameters(parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("actionId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
@@ -343,14 +352,14 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Test
@Description("Handles the GET request of retrieving a specific action on a specific target. Required Permission: READ_TARGET.")
public void getActionFromTargetWithMaintenanceWindow() throws Exception {
final Action action = generateActionForTarget(controllerId, true, true, getTestSchedule(2), getTestDuration(1),
final Action action = generateActionForTarget(targetId, true, true, getTestSchedule(2), getTestDuration(1),
getTestTimeZone());
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/{actionId}", controllerId, action.getId()))
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/{actionId}", targetId, action.getId()))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
pathParameters(parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("actionId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("createdBy").description(ApiModelPropertiesGeneric.CREATED_BY),
fieldWithPath("createdAt").description(ApiModelPropertiesGeneric.CREATED_AT),
@@ -386,7 +395,7 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Test
@Description("Handles the PUT request to switch an action from soft to forced. Required Permission: UPDATE_TARGET.")
public void switchActionToForced() throws Exception {
final Target target = testdataFactory.createTarget(controllerId);
final Target target = testdataFactory.createTarget(targetId);
final DistributionSet set = testdataFactory.createDistributionSet();
final Long actionId = deploymentManagement
.assignDistributionSet(set.getId(), ActionType.SOFT, 0, Arrays.asList(target.getControllerId()))
@@ -396,13 +405,13 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
final Map<String, Object> body = new HashMap<>();
body.put("forceType", "forced");
mockMvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/{actionId}", controllerId, actionId)
mockMvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/{actionId}", targetId, actionId)
.content(this.objectMapper.writeValueAsString(body))
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
pathParameters(parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("actionId").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(
requestFieldWithPath("forceType").description(MgmtApiModelProperties.ACTION_FORCED)),
@@ -428,13 +437,13 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Test
@Description("Handles the GET request of retrieving a specific action on a specific target. Required Permission: READ_TARGET.")
public void getStatusFromAction() throws Exception {
final Action action = generateActionForTarget(controllerId);
final Action action = generateActionForTarget(targetId);
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/{actionId}/" + MgmtRestConstants.TARGET_V1_ACTION_STATUS,
controllerId, action.getId())).andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
targetId, action.getId())).andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID),
pathParameters(parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("actionId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(
fieldWithPath("size").type(JsonFieldType.NUMBER)
@@ -454,9 +463,9 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Test
@Description("Handles the GET request of retrieving all targets within SP based by parameter. Required Permission: READ_TARGET.")
public void getStatusFromActionWithParameters() throws Exception {
final Action action = generateActionForTarget(controllerId);
final Action action = generateActionForTarget(targetId);
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + controllerId + "/"
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + targetId + "/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/"
+ MgmtRestConstants.TARGET_V1_ACTION_STATUS + "?limit=10&sort=id:ASC&offset=0"))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
@@ -469,21 +478,21 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
@Test
@Description("Handles the GET request of retrieving the assigned distribution set of an specific target. Required Permission: READ_TARGET.")
public void getAssignedDistributionSetFromAction() throws Exception {
generateActionForTarget(controllerId);
generateActionForTarget(targetId);
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
+ MgmtRestConstants.TARGET_V1_ASSIGNED_DISTRIBUTION_SET, controllerId)).andExpect(status().isOk())
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/"
+ MgmtRestConstants.TARGET_V1_ASSIGNED_DISTRIBUTION_SET, targetId)).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
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 {
testdataFactory.createTarget(controllerId);
testdataFactory.createTarget(targetId);
final DistributionSet set = testdataFactory.createDistributionSet("one");
final long forceTime = System.currentTimeMillis();
@@ -492,13 +501,13 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
getMaintenanceWindow(getTestSchedule(10), getTestDuration(10), getTestTimeZone()))
.toString();
mockMvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
+ MgmtRestConstants.TARGET_V1_ASSIGNED_DISTRIBUTION_SET, controllerId).content(body)
mockMvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/"
+ MgmtRestConstants.TARGET_V1_ASSIGNED_DISTRIBUTION_SET, targetId).content(body)
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestParameters(parameterWithName("offline")
.description(MgmtApiModelProperties.OFFLINE_UPDATE).optional()),
requestFields(requestFieldWithPath("forcetime").description(MgmtApiModelProperties.FORCETIME),
@@ -528,32 +537,193 @@ public class TargetResourceDocumentationTest extends AbstractApiRestDocumentatio
final Map<String, String> knownControllerAttrs = new HashMap<>();
knownControllerAttrs.put("a", "1");
knownControllerAttrs.put("b", "2");
final Target target = testdataFactory.createTarget(controllerId);
controllerManagement.updateControllerAttributes(controllerId, knownControllerAttrs, null);
final Target target = testdataFactory.createTarget(targetId);
controllerManagement.updateControllerAttributes(targetId, knownControllerAttrs, null);
// test query target over rest resource
mockMvc.perform(
get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/attributes", target.getName()))
get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/attributes", target.getName()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().is2xxSuccessful())
.andExpect(jsonPath("$.a", equalTo("1"))).andExpect(jsonPath("$.b", equalTo("2")))
.andDo(this.document.document(pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID))));
parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Handles the GET request of retrieving the installed distribution set of an specific target. Required Permission: READ_TARGET.")
public void getInstalledDistributionSetFromTarget() throws Exception {
final Target target = createTargetByGivenNameWithAttributes(controllerId, createDistributionSet());
final Target target = createTargetByGivenNameWithAttributes(targetId, createDistributionSet());
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{controllerId}/"
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/"
+ MgmtRestConstants.TARGET_V1_INSTALLED_DISTRIBUTION_SET, target.getName())).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andDo(this.document.document(
pathParameters(
parameterWithName("controllerId").description(ApiModelPropertiesGeneric.ITEM_ID)),
parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
getResponseFieldsDistributionSet(false)));
}
@Test
@Description("Get a paged list of meta data for a target with standard page size." + " Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getMetadata() throws Exception {
final int totalMetadata = 4;
final String knownKeyPrefix = "knownKey";
final String knownValuePrefix = "knownValue";
final Target testTarget = testdataFactory.createTarget(targetId);
for (int index = 0; index < totalMetadata; index++) {
targetManagement.createMetaData(testTarget.getControllerId(), Lists.newArrayList(
entityFactory.generateTargetMetadata(knownKeyPrefix + index, knownValuePrefix + index)));
}
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/metadata",
testTarget.getControllerId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(
parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("content").description(MgmtApiModelProperties.META_DATA),
fieldWithPath("content[].key").description(MgmtApiModelProperties.META_DATA_KEY),
fieldWithPath("content[].value").description(MgmtApiModelProperties.META_DATA_VALUE))));
}
@Test
@Description("Get a paged list of meta data for a target with defined page size and sorting by name descending and key starting with 'known'."
+ " Required Permission: " + SpPermission.READ_REPOSITORY)
public void getMetadataWithParameters() throws Exception {
final int totalMetadata = 4;
final String knownKeyPrefix = "knownKey";
final String knownValuePrefix = "knownValue";
final Target testTarget = testdataFactory.createTarget(targetId);
for (int index = 0; index < totalMetadata; index++) {
targetManagement.createMetaData(testTarget.getControllerId(), Lists.newArrayList(
entityFactory.generateTargetMetadata(knownKeyPrefix + index, knownValuePrefix + index)));
}
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/metadata",
testTarget.getControllerId()).param("offset", "1").param("limit", "2").param("sort", "key:DESC")
.param("q", "key==known*"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
requestParameters(
parameterWithName("limit").attributes(key("type").value("query"))
.description(ApiModelPropertiesGeneric.LIMIT),
parameterWithName("sort").description(ApiModelPropertiesGeneric.SORT),
parameterWithName("offset").description(ApiModelPropertiesGeneric.OFFSET),
parameterWithName("q").description(ApiModelPropertiesGeneric.FIQL)),
responseFields(fieldWithPath("total").description(ApiModelPropertiesGeneric.TOTAL_ELEMENTS),
fieldWithPath("size").type(JsonFieldType.NUMBER)
.description(ApiModelPropertiesGeneric.SIZE),
fieldWithPath("content").description(MgmtApiModelProperties.META_DATA),
fieldWithPath("content[].key").description(MgmtApiModelProperties.META_DATA_KEY),
fieldWithPath("content[].value").description(MgmtApiModelProperties.META_DATA_VALUE))));
}
@Test
@Description("Get a single meta data value for a meta data key." + " Required Permission: "
+ SpPermission.READ_REPOSITORY)
public void getMetadataValue() throws Exception {
// prepare and create metadata
final String knownKey = "knownKey";
final String knownValue = "knownValue";
final Target testTarget = testdataFactory.createTarget(targetId);
targetManagement.createMetaData(testTarget.getControllerId(),
Arrays.asList(entityFactory.generateTargetMetadata(knownKey, knownValue)));
mockMvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/metadata/{metadatakey}",
testTarget.getControllerId(), knownKey)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("metadatakey").description(ApiModelPropertiesGeneric.ITEM_ID)),
responseFields(fieldWithPath("key").description(MgmtApiModelProperties.META_DATA_KEY),
fieldWithPath("value").description(MgmtApiModelProperties.META_DATA_VALUE))));
}
@Test
@Description("Update a single meta data value for specific key." + " Required Permission: "
+ SpPermission.UPDATE_REPOSITORY)
public void updateMetadata() throws Exception {
// prepare and create metadata for update
final String knownKey = "knownKey";
final String knownValue = "knownValue";
final String updateValue = "valueForUpdate";
final Target testTarget = testdataFactory.createTarget(targetId);
targetManagement.createMetaData(testTarget.getControllerId(),
Arrays.asList(entityFactory.generateTargetMetadata(knownKey, knownValue)));
final JSONObject jsonObject = new JSONObject().put("key", knownKey).put("value", updateValue);
mockMvc.perform(put(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/metadata/{metadatakey}",
testTarget.getControllerId(), knownKey)
.contentType(MediaType.APPLICATION_JSON_UTF8).content(jsonObject.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("metadatakey").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(requestFieldWithPath("key").description(MgmtApiModelProperties.META_DATA_KEY),
requestFieldWithPath("value").description(MgmtApiModelProperties.META_DATA_VALUE)),
responseFields(fieldWithPath("key").description(MgmtApiModelProperties.META_DATA_KEY),
fieldWithPath("value").description(MgmtApiModelProperties.META_DATA_VALUE))));
}
@Test
@Description("Delete a single meta data." + " Required Permission: " + SpPermission.UPDATE_REPOSITORY)
public void deleteMetadata() throws Exception {
// prepare and create metadata for deletion
final String knownKey = "knownKey";
final String knownValue = "knownValue";
final Target testTarget = testdataFactory.createTarget(targetId);
targetManagement.createMetaData(testTarget.getControllerId(),
Arrays.asList(entityFactory.generateTargetMetadata(knownKey, knownValue)));
mockMvc.perform(delete(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/metadata/{key}",
testTarget.getControllerId(), knownKey)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andDo(this.document.document(
pathParameters(parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID),
parameterWithName("key").description(ApiModelPropertiesGeneric.ITEM_ID))));
}
@Test
@Description("Create a list of meta data entries" + " Required Permission: " + SpPermission.READ_REPOSITORY
+ " and " + SpPermission.UPDATE_TARGET)
public void createMetadata() throws Exception {
final Target testTarget = testdataFactory.createTarget(targetId);
final String knownKey1 = "knownKey1";
final String knownKey2 = "knownKey2";
final String knownValue1 = "knownValue1";
final String knownValue2 = "knownValue2";
final JSONArray jsonArray = new JSONArray();
jsonArray.put(new JSONObject().put("key", knownKey1).put("value", knownValue1));
jsonArray.put(new JSONObject().put("key", knownKey2).put("value", knownValue2));
mockMvc.perform(
post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/{targetId}/metadata",
testTarget.getControllerId()).contentType(MediaType.APPLICATION_JSON_UTF8)
.content(jsonArray.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andDo(this.document.document(
pathParameters(
parameterWithName("targetId").description(ApiModelPropertiesGeneric.ITEM_ID)),
requestFields(requestFieldWithPath("[]key").description(MgmtApiModelProperties.META_DATA_KEY),
optionalRequestFieldWithPath("[]value")
.description(MgmtApiModelProperties.META_DATA_VALUE))));
}
private String createTargetJsonForPostRequest(final String controllerId, final String name,
final String description) throws JsonProcessingException {
final Map<String, Object> target = new HashMap<>();