Move Mgmt artifacts into hawkbit-mgmt (#2003)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
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 lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
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.json.model.ResponseList;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class MgmtActionMapper {
|
||||
|
||||
/**
|
||||
* 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 -> 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,84 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
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;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@ConditionalOnProperty(name = "hawkbit.rest.MgmtActionResource.enabled", matchIfMissing = true)
|
||||
public class MgmtActionResource implements MgmtActionRestApi {
|
||||
|
||||
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 = getRepresentationModeFromString(representationModeParam);
|
||||
|
||||
return ResponseEntity
|
||||
.ok(new PagedList<>(MgmtActionMapper.toResponse(actions.getContent(), repMode), totalActionCount));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtAction> getAction(final Long actionId) {
|
||||
|
||||
final Action action = deploymentManagement.findAction(actionId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
||||
|
||||
return ResponseEntity.ok(MgmtActionMapper.toResponse(action, MgmtRepresentationMode.FULL));
|
||||
}
|
||||
|
||||
private MgmtRepresentationMode getRepresentationModeFromString(final String representationModeParam) {
|
||||
return 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;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import org.eclipse.hawkbit.rest.OpenApiConfiguration;
|
||||
import org.eclipse.hawkbit.rest.RestConfiguration;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
||||
/**
|
||||
* Enable {@link ComponentScan} in the resource package to setup all
|
||||
* {@link Controller} annotated classes and setup the REST-Resources for the
|
||||
* Management API.
|
||||
*/
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@Import({ RestConfiguration.class, OpenApiConfiguration.class })
|
||||
@PropertySource("classpath:/hawkbit-mgmt-api-defaults.properties")
|
||||
public class MgmtApiConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.auth.MgmtUserInfo;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtBasicAuthRestApi;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling basic auth validation.
|
||||
*/
|
||||
@RestController
|
||||
public class MgmtBasicAuthResource implements MgmtBasicAuthRestApi {
|
||||
|
||||
private final TenantAware tenantAware;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param tenantAware tenantAware
|
||||
*/
|
||||
public MgmtBasicAuthResource(TenantAware tenantAware) {
|
||||
this.tenantAware = tenantAware;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtUserInfo> validateBasicAuth() {
|
||||
MgmtUserInfo userInfo = new MgmtUserInfo();
|
||||
userInfo.setUsername(tenantAware.getCurrentUsername());
|
||||
userInfo.setTenant(tenantAware.getCurrentTenant());
|
||||
return ResponseEntity.ok(userInfo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMaintenanceWindowRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtDistributionSetAssignment;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper;
|
||||
import org.eclipse.hawkbit.repository.model.DeploymentRequestBuilder;
|
||||
|
||||
/**
|
||||
* A mapper for assignment requests
|
||||
*/
|
||||
public final class MgmtDeploymentRequestMapper {
|
||||
|
||||
private MgmtDeploymentRequestMapper() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert assignment information to an {@link DeploymentRequestBuilder}
|
||||
*
|
||||
* @param dsAssignment DS assignment information
|
||||
* @param targetId target to assign the DS to
|
||||
* @return resulting {@link DeploymentRequestBuilder}
|
||||
*/
|
||||
public static DeploymentRequestBuilder createAssignmentRequestBuilder(
|
||||
final MgmtDistributionSetAssignment dsAssignment, final String targetId) {
|
||||
|
||||
return createAssignmentRequestBuilder(targetId, dsAssignment.getId(), dsAssignment.getType(),
|
||||
dsAssignment.getForcetime(), dsAssignment.getWeight(), dsAssignment.getMaintenanceWindow());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert assignment information to an {@link DeploymentRequestBuilder}
|
||||
*
|
||||
* @param targetAssignment target assignment information
|
||||
* @param dsId DS to assign the target to
|
||||
* @return resulting {@link DeploymentRequestBuilder}
|
||||
*/
|
||||
public static DeploymentRequestBuilder createAssignmentRequestBuilder(
|
||||
final MgmtTargetAssignmentRequestBody targetAssignment, final Long dsId) {
|
||||
return createAssignmentRequestBuilder(targetAssignment.getId(), dsId, targetAssignment.getType(),
|
||||
targetAssignment.getForcetime(), targetAssignment.getWeight(), targetAssignment.getMaintenanceWindow());
|
||||
}
|
||||
|
||||
private static DeploymentRequestBuilder createAssignmentRequestBuilder(final String targetId, final Long dsId,
|
||||
final MgmtActionType type, final long forcetime, final Integer weight,
|
||||
final MgmtMaintenanceWindowRequestBody maintenanceWindow) {
|
||||
final DeploymentRequestBuilder request = DeploymentManagement.deploymentRequest(targetId, dsId)
|
||||
.setActionType(MgmtRestModelMapper.convertActionType(type)).setForceTime(forcetime).setWeight(weight);
|
||||
if (maintenanceWindow != null) {
|
||||
final String cronSchedule = maintenanceWindow.getSchedule();
|
||||
final String duration = maintenanceWindow.getDuration();
|
||||
final String timezone = maintenanceWindow.getTimezone();
|
||||
MaintenanceScheduleHelper.validateMaintenanceSchedule(cronSchedule, duration, timezone);
|
||||
request.setMaintenance(cronSchedule, duration, timezone);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtMetadata;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionId;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentResponseBody;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTypeRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetCreate;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.MetaData;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class MgmtDistributionSetMapper {
|
||||
|
||||
/**
|
||||
* {@link MgmtDistributionSetRequestBodyPost}s to {@link DistributionSet}s.
|
||||
*
|
||||
* @param sets to convert
|
||||
* @return converted list of {@link DistributionSet}s
|
||||
*/
|
||||
static List<DistributionSetCreate> dsFromRequest(final Collection<MgmtDistributionSetRequestBodyPost> sets,
|
||||
final EntityFactory entityFactory) {
|
||||
return sets.stream().map(dsRest -> fromRequest(dsRest, entityFactory)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<MetaData> fromRequestDsMetadata(final List<MgmtMetadata> metadata, final EntityFactory entityFactory) {
|
||||
if (metadata == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return metadata.stream()
|
||||
.map(metadataRest -> entityFactory.generateDsMetadata(metadataRest.getKey(), metadataRest.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static MgmtDistributionSet toResponse(final DistributionSet distributionSet) {
|
||||
if (distributionSet == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final MgmtDistributionSet response = new MgmtDistributionSet();
|
||||
MgmtRestModelMapper.mapNamedToNamed(response, distributionSet);
|
||||
|
||||
response.setDsId(distributionSet.getId());
|
||||
response.setVersion(distributionSet.getVersion());
|
||||
response.setComplete(distributionSet.isComplete());
|
||||
response.setType(distributionSet.getType().getKey());
|
||||
response.setTypeName(distributionSet.getType().getName());
|
||||
response.setLocked(distributionSet.isLocked());
|
||||
response.setDeleted(distributionSet.isDeleted());
|
||||
response.setValid(distributionSet.isValid());
|
||||
|
||||
distributionSet.getModules()
|
||||
.forEach(module -> response.getModules().add(MgmtSoftwareModuleMapper.toResponse(module)));
|
||||
|
||||
response.setRequiredMigrationStep(distributionSet.isRequiredMigrationStep());
|
||||
|
||||
response.add(linkTo(methodOn(MgmtDistributionSetRestApi.class).getDistributionSet(response.getDsId()))
|
||||
.withSelfRel().expand());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
static void addLinks(final DistributionSet distributionSet, final MgmtDistributionSet response) {
|
||||
response.add(linkTo(methodOn(MgmtDistributionSetRestApi.class).getAssignedSoftwareModules(response.getDsId(),
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null))
|
||||
.withRel(MgmtRestConstants.DISTRIBUTIONSET_V1_MODULE).expand());
|
||||
|
||||
response.add(linkTo(methodOn(MgmtDistributionSetTypeRestApi.class)
|
||||
.getDistributionSetType(distributionSet.getType().getId())).withRel("type").expand());
|
||||
|
||||
response.add(linkTo(methodOn(MgmtDistributionSetRestApi.class).getMetadata(response.getDsId(),
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null)).withRel("metadata")
|
||||
.expand());
|
||||
}
|
||||
|
||||
static MgmtTargetAssignmentResponseBody toResponse(final DistributionSetAssignmentResult dsAssignmentResult) {
|
||||
final MgmtTargetAssignmentResponseBody result = new MgmtTargetAssignmentResponseBody();
|
||||
result.setAlreadyAssigned(dsAssignmentResult.getAlreadyAssigned());
|
||||
result.setAssignedActions(dsAssignmentResult.getAssignedEntity().stream()
|
||||
.map(a -> new MgmtActionId(a.getTarget().getControllerId(), a.getId())).collect(Collectors.toList()));
|
||||
return result;
|
||||
}
|
||||
|
||||
static MgmtTargetAssignmentResponseBody toResponse(
|
||||
final List<DistributionSetAssignmentResult> dsAssignmentResults) {
|
||||
final MgmtTargetAssignmentResponseBody result = new MgmtTargetAssignmentResponseBody();
|
||||
final int alreadyAssigned = dsAssignmentResults.stream()
|
||||
.mapToInt(DistributionSetAssignmentResult::getAlreadyAssigned).sum();
|
||||
final List<MgmtActionId> assignedActions = dsAssignmentResults.stream()
|
||||
.flatMap(assignmentResult -> assignmentResult.getAssignedEntity().stream())
|
||||
.map(action -> new MgmtActionId(action.getTarget().getControllerId(), action.getId()))
|
||||
.collect(Collectors.toList());
|
||||
result.setAlreadyAssigned(alreadyAssigned);
|
||||
result.setAssignedActions(assignedActions);
|
||||
return result;
|
||||
}
|
||||
|
||||
static List<MgmtDistributionSet> toResponseDistributionSets(final Collection<DistributionSet> sets) {
|
||||
if (sets == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return new ResponseList<>(
|
||||
sets.stream().map(MgmtDistributionSetMapper::toResponse).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
static MgmtMetadata toResponseDsMetadata(final DistributionSetMetadata metadata) {
|
||||
final MgmtMetadata metadataRest = new MgmtMetadata();
|
||||
metadataRest.setKey(metadata.getKey());
|
||||
metadataRest.setValue(metadata.getValue());
|
||||
return metadataRest;
|
||||
}
|
||||
|
||||
static List<MgmtMetadata> toResponseDsMetadata(final List<DistributionSetMetadata> metadata) {
|
||||
final List<MgmtMetadata> mappedList = new ArrayList<>(metadata.size());
|
||||
for (final DistributionSetMetadata distributionSetMetadata : metadata) {
|
||||
mappedList.add(toResponseDsMetadata(distributionSetMetadata));
|
||||
}
|
||||
return mappedList;
|
||||
}
|
||||
|
||||
static List<MgmtDistributionSet> toResponseFromDsList(final List<DistributionSet> sets) {
|
||||
if (sets == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return sets.stream().map(MgmtDistributionSetMapper::toResponse).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link MgmtDistributionSetRequestBodyPost} to {@link DistributionSet}.
|
||||
*
|
||||
* @param dsRest to convert
|
||||
* @return converted {@link DistributionSet}
|
||||
*/
|
||||
private static DistributionSetCreate fromRequest(final MgmtDistributionSetRequestBodyPost dsRest,
|
||||
final EntityFactory entityFactory) {
|
||||
final List<Long> modules = new ArrayList<>();
|
||||
if (dsRest.getOs() != null) {
|
||||
modules.add(dsRest.getOs().getId());
|
||||
}
|
||||
if (dsRest.getApplication() != null) {
|
||||
modules.add(dsRest.getApplication().getId());
|
||||
}
|
||||
if (dsRest.getRuntime() != null) {
|
||||
modules.add(dsRest.getRuntime().getId());
|
||||
}
|
||||
if (dsRest.getModules() != null) {
|
||||
dsRest.getModules().forEach(module -> modules.add(module.getId()));
|
||||
}
|
||||
return entityFactory.distributionSet().create().name(dsRest.getName()).version(dsRest.getVersion())
|
||||
.description(dsRest.getDescription()).type(dsRest.getType()).modules(modules)
|
||||
.requiredMigrationStep(dsRest.getRequiredMigrationStep());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,463 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.ValidationException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.distributionset.MgmtDistributionSet;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetStatistics;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtInvalidateDistributionSetRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentResponseBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleAssigment;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetInvalidationManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.DeploymentRequest;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling for {@link DistributionSet} CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
|
||||
|
||||
private final SoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
private final TargetManagement targetManagement;
|
||||
|
||||
private final TargetFilterQueryManagement targetFilterQueryManagement;
|
||||
|
||||
private final DeploymentManagement deployManagament;
|
||||
|
||||
private final SystemManagement systemManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
|
||||
private final DistributionSetTypeManagement distributionSetTypeManagement;
|
||||
|
||||
private final SystemSecurityContext systemSecurityContext;
|
||||
|
||||
private final DistributionSetInvalidationManagement distributionSetInvalidationManagement;
|
||||
|
||||
private final TenantConfigHelper tenantConfigHelper;
|
||||
|
||||
MgmtDistributionSetResource(final SoftwareModuleManagement softwareModuleManagement,
|
||||
final TargetManagement targetManagement, final TargetFilterQueryManagement targetFilterQueryManagement,
|
||||
final DeploymentManagement deployManagament, final SystemManagement systemManagement,
|
||||
final EntityFactory entityFactory, final DistributionSetManagement distributionSetManagement,
|
||||
final DistributionSetTypeManagement distributionSetTypeManagement, final SystemSecurityContext systemSecurityContext,
|
||||
final DistributionSetInvalidationManagement distributionSetInvalidationManagement,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
this.targetManagement = targetManagement;
|
||||
this.targetFilterQueryManagement = targetFilterQueryManagement;
|
||||
this.deployManagament = deployManagament;
|
||||
this.systemManagement = systemManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
this.distributionSetInvalidationManagement = distributionSetInvalidationManagement;
|
||||
this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtDistributionSet>> getDistributionSets(
|
||||
@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.sanitizeDistributionSetSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Slice<DistributionSet> findDsPage;
|
||||
final long countModulesAll;
|
||||
if (rsqlParam != null) {
|
||||
findDsPage = distributionSetManagement.findByRsql(pageable, rsqlParam);
|
||||
countModulesAll = ((Page<DistributionSet>) findDsPage).getTotalElements();
|
||||
} else {
|
||||
findDsPage = distributionSetManagement.findAll(pageable);
|
||||
countModulesAll = distributionSetManagement.count();
|
||||
}
|
||||
|
||||
final List<MgmtDistributionSet> rest = MgmtDistributionSetMapper.toResponseFromDsList(findDsPage.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, countModulesAll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSet> getDistributionSet(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId) {
|
||||
final DistributionSet foundDs = distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
|
||||
final MgmtDistributionSet response = MgmtDistributionSetMapper.toResponse(foundDs);
|
||||
MgmtDistributionSetMapper.addLinks(foundDs, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtDistributionSet>> createDistributionSets(
|
||||
@RequestBody final List<MgmtDistributionSetRequestBodyPost> sets) {
|
||||
|
||||
log.debug("creating {} distribution sets", sets.size());
|
||||
// set default Ds type if ds type is null
|
||||
final String defaultDsKey = systemSecurityContext
|
||||
.runAsSystem(systemManagement.getTenantMetadata().getDefaultDsType()::getKey);
|
||||
sets.stream().filter(ds -> ds.getType() == null).forEach(ds -> ds.setType(defaultDsKey));
|
||||
|
||||
//check if there is already deleted DS Type
|
||||
for (MgmtDistributionSetRequestBodyPost ds : sets) {
|
||||
final Optional<DistributionSetType> opt = distributionSetTypeManagement.getByKey(ds.getType());
|
||||
opt.ifPresent(dsType -> {
|
||||
if (dsType.isDeleted()) {
|
||||
final String text = "Cannot create Distribution Set from type with key {0}. Distribution Set Type already deleted!";
|
||||
final String message = MessageFormat.format(text, dsType.getKey());
|
||||
throw new ValidationException(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final Collection<DistributionSet> createdDSets = distributionSetManagement
|
||||
.create(MgmtDistributionSetMapper.dsFromRequest(sets, entityFactory));
|
||||
|
||||
log.debug("{} distribution sets created, return status {}", sets.size(), HttpStatus.CREATED);
|
||||
return new ResponseEntity<>(MgmtDistributionSetMapper.toResponseDistributionSets(createdDSets),
|
||||
HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteDistributionSet(@PathVariable("distributionSetId") final Long distributionSetId) {
|
||||
distributionSetManagement.delete(distributionSetId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSet> updateDistributionSet(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@RequestBody final MgmtDistributionSetRequestBodyPut toUpdate) {
|
||||
final DistributionSet updated = distributionSetManagement.update(entityFactory.distributionSet()
|
||||
.update(distributionSetId).name(toUpdate.getName()).description(toUpdate.getDescription())
|
||||
.version(toUpdate.getVersion()).locked(toUpdate.getLocked())
|
||||
.requiredMigrationStep(toUpdate.getRequiredMigrationStep()));
|
||||
|
||||
final MgmtDistributionSet response = MgmtDistributionSetMapper.toResponse(updated);
|
||||
MgmtDistributionSetMapper.addLinks(updated, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTarget>> getAssignedTargets(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@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.sanitizeTargetSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<Target> targetsAssignedDS;
|
||||
if (rsqlParam != null) {
|
||||
targetsAssignedDS = this.targetManagement.findByAssignedDistributionSetAndRsql(pageable, distributionSetId,
|
||||
rsqlParam);
|
||||
} else {
|
||||
targetsAssignedDS = this.targetManagement.findByAssignedDistributionSet(pageable, distributionSetId);
|
||||
}
|
||||
|
||||
return ResponseEntity
|
||||
.ok(new PagedList<>(MgmtTargetMapper.toResponse(targetsAssignedDS.getContent(), tenantConfigHelper),
|
||||
targetsAssignedDS.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTarget>> getInstalledTargets(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@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) {
|
||||
// check if distribution set exists otherwise throw exception
|
||||
// immediately
|
||||
distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeTargetSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<Target> targetsInstalledDS;
|
||||
if (rsqlParam != null) {
|
||||
targetsInstalledDS = this.targetManagement.findByInstalledDistributionSetAndRsql(pageable,
|
||||
distributionSetId, rsqlParam);
|
||||
} else {
|
||||
targetsInstalledDS = this.targetManagement.findByInstalledDistributionSet(pageable, distributionSetId);
|
||||
}
|
||||
|
||||
return ResponseEntity
|
||||
.ok(new PagedList<>(MgmtTargetMapper.toResponse(targetsInstalledDS.getContent(), tenantConfigHelper),
|
||||
targetsInstalledDS.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTargetFilterQuery>> getAutoAssignTargetFilterQueries(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@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.sanitizeTargetFilterQuerySortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<TargetFilterQuery> targetFilterQueries = targetFilterQueryManagement
|
||||
.findByAutoAssignDSAndRsql(pageable, distributionSetId, rsqlParam);
|
||||
|
||||
return ResponseEntity
|
||||
.ok(new PagedList<>(MgmtTargetFilterQueryMapper.toResponse(targetFilterQueries.getContent(),
|
||||
tenantConfigHelper.isConfirmationFlowEnabled(), false), targetFilterQueries.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetAssignmentResponseBody> createAssignedTarget(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@RequestBody final List<MgmtTargetAssignmentRequestBody> assignments,
|
||||
@RequestParam(value = "offline", required = false) final Boolean offline) {
|
||||
if (offline != null && offline) {
|
||||
final List<Entry<String, Long>> offlineAssignments = assignments.stream()
|
||||
.map(assignment -> new SimpleEntry<>(assignment.getId(), distributionSetId))
|
||||
.collect(Collectors.toList());
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper
|
||||
.toResponse(deployManagament.offlineAssignedDistributionSets(offlineAssignments)));
|
||||
}
|
||||
|
||||
final List<DeploymentRequest> deploymentRequests = assignments.stream().map(dsAssignment -> {
|
||||
final boolean isConfirmationRequired = dsAssignment.getConfirmationRequired() == null
|
||||
? tenantConfigHelper.isConfirmationFlowEnabled()
|
||||
: dsAssignment.getConfirmationRequired();
|
||||
return MgmtDeploymentRequestMapper.createAssignmentRequestBuilder(dsAssignment, distributionSetId)
|
||||
.setConfirmationRequired(isConfirmationRequired).build();
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
final List<DistributionSetAssignmentResult> assignmentResults = deployManagament
|
||||
.assignDistributionSets(deploymentRequests);
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponse(assignmentResults));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtMetadata>> getMetadata(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@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<DistributionSetMetadata> metaDataPage;
|
||||
|
||||
if (rsqlParam != null) {
|
||||
metaDataPage = distributionSetManagement.findMetaDataByDistributionSetIdAndRsql(pageable, distributionSetId,
|
||||
rsqlParam);
|
||||
} else {
|
||||
metaDataPage = distributionSetManagement.findMetaDataByDistributionSetId(pageable, distributionSetId);
|
||||
}
|
||||
|
||||
return ResponseEntity
|
||||
.ok(new PagedList<>(MgmtDistributionSetMapper.toResponseDsMetadata(metaDataPage.getContent()),
|
||||
metaDataPage.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtMetadata> getMetadataValue(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@PathVariable("metadataKey") final String metadataKey) {
|
||||
// check if distribution set exists otherwise throw exception
|
||||
// immediately
|
||||
final DistributionSetMetadata findOne = distributionSetManagement
|
||||
.getMetaDataByDistributionSetId(distributionSetId, metadataKey)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetMetadata.class, distributionSetId,
|
||||
metadataKey));
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponseDsMetadata(findOne));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtMetadata> updateMetadata(@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@PathVariable("metadataKey") final String metadataKey, @RequestBody final MgmtMetadataBodyPut metadata) {
|
||||
// check if distribution set exists otherwise throw exception
|
||||
// immediately
|
||||
final DistributionSetMetadata updated = distributionSetManagement.updateMetaData(distributionSetId,
|
||||
entityFactory.generateDsMetadata(metadataKey, metadata.getValue()));
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponseDsMetadata(updated));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteMetadata(@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@PathVariable("metadataKey") final String metadataKey) {
|
||||
// check if distribution set exists otherwise throw exception
|
||||
// immediately
|
||||
distributionSetManagement.deleteMetaData(distributionSetId, metadataKey);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtMetadata>> createMetadata(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@RequestBody final List<MgmtMetadata> metadataRest) {
|
||||
// check if distribution set exists otherwise throw exception
|
||||
// immediately
|
||||
final List<DistributionSetMetadata> created = distributionSetManagement.createMetaData(distributionSetId,
|
||||
MgmtDistributionSetMapper.fromRequestDsMetadata(metadataRest, entityFactory));
|
||||
return new ResponseEntity<>(MgmtDistributionSetMapper.toResponseDsMetadata(created), HttpStatus.CREATED);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> assignSoftwareModules(@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@RequestBody final List<MgmtSoftwareModuleAssigment> softwareModuleIDs) {
|
||||
|
||||
distributionSetManagement.assignSoftwareModules(distributionSetId,
|
||||
softwareModuleIDs.stream().map(MgmtSoftwareModuleAssigment::getId).collect(Collectors.toList()));
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteAssignSoftwareModules(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId) {
|
||||
distributionSetManagement.unassignSoftwareModule(distributionSetId, softwareModuleId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtSoftwareModule>> getAssignedSoftwareModules(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@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 int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeSoftwareModuleSortParam(sortParam);
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<SoftwareModule> softwaremodules = softwareModuleManagement.findByAssignedTo(pageable,
|
||||
distributionSetId);
|
||||
return ResponseEntity.ok(new PagedList<>(MgmtSoftwareModuleMapper.toResponse(softwaremodules.getContent()),
|
||||
softwaremodules.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSetStatistics> getRolloutsCountByStatusForDistributionSet(Long distributionSetId) {
|
||||
MgmtDistributionSetStatistics.Builder statistics = new MgmtDistributionSetStatistics.Builder(false);
|
||||
distributionSetManagement.countRolloutsByStatusForDistributionSet(distributionSetId).forEach(statistic ->
|
||||
statistics.addTotalRolloutPerStatus(String.valueOf(statistic.getName()), Long.parseLong(statistic.getData().toString())));
|
||||
return ResponseEntity.ok(statistics.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSetStatistics> getActionsCountByStatusForDistributionSet(Long distributionSetId) {
|
||||
MgmtDistributionSetStatistics.Builder statistics = new MgmtDistributionSetStatistics.Builder(false);
|
||||
distributionSetManagement.countActionsByStatusForDistributionSet(distributionSetId).forEach(statistic ->
|
||||
statistics.addTotalActionPerStatus(String.valueOf(statistic.getName()), Long.parseLong(statistic.getData().toString())));
|
||||
return ResponseEntity.ok(statistics.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSetStatistics> getAutoAssignmentsCountForDistributionSet(Long distributionSetId) {
|
||||
MgmtDistributionSetStatistics.Builder statistics = new MgmtDistributionSetStatistics.Builder(false);
|
||||
statistics.addTotalAutoAssignments(distributionSetManagement.countAutoAssignmentsForDistributionSet(distributionSetId));
|
||||
return ResponseEntity.ok(statistics.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSetStatistics> getStatisticsForDistributionSet(Long distributionSetId) {
|
||||
MgmtDistributionSetStatistics.Builder statistics = new MgmtDistributionSetStatistics.Builder(true);
|
||||
distributionSetManagement.countRolloutsByStatusForDistributionSet(distributionSetId).forEach(statistic ->
|
||||
statistics.addTotalRolloutPerStatus(String.valueOf(statistic.getName()), Long.parseLong(statistic.getData().toString())));
|
||||
distributionSetManagement.countActionsByStatusForDistributionSet(distributionSetId).forEach(statistic ->
|
||||
statistics.addTotalActionPerStatus(String.valueOf(statistic.getName()), Long.parseLong(statistic.getData().toString())));
|
||||
statistics.addTotalAutoAssignments(distributionSetManagement.countAutoAssignmentsForDistributionSet(distributionSetId));
|
||||
return ResponseEntity.ok(statistics.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> invalidateDistributionSet(
|
||||
@PathVariable("distributionSetId") final Long distributionSetId,
|
||||
@Valid @RequestBody final MgmtInvalidateDistributionSetRequestBody invalidateRequestBody) {
|
||||
distributionSetInvalidationManagement
|
||||
.invalidateDistributionSet(new DistributionSetInvalidation(Arrays.asList(distributionSetId),
|
||||
MgmtRestModelMapper.convertCancelationType(invalidateRequestBody.getActionCancelationType()),
|
||||
invalidateRequestBody.isCancelRollouts()));
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedDistributionSetRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtDistributionSetTagAssigmentResult;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTag;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTagRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling for {@link DistributionSetTag} CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtDistributionSetTagResource implements MgmtDistributionSetTagRestApi {
|
||||
|
||||
private final DistributionSetTagManagement distributionSetTagManagement;
|
||||
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
MgmtDistributionSetTagResource(final DistributionSetTagManagement distributionSetTagManagement,
|
||||
final DistributionSetManagement distributionSetManagement, final EntityFactory entityFactory) {
|
||||
this.distributionSetTagManagement = distributionSetTagManagement;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTag>> getDistributionSetTags(
|
||||
@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.sanitizeTagSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Slice<DistributionSetTag> distributionSetTags;
|
||||
final long count;
|
||||
if (rsqlParam == null) {
|
||||
distributionSetTags = distributionSetTagManagement.findAll(pageable);
|
||||
count = distributionSetTagManagement.count();
|
||||
|
||||
} else {
|
||||
final Page<DistributionSetTag> page = distributionSetTagManagement.findByRsql(pageable, rsqlParam);
|
||||
distributionSetTags = page;
|
||||
count = page.getTotalElements();
|
||||
|
||||
}
|
||||
|
||||
final List<MgmtTag> rest = MgmtTagMapper.toResponseDistributionSetTag(distributionSetTags.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, count));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTag> getDistributionSetTag(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId) {
|
||||
final DistributionSetTag distributionSetTag = findDistributionTagById(distributionsetTagId);
|
||||
|
||||
final MgmtTag response = MgmtTagMapper.toResponse(distributionSetTag);
|
||||
MgmtTagMapper.addLinks(distributionSetTag, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtTag>> createDistributionSetTags(
|
||||
@RequestBody final List<MgmtTagRequestBodyPut> tags) {
|
||||
log.debug("creating {} ds tags", tags.size());
|
||||
|
||||
final List<DistributionSetTag> createdTags = distributionSetTagManagement
|
||||
.create(MgmtTagMapper.mapTagFromRequest(entityFactory, tags));
|
||||
|
||||
return new ResponseEntity<>(MgmtTagMapper.toResponseDistributionSetTag(createdTags), HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTag> updateDistributionSetTag(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
|
||||
@RequestBody final MgmtTagRequestBodyPut restDSTagRest) {
|
||||
|
||||
final DistributionSetTag distributionSetTag = distributionSetTagManagement
|
||||
.update(entityFactory.tag().update(distributionsetTagId).name(restDSTagRest.getName())
|
||||
.description(restDSTagRest.getDescription()).colour(restDSTagRest.getColour()));
|
||||
|
||||
final MgmtTag response = MgmtTagMapper.toResponse(distributionSetTag);
|
||||
MgmtTagMapper.addLinks(distributionSetTag, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteDistributionSetTag(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId) {
|
||||
log.debug("Delete {} distribution set tag", distributionsetTagId);
|
||||
final DistributionSetTag tag = findDistributionTagById(distributionsetTagId);
|
||||
|
||||
distributionSetTagManagement.delete(tag.getName());
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtDistributionSet>> getAssignedDistributionSets(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
|
||||
@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.sanitizeTagSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
Page<DistributionSet> findDistrAll;
|
||||
if (rsqlParam == null) {
|
||||
findDistrAll = distributionSetManagement.findByTag(pageable, distributionsetTagId);
|
||||
|
||||
} else {
|
||||
findDistrAll = distributionSetManagement.findByRsqlAndTag(pageable, rsqlParam, distributionsetTagId);
|
||||
}
|
||||
|
||||
final List<MgmtDistributionSet> rest = MgmtDistributionSetMapper
|
||||
.toResponseFromDsList(findDistrAll.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, findDistrAll.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> assignDistributionSet(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
|
||||
@PathVariable("distributionsetId") final Long distributionsetId) {
|
||||
log.debug("Assign ds {} for ds tag {}", distributionsetId, distributionsetTagId);
|
||||
this.distributionSetManagement.assignTag(List.of(distributionsetId), distributionsetTagId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> assignDistributionSets(
|
||||
final Long distributionsetTagId,
|
||||
final List<Long> distributionsetIds) {
|
||||
log.debug("Assign DistributionSet {} for ds tag {}", distributionsetIds.size(), distributionsetTagId);
|
||||
final List<DistributionSet> assignedDs = this.distributionSetManagement
|
||||
.assignTag(distributionsetIds, distributionsetTagId);
|
||||
log.debug("Assigned DistributionSet {}", assignedDs.size());
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> unassignDistributionSet(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
|
||||
@PathVariable("distributionsetId") final Long distributionsetId) {
|
||||
log.debug("Unassign ds {} for ds tag {}", distributionsetId, distributionsetTagId);
|
||||
this.distributionSetManagement.unassignTag(List.of(distributionsetId), distributionsetTagId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> unassignDistributionSets(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
|
||||
@RequestBody final List<Long> distributionsetIds) {
|
||||
log.debug("Unassign DistributionSet {} for ds tag {}", distributionsetIds.size(), distributionsetTagId);
|
||||
final List<DistributionSet> assignedDs = this.distributionSetManagement
|
||||
.unassignTag(distributionsetIds, distributionsetTagId);
|
||||
log.debug("Unassigned DistributionSet {}", assignedDs.size());
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSetTagAssigmentResult> toggleTagAssignment(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
|
||||
@RequestBody final List<MgmtAssignedDistributionSetRequestBody> assignedDSRequestBodies) {
|
||||
log.debug("Toggle distribution set assignment {} for ds tag {}", assignedDSRequestBodies.size(),
|
||||
distributionsetTagId);
|
||||
|
||||
final DistributionSetTag tag = findDistributionTagById(distributionsetTagId);
|
||||
|
||||
final DistributionSetTagAssignmentResult assigmentResult = this.distributionSetManagement
|
||||
.toggleTagAssignment(findDistributionSetIds(assignedDSRequestBodies), tag.getName());
|
||||
|
||||
final MgmtDistributionSetTagAssigmentResult tagAssigmentResultRest = new MgmtDistributionSetTagAssigmentResult();
|
||||
tagAssigmentResultRest.setAssignedDistributionSets(
|
||||
MgmtDistributionSetMapper.toResponseDistributionSets(assigmentResult.getAssignedEntity()));
|
||||
tagAssigmentResultRest.setUnassignedDistributionSets(
|
||||
MgmtDistributionSetMapper.toResponseDistributionSets(assigmentResult.getUnassignedEntity()));
|
||||
|
||||
log.debug("Toggled assignedDS {} and unassignedDS{}", assigmentResult.getAssigned(),
|
||||
assigmentResult.getUnassigned());
|
||||
|
||||
return ResponseEntity.ok(tagAssigmentResultRest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtDistributionSet>> assignDistributionSetsByRequestBody(
|
||||
@PathVariable("distributionsetTagId") final Long distributionsetTagId,
|
||||
@RequestBody final List<MgmtAssignedDistributionSetRequestBody> assignedDSRequestBodies) {
|
||||
log.debug("Assign DistributionSet {} for ds tag {}", assignedDSRequestBodies.size(), distributionsetTagId);
|
||||
final List<DistributionSet> assignedDs = this.distributionSetManagement
|
||||
.assignTag(findDistributionSetIds(assignedDSRequestBodies), distributionsetTagId);
|
||||
log.debug("Assigned DistributionSet {}", assignedDs.size());
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponseDistributionSets(assignedDs));
|
||||
}
|
||||
|
||||
private static List<Long> findDistributionSetIds(
|
||||
final List<MgmtAssignedDistributionSetRequestBody> assignedDistributionSetRequestBodies) {
|
||||
return assignedDistributionSetRequestBodies.stream()
|
||||
.map(MgmtAssignedDistributionSetRequestBody::getDistributionSetId).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private DistributionSetTag findDistributionTagById(final Long distributionsetTagId) {
|
||||
return distributionSetTagManagement.get(distributionsetTagId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, distributionsetTagId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeAssigment;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTypeRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
final class MgmtDistributionSetTypeMapper {
|
||||
|
||||
// private constructor, utility class
|
||||
private MgmtDistributionSetTypeMapper() {
|
||||
|
||||
}
|
||||
|
||||
static List<DistributionSetTypeCreate> smFromRequest(final EntityFactory entityFactory,
|
||||
final Collection<MgmtDistributionSetTypeRequestBodyPost> smTypesRest) {
|
||||
if (smTypesRest == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return smTypesRest.stream().map(smRest -> fromRequest(entityFactory, smRest)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<MgmtDistributionSetType> toListResponse(final Collection<DistributionSetType> types) {
|
||||
if (types == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return new ResponseList<>(
|
||||
types.stream().map(MgmtDistributionSetTypeMapper::toResponse).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
static MgmtDistributionSetType toResponse(final DistributionSetType type) {
|
||||
final MgmtDistributionSetType result = new MgmtDistributionSetType();
|
||||
|
||||
MgmtRestModelMapper.mapTypeToType(result, type);
|
||||
result.setModuleId(type.getId());
|
||||
|
||||
result.add(linkTo(methodOn(MgmtDistributionSetTypeRestApi.class).getDistributionSetType(result.getModuleId()))
|
||||
.withSelfRel().expand());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void addLinks(final MgmtDistributionSetType result) {
|
||||
|
||||
result.add(linkTo(methodOn(MgmtDistributionSetTypeRestApi.class).getMandatoryModules(result.getModuleId()))
|
||||
.withRel(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_MANDATORY_MODULES).expand());
|
||||
|
||||
result.add(linkTo(methodOn(MgmtDistributionSetTypeRestApi.class).getOptionalModules(result.getModuleId()))
|
||||
.withRel(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_OPTIONAL_MODULES).expand());
|
||||
}
|
||||
|
||||
private static DistributionSetTypeCreate fromRequest(final EntityFactory entityFactory,
|
||||
final MgmtDistributionSetTypeRequestBodyPost smsRest) {
|
||||
return entityFactory.distributionSetType().create().key(smsRest.getKey()).name(smsRest.getName())
|
||||
.description(smsRest.getDescription()).colour(smsRest.getColour())
|
||||
.mandatory(getMandatoryModules(smsRest)).optional(getOptionalmodules(smsRest));
|
||||
}
|
||||
|
||||
private static Collection<Long> getMandatoryModules(final MgmtDistributionSetTypeRequestBodyPost smsRest) {
|
||||
return Optional.ofNullable(smsRest.getMandatorymodules()).map(
|
||||
modules -> modules.stream().map(MgmtSoftwareModuleTypeAssigment::getId).collect(Collectors.toList()))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private static Collection<Long> getOptionalmodules(final MgmtDistributionSetTypeRequestBodyPost smsRest) {
|
||||
return Optional.ofNullable(smsRest.getOptionalmodules()).map(
|
||||
modules -> modules.stream().map(MgmtSoftwareModuleTypeAssigment::getId).collect(Collectors.toList()))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtId;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTypeRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.SoftwareModuleTypeNotInDistributionSetTypeException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling for {@link DistributionSetType} CRUD operations.
|
||||
*/
|
||||
@RestController
|
||||
public class MgmtDistributionSetTypeResource implements MgmtDistributionSetTypeRestApi {
|
||||
|
||||
private final SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
|
||||
private final DistributionSetTypeManagement distributionSetTypeManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
MgmtDistributionSetTypeResource(final SoftwareModuleTypeManagement softwareModuleTypeManagement,
|
||||
final DistributionSetTypeManagement distributionSetTypeManagement, final EntityFactory entityFactory) {
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtDistributionSetType>> getDistributionSetTypes(
|
||||
@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.sanitizeDistributionSetTypeSortParam(sortParam);
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Slice<DistributionSetType> findModuleTypessAll;
|
||||
long countModulesAll;
|
||||
if (rsqlParam != null) {
|
||||
findModuleTypessAll = distributionSetTypeManagement.findByRsql(pageable, rsqlParam);
|
||||
countModulesAll = ((Page<DistributionSetType>) findModuleTypessAll).getTotalElements();
|
||||
} else {
|
||||
findModuleTypessAll = distributionSetTypeManagement.findAll(pageable);
|
||||
countModulesAll = distributionSetTypeManagement.count();
|
||||
}
|
||||
|
||||
final List<MgmtDistributionSetType> rest = MgmtDistributionSetTypeMapper
|
||||
.toListResponse(findModuleTypessAll.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, countModulesAll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSetType> getDistributionSetType(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
|
||||
|
||||
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
|
||||
|
||||
final MgmtDistributionSetType reponse = MgmtDistributionSetTypeMapper.toResponse(foundType);
|
||||
MgmtDistributionSetTypeMapper.addLinks(reponse);
|
||||
|
||||
return ResponseEntity.ok(reponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteDistributionSetType(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
|
||||
distributionSetTypeManagement.delete(distributionSetTypeId);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSetType> updateDistributionSetType(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId,
|
||||
@RequestBody final MgmtDistributionSetTypeRequestBodyPut restDistributionSetType) {
|
||||
|
||||
final DistributionSetType updated = distributionSetTypeManagement.update(entityFactory.distributionSetType()
|
||||
.update(distributionSetTypeId).description(restDistributionSetType.getDescription())
|
||||
.colour(restDistributionSetType.getColour()));
|
||||
|
||||
final MgmtDistributionSetType reponse = MgmtDistributionSetTypeMapper.toResponse(updated);
|
||||
MgmtDistributionSetTypeMapper.addLinks(reponse);
|
||||
|
||||
return ResponseEntity.ok(reponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtDistributionSetType>> createDistributionSetTypes(
|
||||
@RequestBody final List<MgmtDistributionSetTypeRequestBodyPost> distributionSetTypes) {
|
||||
|
||||
final List<DistributionSetType> createdSoftwareModules = distributionSetTypeManagement
|
||||
.create(MgmtDistributionSetTypeMapper.smFromRequest(entityFactory, distributionSetTypes));
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(MgmtDistributionSetTypeMapper.toListResponse(createdSoftwareModules));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtSoftwareModuleType>> getMandatoryModules(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
|
||||
|
||||
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleTypeMapper.toTypesResponse(foundType.getMandatoryModuleTypes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModuleType> getMandatoryModule(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId,
|
||||
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
|
||||
|
||||
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
|
||||
final SoftwareModuleType foundSmType = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId);
|
||||
|
||||
if (!foundType.containsMandatoryModuleType(foundSmType)) {
|
||||
throw new SoftwareModuleTypeNotInDistributionSetTypeException(softwareModuleTypeId, distributionSetTypeId);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleTypeMapper.toResponse(foundSmType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModuleType> getOptionalModule(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId,
|
||||
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
|
||||
|
||||
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
|
||||
final SoftwareModuleType foundSmType = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId);
|
||||
|
||||
if (!foundType.containsOptionalModuleType(foundSmType)) {
|
||||
throw new SoftwareModuleTypeNotInDistributionSetTypeException(softwareModuleTypeId, distributionSetTypeId);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleTypeMapper.toResponse(foundSmType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtSoftwareModuleType>> getOptionalModules(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
|
||||
|
||||
final DistributionSetType foundType = findDistributionSetTypeWithExceptionIfNotFound(distributionSetTypeId);
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleTypeMapper.toTypesResponse(foundType.getOptionalModuleTypes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> removeMandatoryModule(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId,
|
||||
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
|
||||
distributionSetTypeManagement.unassignSoftwareModuleType(distributionSetTypeId, softwareModuleTypeId);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> removeOptionalModule(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId,
|
||||
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
|
||||
|
||||
return removeMandatoryModule(distributionSetTypeId, softwareModuleTypeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> addMandatoryModule(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId, @RequestBody final MgmtId smtId) {
|
||||
|
||||
distributionSetTypeManagement.assignMandatorySoftwareModuleTypes(distributionSetTypeId,
|
||||
Arrays.asList(smtId.getId()));
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> addOptionalModule(
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId, @RequestBody final MgmtId smtId) {
|
||||
|
||||
distributionSetTypeManagement.assignOptionalSoftwareModuleTypes(distributionSetTypeId,
|
||||
Arrays.asList(smtId.getId()));
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
private DistributionSetType findDistributionSetTypeWithExceptionIfNotFound(final Long distributionSetTypeId) {
|
||||
return distributionSetTypeManagement.get(distributionSetTypeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, distributionSetTypeId));
|
||||
}
|
||||
|
||||
private SoftwareModuleType findSoftwareModuleTypeWithExceptionIfNotFound(final Long softwareModuleTypeId) {
|
||||
|
||||
return softwareModuleTypeManagement.get(softwareModuleTypeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleType.class, softwareModuleTypeId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDownloadArtifactRestApi;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.ArtifactBinaryNoLongerExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.ArtifactBinaryNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.rest.util.FileStreamingUtil;
|
||||
import org.eclipse.hawkbit.rest.util.HttpUtil;
|
||||
import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
@Scope(value = WebApplicationContext.SCOPE_REQUEST)
|
||||
public class MgmtDownloadArtifactResource implements MgmtDownloadArtifactRestApi {
|
||||
|
||||
@Autowired
|
||||
private SoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
@Autowired
|
||||
private ArtifactManagement artifactManagement;
|
||||
|
||||
/**
|
||||
* Handles the GET request for downloading an artifact.
|
||||
*
|
||||
* @param softwareModuleId of the parent SoftwareModule
|
||||
* @param artifactId of the related Artifact
|
||||
* @return responseEntity with status ok if successful
|
||||
*/
|
||||
@Override
|
||||
public ResponseEntity<InputStream> downloadArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@PathVariable("artifactId") final Long artifactId) {
|
||||
|
||||
final SoftwareModule module = softwareModuleManagement.get(softwareModuleId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, softwareModuleId));
|
||||
if (module.isDeleted()) {
|
||||
throw new ArtifactBinaryNoLongerExistsException();
|
||||
}
|
||||
final Artifact artifact = module.getArtifact(artifactId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Artifact.class, artifactId));
|
||||
|
||||
final DbArtifact file = artifactManagement
|
||||
.loadArtifactBinary(artifact.getSha1Hash(), module.getId(), module.isEncrypted())
|
||||
.orElseThrow(() -> new ArtifactBinaryNotFoundException(artifact.getSha1Hash()));
|
||||
final HttpServletRequest request = RequestResponseContextHolder.getHttpServletRequest();
|
||||
final String ifMatch = request.getHeader(HttpHeaders.IF_MATCH);
|
||||
if (ifMatch != null && !HttpUtil.matchesHttpHeader(ifMatch, artifact.getSha1Hash())) {
|
||||
return new ResponseEntity<>(HttpStatus.PRECONDITION_FAILED);
|
||||
}
|
||||
|
||||
return FileStreamingUtil.writeFileResponse(file, artifact.getFilename(), artifact.getCreatedAt(),
|
||||
RequestResponseContextHolder.getHttpServletResponse(), request, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import io.swagger.v3.oas.models.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||
import org.eclipse.hawkbit.rest.OpenApiConfiguration;
|
||||
import org.springdoc.core.models.GroupedOpenApi;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnProperty(
|
||||
value = "hawkbit.server.swagger.enabled",
|
||||
havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
public class MgmtOpenApiConfiguration {
|
||||
|
||||
private static final String BASIC_AUTH_SEC_SCHEME_NAME = "Basic Authentication";
|
||||
private static final String BEARER_AUTH_SEC_SCHEME_NAME = "Bearer Authentication";
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(
|
||||
value = OpenApiConfiguration.HAWKBIT_SERVER_SWAGGER_ENABLED,
|
||||
havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
public GroupedOpenApi mgmtApi() {
|
||||
return GroupedOpenApi
|
||||
.builder()
|
||||
.group("Management API")
|
||||
.pathsToMatch("/rest/v1/**")
|
||||
.addOpenApiCustomizer(openApi ->
|
||||
openApi
|
||||
.addSecurityItem(new SecurityRequirement()
|
||||
.addList(BASIC_AUTH_SEC_SCHEME_NAME)
|
||||
.addList(BEARER_AUTH_SEC_SCHEME_NAME))
|
||||
.components(
|
||||
openApi
|
||||
.getComponents()
|
||||
.addSecuritySchemes(BASIC_AUTH_SEC_SCHEME_NAME,
|
||||
new SecurityScheme()
|
||||
.name(BASIC_AUTH_SEC_SCHEME_NAME)
|
||||
.type(SecurityScheme.Type.HTTP)
|
||||
.in(SecurityScheme.In.HEADER)
|
||||
.scheme("basic"))
|
||||
.addSecuritySchemes(BEARER_AUTH_SEC_SCHEME_NAME,
|
||||
new SecurityScheme()
|
||||
.name(BEARER_AUTH_SEC_SCHEME_NAME)
|
||||
.type(SecurityScheme.Type.HTTP)
|
||||
.in(SecurityScheme.In.HEADER)
|
||||
.bearerFormat("JWT")
|
||||
.scheme("bearer"))))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtBaseEntity;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtNamedEntity;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtTypeEntity;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtCancelationType;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation.CancelationType;
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.eclipse.hawkbit.repository.model.Type;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
public final class MgmtRestModelMapper {
|
||||
|
||||
// private constructor, utility class
|
||||
private MgmtRestModelMapper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given {@link MgmtActionType} into a corresponding repository
|
||||
* {@link ActionType}.
|
||||
*
|
||||
* @param actionTypeRest the REST representation of the action type
|
||||
* @return <null> or the repository action type
|
||||
*/
|
||||
public static ActionType convertActionType(final MgmtActionType actionTypeRest) {
|
||||
if (actionTypeRest == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (actionTypeRest) {
|
||||
case SOFT:
|
||||
return ActionType.SOFT;
|
||||
case FORCED:
|
||||
return ActionType.FORCED;
|
||||
case TIMEFORCED:
|
||||
return ActionType.TIMEFORCED;
|
||||
case DOWNLOAD_ONLY:
|
||||
return ActionType.DOWNLOAD_ONLY;
|
||||
default:
|
||||
throw new IllegalStateException("Action Type is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given repository {@link ActionType} into a corresponding
|
||||
* {@link MgmtActionType}.
|
||||
*
|
||||
* @param actionType the repository representation of the action type
|
||||
* @return <null> or the REST action type
|
||||
*/
|
||||
public static MgmtActionType convertActionType(final ActionType actionType) {
|
||||
if (actionType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (actionType) {
|
||||
case SOFT:
|
||||
return MgmtActionType.SOFT;
|
||||
case FORCED:
|
||||
return MgmtActionType.FORCED;
|
||||
case TIMEFORCED:
|
||||
return MgmtActionType.TIMEFORCED;
|
||||
case DOWNLOAD_ONLY:
|
||||
return MgmtActionType.DOWNLOAD_ONLY;
|
||||
default:
|
||||
throw new IllegalStateException("Action Type is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given repository {@link CancelationType} into a
|
||||
* corresponding {@link MgmtCancelationType}.
|
||||
*
|
||||
* @param cancelationType the repository representation of the cancellation type
|
||||
* @return <null> or the REST cancellation type
|
||||
*/
|
||||
public static CancelationType convertCancelationType(final MgmtCancelationType cancelationType) {
|
||||
if (cancelationType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (cancelationType) {
|
||||
case SOFT:
|
||||
return CancelationType.SOFT;
|
||||
case FORCE:
|
||||
return CancelationType.FORCE;
|
||||
case NONE:
|
||||
return CancelationType.NONE;
|
||||
default:
|
||||
throw new IllegalStateException("Action Cancelation Type is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
static void mapBaseToBase(final MgmtBaseEntity response, final TenantAwareBaseEntity base) {
|
||||
response.setCreatedBy(base.getCreatedBy());
|
||||
response.setLastModifiedBy(base.getLastModifiedBy());
|
||||
if (base.getCreatedAt() > 0) {
|
||||
response.setCreatedAt(base.getCreatedAt());
|
||||
}
|
||||
if (base.getLastModifiedAt() > 0) {
|
||||
response.setLastModifiedAt(base.getLastModifiedAt());
|
||||
}
|
||||
}
|
||||
|
||||
static void mapNamedToNamed(final MgmtNamedEntity response, final NamedEntity base) {
|
||||
mapBaseToBase(response, base);
|
||||
|
||||
response.setName(base.getName());
|
||||
response.setDescription(base.getDescription());
|
||||
}
|
||||
|
||||
static void mapTypeToType(final MgmtTypeEntity response, final Type base) {
|
||||
mapNamedToNamed(response, base);
|
||||
|
||||
response.setKey(base.getKey());
|
||||
response.setColour(base.getColour());
|
||||
response.setDeleted(base.isDeleted());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.AbstractMgmtRolloutConditionsEntity;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutCondition;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutCondition.Condition;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutErrorAction;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutErrorAction.ErrorAction;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBodyPut;
|
||||
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.MgmtDynamicRolloutGroupTemplate;
|
||||
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;
|
||||
import org.eclipse.hawkbit.repository.builder.DynamicRolloutGroupTemplate;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutUpdate;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessAction;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
|
||||
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
final class MgmtRolloutMapper {
|
||||
|
||||
private static final String NOT_SUPPORTED = " is not supported";
|
||||
|
||||
private MgmtRolloutMapper() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
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, withDetails)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static MgmtRolloutResponseBody toResponseRollout(final Rollout rollout, final boolean withDetails) {
|
||||
final MgmtRolloutResponseBody body = new MgmtRolloutResponseBody();
|
||||
body.setCreatedAt(rollout.getCreatedAt());
|
||||
body.setCreatedBy(rollout.getCreatedBy());
|
||||
body.setDescription(rollout.getDescription());
|
||||
body.setLastModifiedAt(rollout.getLastModifiedAt());
|
||||
body.setLastModifiedBy(rollout.getLastModifiedBy());
|
||||
body.setName(rollout.getName());
|
||||
body.setRolloutId(rollout.getId());
|
||||
body.setDynamic(rollout.isDynamic());
|
||||
body.setTargetFilterQuery(rollout.getTargetFilterQuery());
|
||||
body.setDistributionSetId(rollout.getDistributionSet().getId());
|
||||
body.setStatus(rollout.getStatus().toString().toLowerCase());
|
||||
body.setTotalTargets(rollout.getTotalTargets());
|
||||
body.setDeleted(rollout.isDeleted());
|
||||
body.setType(MgmtRestModelMapper.convertActionType(rollout.getActionType()));
|
||||
body.setForcetime(rollout.getForcedTime());
|
||||
rollout.getWeight().ifPresent(body::setWeight);
|
||||
|
||||
if (withDetails) {
|
||||
for (final TotalTargetCountStatus.Status status : TotalTargetCountStatus.Status.values()) {
|
||||
body.addTotalTargetsPerStatus(status.name().toLowerCase(),
|
||||
rollout.getTotalTargetCountStatus().getTotalTargetCountByStatus(status));
|
||||
}
|
||||
body.setTotalGroups(rollout.getRolloutGroupsCreated());
|
||||
body.setStartAt(rollout.getStartAt());
|
||||
|
||||
body.setApproveDecidedBy(rollout.getApprovalDecidedBy());
|
||||
body.setApprovalRemark(rollout.getApprovalRemark());
|
||||
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).start(rollout.getId())).withRel("start").expand());
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).pause(rollout.getId())).withRel("pause").expand());
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).resume(rollout.getId())).withRel("resume").expand());
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).triggerNextGroup(rollout.getId()))
|
||||
.withRel("triggerNextGroup").expand());
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).approve(rollout.getId(), null)).withRel("approve")
|
||||
.expand());
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).deny(rollout.getId(), null)).withRel("deny").expand());
|
||||
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, null)).withRel("groups")
|
||||
.expand());
|
||||
|
||||
final DistributionSet distributionSet = rollout.getDistributionSet();
|
||||
body.add(linkTo(methodOn(MgmtDistributionSetRestApi.class).getDistributionSet(distributionSet.getId()))
|
||||
.withRel("distributionset").withName(distributionSet.getName() + ":" + distributionSet.getVersion())
|
||||
.expand());
|
||||
}
|
||||
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRollout(rollout.getId())).withSelfRel().expand());
|
||||
return body;
|
||||
}
|
||||
|
||||
static RolloutCreate fromRequest(final EntityFactory entityFactory, final MgmtRolloutRestRequestBodyPost restRequest,
|
||||
final DistributionSet distributionSet) {
|
||||
return entityFactory.rollout().create()
|
||||
.name(restRequest.getName())
|
||||
.description(restRequest.getDescription())
|
||||
.distributionSetId(distributionSet)
|
||||
.targetFilterQuery(restRequest.getTargetFilterQuery())
|
||||
.actionType(MgmtRestModelMapper.convertActionType(restRequest.getType()))
|
||||
.forcedTime(restRequest.getForcetime()).startAt(restRequest.getStartAt())
|
||||
.weight(restRequest.getWeight())
|
||||
.dynamic(restRequest.isDynamic());
|
||||
}
|
||||
|
||||
static RolloutUpdate fromRequest(final EntityFactory entityFactory, final MgmtRolloutRestRequestBodyPut restRequest, final long rolloutId) {
|
||||
return entityFactory.rollout().update(rolloutId)
|
||||
.name(restRequest.getName())
|
||||
.description(restRequest.getDescription());
|
||||
}
|
||||
|
||||
static RolloutCreate fromRetriedRollout(final EntityFactory entityFactory, final Rollout rollout) {
|
||||
return entityFactory.rollout().create()
|
||||
.name(rollout.getName().concat("_retry"))
|
||||
.description(rollout.getDescription())
|
||||
.distributionSetId(rollout.getDistributionSet())
|
||||
.targetFilterQuery("failedrollout==".concat(String.valueOf(rollout.getId())))
|
||||
.actionType(rollout.getActionType())
|
||||
.forcedTime(rollout.getForcedTime())
|
||||
.startAt(rollout.getStartAt())
|
||||
.weight(null);
|
||||
}
|
||||
|
||||
static RolloutGroupCreate fromRequest(final EntityFactory entityFactory, final MgmtRolloutGroup restRequest) {
|
||||
return entityFactory.rolloutGroup().create().name(restRequest.getName())
|
||||
.description(restRequest.getDescription()).targetFilterQuery(restRequest.getTargetFilterQuery())
|
||||
.targetPercentage(restRequest.getTargetPercentage()).conditions(fromRequest(restRequest, false));
|
||||
}
|
||||
|
||||
static DynamicRolloutGroupTemplate fromRequest(final MgmtDynamicRolloutGroupTemplate restRequest) {
|
||||
if (restRequest == null) {
|
||||
return null;
|
||||
}
|
||||
return DynamicRolloutGroupTemplate.builder()
|
||||
.nameSuffix(Optional.ofNullable(restRequest.getNameSuffix()).orElse(""))
|
||||
.targetCount(restRequest.getTargetCount())
|
||||
.build();
|
||||
}
|
||||
|
||||
static RolloutGroupConditions fromRequest(final AbstractMgmtRolloutConditionsEntity restRequest,
|
||||
final boolean withDefaults) {
|
||||
final RolloutGroupConditionBuilder conditions = new RolloutGroupConditionBuilder();
|
||||
|
||||
if (withDefaults) {
|
||||
conditions.withDefaults();
|
||||
}
|
||||
|
||||
if (restRequest.getSuccessCondition() != null) {
|
||||
conditions.successCondition(mapFinishCondition(restRequest.getSuccessCondition().getCondition()),
|
||||
restRequest.getSuccessCondition().getExpression());
|
||||
}
|
||||
if (restRequest.getSuccessAction() != null) {
|
||||
conditions.successAction(map(restRequest.getSuccessAction().getAction()),
|
||||
restRequest.getSuccessAction().getExpression());
|
||||
}
|
||||
|
||||
if (restRequest.getErrorCondition() != null) {
|
||||
conditions.errorCondition(mapErrorCondition(restRequest.getErrorCondition().getCondition()),
|
||||
restRequest.getErrorCondition().getExpression());
|
||||
}
|
||||
if (restRequest.getErrorAction() != null) {
|
||||
conditions.errorAction(map(restRequest.getErrorAction().getAction()),
|
||||
restRequest.getErrorAction().getExpression());
|
||||
}
|
||||
|
||||
return conditions.build();
|
||||
}
|
||||
|
||||
static List<MgmtRolloutGroupResponseBody> toResponseRolloutGroup(final List<RolloutGroup> rollouts,
|
||||
final boolean confirmationFlowEnabled, final boolean withDetails) {
|
||||
if (rollouts == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return rollouts.stream().map(group -> toResponseRolloutGroup(group, withDetails, confirmationFlowEnabled))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static MgmtRolloutGroupResponseBody toResponseRolloutGroup(final RolloutGroup rolloutGroup,
|
||||
final boolean withDetailedStatus, final boolean confirmationFlowEnabled) {
|
||||
final MgmtRolloutGroupResponseBody body = new MgmtRolloutGroupResponseBody();
|
||||
body.setCreatedAt(rolloutGroup.getCreatedAt());
|
||||
body.setCreatedBy(rolloutGroup.getCreatedBy());
|
||||
body.setDescription(rolloutGroup.getDescription());
|
||||
body.setLastModifiedAt(rolloutGroup.getLastModifiedAt());
|
||||
body.setLastModifiedBy(rolloutGroup.getLastModifiedBy());
|
||||
body.setName(rolloutGroup.getName());
|
||||
body.setRolloutGroupId(rolloutGroup.getId());
|
||||
body.setStatus(rolloutGroup.getStatus().toString().toLowerCase());
|
||||
body.setTargetPercentage(rolloutGroup.getTargetPercentage());
|
||||
body.setTargetFilterQuery(rolloutGroup.getTargetFilterQuery());
|
||||
body.setTotalTargets(rolloutGroup.getTotalTargets());
|
||||
|
||||
if (confirmationFlowEnabled) {
|
||||
body.setConfirmationRequired(rolloutGroup.isConfirmationRequired());
|
||||
}
|
||||
|
||||
body.setDynamic(rolloutGroup.isDynamic());
|
||||
|
||||
body.setSuccessCondition(new MgmtRolloutCondition(map(rolloutGroup.getSuccessCondition()),
|
||||
rolloutGroup.getSuccessConditionExp()));
|
||||
body.setSuccessAction(
|
||||
new MgmtRolloutSuccessAction(map(rolloutGroup.getSuccessAction()), rolloutGroup.getSuccessActionExp()));
|
||||
|
||||
body.setErrorCondition(
|
||||
new MgmtRolloutCondition(map(rolloutGroup.getErrorCondition()), rolloutGroup.getErrorConditionExp()));
|
||||
body.setErrorAction(
|
||||
new MgmtRolloutErrorAction(map(rolloutGroup.getErrorAction()), rolloutGroup.getErrorActionExp()));
|
||||
|
||||
if (withDetailedStatus) {
|
||||
for (final TotalTargetCountStatus.Status status : TotalTargetCountStatus.Status.values()) {
|
||||
body.addTotalTargetsPerStatus(status.name().toLowerCase(),
|
||||
rolloutGroup.getTotalTargetCountStatus().getTotalTargetCountByStatus(status));
|
||||
}
|
||||
}
|
||||
|
||||
body.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRolloutGroup(rolloutGroup.getRollout().getId(),
|
||||
rolloutGroup.getId())).withSelfRel());
|
||||
return body;
|
||||
}
|
||||
|
||||
private static RolloutGroupErrorCondition mapErrorCondition(final Condition condition) {
|
||||
if (Condition.THRESHOLD == condition) {
|
||||
return RolloutGroupErrorCondition.THRESHOLD;
|
||||
}
|
||||
throw new IllegalArgumentException(createIllegalArgumentLiteral(condition));
|
||||
}
|
||||
|
||||
private static RolloutGroupSuccessCondition mapFinishCondition(final Condition condition) {
|
||||
if (Condition.THRESHOLD == condition) {
|
||||
return RolloutGroupSuccessCondition.THRESHOLD;
|
||||
}
|
||||
throw new IllegalArgumentException(createIllegalArgumentLiteral(condition));
|
||||
}
|
||||
|
||||
private static Condition map(final RolloutGroupSuccessCondition rolloutCondition) {
|
||||
if (RolloutGroupSuccessCondition.THRESHOLD == rolloutCondition) {
|
||||
return Condition.THRESHOLD;
|
||||
}
|
||||
throw new IllegalArgumentException("Rollout group condition " + rolloutCondition + NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
private static Condition map(final RolloutGroupErrorCondition rolloutCondition) {
|
||||
if (RolloutGroupErrorCondition.THRESHOLD == rolloutCondition) {
|
||||
return Condition.THRESHOLD;
|
||||
}
|
||||
throw new IllegalArgumentException("Rollout group condition " + rolloutCondition + NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
private static RolloutGroupErrorAction map(final ErrorAction action) {
|
||||
if (ErrorAction.PAUSE == action) {
|
||||
return RolloutGroupErrorAction.PAUSE;
|
||||
}
|
||||
throw new IllegalArgumentException("Error Action " + action + NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
private static RolloutGroupSuccessAction map(final SuccessAction action) {
|
||||
if (SuccessAction.NEXTGROUP == action) {
|
||||
return RolloutGroupSuccessAction.NEXTGROUP;
|
||||
}
|
||||
throw new IllegalArgumentException("Success Action " + action + NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
private static SuccessAction map(final RolloutGroupSuccessAction successAction) {
|
||||
if (RolloutGroupSuccessAction.NEXTGROUP == successAction) {
|
||||
return SuccessAction.NEXTGROUP;
|
||||
}
|
||||
throw new IllegalArgumentException("Rollout group success action " + successAction + NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
private static ErrorAction map(final RolloutGroupErrorAction errorAction) {
|
||||
if (RolloutGroupErrorAction.PAUSE == errorAction) {
|
||||
return ErrorAction.PAUSE;
|
||||
}
|
||||
throw new IllegalArgumentException("Rollout group error action " + errorAction + NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
private static String createIllegalArgumentLiteral(final Condition condition) {
|
||||
return "Condition " + condition + NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.validation.ValidationException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rolloutgroup.MgmtRolloutGroup;
|
||||
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.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling rollout CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtRolloutResource implements MgmtRolloutRestApi {
|
||||
|
||||
private final RolloutManagement rolloutManagement;
|
||||
|
||||
private final RolloutGroupManagement rolloutGroupManagement;
|
||||
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
|
||||
private final TargetFilterQueryManagement targetFilterQueryManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
private final TenantConfigHelper tenantConfigHelper;
|
||||
|
||||
MgmtRolloutResource(final RolloutManagement rolloutManagement, final RolloutGroupManagement rolloutGroupManagement,
|
||||
final DistributionSetManagement distributionSetManagement,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement, final EntityFactory entityFactory,
|
||||
final SystemSecurityContext systemSecurityContext,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
this.rolloutManagement = rolloutManagement;
|
||||
this.rolloutGroupManagement = rolloutGroupManagement;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.targetFilterQueryManagement = targetFilterQueryManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtRolloutResponseBody>> getRollouts(
|
||||
@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 String representationModeParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeRolloutSortParam(sortParam);
|
||||
|
||||
final boolean isFullMode = parseRepresentationMode(representationModeParam) == MgmtRepresentationMode.FULL;
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<Rollout> rollouts;
|
||||
if (rsqlParam != null) {
|
||||
rollouts = this.rolloutManagement.findByRsql(pageable, rsqlParam, false);
|
||||
} else {
|
||||
rollouts = this.rolloutManagement.findAll(pageable, false);
|
||||
}
|
||||
|
||||
final long totalElements = rollouts.getTotalElements();
|
||||
|
||||
if (isFullMode) {
|
||||
this.rolloutManagement.setRolloutStatusDetails(rollouts);
|
||||
}
|
||||
|
||||
final List<MgmtRolloutResponseBody> rest = MgmtRolloutMapper.toResponseRollout(rollouts.getContent(),
|
||||
isFullMode);
|
||||
|
||||
return ResponseEntity.ok(new PagedList<>(rest, totalElements));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtRolloutResponseBody> getRollout(@PathVariable("rolloutId") final Long rolloutId) {
|
||||
final Rollout findRolloutById = rolloutManagement.getWithDetailedStatus(rolloutId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId));
|
||||
|
||||
return ResponseEntity.ok(MgmtRolloutMapper.toResponseRollout(findRolloutById, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtRolloutResponseBody> create(
|
||||
@RequestBody final MgmtRolloutRestRequestBodyPost rolloutRequestBody) {
|
||||
// first check the given RSQL query if it's well-formed, otherwise and
|
||||
// exception is thrown
|
||||
final String targetFilterQuery = rolloutRequestBody.getTargetFilterQuery();
|
||||
if (targetFilterQuery == null) {
|
||||
// Use RSQLParameterSyntaxException due to backwards compatibility
|
||||
throw new RSQLParameterSyntaxException("Cannot create a Rollout with an empty target query filter!");
|
||||
}
|
||||
targetFilterQueryManagement.verifyTargetFilterQuerySyntax(targetFilterQuery);
|
||||
final DistributionSet distributionSet = distributionSetManagement
|
||||
.getValidAndComplete(rolloutRequestBody.getDistributionSetId());
|
||||
final RolloutGroupConditions rolloutGroupConditions = MgmtRolloutMapper.fromRequest(rolloutRequestBody, true);
|
||||
final RolloutCreate create = MgmtRolloutMapper.fromRequest(entityFactory, rolloutRequestBody, distributionSet);
|
||||
final boolean confirmationFlowActive = tenantConfigHelper.isConfirmationFlowEnabled();
|
||||
|
||||
final Rollout rollout;
|
||||
if (rolloutRequestBody.getGroups() != null) {
|
||||
if (rolloutRequestBody.isDynamic()) {
|
||||
throw new ValidationException("Dynamic rollouts are not supported with groups");
|
||||
}
|
||||
if (rolloutRequestBody.getAmountGroups() != null) {
|
||||
throw new ValidationException("Either 'amountGroups' or 'groups' must be defined in the request");
|
||||
}
|
||||
final List<RolloutGroupCreate> rolloutGroups = rolloutRequestBody.getGroups().stream()
|
||||
.map(mgmtRolloutGroup -> {
|
||||
final boolean confirmationRequired = isConfirmationRequiredForGroup(mgmtRolloutGroup,
|
||||
rolloutRequestBody).orElse(confirmationFlowActive);
|
||||
return MgmtRolloutMapper.fromRequest(entityFactory, mgmtRolloutGroup)
|
||||
.confirmationRequired(confirmationRequired);
|
||||
}).collect(Collectors.toList());
|
||||
rollout = rolloutManagement.create(create, rolloutGroups, rolloutGroupConditions);
|
||||
} else if (rolloutRequestBody.getAmountGroups() != null) {
|
||||
final boolean confirmationRequired = rolloutRequestBody.getConfirmationRequired() == null
|
||||
? confirmationFlowActive
|
||||
: rolloutRequestBody.getConfirmationRequired();
|
||||
rollout = rolloutManagement.create(create, rolloutRequestBody.getAmountGroups(), confirmationRequired,
|
||||
rolloutGroupConditions, MgmtRolloutMapper.fromRequest(rolloutRequestBody.getDynamicGroupTemplate()));
|
||||
} else {
|
||||
throw new ValidationException("Either 'amountGroups' or 'groups' must be defined in the request");
|
||||
}
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(MgmtRolloutMapper.toResponseRollout(rollout, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtRolloutResponseBody> update(
|
||||
@PathVariable("rolloutId") final Long rolloutId,
|
||||
@RequestBody final MgmtRolloutRestRequestBodyPut rolloutUpdateBody) {
|
||||
final Rollout updated =
|
||||
rolloutManagement.update(MgmtRolloutMapper.fromRequest(entityFactory, rolloutUpdateBody, rolloutId));
|
||||
return ResponseEntity.ok(MgmtRolloutMapper.toResponseRollout(updated, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> approve(@PathVariable("rolloutId") final Long rolloutId, final String remark) {
|
||||
rolloutManagement.approveOrDeny(rolloutId, Rollout.ApprovalDecision.APPROVED, remark);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deny(@PathVariable("rolloutId") final Long rolloutId, final String remark) {
|
||||
rolloutManagement.approveOrDeny(rolloutId, Rollout.ApprovalDecision.DENIED, remark);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> start(@PathVariable("rolloutId") final Long rolloutId) {
|
||||
this.rolloutManagement.start(rolloutId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> pause(@PathVariable("rolloutId") final Long rolloutId) {
|
||||
this.rolloutManagement.pauseRollout(rolloutId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> delete(@PathVariable("rolloutId") final Long rolloutId) {
|
||||
this.rolloutManagement.delete(rolloutId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> resume(@PathVariable("rolloutId") final Long rolloutId) {
|
||||
this.rolloutManagement.resumeRollout(rolloutId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtRolloutGroupResponseBody>> getRolloutGroups(
|
||||
@PathVariable("rolloutId") final Long rolloutId,
|
||||
@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 String representationModeParam) {
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeRolloutGroupSortParam(sortParam);
|
||||
|
||||
final boolean isFullMode = parseRepresentationMode(representationModeParam) == MgmtRepresentationMode.FULL;
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Page<RolloutGroup> rolloutGroups;
|
||||
if (rsqlParam != null) {
|
||||
if (isFullMode) {
|
||||
rolloutGroups = this.rolloutGroupManagement.findByRolloutAndRsqlWithDetailedStatus(pageable,
|
||||
rolloutId, rsqlParam);
|
||||
} else {
|
||||
rolloutGroups = this.rolloutGroupManagement.findByRolloutAndRsql(pageable, rolloutId, rsqlParam);
|
||||
}
|
||||
} else {
|
||||
if (isFullMode) {
|
||||
rolloutGroups = this.rolloutGroupManagement.findByRolloutWithDetailedStatus(pageable, rolloutId);
|
||||
} else {
|
||||
rolloutGroups = this.rolloutGroupManagement.findByRollout(pageable, rolloutId);
|
||||
}
|
||||
}
|
||||
|
||||
final List<MgmtRolloutGroupResponseBody> rest = MgmtRolloutMapper.toResponseRolloutGroup(
|
||||
rolloutGroups.getContent(), tenantConfigHelper.isConfirmationFlowEnabled(), isFullMode);
|
||||
return ResponseEntity.ok(new PagedList<>(rest, rolloutGroups.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtRolloutGroupResponseBody> getRolloutGroup(@PathVariable("rolloutId") final Long rolloutId,
|
||||
@PathVariable("groupId") final Long groupId) {
|
||||
findRolloutOrThrowException(rolloutId);
|
||||
|
||||
final RolloutGroup rolloutGroup = rolloutGroupManagement.getWithDetailedStatus(groupId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(RolloutGroup.class, rolloutId));
|
||||
|
||||
if (!Objects.equals(rolloutId, rolloutGroup.getRollout().getId())) {
|
||||
throw new EntityNotFoundException(RolloutGroup.class, groupId);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(MgmtRolloutMapper.toResponseRolloutGroup(rolloutGroup, true,
|
||||
tenantConfigHelper.isConfirmationFlowEnabled()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTarget>> getRolloutGroupTargets(@PathVariable("rolloutId") final Long rolloutId,
|
||||
@PathVariable("groupId") final Long groupId,
|
||||
@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) {
|
||||
findRolloutOrThrowException(rolloutId);
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeTargetSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Page<Target> rolloutGroupTargets;
|
||||
if (rsqlParam != null) {
|
||||
rolloutGroupTargets = this.rolloutGroupManagement.findTargetsOfRolloutGroupByRsql(pageable, groupId,
|
||||
rsqlParam);
|
||||
} else {
|
||||
final Page<Target> pageTargets = this.rolloutGroupManagement.findTargetsOfRolloutGroup(pageable, groupId);
|
||||
rolloutGroupTargets = pageTargets;
|
||||
}
|
||||
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(rolloutGroupTargets.getContent(), tenantConfigHelper);
|
||||
return ResponseEntity.ok(new PagedList<>(rest, rolloutGroupTargets.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> triggerNextGroup(@PathVariable("rolloutId") final Long rolloutId) {
|
||||
this.rolloutManagement.triggerNextGroup(rolloutId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtRolloutResponseBody> retryRollout(final Long rolloutId) {
|
||||
final Rollout rolloutForRetry = this.rolloutManagement.get(rolloutId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Rollout.class, rolloutId));
|
||||
|
||||
if (rolloutForRetry.isDeleted()) {
|
||||
throw new EntityNotFoundException(Rollout.class, rolloutId);
|
||||
}
|
||||
|
||||
if (!rolloutForRetry.getStatus().equals(Rollout.RolloutStatus.FINISHED)) {
|
||||
throw new ValidationException("Rollout must be finished in order to be retried!");
|
||||
}
|
||||
|
||||
final RolloutCreate create = MgmtRolloutMapper.fromRetriedRollout(entityFactory, rolloutForRetry);
|
||||
final RolloutGroupConditions groupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
|
||||
|
||||
final Rollout retriedRollout = rolloutManagement.create(create, 1, false, groupConditions, null);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(MgmtRolloutMapper.toResponseRollout(retriedRollout, true));
|
||||
}
|
||||
|
||||
private static MgmtRepresentationMode parseRepresentationMode(final String representationModeParam) {
|
||||
return 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;
|
||||
});
|
||||
}
|
||||
|
||||
private Optional<Boolean> isConfirmationRequiredForGroup(final MgmtRolloutGroup group,
|
||||
final MgmtRolloutRestRequestBodyPost request) {
|
||||
if (group.getConfirmationRequired() != null) {
|
||||
return Optional.of(group.getConfirmationRequired());
|
||||
} else if (request.getConfirmationRequired() != null) {
|
||||
return Optional.of(request.getConfirmationRequired());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private void findRolloutOrThrowException(final Long rolloutId) {
|
||||
if (!rolloutManagement.exists(rolloutId)) {
|
||||
throw new EntityNotFoundException(Rollout.class, rolloutId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.artifact.repository.urlhandler.ApiType;
|
||||
import org.eclipse.hawkbit.artifact.repository.urlhandler.ArtifactUrl;
|
||||
import org.eclipse.hawkbit.artifact.repository.urlhandler.ArtifactUrlHandler;
|
||||
import org.eclipse.hawkbit.artifact.repository.urlhandler.URLPlaceholder;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifactHash;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
import org.springframework.hateoas.Link;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class MgmtSoftwareModuleMapper {
|
||||
|
||||
static List<SoftwareModuleMetadataCreate> fromRequestSwMetadata(final EntityFactory entityFactory,
|
||||
final Long softwareModuleId, final Collection<MgmtSoftwareModuleMetadata> metadata) {
|
||||
if (metadata == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return metadata.stream()
|
||||
.map(metadataRest -> entityFactory.softwareModuleMetadata().create(softwareModuleId)
|
||||
.key(metadataRest.getKey()).value(metadataRest.getValue())
|
||||
.targetVisible(metadataRest.isTargetVisible()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<SoftwareModuleCreate> smFromRequest(final EntityFactory entityFactory,
|
||||
final Collection<MgmtSoftwareModuleRequestBodyPost> smsRest) {
|
||||
if (smsRest == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return smsRest.stream().map(smRest -> fromRequest(entityFactory, smRest)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<MgmtSoftwareModule> toResponse(final Collection<SoftwareModule> softwareModules) {
|
||||
if (softwareModules == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return new ResponseList<>(
|
||||
softwareModules.stream().map(MgmtSoftwareModuleMapper::toResponse).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
static List<MgmtSoftwareModuleMetadata> toResponseSwMetadata(final Collection<SoftwareModuleMetadata> metadata) {
|
||||
if (metadata == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return metadata.stream().map(MgmtSoftwareModuleMapper::toResponseSwMetadata).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static MgmtSoftwareModuleMetadata toResponseSwMetadata(final SoftwareModuleMetadata metadata) {
|
||||
final MgmtSoftwareModuleMetadata metadataRest = new MgmtSoftwareModuleMetadata();
|
||||
metadataRest.setKey(metadata.getKey());
|
||||
metadataRest.setValue(metadata.getValue());
|
||||
metadataRest.setTargetVisible(metadata.isTargetVisible());
|
||||
return metadataRest;
|
||||
}
|
||||
|
||||
static MgmtSoftwareModule toResponse(final SoftwareModule softwareModule) {
|
||||
if (softwareModule == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final MgmtSoftwareModule response = new MgmtSoftwareModule();
|
||||
MgmtRestModelMapper.mapNamedToNamed(response, softwareModule);
|
||||
response.setModuleId(softwareModule.getId());
|
||||
response.setVersion(softwareModule.getVersion());
|
||||
response.setType(softwareModule.getType().getKey());
|
||||
response.setTypeName(softwareModule.getType().getName());
|
||||
response.setVendor(softwareModule.getVendor());
|
||||
response.setLocked(softwareModule.isLocked());
|
||||
response.setDeleted(softwareModule.isDeleted());
|
||||
response.setEncrypted(softwareModule.isEncrypted());
|
||||
|
||||
response.add(linkTo(methodOn(MgmtSoftwareModuleRestApi.class).getSoftwareModule(response.getModuleId()))
|
||||
.withSelfRel().expand());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
static void addLinks(final SoftwareModule softwareModule, final MgmtSoftwareModule response) {
|
||||
response.add(linkTo(methodOn(MgmtSoftwareModuleRestApi.class).getArtifacts(response.getModuleId(), null, null))
|
||||
.withRel(MgmtRestConstants.SOFTWAREMODULE_V1_ARTIFACT).expand());
|
||||
|
||||
response.add(linkTo(
|
||||
methodOn(MgmtSoftwareModuleTypeRestApi.class).getSoftwareModuleType(softwareModule.getType().getId()))
|
||||
.withRel(MgmtRestConstants.SOFTWAREMODULE_V1_TYPE).expand());
|
||||
|
||||
response.add(linkTo(methodOn(MgmtSoftwareModuleResource.class).getMetadata(response.getModuleId(),
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null)).withRel("metadata")
|
||||
.expand().expand());
|
||||
}
|
||||
|
||||
static MgmtArtifact toResponse(final Artifact artifact) {
|
||||
final MgmtArtifact artifactRest = new MgmtArtifact();
|
||||
artifactRest.setArtifactId(artifact.getId());
|
||||
artifactRest.setSize(artifact.getSize());
|
||||
artifactRest.setHashes(
|
||||
new MgmtArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash(), artifact.getSha256Hash()));
|
||||
|
||||
artifactRest.setProvidedFilename(artifact.getFilename());
|
||||
|
||||
MgmtRestModelMapper.mapBaseToBase(artifactRest, artifact);
|
||||
|
||||
artifactRest.add(linkTo(methodOn(MgmtSoftwareModuleRestApi.class)
|
||||
.getArtifact(artifact.getSoftwareModule().getId(), artifact.getId(), null)).withSelfRel().expand());
|
||||
|
||||
return artifactRest;
|
||||
}
|
||||
|
||||
static void addLinks(final Artifact artifact, final MgmtArtifact response) {
|
||||
response.add(linkTo(methodOn(MgmtDownloadArtifactResource.class)
|
||||
.downloadArtifact(artifact.getSoftwareModule().getId(), artifact.getId())).withRel("download")
|
||||
.expand());
|
||||
}
|
||||
|
||||
static void addLinks(final Artifact artifact, final MgmtArtifact response,
|
||||
final ArtifactUrlHandler artifactUrlHandler, final SystemManagement systemManagement) {
|
||||
final List<ArtifactUrl> urls = artifactUrlHandler.getUrls(
|
||||
new URLPlaceholder(systemManagement.getTenantMetadata().getTenant(),
|
||||
systemManagement.getTenantMetadata().getId(), null, null,
|
||||
new URLPlaceholder.SoftwareData(artifact.getSoftwareModule().getId(), artifact.getFilename(),
|
||||
artifact.getId(), artifact.getSha1Hash())), ApiType.MGMT, null);
|
||||
urls.forEach(entry -> response.add(Link.of(entry.getRef()).withRel(entry.getRel()).expand()));
|
||||
}
|
||||
|
||||
private static SoftwareModuleCreate fromRequest(final EntityFactory entityFactory,
|
||||
final MgmtSoftwareModuleRequestBodyPost smsRest) {
|
||||
return entityFactory.softwareModule().create().type(smsRest.getType()).name(smsRest.getName())
|
||||
.version(smsRest.getVersion()).description(smsRest.getDescription()).vendor(smsRest.getVendor())
|
||||
.encrypted(smsRest.isEncrypted());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.validation.ValidationException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.artifact.repository.urlhandler.ArtifactUrlHandler;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleMetadataBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRepresentationMode;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* REST Resource handling for {@link SoftwareModule} and related
|
||||
* {@link Artifact} CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtSoftwareModuleResource implements MgmtSoftwareModuleRestApi {
|
||||
|
||||
private final ArtifactManagement artifactManagement;
|
||||
private final SoftwareModuleManagement softwareModuleManagement;
|
||||
private final SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
private final ArtifactUrlHandler artifactUrlHandler;
|
||||
private final SystemManagement systemManagement;
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
MgmtSoftwareModuleResource(final ArtifactManagement artifactManagement, final SoftwareModuleManagement softwareModuleManagement,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement,
|
||||
final ArtifactUrlHandler artifactUrlHandler, final SystemManagement systemManagement,
|
||||
final EntityFactory entityFactory) {
|
||||
this.artifactManagement = artifactManagement;
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
this.artifactUrlHandler = artifactUrlHandler;
|
||||
this.systemManagement = systemManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtArtifact> uploadArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@RequestPart("file") final MultipartFile file,
|
||||
@RequestParam(value = "filename", required = false) final String optionalFileName,
|
||||
@RequestParam(value = "md5sum", required = false) final String md5Sum,
|
||||
@RequestParam(value = "sha1sum", required = false) final String sha1Sum,
|
||||
@RequestParam(value = "sha256sum", required = false) final String sha256Sum) {
|
||||
|
||||
if (file.isEmpty()) {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
String fileName = optionalFileName;
|
||||
|
||||
if (fileName == null) {
|
||||
fileName = file.getOriginalFilename();
|
||||
}
|
||||
|
||||
try (final InputStream in = file.getInputStream()) {
|
||||
final Artifact result = artifactManagement.create(new ArtifactUpload(in, softwareModuleId, fileName,
|
||||
md5Sum == null ? null : md5Sum.toLowerCase(), sha1Sum == null ? null : sha1Sum.toLowerCase(),
|
||||
sha256Sum == null ? null : sha256Sum.toLowerCase(), false, file.getContentType(), file.getSize()));
|
||||
|
||||
final MgmtArtifact reponse = MgmtSoftwareModuleMapper.toResponse(result);
|
||||
MgmtSoftwareModuleMapper.addLinks(result, reponse);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(reponse);
|
||||
} catch (final IOException e) {
|
||||
log.error("Failed to store artifact", e);
|
||||
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtArtifact>> getArtifacts(
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId, final String representationModeParam,
|
||||
final Boolean useArtifactUrlHandler) {
|
||||
final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
|
||||
|
||||
final boolean isFullMode = parseRepresentationMode(representationModeParam) == MgmtRepresentationMode.FULL;
|
||||
|
||||
final List<MgmtArtifact> response = module.getArtifacts().stream().map(artifact -> {
|
||||
final MgmtArtifact mgmtArtifact = MgmtSoftwareModuleMapper.toResponse(artifact);
|
||||
if (isFullMode && !module.isDeleted() && Boolean.TRUE.equals(useArtifactUrlHandler)) {
|
||||
MgmtSoftwareModuleMapper.addLinks(artifact, mgmtArtifact, artifactUrlHandler, systemManagement);
|
||||
} else if (isFullMode && !module.isDeleted()) {
|
||||
MgmtSoftwareModuleMapper.addLinks(artifact, mgmtArtifact);
|
||||
}
|
||||
return mgmtArtifact;
|
||||
}).toList();
|
||||
return ResponseEntity.ok(new ResponseList<>(response));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ResponseBody
|
||||
// Exception squid:S3655 - Optional access is checked in
|
||||
// findSoftwareModuleWithExceptionIfNotFound
|
||||
// subroutine
|
||||
@SuppressWarnings("squid:S3655")
|
||||
public ResponseEntity<MgmtArtifact> getArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@PathVariable("artifactId") final Long artifactId,
|
||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_USE_ARTIFACT_URL_HANDLER, required = false) final Boolean useArtifactUrlHandler) {
|
||||
final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId);
|
||||
|
||||
final MgmtArtifact response = MgmtSoftwareModuleMapper.toResponse(module.getArtifact(artifactId).get());
|
||||
if (!module.isDeleted()) {
|
||||
if (Boolean.TRUE.equals(useArtifactUrlHandler)) {
|
||||
MgmtSoftwareModuleMapper.addLinks(module.getArtifact(artifactId).get(), response, artifactUrlHandler,
|
||||
systemManagement);
|
||||
} else {
|
||||
MgmtSoftwareModuleMapper.addLinks(module.getArtifact(artifactId).get(), response);
|
||||
}
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ResponseBody
|
||||
public ResponseEntity<Void> deleteArtifact(@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@PathVariable("artifactId") final Long artifactId) {
|
||||
|
||||
findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, artifactId);
|
||||
artifactManagement.delete(artifactId);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtSoftwareModule>> getSoftwareModules(
|
||||
@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.sanitizeSoftwareModuleSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Slice<SoftwareModule> findModulesAll;
|
||||
final long countModulesAll;
|
||||
if (rsqlParam != null) {
|
||||
findModulesAll = softwareModuleManagement.findByRsql(pageable, rsqlParam);
|
||||
countModulesAll = ((Page<SoftwareModule>) findModulesAll).getTotalElements();
|
||||
} else {
|
||||
findModulesAll = softwareModuleManagement.findAll(pageable);
|
||||
countModulesAll = softwareModuleManagement.count();
|
||||
}
|
||||
|
||||
final List<MgmtSoftwareModule> rest = MgmtSoftwareModuleMapper.toResponse(findModulesAll.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, countModulesAll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModule> getSoftwareModule(
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId) {
|
||||
|
||||
final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
|
||||
|
||||
final MgmtSoftwareModule response = MgmtSoftwareModuleMapper.toResponse(module);
|
||||
MgmtSoftwareModuleMapper.addLinks(module, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtSoftwareModule>> createSoftwareModules(
|
||||
@RequestBody final List<MgmtSoftwareModuleRequestBodyPost> softwareModules) {
|
||||
|
||||
log.debug("creating {} softwareModules", softwareModules.size());
|
||||
|
||||
for (final MgmtSoftwareModuleRequestBodyPost sm : softwareModules) {
|
||||
final Optional<SoftwareModuleType> opt = softwareModuleTypeManagement.getByKey(sm.getType());
|
||||
opt.ifPresent(smType -> {
|
||||
if (smType.isDeleted()) {
|
||||
final String text = "Cannot create Software Module from type with key {0}. Software Module Type already deleted!";
|
||||
final String message = MessageFormat.format(text, smType.getKey());
|
||||
throw new ValidationException(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
final Collection<SoftwareModule> createdSoftwareModules = softwareModuleManagement
|
||||
.create(MgmtSoftwareModuleMapper.smFromRequest(entityFactory, softwareModules));
|
||||
log.debug("{} softwareModules created, return status {}", softwareModules.size(), HttpStatus.CREATED);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED)
|
||||
.body(MgmtSoftwareModuleMapper.toResponse(createdSoftwareModules));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModule> updateSoftwareModule(
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@RequestBody final MgmtSoftwareModuleRequestBodyPut restSoftwareModule) {
|
||||
final SoftwareModule module = softwareModuleManagement
|
||||
.update(entityFactory.softwareModule().update(softwareModuleId)
|
||||
.description(restSoftwareModule.getDescription())
|
||||
.vendor(restSoftwareModule.getVendor())
|
||||
.locked(restSoftwareModule.getLocked()));
|
||||
|
||||
final MgmtSoftwareModule response = MgmtSoftwareModuleMapper.toResponse(module);
|
||||
MgmtSoftwareModuleMapper.addLinks(module, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteSoftwareModule(@PathVariable("softwareModuleId") final Long softwareModuleId) {
|
||||
|
||||
final SoftwareModule module = findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
|
||||
softwareModuleManagement.delete(module.getId());
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtSoftwareModuleMetadata>> getMetadata(
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@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) {
|
||||
|
||||
// check if software module exists otherwise throw exception immediately
|
||||
findSoftwareModuleWithExceptionIfNotFound(softwareModuleId, null);
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeSoftwareModuleMetadataSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<SoftwareModuleMetadata> metaDataPage;
|
||||
|
||||
if (rsqlParam != null) {
|
||||
metaDataPage = softwareModuleManagement.findMetaDataByRsql(pageable, softwareModuleId, rsqlParam);
|
||||
} else {
|
||||
metaDataPage = softwareModuleManagement.findMetaDataBySoftwareModuleId(pageable, softwareModuleId);
|
||||
}
|
||||
|
||||
return ResponseEntity
|
||||
.ok(new PagedList<>(MgmtSoftwareModuleMapper.toResponseSwMetadata(metaDataPage.getContent()),
|
||||
metaDataPage.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModuleMetadata> getMetadataValue(
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@PathVariable("metadataKey") final String metadataKey) {
|
||||
|
||||
final SoftwareModuleMetadata findOne = softwareModuleManagement
|
||||
.getMetaDataBySoftwareModuleId(softwareModuleId, metadataKey).orElseThrow(
|
||||
() -> new EntityNotFoundException(SoftwareModuleMetadata.class, softwareModuleId, metadataKey));
|
||||
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleMapper.toResponseSwMetadata(findOne));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModuleMetadata> updateMetadata(
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@PathVariable("metadataKey") final String metadataKey,
|
||||
@RequestBody final MgmtSoftwareModuleMetadataBodyPut metadata) {
|
||||
final SoftwareModuleMetadata updated = softwareModuleManagement
|
||||
.updateMetaData(entityFactory.softwareModuleMetadata().update(softwareModuleId, metadataKey)
|
||||
.value(metadata.getValue()).targetVisible(metadata.getTargetVisible()));
|
||||
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleMapper.toResponseSwMetadata(updated));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteMetadata(@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@PathVariable("metadataKey") final String metadataKey) {
|
||||
softwareModuleManagement.deleteMetaData(softwareModuleId, metadataKey);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtSoftwareModuleMetadata>> createMetadata(
|
||||
@PathVariable("softwareModuleId") final Long softwareModuleId,
|
||||
@RequestBody final List<MgmtSoftwareModuleMetadata> metadataRest) {
|
||||
|
||||
final List<SoftwareModuleMetadata> created = softwareModuleManagement.createMetaData(
|
||||
MgmtSoftwareModuleMapper.fromRequestSwMetadata(entityFactory, softwareModuleId, metadataRest));
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(MgmtSoftwareModuleMapper.toResponseSwMetadata(created));
|
||||
}
|
||||
|
||||
private static MgmtRepresentationMode parseRepresentationMode(final String representationModeParam) {
|
||||
return 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;
|
||||
});
|
||||
}
|
||||
|
||||
private SoftwareModule findSoftwareModuleWithExceptionIfNotFound(final Long softwareModuleId,
|
||||
final Long artifactId) {
|
||||
|
||||
final SoftwareModule module = softwareModuleManagement.get(softwareModuleId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, softwareModuleId));
|
||||
|
||||
if (artifactId != null && !module.getArtifact(artifactId).isPresent()) {
|
||||
throw new EntityNotFoundException(Artifact.class, artifactId);
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
final class MgmtSoftwareModuleTypeMapper {
|
||||
|
||||
// private constructor, utility class
|
||||
private MgmtSoftwareModuleTypeMapper() {
|
||||
|
||||
}
|
||||
|
||||
static List<SoftwareModuleTypeCreate> smFromRequest(final EntityFactory entityFactory,
|
||||
final Collection<MgmtSoftwareModuleTypeRequestBodyPost> smTypesRest) {
|
||||
if (smTypesRest == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return smTypesRest.stream().map(smRest -> fromRequest(entityFactory, smRest)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<MgmtSoftwareModuleType> toTypesResponse(final Collection<SoftwareModuleType> types) {
|
||||
if (types == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return new ResponseList<>(
|
||||
types.stream().map(MgmtSoftwareModuleTypeMapper::toResponse).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
static MgmtSoftwareModuleType toResponse(final SoftwareModuleType type) {
|
||||
final MgmtSoftwareModuleType result = new MgmtSoftwareModuleType();
|
||||
|
||||
MgmtRestModelMapper.mapTypeToType(result, type);
|
||||
result.setMaxAssignments(type.getMaxAssignments());
|
||||
result.setModuleId(type.getId());
|
||||
|
||||
result.add(linkTo(methodOn(MgmtSoftwareModuleTypeRestApi.class).getSoftwareModuleType(result.getModuleId()))
|
||||
.withSelfRel().expand());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static SoftwareModuleTypeCreate fromRequest(final EntityFactory entityFactory,
|
||||
final MgmtSoftwareModuleTypeRequestBodyPost smsRest) {
|
||||
return entityFactory.softwareModuleType().create().key(smsRest.getKey()).name(smsRest.getName())
|
||||
.description(smsRest.getDescription()).colour(smsRest.getColour())
|
||||
.maxAssignments(smsRest.getMaxAssignments());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremoduletype.MgmtSoftwareModuleTypeRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleTypeRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling for {@link SoftwareModuleType} CRUD operations.
|
||||
*/
|
||||
@RestController
|
||||
public class MgmtSoftwareModuleTypeResource implements MgmtSoftwareModuleTypeRestApi {
|
||||
|
||||
private final SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
MgmtSoftwareModuleTypeResource(final SoftwareModuleTypeManagement softwareModuleTypeManagement,
|
||||
final EntityFactory entityFactory) {
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtSoftwareModuleType>> getTypes(
|
||||
@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.sanitizeSoftwareModuleTypeSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Slice<SoftwareModuleType> findModuleTypessAll;
|
||||
Long countModulesAll;
|
||||
if (rsqlParam != null) {
|
||||
findModuleTypessAll = softwareModuleTypeManagement.findByRsql(pageable, rsqlParam);
|
||||
countModulesAll = ((Page<SoftwareModuleType>) findModuleTypessAll).getTotalElements();
|
||||
} else {
|
||||
findModuleTypessAll = softwareModuleTypeManagement.findAll(pageable);
|
||||
countModulesAll = softwareModuleTypeManagement.count();
|
||||
}
|
||||
|
||||
final List<MgmtSoftwareModuleType> rest = MgmtSoftwareModuleTypeMapper
|
||||
.toTypesResponse(findModuleTypessAll.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, countModulesAll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModuleType> getSoftwareModuleType(
|
||||
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
|
||||
final SoftwareModuleType foundType = findSoftwareModuleTypeWithExceptionIfNotFound(softwareModuleTypeId);
|
||||
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleTypeMapper.toResponse(foundType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteSoftwareModuleType(
|
||||
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId) {
|
||||
softwareModuleTypeManagement.delete(softwareModuleTypeId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSoftwareModuleType> updateSoftwareModuleType(
|
||||
@PathVariable("softwareModuleTypeId") final Long softwareModuleTypeId,
|
||||
@RequestBody final MgmtSoftwareModuleTypeRequestBodyPut restSoftwareModuleType) {
|
||||
|
||||
final SoftwareModuleType updatedSoftwareModuleType = softwareModuleTypeManagement.update(entityFactory
|
||||
.softwareModuleType().update(softwareModuleTypeId).description(restSoftwareModuleType.getDescription())
|
||||
.colour(restSoftwareModuleType.getColour()));
|
||||
|
||||
return ResponseEntity.ok(MgmtSoftwareModuleTypeMapper.toResponse(updatedSoftwareModuleType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtSoftwareModuleType>> createSoftwareModuleTypes(
|
||||
@RequestBody final List<MgmtSoftwareModuleTypeRequestBodyPost> softwareModuleTypes) {
|
||||
|
||||
final List<SoftwareModuleType> createdSoftwareModules = softwareModuleTypeManagement
|
||||
.create(MgmtSoftwareModuleTypeMapper.smFromRequest(entityFactory, softwareModuleTypes));
|
||||
|
||||
return new ResponseEntity<>(MgmtSoftwareModuleTypeMapper.toTypesResponse(createdSoftwareModules),
|
||||
HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
private SoftwareModuleType findSoftwareModuleTypeWithExceptionIfNotFound(final Long softwareModuleTypeId) {
|
||||
return softwareModuleTypeManagement.get(softwareModuleTypeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleType.class, softwareModuleTypeId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.systemmanagement.MgmtSystemCache;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.systemmanagement.MgmtSystemStatisticsRest;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.systemmanagement.MgmtSystemTenantServiceUsage;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtSystemManagementRestApi;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.report.model.SystemUsageReportWithTenants;
|
||||
import org.eclipse.hawkbit.repository.report.model.TenantUsage;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* {@link SystemManagement} capabilities by REST.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtSystemManagementResource implements MgmtSystemManagementRestApi {
|
||||
|
||||
private final SystemManagement systemManagement;
|
||||
|
||||
private final CacheManager cacheManager;
|
||||
|
||||
MgmtSystemManagementResource(final SystemManagement systemManagement, final CacheManager cacheManager) {
|
||||
this.systemManagement = systemManagement;
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the tenant data of a given tenant. USE WITH CARE!
|
||||
*
|
||||
* @param tenant to delete
|
||||
* @return HttpStatus.OK
|
||||
*/
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteTenant(@PathVariable("tenant") final String tenant) {
|
||||
systemManagement.deleteTenant(tenant);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects and returns system usage statistics. It provides a system wide
|
||||
* overview and tenant based stats.
|
||||
*
|
||||
* @return system usage statistics
|
||||
*/
|
||||
@Override
|
||||
public ResponseEntity<MgmtSystemStatisticsRest> getSystemUsageStats() {
|
||||
final SystemUsageReportWithTenants report = systemManagement.getSystemUsageStatisticsWithTenants();
|
||||
|
||||
final MgmtSystemStatisticsRest result = new MgmtSystemStatisticsRest()
|
||||
.setOverallActions(report.getOverallActions()).setOverallArtifacts(report.getOverallArtifacts())
|
||||
.setOverallArtifactVolumeInBytes(report.getOverallArtifactVolumeInBytes())
|
||||
.setOverallTargets(report.getOverallTargets()).setOverallTenants(report.getTenants().size());
|
||||
|
||||
result.setTenantStats(report.getTenants().stream().map(MgmtSystemManagementResource::convertTenant)
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all caches.
|
||||
*
|
||||
* @return a list of caches for all tenants
|
||||
*/
|
||||
@Override
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
|
||||
public ResponseEntity<Collection<MgmtSystemCache>> getCaches() {
|
||||
final Collection<String> cacheNames = cacheManager.getCacheNames();
|
||||
return ResponseEntity
|
||||
.ok(cacheNames.stream().map(cacheManager::getCache)
|
||||
.filter(Objects::nonNull)
|
||||
.map(cache -> new MgmtSystemCache(cache.getName(), Collections.emptyList()))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates all caches for all tenants.
|
||||
*
|
||||
* @return a list of cache names which has been invalidated
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
|
||||
@Override
|
||||
public ResponseEntity<Collection<String>> invalidateCaches() {
|
||||
final Collection<String> cacheNames = cacheManager.getCacheNames();
|
||||
log.info("Invalidating caches {}", cacheNames);
|
||||
cacheNames.forEach(cacheName -> cacheManager.getCache(cacheName).clear());
|
||||
return ResponseEntity.ok(cacheNames);
|
||||
}
|
||||
|
||||
private static MgmtSystemTenantServiceUsage convertTenant(final TenantUsage tenant) {
|
||||
final MgmtSystemTenantServiceUsage result = new MgmtSystemTenantServiceUsage();
|
||||
result.setTenantName(tenant.getTenantName());
|
||||
result.setActions(tenant.getActions());
|
||||
result.setArtifacts(tenant.getArtifacts());
|
||||
result.setOverallArtifactVolumeInBytes(tenant.getOverallArtifactVolumeInBytes());
|
||||
result.setTargets(tenant.getTargets());
|
||||
if (!tenant.getUsageData().isEmpty()) {
|
||||
result.setUsageData(tenant.getUsageData());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTag;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTagRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTagRestApi;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.TagCreate;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and back.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
final class MgmtTagMapper {
|
||||
|
||||
static List<MgmtTag> toResponse(final List<TargetTag> targetTags) {
|
||||
final List<MgmtTag> tagsRest = new ArrayList<>();
|
||||
if (targetTags == null) {
|
||||
return tagsRest;
|
||||
}
|
||||
|
||||
for (final TargetTag target : targetTags) {
|
||||
final MgmtTag response = toResponse(target);
|
||||
|
||||
tagsRest.add(response);
|
||||
}
|
||||
return new ResponseList<>(tagsRest);
|
||||
}
|
||||
|
||||
static MgmtTag toResponse(final TargetTag targetTag) {
|
||||
final MgmtTag response = new MgmtTag();
|
||||
if (targetTag == null) {
|
||||
return response;
|
||||
}
|
||||
|
||||
mapTag(response, targetTag);
|
||||
|
||||
response.add(
|
||||
linkTo(methodOn(MgmtTargetTagRestApi.class).getTargetTag(targetTag.getId())).withSelfRel().expand());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
static void addLinks(final TargetTag targetTag, final MgmtTag response) {
|
||||
response.add(linkTo(methodOn(MgmtTargetTagRestApi.class).getAssignedTargets(targetTag.getId(),
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null)).withRel("assignedTargets")
|
||||
.expand());
|
||||
|
||||
}
|
||||
|
||||
static List<MgmtTag> toResponseDistributionSetTag(final List<DistributionSetTag> distributionSetTags) {
|
||||
final List<MgmtTag> tagsRest = new ArrayList<>();
|
||||
if (distributionSetTags == null) {
|
||||
return tagsRest;
|
||||
}
|
||||
|
||||
for (final DistributionSetTag distributionSetTag : distributionSetTags) {
|
||||
final MgmtTag response = toResponse(distributionSetTag);
|
||||
|
||||
tagsRest.add(response);
|
||||
}
|
||||
return new ResponseList<>(tagsRest);
|
||||
}
|
||||
|
||||
static MgmtTag toResponse(final DistributionSetTag distributionSetTag) {
|
||||
final MgmtTag response = new MgmtTag();
|
||||
if (distributionSetTag == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
mapTag(response, distributionSetTag);
|
||||
|
||||
response.add(
|
||||
linkTo(methodOn(MgmtDistributionSetTagRestApi.class).getDistributionSetTag(distributionSetTag.getId()))
|
||||
.withSelfRel().expand());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
static void addLinks(final DistributionSetTag distributionSetTag, final MgmtTag response) {
|
||||
response.add(linkTo(methodOn(MgmtDistributionSetTagRestApi.class).getAssignedDistributionSets(
|
||||
distributionSetTag.getId(), MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE, null, null))
|
||||
.withRel("assignedDistributionSets").expand());
|
||||
}
|
||||
|
||||
static List<TagCreate> mapTagFromRequest(final EntityFactory entityFactory,
|
||||
final Collection<MgmtTagRequestBodyPut> tags) {
|
||||
return tags.stream()
|
||||
.map(tagRest -> entityFactory.tag().create().name(tagRest.getName())
|
||||
.description(tagRest.getDescription()).colour(tagRest.getColour()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static void mapTag(final MgmtTag response, final Tag tag) {
|
||||
MgmtRestModelMapper.mapNamedToNamed(response, tag);
|
||||
response.setTagId(tag.getId());
|
||||
response.setColour(tag.getColour());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtDistributionSetAutoAssignment;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQueryRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetFilterQueryRestApi;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryCreate;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
public final class MgmtTargetFilterQueryMapper {
|
||||
|
||||
private MgmtTargetFilterQueryMapper() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
static List<MgmtTargetFilterQuery> toResponse(final List<TargetFilterQuery> filters,
|
||||
final boolean confirmationFlowEnabled, final boolean isRepresentationFull) {
|
||||
if (CollectionUtils.isEmpty(filters)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return filters.stream().map(filter -> toResponse(filter, confirmationFlowEnabled, isRepresentationFull)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static MgmtTargetFilterQuery toResponse(final TargetFilterQuery filter, final boolean confirmationFlowEnabled,
|
||||
final boolean isReprentationFull) {
|
||||
final MgmtTargetFilterQuery targetRest = new MgmtTargetFilterQuery();
|
||||
targetRest.setFilterId(filter.getId());
|
||||
targetRest.setName(filter.getName());
|
||||
targetRest.setQuery(filter.getQuery());
|
||||
|
||||
targetRest.setCreatedBy(filter.getCreatedBy());
|
||||
targetRest.setLastModifiedBy(filter.getLastModifiedBy());
|
||||
|
||||
targetRest.setCreatedAt(filter.getCreatedAt());
|
||||
targetRest.setLastModifiedAt(filter.getLastModifiedAt());
|
||||
|
||||
final DistributionSet distributionSet = filter.getAutoAssignDistributionSet();
|
||||
if (distributionSet != null) {
|
||||
targetRest.setAutoAssignDistributionSet(distributionSet.getId());
|
||||
targetRest.setAutoAssignActionType(MgmtRestModelMapper.convertActionType(filter.getAutoAssignActionType()));
|
||||
filter.getAutoAssignWeight().ifPresent(targetRest::setAutoAssignWeight);
|
||||
if (confirmationFlowEnabled) {
|
||||
targetRest.setConfirmationRequired(filter.isConfirmationRequired());
|
||||
}
|
||||
}
|
||||
|
||||
targetRest.add(
|
||||
linkTo(methodOn(MgmtTargetFilterQueryRestApi.class).getFilter(filter.getId())).withSelfRel().expand());
|
||||
if (isReprentationFull && distributionSet != null) {
|
||||
targetRest.add(
|
||||
linkTo(methodOn(MgmtDistributionSetRestApi.class).getDistributionSets(
|
||||
Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET),
|
||||
Integer.parseInt(MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT), null,
|
||||
"name==" + distributionSet.getName() + ";version==" + distributionSet.getVersion())).withRel("DS").expand());
|
||||
}
|
||||
|
||||
return targetRest;
|
||||
}
|
||||
|
||||
static void addLinks(final MgmtTargetFilterQuery targetRest) {
|
||||
targetRest.add(linkTo(methodOn(MgmtTargetFilterQueryRestApi.class)
|
||||
.postAssignedDistributionSet(targetRest.getFilterId(), null)).withRel("autoAssignDS").expand());
|
||||
}
|
||||
|
||||
static TargetFilterQueryCreate fromRequest(final EntityFactory entityFactory,
|
||||
final MgmtTargetFilterQueryRequestBody filterRest) {
|
||||
|
||||
return entityFactory.targetFilterQuery().create().name(filterRest.getName()).query(filterRest.getQuery());
|
||||
}
|
||||
|
||||
static AutoAssignDistributionSetUpdate fromRequest(final EntityFactory entityFactory, final long filterId,
|
||||
final MgmtDistributionSetAutoAssignment assignRest) {
|
||||
final ActionType type = MgmtRestModelMapper.convertActionType(assignRest.getType());
|
||||
|
||||
return entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(assignRest.getId()).actionType(type)
|
||||
.weight(assignRest.getWeight());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtDistributionSetAutoAssignment;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQueryRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRepresentationMode;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetFilterQueryRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling target CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtTargetFilterQueryResource implements MgmtTargetFilterQueryRestApi {
|
||||
|
||||
private final TargetFilterQueryManagement filterManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
private final TenantConfigHelper tenantConfigHelper;
|
||||
|
||||
MgmtTargetFilterQueryResource(final TargetFilterQueryManagement filterManagement, final EntityFactory entityFactory,
|
||||
final SystemSecurityContext systemSecurityContext,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
this.filterManagement = filterManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetFilterQuery> getFilter(@PathVariable("filterId") final Long filterId) {
|
||||
final TargetFilterQuery findTarget = findFilterWithExceptionIfNotFound(filterId);
|
||||
// to single response include poll status
|
||||
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(findTarget,
|
||||
tenantConfigHelper.isConfirmationFlowEnabled(), true);
|
||||
MgmtTargetFilterQueryMapper.addLinks(response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTargetFilterQuery>> getFilters(
|
||||
@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_REPRESENTATION_MODE, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE_DEFAULT) String representationModeParam) {
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeTargetFilterQuerySortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Slice<TargetFilterQuery> findTargetFiltersAll;
|
||||
final Long countTargetsAll;
|
||||
if (rsqlParam != null) {
|
||||
final Page<TargetFilterQuery> findFilterPage = filterManagement.findByRsql(pageable, rsqlParam);
|
||||
countTargetsAll = findFilterPage.getTotalElements();
|
||||
findTargetFiltersAll = findFilterPage;
|
||||
} else {
|
||||
findTargetFiltersAll = filterManagement.findAll(pageable);
|
||||
countTargetsAll = filterManagement.count();
|
||||
}
|
||||
|
||||
final boolean isRepresentationFull = parseRepresentationMode(representationModeParam) == MgmtRepresentationMode.FULL;
|
||||
|
||||
final List<MgmtTargetFilterQuery> rest = MgmtTargetFilterQueryMapper
|
||||
.toResponse(findTargetFiltersAll.getContent(), tenantConfigHelper.isConfirmationFlowEnabled(), isRepresentationFull);
|
||||
return ResponseEntity.ok(new PagedList<>(rest, countTargetsAll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetFilterQuery> createFilter(
|
||||
@RequestBody final MgmtTargetFilterQueryRequestBody filter) {
|
||||
final TargetFilterQuery createdTarget = filterManagement
|
||||
.create(MgmtTargetFilterQueryMapper.fromRequest(entityFactory, filter));
|
||||
|
||||
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(createdTarget,
|
||||
tenantConfigHelper.isConfirmationFlowEnabled(), false);
|
||||
MgmtTargetFilterQueryMapper.addLinks(response);
|
||||
|
||||
return new ResponseEntity<>(response, HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetFilterQuery> updateFilter(@PathVariable("filterId") final Long filterId,
|
||||
@RequestBody final MgmtTargetFilterQueryRequestBody targetFilterRest) {
|
||||
log.debug("updating target filter query {}", filterId);
|
||||
|
||||
final TargetFilterQuery updateFilter = filterManagement
|
||||
.update(entityFactory.targetFilterQuery().update(filterId).name(targetFilterRest.getName())
|
||||
.query(targetFilterRest.getQuery()));
|
||||
|
||||
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(updateFilter,
|
||||
tenantConfigHelper.isConfirmationFlowEnabled(), false);
|
||||
MgmtTargetFilterQueryMapper.addLinks(response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteFilter(@PathVariable("filterId") final Long filterId) {
|
||||
filterManagement.delete(filterId);
|
||||
log.debug("{} target filter query deleted, return status {}", filterId, HttpStatus.OK);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSet> getAssignedDistributionSet(
|
||||
@PathVariable("filterId") final Long filterId) {
|
||||
final TargetFilterQuery filter = findFilterWithExceptionIfNotFound(filterId);
|
||||
final DistributionSet autoAssignDistributionSet = filter.getAutoAssignDistributionSet();
|
||||
|
||||
if (autoAssignDistributionSet == null) {
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
final MgmtDistributionSet response = MgmtDistributionSetMapper.toResponse(autoAssignDistributionSet);
|
||||
MgmtDistributionSetMapper.addLinks(autoAssignDistributionSet, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetFilterQuery> postAssignedDistributionSet(
|
||||
@PathVariable("filterId") final Long filterId,
|
||||
@RequestBody final MgmtDistributionSetAutoAssignment autoAssignRequest) {
|
||||
|
||||
final boolean confirmationRequired = autoAssignRequest.getConfirmationRequired() == null
|
||||
? tenantConfigHelper.isConfirmationFlowEnabled()
|
||||
: autoAssignRequest.getConfirmationRequired();
|
||||
|
||||
final AutoAssignDistributionSetUpdate update = MgmtTargetFilterQueryMapper
|
||||
.fromRequest(entityFactory, filterId, autoAssignRequest).confirmationRequired(confirmationRequired);
|
||||
|
||||
final TargetFilterQuery updateFilter = filterManagement.updateAutoAssignDS(update);
|
||||
|
||||
final MgmtTargetFilterQuery response = MgmtTargetFilterQueryMapper.toResponse(updateFilter,
|
||||
tenantConfigHelper.isConfirmationFlowEnabled(), false);
|
||||
MgmtTargetFilterQueryMapper.addLinks(response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteAssignedDistributionSet(@PathVariable("filterId") final Long filterId) {
|
||||
filterManagement.updateAutoAssignDS(entityFactory.targetFilterQuery().updateAutoAssign(filterId).ds(null));
|
||||
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
private static MgmtRepresentationMode parseRepresentationMode(final String representationModeParam) {
|
||||
return 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;
|
||||
});
|
||||
}
|
||||
|
||||
private TargetFilterQuery findFilterWithExceptionIfNotFound(final Long filterId) {
|
||||
return filterManagement.get(filterId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetFilterQuery.class, filterId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
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;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetAutoConfirm;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTypeRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.SortDirection;
|
||||
import org.eclipse.hawkbit.repository.ActionFields;
|
||||
import org.eclipse.hawkbit.repository.ActionStatusFields;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
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.AutoConfirmationStatus;
|
||||
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;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
import org.eclipse.hawkbit.util.IpUtil;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
public final class MgmtTargetMapper {
|
||||
|
||||
private MgmtTargetMapper() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* Add links to a target response.
|
||||
*
|
||||
* @param response the target response
|
||||
*/
|
||||
public static void addTargetLinks(final MgmtTarget response) {
|
||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getAssignedDistributionSet(response.getControllerId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ASSIGNED_DISTRIBUTION_SET).expand());
|
||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getInstalledDistributionSet(response.getControllerId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_INSTALLED_DISTRIBUTION_SET).expand());
|
||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getAttributes(response.getControllerId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ATTRIBUTES).expand());
|
||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getActionHistory(response.getControllerId(), 0,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE,
|
||||
ActionFields.ID.getJpaEntityFieldName() + ":" + 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")
|
||||
.expand());
|
||||
if (response.getTargetType() != null) {
|
||||
response.add(linkTo(methodOn(MgmtTargetTypeRestApi.class).getTargetType(response.getTargetType()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ASSIGNED_TARGET_TYPE).expand());
|
||||
}
|
||||
if (response.getAutoConfirmActive() != null) {
|
||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).getAutoConfirmStatus(response.getControllerId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_AUTO_CONFIRM).expand());
|
||||
}
|
||||
}
|
||||
|
||||
public static MgmtTargetAutoConfirm getTargetAutoConfirmResponse(final Target target) {
|
||||
final AutoConfirmationStatus status = target.getAutoConfirmationStatus();
|
||||
final MgmtTargetAutoConfirm response;
|
||||
if (status != null) {
|
||||
response = MgmtTargetAutoConfirm.active(status.getActivatedAt());
|
||||
response.setInitiator(status.getInitiator());
|
||||
response.setRemark(status.getRemark());
|
||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).deactivateAutoConfirm(target.getControllerId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_DEACTIVATE_AUTO_CONFIRM).expand());
|
||||
} else {
|
||||
response = MgmtTargetAutoConfirm.disabled();
|
||||
response.add(linkTo(methodOn(MgmtTargetRestApi.class).activateAutoConfirm(target.getControllerId(), null))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ACTIVATE_AUTO_CONFIRM).expand());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a response for targets.
|
||||
*
|
||||
* @param targets list of targets
|
||||
* @return the response
|
||||
*/
|
||||
public static List<MgmtTarget> toResponse(final Collection<Target> targets, final TenantConfigHelper configHelper) {
|
||||
if (targets == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final Function<Target, PollStatus> pollStatusResolver = configHelper.pollStatusResolver();
|
||||
return new ResponseList<>(
|
||||
targets.stream().map(target -> toResponse(target, configHelper, pollStatusResolver)).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a response for target.
|
||||
*
|
||||
* @param target the target
|
||||
* @return the response
|
||||
*/
|
||||
public static MgmtTarget toResponse(final Target target, final TenantConfigHelper configHelper,
|
||||
final Function<Target, PollStatus> pollStatusResolver) {
|
||||
if (target == null) {
|
||||
return null;
|
||||
}
|
||||
final MgmtTarget targetRest = new MgmtTarget();
|
||||
targetRest.setControllerId(target.getControllerId());
|
||||
targetRest.setDescription(target.getDescription());
|
||||
targetRest.setName(target.getName());
|
||||
targetRest.setUpdateStatus(target.getUpdateStatus().name().toLowerCase());
|
||||
|
||||
final URI address = target.getAddress();
|
||||
if (address != null) {
|
||||
if (IpUtil.isIpAddresKnown(address)) {
|
||||
targetRest.setIpAddress(address.getHost());
|
||||
}
|
||||
targetRest.setAddress(address.toString());
|
||||
}
|
||||
|
||||
targetRest.setCreatedBy(target.getCreatedBy());
|
||||
targetRest.setLastModifiedBy(target.getLastModifiedBy());
|
||||
|
||||
targetRest.setCreatedAt(target.getCreatedAt());
|
||||
targetRest.setLastModifiedAt(target.getLastModifiedAt());
|
||||
|
||||
targetRest.setSecurityToken(target.getSecurityToken());
|
||||
targetRest.setRequestAttributes(target.isRequestControllerAttributes());
|
||||
|
||||
// last target query is the last controller request date
|
||||
final Long lastTargetQuery = target.getLastTargetQuery();
|
||||
final Long installationDate = target.getInstallationDate();
|
||||
|
||||
if (lastTargetQuery != null) {
|
||||
targetRest.setLastControllerRequestAt(lastTargetQuery);
|
||||
}
|
||||
if (installationDate != null) {
|
||||
targetRest.setInstalledAt(installationDate);
|
||||
}
|
||||
if (target.getTargetType() != null) {
|
||||
targetRest.setTargetType(target.getTargetType().getId());
|
||||
targetRest.setTargetTypeName(target.getTargetType().getName());
|
||||
}
|
||||
if (configHelper.isConfirmationFlowEnabled()) {
|
||||
targetRest.setAutoConfirmActive(target.getAutoConfirmationStatus() != null);
|
||||
}
|
||||
|
||||
targetRest.add(
|
||||
linkTo(methodOn(MgmtTargetRestApi.class).getTarget(target.getControllerId())).withSelfRel().expand());
|
||||
|
||||
addPollStatus(target, targetRest, pollStatusResolver == null ? configHelper.pollStatusResolver() : pollStatusResolver);
|
||||
|
||||
return targetRest;
|
||||
}
|
||||
|
||||
static List<TargetCreate> fromRequest(final EntityFactory entityFactory,
|
||||
final Collection<MgmtTargetRequestBody> targetsRest) {
|
||||
if (targetsRest == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return targetsRest.stream().map(targetRest -> fromRequest(entityFactory, targetRest))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
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) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return actionStatus.stream()
|
||||
.map(status -> toResponse(status,
|
||||
deploymentManagement.findMessagesByActionStatusId(
|
||||
PageRequest.of(0, MgmtRestConstants.REQUEST_PARAMETER_PAGING_MAX_LIMIT), status.getId())
|
||||
.getContent()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static MgmtAction toResponse(final String targetId, final Action action) {
|
||||
final MgmtAction result = new MgmtAction();
|
||||
|
||||
result.setActionId(action.getId());
|
||||
result.setType(getType(action));
|
||||
if (ActionType.TIMEFORCED == action.getActionType()) {
|
||||
result.setForceTime(action.getForcedTime());
|
||||
}
|
||||
action.getWeight().ifPresent(result::setWeight);
|
||||
result.setActionType(MgmtRestModelMapper.convertActionType(action.getActionType()));
|
||||
|
||||
if (action.isActive()) {
|
||||
result.setStatus(MgmtAction.ACTION_PENDING);
|
||||
} else {
|
||||
result.setStatus(MgmtAction.ACTION_FINISHED);
|
||||
}
|
||||
|
||||
result.setDetailStatus(action.getStatus().toString().toLowerCase());
|
||||
|
||||
action.getLastActionStatusCode().ifPresent(statusCode -> {
|
||||
result.setLastStatusCode(statusCode);
|
||||
});
|
||||
|
||||
final Rollout rollout = action.getRollout();
|
||||
if (rollout != null) {
|
||||
result.setRollout(rollout.getId());
|
||||
result.setRolloutName(rollout.getName());
|
||||
}
|
||||
|
||||
if (action.hasMaintenanceSchedule()) {
|
||||
final MgmtMaintenanceWindow maintenanceWindow = new MgmtMaintenanceWindow();
|
||||
maintenanceWindow.setSchedule(action.getMaintenanceWindowSchedule());
|
||||
maintenanceWindow.setDuration(action.getMaintenanceWindowDuration());
|
||||
maintenanceWindow.setTimezone(action.getMaintenanceWindowTimeZone());
|
||||
action.getMaintenanceWindowStartTime()
|
||||
.ifPresent(nextStart -> maintenanceWindow.setNextStartAt(nextStart.toInstant().toEpochMilli()));
|
||||
result.setMaintenanceWindow(maintenanceWindow);
|
||||
}
|
||||
|
||||
final String externalRef = action.getExternalRef();
|
||||
if (!ObjectUtils.isEmpty(externalRef)) {
|
||||
result.setExternalRef(externalRef);
|
||||
}
|
||||
|
||||
MgmtRestModelMapper.mapBaseToBase(result, action);
|
||||
|
||||
result.add(
|
||||
linkTo(methodOn(MgmtTargetRestApi.class).getAction(targetId, action.getId())).withSelfRel().expand());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static MgmtAction toResponseWithLinks(final String controllerId, final Action action) {
|
||||
final MgmtAction result = toResponse(controllerId, action);
|
||||
|
||||
if (action.isCancelingOrCanceled()) {
|
||||
result.add(linkTo(methodOn(MgmtTargetRestApi.class).getAction(controllerId, action.getId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_CANCELED_ACTION).expand());
|
||||
}
|
||||
|
||||
result.add(linkTo(methodOn(MgmtTargetRestApi.class).getTarget(controllerId)).withRel("target")
|
||||
.withName(action.getTarget().getName()).expand());
|
||||
|
||||
final DistributionSet distributionSet = action.getDistributionSet();
|
||||
result.add(linkTo(methodOn(MgmtDistributionSetRestApi.class).getDistributionSet(distributionSet.getId()))
|
||||
.withRel("distributionset").withName(distributionSet.getName() + ":" + distributionSet.getVersion())
|
||||
.expand());
|
||||
|
||||
result.add(linkTo(methodOn(MgmtTargetRestApi.class).getActionStatusList(controllerId, action.getId(), 0,
|
||||
MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE,
|
||||
ActionStatusFields.ID.getJpaEntityFieldName() + ":" + SortDirection.DESC))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ACTION_STATUS).expand());
|
||||
|
||||
final Rollout rollout = action.getRollout();
|
||||
if (rollout != null) {
|
||||
result.add(linkTo(methodOn(MgmtRolloutRestApi.class).getRollout(rollout.getId()))
|
||||
.withRel(MgmtRestConstants.TARGET_V1_ROLLOUT).withName(rollout.getName()).expand());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static List<MgmtAction> toResponse(final String targetId, final Collection<Action> actions) {
|
||||
if (actions == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return actions.stream().map(action -> toResponse(targetId, action)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
private static void addPollStatus(final Target target, final MgmtTarget targetRest, final Function<Target, PollStatus> pollStatusResolver) {
|
||||
final PollStatus pollStatus = pollStatusResolver == null ? target.getPollStatus() : pollStatusResolver.apply(target);
|
||||
if (pollStatus != null) {
|
||||
final MgmtPollStatus pollStatusRest = new MgmtPollStatus();
|
||||
pollStatusRest.setLastRequestAt(
|
||||
Date.from(pollStatus.getLastPollDate().atZone(ZoneId.systemDefault()).toInstant()).getTime());
|
||||
pollStatusRest.setNextExpectedRequestAt(
|
||||
Date.from(pollStatus.getNextPollDate().atZone(ZoneId.systemDefault()).toInstant()).getTime());
|
||||
pollStatusRest.setOverdue(pollStatus.isOverdue());
|
||||
targetRest.setPollStatus(pollStatusRest);
|
||||
}
|
||||
}
|
||||
|
||||
private static TargetCreate fromRequest(final EntityFactory entityFactory, final MgmtTargetRequestBody targetRest) {
|
||||
return entityFactory.target().create().controllerId(targetRest.getControllerId()).name(targetRest.getName())
|
||||
.description(targetRest.getDescription()).securityToken(targetRest.getSecurityToken())
|
||||
.address(targetRest.getAddress()).targetType(targetRest.getTargetType());
|
||||
}
|
||||
|
||||
private static String getType(final Action action) {
|
||||
if (!action.isCancelingOrCanceled()) {
|
||||
return MgmtAction.ACTION_UPDATE;
|
||||
} else if (action.isCancelingOrCanceled()) {
|
||||
return MgmtAction.ACTION_CANCEL;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static MgmtActionStatus toResponse(final ActionStatus actionStatus, final List<String> messages) {
|
||||
final MgmtActionStatus result = new MgmtActionStatus();
|
||||
|
||||
result.setMessages(messages);
|
||||
result.setReportedAt(actionStatus.getCreatedAt());
|
||||
result.setStatusId(actionStatus.getId());
|
||||
result.setType(actionStatus.getStatus().name().toLowerCase());
|
||||
actionStatus.getCode().ifPresent(result::setCode);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,488 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.validation.ValidationException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.MgmtId;
|
||||
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;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtActionStatus;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentResponseBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTag;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtDistributionSetAssignments;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetAttributes;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetAutoConfirm;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetAutoConfirmUpdate;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.ConfirmationManagement;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
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.DeploymentRequest;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling target CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtTargetResource implements MgmtTargetRestApi {
|
||||
|
||||
private static final String ACTION_TARGET_MISSING_ASSIGN_WARN = "given action ({}) is not assigned to given target ({}).";
|
||||
|
||||
private final TargetManagement targetManagement;
|
||||
|
||||
private final ConfirmationManagement confirmationManagement;
|
||||
|
||||
private final DeploymentManagement deploymentManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
private final TenantConfigHelper tenantConfigHelper;
|
||||
|
||||
MgmtTargetResource(final TargetManagement targetManagement, final DeploymentManagement deploymentManagement,
|
||||
final ConfirmationManagement confirmationManagement, final EntityFactory entityFactory,
|
||||
final SystemSecurityContext systemSecurityContext,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
this.targetManagement = targetManagement;
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
this.confirmationManagement = confirmationManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
this.tenantConfigHelper = TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigurationManagement);
|
||||
}
|
||||
|
||||
@Override
|
||||
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, tenantConfigHelper, null);
|
||||
MgmtTargetMapper.addTargetLinks(response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTarget>> getTargets(
|
||||
@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.sanitizeTargetSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Slice<Target> findTargetsAll;
|
||||
final long countTargetsAll;
|
||||
if (rsqlParam != null) {
|
||||
findTargetsAll = targetManagement.findByRsql(pageable, rsqlParam);
|
||||
countTargetsAll = targetManagement.countByRsql(rsqlParam);
|
||||
} else {
|
||||
findTargetsAll = targetManagement.findAll(pageable);
|
||||
countTargetsAll = targetManagement.count();
|
||||
}
|
||||
|
||||
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(findTargetsAll.getContent(), tenantConfigHelper);
|
||||
return ResponseEntity.ok(new PagedList<>(rest, countTargetsAll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtTarget>> createTargets(@RequestBody final List<MgmtTargetRequestBody> targets) {
|
||||
log.debug("creating {} targets", targets.size());
|
||||
final Collection<Target> createdTargets = this.targetManagement
|
||||
.create(MgmtTargetMapper.fromRequest(entityFactory, targets));
|
||||
log.debug("{} targets created, return status {}", targets.size(), HttpStatus.CREATED);
|
||||
return new ResponseEntity<>(MgmtTargetMapper.toResponse(createdTargets, tenantConfigHelper),
|
||||
HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTarget> updateTarget(@PathVariable("targetId") final String targetId,
|
||||
@RequestBody final MgmtTargetRequestBody targetRest) {
|
||||
|
||||
if (targetRest.getRequestAttributes() != null) {
|
||||
if (targetRest.getRequestAttributes()) {
|
||||
targetManagement.requestControllerAttributes(targetId);
|
||||
} else {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
}
|
||||
|
||||
Target updateTarget;
|
||||
|
||||
if (targetRest.getTargetType() != null && targetRest.getTargetType() == -1L) {
|
||||
// if targetType in request is -1 - unassign targetType from target
|
||||
this.targetManagement.unassignType(targetId);
|
||||
// update target without targetType here ...
|
||||
updateTarget = this.targetManagement.update(entityFactory.target().update(targetId)
|
||||
.name(targetRest.getName()).description(targetRest.getDescription()).address(targetRest.getAddress())
|
||||
.securityToken(targetRest.getSecurityToken()).requestAttributes(targetRest.getRequestAttributes()));
|
||||
|
||||
} else {
|
||||
updateTarget = this.targetManagement.update(
|
||||
entityFactory.target().update(targetId).name(targetRest.getName()).description(targetRest.getDescription())
|
||||
.address(targetRest.getAddress()).targetType(targetRest.getTargetType())
|
||||
.securityToken(targetRest.getSecurityToken())
|
||||
.requestAttributes(targetRest.getRequestAttributes()));
|
||||
|
||||
}
|
||||
|
||||
final MgmtTarget response = MgmtTargetMapper.toResponse(updateTarget, tenantConfigHelper, null);
|
||||
MgmtTargetMapper.addTargetLinks(response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
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<Void> unassignTargetType(@PathVariable("targetId") final String targetId) {
|
||||
this.targetManagement.unassignType(targetId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> assignTargetType(@PathVariable("targetId") final String targetId,
|
||||
@RequestBody final MgmtId targetTypeId) {
|
||||
this.targetManagement.assignType(targetId, targetTypeId.getId());
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetAttributes> getAttributes(@PathVariable("targetId") final String targetId) {
|
||||
final Map<String, String> controllerAttributes = targetManagement.getControllerAttributes(targetId);
|
||||
if (controllerAttributes.isEmpty()) {
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
final MgmtTargetAttributes result = new MgmtTargetAttributes();
|
||||
result.putAll(controllerAttributes);
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtAction>> getActionHistory(@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(targetId);
|
||||
|
||||
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> activeActions;
|
||||
final Long totalActionCount;
|
||||
if (rsqlParam != null) {
|
||||
activeActions = this.deploymentManagement.findActionsByTarget(rsqlParam, targetId, pageable);
|
||||
totalActionCount = this.deploymentManagement.countActionsByTarget(rsqlParam, targetId);
|
||||
} else {
|
||||
activeActions = this.deploymentManagement.findActionsByTarget(targetId, pageable);
|
||||
totalActionCount = this.deploymentManagement.countActionsByTarget(targetId);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(
|
||||
new PagedList<>(MgmtTargetMapper.toResponse(targetId, activeActions.getContent()), totalActionCount));
|
||||
}
|
||||
|
||||
@Override
|
||||
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(targetId)) {
|
||||
log.warn(ACTION_TARGET_MISSING_ASSIGN_WARN, action.getId(), targetId);
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(MgmtTargetMapper.toResponseWithLinks(targetId, action));
|
||||
}
|
||||
|
||||
@Override
|
||||
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(targetId)) {
|
||||
log.warn(ACTION_TARGET_MISSING_ASSIGN_WARN, actionId, targetId);
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
if (force) {
|
||||
this.deploymentManagement.forceQuitAction(actionId);
|
||||
} else {
|
||||
this.deploymentManagement.cancelAction(actionId);
|
||||
}
|
||||
// both functions will throw an exception, when action is in wrong
|
||||
// state, which is mapped by MgmtResponseExceptionHandler.
|
||||
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
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(targetId)) {
|
||||
log.warn(ACTION_TARGET_MISSING_ASSIGN_WARN, action.getId(), targetId);
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
if (MgmtActionType.FORCED != actionUpdate.getActionType()) {
|
||||
throw new ValidationException("Resource supports only switch to FORCED.");
|
||||
}
|
||||
|
||||
action = deploymentManagement.forceTargetAction(actionId);
|
||||
|
||||
return ResponseEntity.ok(MgmtTargetMapper.toResponseWithLinks(targetId, action));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtActionStatus>> getActionStatusList(
|
||||
@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(targetId);
|
||||
|
||||
final Action action = deploymentManagement.findAction(actionId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
||||
|
||||
if (!action.getTarget().getId().equals(target.getId())) {
|
||||
log.warn(ACTION_TARGET_MISSING_ASSIGN_WARN, action.getId(), target.getId());
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
final int sanitizedOffsetParam = PagingUtility.sanitizeOffsetParam(pagingOffsetParam);
|
||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||
final Sort sorting = PagingUtility.sanitizeActionStatusSortParam(sortParam);
|
||||
|
||||
final Page<ActionStatus> statusList = this.deploymentManagement.findActionStatusByAction(
|
||||
new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting), action.getId());
|
||||
|
||||
return ResponseEntity.ok(new PagedList<>(
|
||||
MgmtTargetMapper.toActionStatusRestResponse(statusList.getContent(), deploymentManagement),
|
||||
statusList.getTotalElements()));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSet> getAssignedDistributionSet(
|
||||
@PathVariable("targetId") final String targetId) {
|
||||
final MgmtDistributionSet distributionSetRest = deploymentManagement.getAssignedDistributionSet(targetId)
|
||||
.map(ds -> {
|
||||
final MgmtDistributionSet response = MgmtDistributionSetMapper.toResponse(ds);
|
||||
MgmtDistributionSetMapper.addLinks(ds, response);
|
||||
|
||||
return response;
|
||||
}).orElse(null);
|
||||
|
||||
if (distributionSetRest == null) {
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
return ResponseEntity.ok(distributionSetRest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetAssignmentResponseBody> postAssignedDistributionSet(
|
||||
@PathVariable("targetId") final String targetId,
|
||||
@RequestBody final MgmtDistributionSetAssignments dsAssignments,
|
||||
@RequestParam(value = "offline", required = false) final Boolean offline) {
|
||||
if (offline != null && offline) {
|
||||
final List<Entry<String, Long>> offlineAssignments = dsAssignments.stream()
|
||||
.map(dsAssignment -> new SimpleEntry<String, Long>(targetId, dsAssignment.getId()))
|
||||
.collect(Collectors.toList());
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper
|
||||
.toResponse(deploymentManagement.offlineAssignedDistributionSets(offlineAssignments)));
|
||||
}
|
||||
findTargetWithExceptionIfNotFound(targetId);
|
||||
|
||||
final List<DeploymentRequest> deploymentRequests = dsAssignments.stream().map(dsAssignment -> {
|
||||
final boolean isConfirmationRequired = dsAssignment.getConfirmationRequired() == null
|
||||
? tenantConfigHelper.isConfirmationFlowEnabled()
|
||||
: dsAssignment.getConfirmationRequired();
|
||||
return MgmtDeploymentRequestMapper.createAssignmentRequestBuilder(dsAssignment, targetId)
|
||||
.setConfirmationRequired(isConfirmationRequired).build();
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
final List<DistributionSetAssignmentResult> assignmentResults = deploymentManagement
|
||||
.assignDistributionSets(deploymentRequests);
|
||||
return ResponseEntity.ok(MgmtDistributionSetMapper.toResponse(assignmentResults));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtDistributionSet> getInstalledDistributionSet(
|
||||
@PathVariable("targetId") final String targetId) {
|
||||
final MgmtDistributionSet distributionSetRest = deploymentManagement.getInstalledDistributionSet(targetId)
|
||||
.map(set -> {
|
||||
final MgmtDistributionSet response = MgmtDistributionSetMapper.toResponse(set);
|
||||
MgmtDistributionSetMapper.addLinks(set, response);
|
||||
|
||||
return response;
|
||||
}).orElse(null);
|
||||
|
||||
if (distributionSetRest == null) {
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(distributionSetRest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtTag>> getTags(@PathVariable("targetId") String targetId) {
|
||||
final Set<TargetTag> tags = targetManagement.getTagsByControllerId(targetId);
|
||||
return ResponseEntity.ok(
|
||||
MgmtTagMapper.toResponse(tags == null ? Collections.emptyList() : tags.stream().toList()));
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetAutoConfirm> getAutoConfirmStatus(@PathVariable("targetId") final String targetId) {
|
||||
final Target findTarget = findTargetWithExceptionIfNotFound(targetId);
|
||||
final MgmtTargetAutoConfirm state = MgmtTargetMapper.getTargetAutoConfirmResponse(findTarget);
|
||||
return ResponseEntity.ok(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> activateAutoConfirm(@PathVariable("targetId") final String targetId,
|
||||
@RequestBody(required = false) final MgmtTargetAutoConfirmUpdate update) {
|
||||
final String initiator = getNullIfEmpty(update, MgmtTargetAutoConfirmUpdate::getInitiator);
|
||||
final String remark = getNullIfEmpty(update, MgmtTargetAutoConfirmUpdate::getRemark);
|
||||
confirmationManagement.activateAutoConfirmation(targetId, initiator, remark);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deactivateAutoConfirm(@PathVariable("targetId") final String targetId) {
|
||||
confirmationManagement.deactivateAutoConfirmation(targetId);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
private Target findTargetWithExceptionIfNotFound(final String targetId) {
|
||||
return targetManagement.getByControllerID(targetId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Target.class, targetId));
|
||||
}
|
||||
|
||||
private <T, R> R getNullIfEmpty(final T object, final Function<T, R> extractMethod) {
|
||||
return object == null ? null : extractMethod.apply(object);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtAssignedTargetRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTag;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTagRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.tag.MgmtTargetTagAssigmentResult;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTagRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling for tag CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtTargetTagResource implements MgmtTargetTagRestApi {
|
||||
|
||||
private final TargetTagManagement tagManagement;
|
||||
|
||||
private final TargetManagement targetManagement;
|
||||
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
private final TenantConfigHelper tenantConfigHelper;
|
||||
|
||||
MgmtTargetTagResource(final TargetTagManagement tagManagement, final TargetManagement targetManagement,
|
||||
final EntityFactory entityFactory, final SystemSecurityContext securityContext,
|
||||
final TenantConfigurationManagement configurationManagement) {
|
||||
this.tagManagement = tagManagement;
|
||||
this.targetManagement = targetManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
this.tenantConfigHelper = TenantConfigHelper.usingContext(securityContext, configurationManagement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTag>> getTargetTags(
|
||||
@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.sanitizeTagSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
Page<TargetTag> findTargetsAll;
|
||||
if (rsqlParam == null) {
|
||||
findTargetsAll = this.tagManagement.findAll(pageable);
|
||||
|
||||
} else {
|
||||
findTargetsAll = this.tagManagement.findByRsql(pageable, rsqlParam);
|
||||
|
||||
}
|
||||
|
||||
final List<MgmtTag> rest = MgmtTagMapper.toResponse(findTargetsAll.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, findTargetsAll.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTag> getTargetTag(@PathVariable("targetTagId") final Long targetTagId) {
|
||||
final TargetTag tag = findTargetTagById(targetTagId);
|
||||
|
||||
final MgmtTag response = MgmtTagMapper.toResponse(tag);
|
||||
MgmtTagMapper.addLinks(tag, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtTag>> createTargetTags(@RequestBody final List<MgmtTagRequestBodyPut> tags) {
|
||||
log.debug("creating {} target tags", tags.size());
|
||||
final List<TargetTag> createdTargetTags = this.tagManagement
|
||||
.create(MgmtTagMapper.mapTagFromRequest(entityFactory, tags));
|
||||
return new ResponseEntity<>(MgmtTagMapper.toResponse(createdTargetTags), HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTag> updateTargetTag(@PathVariable("targetTagId") final Long targetTagId,
|
||||
@RequestBody final MgmtTagRequestBodyPut restTargetTagRest) {
|
||||
log.debug("update {} target tag", restTargetTagRest);
|
||||
|
||||
final TargetTag updateTargetTag = tagManagement
|
||||
.update(entityFactory.tag().update(targetTagId).name(restTargetTagRest.getName())
|
||||
.description(restTargetTagRest.getDescription()).colour(restTargetTagRest.getColour()));
|
||||
|
||||
log.debug("target tag updated");
|
||||
|
||||
final MgmtTag response = MgmtTagMapper.toResponse(updateTargetTag);
|
||||
MgmtTagMapper.addLinks(updateTargetTag, response);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteTargetTag(@PathVariable("targetTagId") final Long targetTagId) {
|
||||
log.debug("Delete {} target tag", targetTagId);
|
||||
final TargetTag targetTag = findTargetTagById(targetTagId);
|
||||
|
||||
this.tagManagement.delete(targetTag.getName());
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTarget>> getAssignedTargets(@PathVariable("targetTagId") final Long targetTagId,
|
||||
@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.sanitizeTargetSortParam(sortParam);
|
||||
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
final Page<Target> findTargetsAll;
|
||||
if (rsqlParam == null) {
|
||||
findTargetsAll = targetManagement.findByTag(pageable, targetTagId);
|
||||
} else {
|
||||
findTargetsAll = targetManagement.findByRsqlAndTag(pageable, rsqlParam, targetTagId);
|
||||
}
|
||||
|
||||
final List<MgmtTarget> rest = MgmtTargetMapper.toResponse(findTargetsAll.getContent(), tenantConfigHelper);
|
||||
return ResponseEntity.ok(new PagedList<>(rest, findTargetsAll.getTotalElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> assignTarget(final Long targetTagId, final String controllerId) {
|
||||
log.debug("Assign target {} for target tag {}", controllerId, targetTagId);
|
||||
this.targetManagement.assignTag(List.of(controllerId), targetTagId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> assignTargets(final Long targetTagId, final OnNotFoundPolicy onNotFoundPolicy,
|
||||
final List<String> controllerIds) {
|
||||
log.debug("Assign {} targets for target tag {}", controllerIds.size(), targetTagId);
|
||||
if (onNotFoundPolicy == OnNotFoundPolicy.FAIL) {
|
||||
this.targetManagement.assignTag(controllerIds, targetTagId);
|
||||
} else {
|
||||
final AtomicReference<Collection<String>> notFound = new AtomicReference<>();
|
||||
this.targetManagement.assignTag(controllerIds, targetTagId, notFound::set);
|
||||
if (notFound.get() != null) {
|
||||
// has not found
|
||||
if (onNotFoundPolicy == OnNotFoundPolicy.ON_WHAT_FOUND_AND_FAIL) {
|
||||
throw new EntityNotFoundException(Target.class, notFound.get());
|
||||
} // else - success
|
||||
}
|
||||
}
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> unassignTarget(final Long targetTagId,
|
||||
@PathVariable("controllerId") final String controllerId) {
|
||||
log.debug("Unassign target {} for target tag {}", controllerId, targetTagId);
|
||||
this.targetManagement.unassignTag(controllerId, targetTagId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> unassignTargets(final Long targetTagId, final OnNotFoundPolicy onNotFoundPolicy,
|
||||
final List<String> controllerIds) {
|
||||
log.debug("Unassign {} targets for target tag {}", controllerIds.size(), targetTagId);
|
||||
if (onNotFoundPolicy == OnNotFoundPolicy.FAIL) {
|
||||
this.targetManagement.unassignTag(controllerIds, targetTagId);
|
||||
} else {
|
||||
final AtomicReference<Collection<String>> notFound = new AtomicReference<>();
|
||||
this.targetManagement.unassignTag(controllerIds, targetTagId, notFound::set);
|
||||
if (notFound.get() != null) {
|
||||
// has not found
|
||||
if (onNotFoundPolicy == OnNotFoundPolicy.ON_WHAT_FOUND_AND_FAIL) {
|
||||
throw new EntityNotFoundException(Target.class, notFound.get());
|
||||
} // else - success
|
||||
}
|
||||
}
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetTagAssigmentResult> toggleTagAssignment(
|
||||
@PathVariable("targetTagId") final Long targetTagId,
|
||||
@RequestBody final List<MgmtAssignedTargetRequestBody> assignedTargetRequestBodies) {
|
||||
log.debug("Toggle Target assignment {} for target tag {}", assignedTargetRequestBodies.size(), targetTagId);
|
||||
|
||||
final TargetTag targetTag = findTargetTagById(targetTagId);
|
||||
final TargetTagAssignmentResult assigmentResult = this.targetManagement
|
||||
.toggleTagAssignment(findTargetControllerIds(assignedTargetRequestBodies), targetTag.getName());
|
||||
|
||||
final MgmtTargetTagAssigmentResult tagAssigmentResultRest = new MgmtTargetTagAssigmentResult();
|
||||
tagAssigmentResultRest.setAssignedTargets(
|
||||
MgmtTargetMapper.toResponse(assigmentResult.getAssignedEntity(), tenantConfigHelper));
|
||||
tagAssigmentResultRest.setUnassignedTargets(
|
||||
MgmtTargetMapper.toResponse(assigmentResult.getUnassignedEntity(), tenantConfigHelper));
|
||||
return ResponseEntity.ok(tagAssigmentResultRest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtTarget>> assignTargetsByRequestBody(@PathVariable("targetTagId") final Long targetTagId,
|
||||
@RequestBody final List<MgmtAssignedTargetRequestBody> assignedTargetRequestBodies) {
|
||||
log.debug("Assign targets {} for target tag {}", assignedTargetRequestBodies, targetTagId);
|
||||
final List<Target> assignedTarget = this.targetManagement
|
||||
.assignTag(findTargetControllerIds(assignedTargetRequestBodies), targetTagId);
|
||||
return ResponseEntity.ok(MgmtTargetMapper.toResponse(assignedTarget, tenantConfigHelper));
|
||||
}
|
||||
|
||||
private TargetTag findTargetTagById(final Long targetTagId) {
|
||||
return tagManagement.get(targetTagId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetTag.class, targetTagId));
|
||||
}
|
||||
|
||||
private List<String> findTargetControllerIds(
|
||||
final List<MgmtAssignedTargetRequestBody> assignedTargetRequestBodies) {
|
||||
return assignedTargetRequestBodies.stream().map(MgmtAssignedTargetRequestBody::getControllerId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeAssignment;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetTypeRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTypeRestApi;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.rest.json.model.ResponseList;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and back.
|
||||
*/
|
||||
public final class MgmtTargetTypeMapper {
|
||||
|
||||
// private constructor, utility class
|
||||
private MgmtTargetTypeMapper() {
|
||||
}
|
||||
|
||||
static List<TargetTypeCreate> targetFromRequest(final EntityFactory entityFactory,
|
||||
final Collection<MgmtTargetTypeRequestBodyPost> targetTypesRest) {
|
||||
if (targetTypesRest == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return targetTypesRest.stream().map(targetRest -> fromRequest(entityFactory, targetRest))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<MgmtTargetType> toListResponse(final List<TargetType> types) {
|
||||
if (types == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return new ResponseList<>(types.stream().map(MgmtTargetTypeMapper::toResponse).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
static MgmtTargetType toResponse(final TargetType type) {
|
||||
final MgmtTargetType result = new MgmtTargetType();
|
||||
|
||||
MgmtRestModelMapper.mapTypeToType(result, type);
|
||||
result.setTypeId(type.getId());
|
||||
result.add(
|
||||
linkTo(methodOn(MgmtTargetTypeRestApi.class).getTargetType(result.getTypeId())).withSelfRel().expand());
|
||||
return result;
|
||||
}
|
||||
|
||||
static void addLinks(final MgmtTargetType result) {
|
||||
result.add(linkTo(methodOn(MgmtTargetTypeRestApi.class).getCompatibleDistributionSets(result.getTypeId()))
|
||||
.withRel(MgmtRestConstants.TARGETTYPE_V1_DS_TYPES).expand());
|
||||
}
|
||||
|
||||
private static TargetTypeCreate fromRequest(final EntityFactory entityFactory,
|
||||
final MgmtTargetTypeRequestBodyPost targetTypesRest) {
|
||||
return entityFactory.targetType().create()
|
||||
.name(targetTypesRest.getName()).description(targetTypesRest.getDescription())
|
||||
.key(targetTypesRest.getKey()).colour(targetTypesRest.getColour())
|
||||
.compatible(getDistributionSets(targetTypesRest));
|
||||
}
|
||||
|
||||
private static Collection<Long> getDistributionSets(final MgmtTargetTypeRequestBodyPost targetTypesRest) {
|
||||
return Optional.ofNullable(targetTypesRest.getCompatibledistributionsettypes())
|
||||
.map(ds -> ds.stream().map(MgmtDistributionSetTypeAssignment::getId).collect(Collectors.toList()))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetTypeAssignment;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetTypeRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targettype.MgmtTargetTypeRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTypeRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.util.PagingUtility;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling for {@link TargetType} CRUD operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtTargetTypeResource implements MgmtTargetTypeRestApi {
|
||||
|
||||
private final TargetTypeManagement targetTypeManagement;
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
public MgmtTargetTypeResource(final TargetTypeManagement targetTypeManagement, final EntityFactory entityFactory) {
|
||||
this.targetTypeManagement = targetTypeManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PagedList<MgmtTargetType>> getTargetTypes(
|
||||
@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.sanitizeTargetTypeSortParam(sortParam);
|
||||
final Pageable pageable = new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting);
|
||||
|
||||
final Slice<TargetType> findTargetTypesAll;
|
||||
long countTargetTypesAll;
|
||||
if (rsqlParam != null) {
|
||||
findTargetTypesAll = targetTypeManagement.findByRsql(pageable, rsqlParam);
|
||||
countTargetTypesAll = ((Page<TargetType>) findTargetTypesAll).getTotalElements();
|
||||
} else {
|
||||
findTargetTypesAll = targetTypeManagement.findAll(pageable);
|
||||
countTargetTypesAll = targetTypeManagement.count();
|
||||
}
|
||||
|
||||
final List<MgmtTargetType> rest = MgmtTargetTypeMapper.toListResponse(findTargetTypesAll.getContent());
|
||||
return ResponseEntity.ok(new PagedList<>(rest, countTargetTypesAll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetType> getTargetType(@PathVariable("targetTypeId") final Long targetTypeId) {
|
||||
final TargetType foundType = findTargetTypeWithExceptionIfNotFound(targetTypeId);
|
||||
final MgmtTargetType response = MgmtTargetTypeMapper.toResponse(foundType);
|
||||
MgmtTargetTypeMapper.addLinks(response);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteTargetType(@PathVariable("targetTypeId") final Long targetTypeId) {
|
||||
log.debug("Delete {} target type", targetTypeId);
|
||||
targetTypeManagement.delete(targetTypeId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtTargetType> updateTargetType(@PathVariable("targetTypeId") final Long targetTypeId,
|
||||
@RequestBody final MgmtTargetTypeRequestBodyPut restTargetType) {
|
||||
|
||||
final TargetType updated = targetTypeManagement
|
||||
.update(entityFactory.targetType().update(targetTypeId).name(restTargetType.getName())
|
||||
.description(restTargetType.getDescription()).colour(restTargetType.getColour()));
|
||||
final MgmtTargetType response = MgmtTargetTypeMapper.toResponse(updated);
|
||||
MgmtTargetTypeMapper.addLinks(response);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtTargetType>> createTargetTypes(
|
||||
@RequestBody final List<MgmtTargetTypeRequestBodyPost> targetTypes) {
|
||||
|
||||
final List<TargetType> createdTargetTypes = targetTypeManagement
|
||||
.create(MgmtTargetTypeMapper.targetFromRequest(entityFactory, targetTypes));
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(MgmtTargetTypeMapper.toListResponse(createdTargetTypes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtDistributionSetType>> getCompatibleDistributionSets(
|
||||
@PathVariable("targetTypeId") final Long targetTypeId) {
|
||||
|
||||
final TargetType foundType = findTargetTypeWithExceptionIfNotFound(targetTypeId);
|
||||
return ResponseEntity
|
||||
.ok(MgmtDistributionSetTypeMapper.toListResponse(foundType.getCompatibleDistributionSetTypes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> removeCompatibleDistributionSet(@PathVariable("targetTypeId") final Long targetTypeId,
|
||||
@PathVariable("distributionSetTypeId") final Long distributionSetTypeId) {
|
||||
|
||||
targetTypeManagement.unassignDistributionSetType(targetTypeId, distributionSetTypeId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> addCompatibleDistributionSets(@PathVariable("targetTypeId") final Long targetTypeId,
|
||||
@RequestBody final List<MgmtDistributionSetTypeAssignment> distributionSetTypeIds) {
|
||||
|
||||
targetTypeManagement.assignCompatibleDistributionSetTypes(targetTypeId, distributionSetTypeIds.stream()
|
||||
.map(MgmtDistributionSetTypeAssignment::getId).collect(Collectors.toList()));
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
private TargetType findTargetTypeWithExceptionIfNotFound(final Long targetTypeId) {
|
||||
return targetTypeManagement.get(targetTypeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetType.class, targetTypeId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
public final class MgmtTenantManagementMapper {
|
||||
|
||||
public static String DEFAULT_DISTRIBUTION_SET_TYPE_KEY = "default.ds.type";
|
||||
|
||||
private MgmtTenantManagementMapper() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
public static MgmtSystemTenantConfigurationValue toResponseTenantConfigurationValue(String key, TenantConfigurationValue<?> repoConfValue) {
|
||||
final MgmtSystemTenantConfigurationValue restConfValue = new MgmtSystemTenantConfigurationValue();
|
||||
restConfValue.setValue(repoConfValue.getValue());
|
||||
restConfValue.setGlobal(repoConfValue.isGlobal());
|
||||
restConfValue.setCreatedAt(repoConfValue.getCreatedAt());
|
||||
restConfValue.setCreatedBy(repoConfValue.getCreatedBy());
|
||||
restConfValue.setLastModifiedAt(repoConfValue.getLastModifiedAt());
|
||||
restConfValue.setLastModifiedBy(repoConfValue.getLastModifiedBy());
|
||||
restConfValue.add(linkTo(methodOn(MgmtTenantManagementResource.class).getTenantConfigurationValue(key))
|
||||
.withSelfRel().expand());
|
||||
return restConfValue;
|
||||
}
|
||||
|
||||
public static MgmtSystemTenantConfigurationValue toResponseDefaultDsType(Long defaultDistributionSetType) {
|
||||
final MgmtSystemTenantConfigurationValue restConfValue = new MgmtSystemTenantConfigurationValue();
|
||||
restConfValue.setValue(defaultDistributionSetType);
|
||||
restConfValue.setGlobal(Boolean.FALSE);
|
||||
restConfValue.add(linkTo(methodOn(MgmtTenantManagementResource.class).getTenantConfigurationValue(DEFAULT_DISTRIBUTION_SET_TYPE_KEY))
|
||||
.withSelfRel().expand());
|
||||
return restConfValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValueRequest;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTenantManagementRestApi;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
|
||||
import org.eclipse.hawkbit.repository.exception.TenantConfigurationValidatorException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource for handling tenant specific configuration operations.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class MgmtTenantManagementResource implements MgmtTenantManagementRestApi {
|
||||
|
||||
private final TenantConfigurationManagement tenantConfigurationManagement;
|
||||
private final TenantConfigurationProperties tenantConfigurationProperties;
|
||||
private final SystemManagement systemManagement;
|
||||
|
||||
MgmtTenantManagementResource(final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final TenantConfigurationProperties tenantConfigurationProperties,
|
||||
final SystemManagement systemManagement) {
|
||||
this.tenantConfigurationManagement = tenantConfigurationManagement;
|
||||
this.tenantConfigurationProperties = tenantConfigurationProperties;
|
||||
this.systemManagement = systemManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Map<String, MgmtSystemTenantConfigurationValue>> getTenantConfiguration() {
|
||||
// Load and Construct default Tenant Configuration
|
||||
final Map<String, MgmtSystemTenantConfigurationValue> tenantConfigurationValueMap = new HashMap<>();
|
||||
tenantConfigurationProperties.getConfigurationKeys().forEach(key -> {
|
||||
try {
|
||||
tenantConfigurationValueMap.put(key.getKeyName(), loadTenantConfigurationValueBy(key.getKeyName()));
|
||||
} catch (final InsufficientPermissionException e) {
|
||||
// some values as gateway token may not be accessibly for the caller - just skip them
|
||||
}
|
||||
});
|
||||
|
||||
// Load and Add Default DistributionSetType
|
||||
final MgmtSystemTenantConfigurationValue defaultDsTypeId = loadTenantConfigurationValueBy(
|
||||
MgmtTenantManagementMapper.DEFAULT_DISTRIBUTION_SET_TYPE_KEY);
|
||||
tenantConfigurationValueMap.put(MgmtTenantManagementMapper.DEFAULT_DISTRIBUTION_SET_TYPE_KEY, defaultDsTypeId);
|
||||
|
||||
// return combined TenantConfiguration and TenantMetadata
|
||||
log.debug("getTenantConfiguration, return status {}", HttpStatus.OK);
|
||||
return ResponseEntity.ok(tenantConfigurationValueMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Void> deleteTenantConfigurationValue(@PathVariable("keyName") final String keyName) {
|
||||
|
||||
//Default DistributionSet Type cannot be deleted as is part of TenantMetadata
|
||||
if (isDefaultDistributionSetTypeKey(keyName)) {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
tenantConfigurationManagement.deleteConfiguration(keyName);
|
||||
|
||||
log.debug("{} config value deleted, return status {}", keyName, HttpStatus.OK);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSystemTenantConfigurationValue> getTenantConfigurationValue(
|
||||
@PathVariable("keyName") final String keyName) {
|
||||
return ResponseEntity.ok(loadTenantConfigurationValueBy(keyName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<MgmtSystemTenantConfigurationValue> updateTenantConfigurationValue(
|
||||
@PathVariable("keyName") final String keyName,
|
||||
@RequestBody final MgmtSystemTenantConfigurationValueRequest configurationValueRest) {
|
||||
Serializable configurationValue = configurationValueRest.getValue();
|
||||
final MgmtSystemTenantConfigurationValue responseUpdatedValue;
|
||||
if (isDefaultDistributionSetTypeKey(keyName)) {
|
||||
responseUpdatedValue = updateDefaultDsType(configurationValue);
|
||||
} else {
|
||||
final TenantConfigurationValue<? extends Serializable> updatedTenantConfigurationValue = tenantConfigurationManagement
|
||||
.addOrUpdateConfiguration(keyName, configurationValueRest.getValue());
|
||||
responseUpdatedValue = MgmtTenantManagementMapper.toResponseTenantConfigurationValue(keyName, updatedTenantConfigurationValue);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(responseUpdatedValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<List<MgmtSystemTenantConfigurationValue>> updateTenantConfiguration(
|
||||
Map<String, Serializable> configurationValueMap) {
|
||||
|
||||
boolean containsNull = configurationValueMap.keySet().stream()
|
||||
.anyMatch(Objects::isNull);
|
||||
|
||||
if (containsNull) {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
|
||||
//Try update TenantMetadata first
|
||||
Serializable defaultDsTypeValueUpdate = configurationValueMap.remove(MgmtTenantManagementMapper.DEFAULT_DISTRIBUTION_SET_TYPE_KEY);
|
||||
Long oldDefaultDsType = null;
|
||||
MgmtSystemTenantConfigurationValue updatedDefaultDsType = null;
|
||||
if (defaultDsTypeValueUpdate != null) {
|
||||
oldDefaultDsType = systemManagement.getTenantMetadata().getDefaultDsType().getId();
|
||||
updatedDefaultDsType = updateDefaultDsType(defaultDsTypeValueUpdate);
|
||||
}
|
||||
//try update TenantConfiguration, in case of Error -> rollback TenantMetadata
|
||||
Map<String, TenantConfigurationValue<Serializable>> tenantConfigurationValues;
|
||||
try {
|
||||
tenantConfigurationValues = tenantConfigurationManagement.addOrUpdateConfiguration(configurationValueMap);
|
||||
} catch (Exception ex) {
|
||||
//if DefaultDsType was updated, rollback it in case of TenantConfiguration update.
|
||||
if (updatedDefaultDsType != null) {
|
||||
systemManagement.updateTenantMetadata(oldDefaultDsType);
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
|
||||
List<MgmtSystemTenantConfigurationValue> tenantConfigurationListUpdated = new java.util.ArrayList<>(
|
||||
tenantConfigurationValues.entrySet().stream()
|
||||
.map(entry -> MgmtTenantManagementMapper.toResponseTenantConfigurationValue(entry.getKey(), entry.getValue()))
|
||||
.toList());
|
||||
if (updatedDefaultDsType != null) {
|
||||
tenantConfigurationListUpdated.add(updatedDefaultDsType);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(tenantConfigurationListUpdated);
|
||||
}
|
||||
|
||||
private static boolean isDefaultDistributionSetTypeKey(String keyName) {
|
||||
return MgmtTenantManagementMapper.DEFAULT_DISTRIBUTION_SET_TYPE_KEY.equals(keyName);
|
||||
}
|
||||
|
||||
private MgmtSystemTenantConfigurationValue loadTenantConfigurationValueBy(String keyName) {
|
||||
|
||||
//Check if requested key is TenantConfiguration or TenantMetadata, load it and return it as rest response
|
||||
MgmtSystemTenantConfigurationValue response;
|
||||
if (isDefaultDistributionSetTypeKey(keyName)) {
|
||||
response = MgmtTenantManagementMapper.toResponseDefaultDsType(systemManagement.getTenantMetadata().getDefaultDsType().getId());
|
||||
} else {
|
||||
response = MgmtTenantManagementMapper.toResponseTenantConfigurationValue(keyName,
|
||||
tenantConfigurationManagement.getConfigurationValue(keyName));
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private MgmtSystemTenantConfigurationValue updateDefaultDsType(Serializable defaultDsType) {
|
||||
long updateDefaultDsType;
|
||||
try {
|
||||
updateDefaultDsType = ((Number) defaultDsType).longValue();
|
||||
} catch (ClassCastException cce) {
|
||||
throw new TenantConfigurationValidatorException(String.format(
|
||||
"Default DistributionSetType Value Type is incorrect. Expected Long, received %s", defaultDsType.getClass().getName()));
|
||||
}
|
||||
systemManagement.updateTenantMetadata(updateDefaultDsType);
|
||||
return MgmtTenantManagementMapper.toResponseDefaultDsType(updateDefaultDsType);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource.exception;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
|
||||
/**
|
||||
* Exception used by the REST API in case of invalid sort parameter syntax.
|
||||
*/
|
||||
public class SortParameterSyntaxErrorException extends AbstractServerRtException {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new SortParameterSyntaxErrorException with {@link SpServerError#SP_REST_SORT_PARAM_SYNTAX} error.
|
||||
*/
|
||||
public SortParameterSyntaxErrorException() {
|
||||
super(SpServerError.SP_REST_SORT_PARAM_SYNTAX);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource.exception;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
|
||||
/**
|
||||
* Exception used by the REST API in case of invalid sort parameter direction name.
|
||||
*/
|
||||
public class SortParameterUnsupportedDirectionException extends AbstractServerRtException {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new SortParameterSyntaxErrorException with {@link SpServerError#SP_REST_SORT_PARAM_INVALID_DIRECTION} error.
|
||||
*
|
||||
* @param cause the cause (which is saved for later retrieval by the getCause() method). (A null value is permitted, and indicates
|
||||
* that the cause is nonexistent or unknown.)
|
||||
*/
|
||||
public SortParameterUnsupportedDirectionException(final Throwable cause) {
|
||||
super(SpServerError.SP_REST_SORT_PARAM_INVALID_DIRECTION, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource.exception;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
|
||||
/**
|
||||
* Exception used by the REST API in case of invalid field name in the sort parameter.
|
||||
*/
|
||||
public class SortParameterUnsupportedFieldException extends AbstractServerRtException {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new SortParameterSyntaxErrorException with {@link SpServerError#SP_REST_SORT_PARAM_INVALID_FIELD} error.
|
||||
*
|
||||
* @param cause the cause (which is saved for later retrieval by the getCause() method). (A null value is permitted, and indicates
|
||||
* that the cause is nonexistent or unknown.)
|
||||
*/
|
||||
public SortParameterUnsupportedFieldException(final Throwable cause) {
|
||||
super(SpServerError.SP_REST_SORT_PARAM_INVALID_FIELD, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource.util;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.ActionFields;
|
||||
import org.eclipse.hawkbit.repository.ActionStatusFields;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetFields;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetMetadataFields;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeFields;
|
||||
import org.eclipse.hawkbit.repository.RolloutFields;
|
||||
import org.eclipse.hawkbit.repository.RolloutGroupFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields;
|
||||
import org.eclipse.hawkbit.repository.TagFields;
|
||||
import org.eclipse.hawkbit.repository.TargetFields;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryFields;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeFields;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
|
||||
/**
|
||||
* Utility class for for paged body generation.
|
||||
*/
|
||||
public final class PagingUtility {
|
||||
|
||||
/*
|
||||
* utility constructor private.
|
||||
*/
|
||||
private PagingUtility() {
|
||||
}
|
||||
|
||||
public static int sanitizeOffsetParam(final int offset) {
|
||||
if (offset < 0) {
|
||||
return MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET_VALUE;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
public static int sanitizePageLimitParam(final int pageLimit) {
|
||||
if (pageLimit < 1) {
|
||||
return MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_LIMIT_VALUE;
|
||||
} else if (pageLimit > MgmtRestConstants.REQUEST_PARAMETER_PAGING_MAX_LIMIT) {
|
||||
return MgmtRestConstants.REQUEST_PARAMETER_PAGING_MAX_LIMIT;
|
||||
}
|
||||
return pageLimit;
|
||||
}
|
||||
|
||||
public static Sort sanitizeTargetSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, TargetFields.CONTROLLERID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(TargetFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeTargetTypeSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, TargetTypeFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(TargetTypeFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeTagSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, TagFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(TagFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeTargetFilterQuerySortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, TargetFilterQueryFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(TargetFilterQueryFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeSoftwareModuleSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, SoftwareModuleFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(SoftwareModuleFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeSoftwareModuleTypeSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, SoftwareModuleTypeFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(SoftwareModuleTypeFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeDistributionSetSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, DistributionSetFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(DistributionSetFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeDistributionSetTypeSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, DistributionSetTypeFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(DistributionSetTypeFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeActionSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default sort is DESC in case of action to match behavior
|
||||
// of management UI (last entry on top)
|
||||
return Sort.by(Direction.DESC, ActionFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(ActionFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeActionStatusSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default sort is DESC in case of action status to match behavior
|
||||
// of management UI (last entry on top)
|
||||
return Sort.by(Direction.DESC, ActionStatusFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(ActionStatusFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeDistributionSetMetadataSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, DistributionSetMetadataFields.KEY.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(DistributionSetMetadataFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeSoftwareModuleMetadataSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, SoftwareModuleMetadataFields.KEY.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(SoftwareModuleMetadataFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeRolloutSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, RolloutFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(RolloutFields.class, sortParam));
|
||||
}
|
||||
|
||||
public static Sort sanitizeRolloutGroupSortParam(final String sortParam) {
|
||||
if (sortParam == null) {
|
||||
// default
|
||||
return Sort.by(Direction.ASC, RolloutGroupFields.ID.getJpaEntityFieldName());
|
||||
}
|
||||
return Sort.by(SortUtility.parse(RolloutGroupFields.class, sortParam));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.mgmt.rest.resource.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterSyntaxErrorException;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterUnsupportedDirectionException;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterUnsupportedFieldException;
|
||||
import org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
|
||||
/**
|
||||
* A utility class for parsing query parameters which define the sorting of elements.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class SortUtility {
|
||||
|
||||
/**
|
||||
* the delimiter between the different field directions in the sort request.
|
||||
*/
|
||||
public static final String DELIMITER_SORT_TUPLE = ",";
|
||||
/**
|
||||
* the delimiter between the field and direction in the sort request.
|
||||
*/
|
||||
public static final String DELIMITER_FIELD_DIRECTION = ":";
|
||||
|
||||
/**
|
||||
* Parses the sort string e.g. given in a REST call based on the definition
|
||||
* of sorting: <code>http://localhost/entity?s=field1:ASC,field2:DESC</code> The fields
|
||||
* will be split into the keys of the returned map. The direction of the
|
||||
* sorting will be mapped into the {@link Direction} enum.
|
||||
*
|
||||
* @param enumType the class of the enum which the fields in the sort string should be related to.
|
||||
* @param <T> the type of the enumeration which must be derived from {@link RsqlQueryField}
|
||||
* @param sortString the string representation of the query parameters. Might be {@code null} or an empty string.
|
||||
* @return a list which holds the {@link RsqlQueryField} and the specific {@link Direction} for them as a tuple. Never {@code null}.
|
||||
* In case of no sorting parameters an empty map will be returned.
|
||||
* @throws SortParameterSyntaxErrorException if the sorting query parameter is not well-formed
|
||||
* @throws SortParameterUnsupportedFieldException if a field name cannot be mapped to the enum type
|
||||
* @throws SortParameterUnsupportedDirectionException if the given direction is not "ASC" or "DESC"
|
||||
*/
|
||||
public static <T extends Enum<T> & RsqlQueryField> List<Order> parse(final Class<T> enumType, final String sortString)
|
||||
throws SortParameterSyntaxErrorException {
|
||||
final List<Order> orders = new ArrayList<>();
|
||||
// scan the sort tuples e.g. field:direction
|
||||
if (sortString != null) {
|
||||
final StringTokenizer tupleTokenizer = new StringTokenizer(sortString, DELIMITER_SORT_TUPLE);
|
||||
while (tupleTokenizer.hasMoreTokens()) {
|
||||
final String sortTuple = tupleTokenizer.nextToken().trim();
|
||||
final StringTokenizer fieldDirectionTokenizer = new StringTokenizer(sortTuple, DELIMITER_FIELD_DIRECTION);
|
||||
if (fieldDirectionTokenizer.countTokens() == 2) {
|
||||
final String fieldName = fieldDirectionTokenizer.nextToken().trim().toUpperCase();
|
||||
final String sortDirectionStr = fieldDirectionTokenizer.nextToken().trim();
|
||||
|
||||
final T identifier;
|
||||
try {
|
||||
identifier = Enum.valueOf(enumType, fieldName.toUpperCase());
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new SortParameterUnsupportedFieldException(e);
|
||||
}
|
||||
|
||||
final Direction sortDirection;
|
||||
try {
|
||||
sortDirection = Direction.fromString(sortDirectionStr);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new SortParameterUnsupportedDirectionException(e);
|
||||
}
|
||||
|
||||
orders.add(new Order(sortDirection, identifier.getJpaEntityFieldName()));
|
||||
} else {
|
||||
throw new SortParameterSyntaxErrorException();
|
||||
}
|
||||
}
|
||||
}
|
||||
return orders;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# Copyright (c) 2018 Microsoft and others
|
||||
#
|
||||
# This program and the accompanying materials are made
|
||||
# available under the terms of the Eclipse Public License 2.0
|
||||
# which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
#
|
||||
# SPDX-License-Identifier: EPL-2.0
|
||||
#
|
||||
|
||||
# Upload of large files
|
||||
spring.servlet.multipart.max-file-size=1024MB
|
||||
spring.servlet.multipart.max-request-size=-1
|
||||
spring.servlet.multipart.file-size-threshold=1MB
|
||||
Reference in New Issue
Block a user