Adapt cancel flow (#1274)
* Adapt assignment events to communicate mass cancel operations within one event. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Fix edge cases identified by test failures. Adapt tests and reduce amount of published cancel events. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Fix license header Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Refactor visibility of methods in assignment strategy classes. Avoid having empty action status messages. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Fix api docs Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> Co-authored-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>
This commit is contained in:
@@ -12,16 +12,19 @@ import static org.eclipse.hawkbit.repository.RepositoryConstants.MAX_ACTION_COUN
|
|||||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.BATCH_ASSIGNMENTS_ENABLED;
|
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.BATCH_ASSIGNMENTS_ENABLED;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import org.eclipse.hawkbit.api.ApiType;
|
import org.eclipse.hawkbit.api.ApiType;
|
||||||
import org.eclipse.hawkbit.api.ArtifactUrl;
|
import org.eclipse.hawkbit.api.ArtifactUrl;
|
||||||
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
|
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
|
||||||
@@ -50,7 +53,7 @@ import org.eclipse.hawkbit.repository.event.remote.MultiActionEvent;
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
|
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
import org.eclipse.hawkbit.repository.model.ActionProperties;
|
import org.eclipse.hawkbit.repository.model.ActionProperties;
|
||||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||||
@@ -70,6 +73,8 @@ import org.springframework.cloud.bus.ServiceMatcher;
|
|||||||
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
|
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,6 +89,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(AmqpMessageDispatcherService.class);
|
private static final Logger LOG = LoggerFactory.getLogger(AmqpMessageDispatcherService.class);
|
||||||
|
|
||||||
|
private static final int MAX_PROCESSING_SIZE = 1000;
|
||||||
|
|
||||||
private final ArtifactUrlHandler artifactUrlHandler;
|
private final ArtifactUrlHandler artifactUrlHandler;
|
||||||
private final AmqpMessageSenderService amqpSenderService;
|
private final AmqpMessageSenderService amqpSenderService;
|
||||||
private final SystemSecurityContext systemSecurityContext;
|
private final SystemSecurityContext systemSecurityContext;
|
||||||
@@ -177,14 +184,16 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<Target> getTargetsWithoutPendingCancellations(final Set<String> controllerIds) {
|
private List<Target> getTargetsWithoutPendingCancellations(final Set<String> controllerIds) {
|
||||||
return targetManagement.getByControllerID(controllerIds).stream().filter(target -> {
|
return partitionedParallelExecution(controllerIds, partition -> {
|
||||||
if (hasPendingCancellations(target.getControllerId())) {
|
return targetManagement.getByControllerID(partition).stream().filter(target -> {
|
||||||
LOG.debug("Target {} has pending cancellations. Will not send update message to it.",
|
if (hasPendingCancellations(target.getControllerId())) {
|
||||||
target.getControllerId());
|
LOG.debug("Target {} has pending cancellations. Will not send update message to it.",
|
||||||
return false;
|
target.getControllerId());
|
||||||
}
|
return false;
|
||||||
return true;
|
}
|
||||||
}).collect(Collectors.toList());
|
return true;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendUpdateMessageToTarget(final TargetAssignDistributionSetEvent assignedEvent,
|
private void sendUpdateMessageToTarget(final TargetAssignDistributionSetEvent assignedEvent,
|
||||||
@@ -319,18 +328,45 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Optional<Target> eventEntity = cancelEvent.getEntity();
|
final List<Target> eventTargets = partitionedParallelExecution(cancelEvent.getActions().keySet(),
|
||||||
if (eventEntity.isPresent()) {
|
targetManagement::getByControllerID);
|
||||||
final Target target = eventEntity.get();
|
|
||||||
sendCancelMessageToTarget(cancelEvent.getTenant(), target.getControllerId(), cancelEvent.getActionId(),
|
eventTargets.forEach(target -> {
|
||||||
target.getAddress());
|
cancelEvent.getActionPropertiesForController(target.getControllerId()).map(ActionProperties::getId)
|
||||||
} else {
|
.ifPresent(actionId -> {
|
||||||
LOG.warn(
|
sendCancelMessageToTarget(cancelEvent.getTenant(), target.getControllerId(), actionId,
|
||||||
"Cannot process the received CancelTargetAssignmentEvent with action ID {} because the referenced target with ID {} does no longer exist.",
|
target.getAddress());
|
||||||
cancelEvent.getActionId(), cancelEvent.getEntityId());
|
});
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <T, R> List<R> partitionedParallelExecution(final Collection<T> controllerIds,
|
||||||
|
final Function<Collection<T>, List<R>> loadingFunction) {
|
||||||
|
// Ensure not exceeding the max value of MAX_PROCESSING_SIZE
|
||||||
|
if (controllerIds.size() > MAX_PROCESSING_SIZE) {
|
||||||
|
// Split the provided collection
|
||||||
|
final Iterable<List<T>> partitions = Iterables.partition(controllerIds, MAX_PROCESSING_SIZE);
|
||||||
|
// Preserve the security context because it gets lost when executing
|
||||||
|
// loading calls in new threads
|
||||||
|
final SecurityContext context = SecurityContextHolder.getContext();
|
||||||
|
// Handling remote request in parallel streams
|
||||||
|
return StreamSupport.stream(partitions.spliterator(), true) //
|
||||||
|
.flatMap(partition -> withSecurityContext(() -> loadingFunction.apply(partition), context).stream())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
return loadingFunction.apply(controllerIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T withSecurityContext(final Supplier<T> callable, final SecurityContext securityContext) {
|
||||||
|
final SecurityContext oldContext = SecurityContextHolder.getContext();
|
||||||
|
try {
|
||||||
|
SecurityContextHolder.setContext(securityContext);
|
||||||
|
return callable.get();
|
||||||
|
} finally {
|
||||||
|
SecurityContextHolder.setContext(oldContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to send a message to a RabbitMQ Exchange after a Target was
|
* Method to send a message to a RabbitMQ Exchange after a Target was
|
||||||
* deleted.
|
* deleted.
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.amqp;
|
|||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -37,7 +38,7 @@ import org.eclipse.hawkbit.repository.SystemManagement;
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
|
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
||||||
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||||
@@ -230,12 +231,14 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
@Description("Verifies that send cancel event works")
|
@Description("Verifies that send cancel event works")
|
||||||
void testSendCancelRequest() {
|
void testSendCancelRequest() {
|
||||||
|
final Action action = mock(Action.class);
|
||||||
|
when(action.getId()).thenReturn(1L);
|
||||||
|
when(action.getTarget()).thenReturn(testTarget);
|
||||||
final CancelTargetAssignmentEvent cancelTargetAssignmentDistributionSetEvent = new CancelTargetAssignmentEvent(
|
final CancelTargetAssignmentEvent cancelTargetAssignmentDistributionSetEvent = new CancelTargetAssignmentEvent(
|
||||||
testTarget, 1L, serviceMatcher.getServiceId());
|
action, serviceMatcher.getServiceId());
|
||||||
amqpMessageDispatcherService
|
amqpMessageDispatcherService
|
||||||
.targetCancelAssignmentToDistributionSet(cancelTargetAssignmentDistributionSetEvent);
|
.targetCancelAssignmentToDistributionSet(cancelTargetAssignmentDistributionSetEvent);
|
||||||
final Message sendMessage = createArgumentCapture(
|
final Message sendMessage = createArgumentCapture(AMQP_URI);
|
||||||
cancelTargetAssignmentDistributionSetEvent.getEntity().get().getAddress());
|
|
||||||
assertCancelMessage(sendMessage);
|
assertCancelMessage(sendMessage);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
|
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupCreatedEvent;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEven
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
|
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedEvent;
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2022 Bosch.IO GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.repository.event.remote;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
|
import org.eclipse.hawkbit.repository.model.ActionProperties;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class providing information about an assignment.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractAssignmentEvent extends RemoteTenantAwareEvent {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final Map<String, ActionProperties> actions = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
protected AbstractAssignmentEvent() {
|
||||||
|
// for serialization libs like jackson
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractAssignmentEvent(final Object source, final Action a, final String applicationId) {
|
||||||
|
super(source, a.getTenant(), applicationId);
|
||||||
|
actions.put(a.getTarget().getControllerId(), new ActionProperties(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractAssignmentEvent(final Object source, final String tenant, final List<Action> a,
|
||||||
|
final String applicationId) {
|
||||||
|
super(source, tenant, applicationId);
|
||||||
|
actions.putAll(a.stream()
|
||||||
|
.collect(Collectors.toMap(action -> action.getTarget().getControllerId(), ActionProperties::new)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, ActionProperties> getActions() {
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<ActionProperties> getActionPropertiesForController(final String controllerId) {
|
||||||
|
return Optional.ofNullable(actions.get(controllerId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2022 Bosch.IO GmbH and others.
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.hawkbit.repository.event.remote;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event that gets sent when the assignment of a distribution set to a target
|
||||||
|
* gets canceled.
|
||||||
|
*/
|
||||||
|
public class CancelTargetAssignmentEvent extends AbstractAssignmentEvent {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
public CancelTargetAssignmentEvent() {
|
||||||
|
// for serialization libs like jackson
|
||||||
|
}
|
||||||
|
|
||||||
|
public CancelTargetAssignmentEvent(final Action a, final String applicationId) {
|
||||||
|
super(applicationId, a, applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CancelTargetAssignmentEvent(final String tenant, final List<Action> a, final String applicationId) {
|
||||||
|
super(applicationId, tenant, a, applicationId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,19 +9,16 @@
|
|||||||
package org.eclipse.hawkbit.repository.event.remote;
|
package org.eclipse.hawkbit.repository.event.remote;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
import org.eclipse.hawkbit.repository.model.ActionProperties;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TenantAwareEvent that gets sent when a distribution set gets assigned to a
|
* TenantAwareEvent that gets sent when a distribution set gets assigned to a
|
||||||
* target.
|
* target.
|
||||||
*/
|
*/
|
||||||
public class TargetAssignDistributionSetEvent extends RemoteTenantAwareEvent {
|
public class TargetAssignDistributionSetEvent extends AbstractAssignmentEvent {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@@ -29,8 +26,6 @@ public class TargetAssignDistributionSetEvent extends RemoteTenantAwareEvent {
|
|||||||
|
|
||||||
private boolean maintenanceWindowAvailable;
|
private boolean maintenanceWindowAvailable;
|
||||||
|
|
||||||
private final Map<String, ActionProperties> actions = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor.
|
* Default constructor.
|
||||||
*/
|
*/
|
||||||
@@ -54,12 +49,12 @@ public class TargetAssignDistributionSetEvent extends RemoteTenantAwareEvent {
|
|||||||
*/
|
*/
|
||||||
public TargetAssignDistributionSetEvent(final String tenant, final long distributionSetId, final List<Action> a,
|
public TargetAssignDistributionSetEvent(final String tenant, final long distributionSetId, final List<Action> a,
|
||||||
final String applicationId, final boolean maintenanceWindowAvailable) {
|
final String applicationId, final boolean maintenanceWindowAvailable) {
|
||||||
super(distributionSetId, tenant, applicationId);
|
super(distributionSetId, tenant,
|
||||||
|
a.stream().filter(action -> action.getDistributionSet().getId().longValue() == distributionSetId)
|
||||||
|
.collect(Collectors.toList()),
|
||||||
|
applicationId);
|
||||||
this.distributionSetId = distributionSetId;
|
this.distributionSetId = distributionSetId;
|
||||||
this.maintenanceWindowAvailable = maintenanceWindowAvailable;
|
this.maintenanceWindowAvailable = maintenanceWindowAvailable;
|
||||||
actions.putAll(a.stream().filter(action -> action.getDistributionSet().getId().longValue() == distributionSetId)
|
|
||||||
.collect(Collectors.toMap(action -> action.getTarget().getControllerId(), ActionProperties::new)));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,8 +78,4 @@ public class TargetAssignDistributionSetEvent extends RemoteTenantAwareEvent {
|
|||||||
return maintenanceWindowAvailable;
|
return maintenanceWindowAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, ActionProperties> getActions() {
|
|
||||||
return actions;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
|
||||||
*
|
|
||||||
* All rights reserved. This program and the accompanying materials
|
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
|
||||||
* which accompanies this distribution, and is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-v10.html
|
|
||||||
*/
|
|
||||||
package org.eclipse.hawkbit.repository.event.remote.entity;
|
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event that gets sent when the assignment of a distribution set to a target
|
|
||||||
* gets canceled.
|
|
||||||
*/
|
|
||||||
public class CancelTargetAssignmentEvent extends RemoteEntityEvent<Target> {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private Long actionId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor.
|
|
||||||
*/
|
|
||||||
public CancelTargetAssignmentEvent() {
|
|
||||||
// for serialization libs like jackson
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*
|
|
||||||
* @param baseEntity
|
|
||||||
* the target
|
|
||||||
* @param actionId
|
|
||||||
* the actionId
|
|
||||||
* @param applicationId
|
|
||||||
* the origin application id
|
|
||||||
*/
|
|
||||||
public CancelTargetAssignmentEvent(final Target baseEntity, final Long actionId, final String applicationId) {
|
|
||||||
super(baseEntity, applicationId);
|
|
||||||
this.actionId = actionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the action id of the assignment
|
|
||||||
*/
|
|
||||||
public Long getActionId() {
|
|
||||||
return actionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -34,7 +34,7 @@ import org.eclipse.hawkbit.repository.event.remote.TargetTypeDeletedEvent;
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.TenantConfigurationDeletedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TenantConfigurationDeletedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
|
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpdatedEvent;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
package org.eclipse.hawkbit.repository.jpa;
|
package org.eclipse.hawkbit.repository.jpa;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -17,7 +18,7 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||||
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
|
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||||
@@ -30,11 +31,15 @@ import org.eclipse.hawkbit.repository.model.Action;
|
|||||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||||
|
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||||
|
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetWithActionType;
|
import org.eclipse.hawkbit.repository.model.TargetWithActionType;
|
||||||
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link DistributionSet} to {@link Target} assignment strategy as utility for
|
* {@link DistributionSet} to {@link Target} assignment strategy as utility for
|
||||||
@@ -144,19 +149,22 @@ public abstract class AbstractDsAssignmentStrategy {
|
|||||||
.findByActiveAndTargetIdInAndActionStatusNotEqualToAndDistributionSetNotRequiredMigrationStep(
|
.findByActiveAndTargetIdInAndActionStatusNotEqualToAndDistributionSetNotRequiredMigrationStep(
|
||||||
targetsIds, Action.Status.CANCELING);
|
targetsIds, Action.Status.CANCELING);
|
||||||
|
|
||||||
return activeActions.stream().map(action -> {
|
final List<Long> targetIds = activeActions.stream().map(action -> {
|
||||||
action.setStatus(Status.CANCELING);
|
action.setStatus(Status.CANCELING);
|
||||||
|
|
||||||
// document that the status has been retrieved
|
// document that the status has been retrieved
|
||||||
actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELING, System.currentTimeMillis(),
|
actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELING, System.currentTimeMillis(),
|
||||||
RepositoryConstants.SERVER_MESSAGE_PREFIX + "cancel obsolete action due to new update"));
|
RepositoryConstants.SERVER_MESSAGE_PREFIX + "cancel obsolete action due to new update"));
|
||||||
actionRepository.save(action);
|
actionRepository.save(action);
|
||||||
|
|
||||||
cancelAssignDistributionSetEvent(action.getTarget(), action.getId());
|
|
||||||
|
|
||||||
return action.getTarget().getId();
|
return action.getTarget().getId();
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (!activeActions.isEmpty()) {
|
||||||
|
cancelAssignDistributionSetEvent(Collections.unmodifiableList(activeActions));
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,20 +196,28 @@ public abstract class AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the {@link CancelTargetAssignmentEvent} for a specific target to
|
* Sends the {@link CancelTargetAssignmentEvent} for a specific action to
|
||||||
* the eventPublisher.
|
* the eventPublisher.
|
||||||
*
|
*
|
||||||
* @param target
|
* @param action
|
||||||
* the Target which has been assigned to a distribution set
|
* the action of the assignment
|
||||||
* @param actionId
|
|
||||||
* the action id of the assignment
|
|
||||||
*/
|
*/
|
||||||
void cancelAssignDistributionSetEvent(final Target target, final Long actionId) {
|
protected void cancelAssignDistributionSetEvent(final Action action) {
|
||||||
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher().publishEvent(
|
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher().publishEvent(
|
||||||
new CancelTargetAssignmentEvent(target, actionId, eventPublisherHolder.getApplicationId())));
|
new CancelTargetAssignmentEvent(action, eventPublisherHolder.getApplicationId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
JpaAction createTargetAction(final String initiatedBy, final TargetWithActionType targetWithActionType,
|
private void cancelAssignDistributionSetEvent(final List<Action> actions) {
|
||||||
|
if (CollectionUtils.isEmpty(actions)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String tenant = actions.get(0).getTenant();
|
||||||
|
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher()
|
||||||
|
.publishEvent(new CancelTargetAssignmentEvent(tenant,
|
||||||
|
actions, eventPublisherHolder.getApplicationId())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public JpaAction createTargetAction(final String initiatedBy, final TargetWithActionType targetWithActionType,
|
||||||
final List<JpaTarget> targets, final JpaDistributionSet set) {
|
final List<JpaTarget> targets, final JpaDistributionSet set) {
|
||||||
final Optional<JpaTarget> optTarget = targets.stream()
|
final Optional<JpaTarget> optTarget = targets.stream()
|
||||||
.filter(t -> t.getControllerId().equals(targetWithActionType.getControllerId())).findFirst();
|
.filter(t -> t.getControllerId().equals(targetWithActionType.getControllerId())).findFirst();
|
||||||
@@ -227,18 +243,30 @@ public abstract class AbstractDsAssignmentStrategy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
JpaActionStatus createActionStatus(final JpaAction action, final String actionMessage) {
|
public JpaActionStatus createActionStatus(final JpaAction action, final String actionMessage) {
|
||||||
final JpaActionStatus actionStatus = new JpaActionStatus();
|
final JpaActionStatus actionStatus = new JpaActionStatus();
|
||||||
actionStatus.setAction(action);
|
actionStatus.setAction(action);
|
||||||
actionStatus.setOccurredAt(action.getCreatedAt());
|
actionStatus.setOccurredAt(action.getCreatedAt());
|
||||||
|
|
||||||
if (actionMessage != null) {
|
if (StringUtils.hasText(actionMessage)) {
|
||||||
actionStatus.addMessage(actionMessage);
|
actionStatus.addMessage(actionMessage);
|
||||||
|
} else {
|
||||||
|
actionStatus.addMessage(getActionMessage(action));
|
||||||
}
|
}
|
||||||
|
|
||||||
return actionStatus;
|
return actionStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getActionMessage(final Action action) {
|
||||||
|
final RolloutGroup rolloutGroup = action.getRolloutGroup();
|
||||||
|
if (rolloutGroup != null) {
|
||||||
|
final Rollout rollout = rolloutGroup.getRollout();
|
||||||
|
return String.format("Initiated by Rollout Group '%s' [Rollout %s:%s]", rolloutGroup.getName(),
|
||||||
|
rollout.getName(), rollout.getId());
|
||||||
|
}
|
||||||
|
return String.format("Assignment initiated by user '%s'", action.getInitiatedBy());
|
||||||
|
}
|
||||||
|
|
||||||
private void assertActionsPerTargetQuota(final Target target, final int requested) {
|
private void assertActionsPerTargetQuota(final Target target, final int requested) {
|
||||||
final int quota = quotaManagement.getMaxActionsPerTarget();
|
final int quota = quotaManagement.getMaxActionsPerTarget();
|
||||||
QuotaHelper.assertAssignmentQuota(target.getId(), requested, quota, Action.class, Target.class,
|
QuotaHelper.assertAssignmentQuota(target.getId(), requested, quota, Action.class, Target.class,
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ import org.eclipse.hawkbit.repository.UpdateMode;
|
|||||||
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
|
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
|
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
||||||
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||||
@@ -1041,7 +1041,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
|||||||
actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELING, System.currentTimeMillis(),
|
actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELING, System.currentTimeMillis(),
|
||||||
"manual cancelation requested"));
|
"manual cancelation requested"));
|
||||||
final Action saveAction = actionRepository.save(action);
|
final Action saveAction = actionRepository.save(action);
|
||||||
cancelAssignDistributionSetEvent((JpaTarget) action.getTarget(), action.getId());
|
cancelAssignDistributionSetEvent(action);
|
||||||
|
|
||||||
return saveAction;
|
return saveAction;
|
||||||
} else {
|
} else {
|
||||||
@@ -1074,9 +1074,9 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelAssignDistributionSetEvent(final JpaTarget target, final Long actionId) {
|
private void cancelAssignDistributionSetEvent(final Action action) {
|
||||||
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher().publishEvent(
|
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher().publishEvent(
|
||||||
new CancelTargetAssignmentEvent(target, actionId, eventPublisherHolder.getApplicationId())));
|
new CancelTargetAssignmentEvent(action, eventPublisherHolder.getApplicationId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
// for testing
|
// for testing
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
|
|||||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation.CancelationType;
|
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation.CancelationType;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||||
|
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||||
|
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||||
@@ -580,19 +582,28 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
if (rolloutGroupActions.getContent().isEmpty()) {
|
if (rolloutGroupActions.getContent().isEmpty()) {
|
||||||
return 0L;
|
return 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<Action> newTargetAssignments = handleTargetAssignments(rolloutGroupActions);
|
||||||
|
|
||||||
final List<Action> targetAssignments = rolloutGroupActions.getContent().stream().map(JpaAction.class::cast)
|
if (!newTargetAssignments.isEmpty()) {
|
||||||
.map(this::closeActionIfSetWasAlreadyAssigned).filter(Objects::nonNull)
|
onlineDsAssignmentStrategy.sendDeploymentEvents(distributionSetId, newTargetAssignments);
|
||||||
.map(this::startScheduledActionIfNoCancelationHasToBeHandledFirst).filter(Objects::nonNull)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
if (!targetAssignments.isEmpty()) {
|
|
||||||
onlineDsAssignmentStrategy.sendDeploymentEvents(distributionSetId, targetAssignments);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rolloutGroupActions.getTotalElements();
|
return rolloutGroupActions.getTotalElements();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Action> handleTargetAssignments(final Page<Action> rolloutGroupActions) {
|
||||||
|
// Close actions already assigned and collect pending assignments
|
||||||
|
final List<JpaAction> pendingTargetAssignments = rolloutGroupActions.getContent().stream()
|
||||||
|
.map(JpaAction.class::cast).map(this::closeActionIfSetWasAlreadyAssigned).filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (pendingTargetAssignments.isEmpty()) {
|
||||||
|
return new ArrayList<>(pendingTargetAssignments);
|
||||||
|
}
|
||||||
|
// check if old actions needs to be canceled first
|
||||||
|
return startScheduledActionsAndHandleOpenCancellationFirst(pendingTargetAssignments);
|
||||||
|
}
|
||||||
|
|
||||||
private Page<Action> findActionsByRolloutAndRolloutGroupParent(final Long rolloutId,
|
private Page<Action> findActionsByRolloutAndRolloutGroupParent(final Long rolloutId,
|
||||||
final Long rolloutGroupParentId, final int limit) {
|
final Long rolloutGroupParentId, final int limit) {
|
||||||
@@ -630,41 +641,51 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
|||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JpaAction startScheduledActionIfNoCancelationHasToBeHandledFirst(final JpaAction action) {
|
private List<Action> startScheduledActionsAndHandleOpenCancellationFirst(final List<JpaAction> actions) {
|
||||||
// check if we need to override running update actions
|
if (!isMultiAssignmentsEnabled()) {
|
||||||
final List<Long> overrideObsoleteUpdateActions;
|
closeOrCancelOpenDeviceActions(actions);
|
||||||
|
}
|
||||||
|
final List<JpaAction> savedActions = activateActions(actions);
|
||||||
|
setInitialActionStatus(savedActions);
|
||||||
|
setAssignmentOnTargets(savedActions);
|
||||||
|
return Collections.unmodifiableList(savedActions);
|
||||||
|
}
|
||||||
|
|
||||||
if (isMultiAssignmentsEnabled()) {
|
private void closeOrCancelOpenDeviceActions(final List<JpaAction> actions){
|
||||||
overrideObsoleteUpdateActions = Collections.emptyList();
|
final List<Long> targetIds = actions.stream().map(JpaAction::getTarget).map(Target::getId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (isActionsAutocloseEnabled()) {
|
||||||
|
onlineDsAssignmentStrategy.closeObsoleteUpdateActions(targetIds);
|
||||||
} else {
|
} else {
|
||||||
final List<Long> targetId = Collections.singletonList(action.getTarget().getId());
|
onlineDsAssignmentStrategy.overrideObsoleteUpdateActions(targetIds);
|
||||||
if (isActionsAutocloseEnabled()) {
|
|
||||||
overrideObsoleteUpdateActions = Collections.emptyList();
|
|
||||||
onlineDsAssignmentStrategy.closeObsoleteUpdateActions(targetId);
|
|
||||||
} else {
|
|
||||||
overrideObsoleteUpdateActions = onlineDsAssignmentStrategy.overrideObsoleteUpdateActions(targetId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
action.setActive(true);
|
private List<JpaAction> activateActions(final List<JpaAction> actions){
|
||||||
action.setStatus(Status.RUNNING);
|
actions.forEach(action -> {
|
||||||
final JpaAction savedAction = actionRepository.save(action);
|
action.setActive(true);
|
||||||
|
action.setStatus(Status.RUNNING);
|
||||||
|
});
|
||||||
|
return actionRepository.saveAll(actions);
|
||||||
|
}
|
||||||
|
|
||||||
actionStatusRepository.save(onlineDsAssignmentStrategy.createActionStatus(savedAction, null));
|
private void setAssignmentOnTargets(final List<JpaAction> actions) {
|
||||||
|
final List<JpaTarget> assignedDsTargets = actions.stream().map(savedAction -> {
|
||||||
|
final JpaTarget mergedTarget = (JpaTarget) entityManager.merge(savedAction.getTarget());
|
||||||
|
mergedTarget.setAssignedDistributionSet(savedAction.getDistributionSet());
|
||||||
|
mergedTarget.setUpdateStatus(TargetUpdateStatus.PENDING);
|
||||||
|
return mergedTarget;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
final JpaTarget target = (JpaTarget) entityManager.merge(savedAction.getTarget());
|
targetRepository.saveAll(assignedDsTargets);
|
||||||
|
}
|
||||||
|
|
||||||
target.setAssignedDistributionSet(savedAction.getDistributionSet());
|
private void setInitialActionStatus(final List<JpaAction> actions) {
|
||||||
target.setUpdateStatus(TargetUpdateStatus.PENDING);
|
final List<JpaActionStatus> statusList = new ArrayList<>();
|
||||||
targetRepository.save(target);
|
for (final JpaAction action : actions) {
|
||||||
|
statusList.add(onlineDsAssignmentStrategy.createActionStatus(action, null));
|
||||||
// in case we canceled an action before for this target, then don't fire
|
|
||||||
// assignment event
|
|
||||||
if (overrideObsoleteUpdateActions.contains(savedAction.getId())) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
actionStatusRepository.saveAll(statusList);
|
||||||
return savedAction;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setSkipActionStatus(final JpaAction action) {
|
private void setSkipActionStatus(final JpaAction action) {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void sendTargetUpdatedEvents(final DistributionSet set, final List<JpaTarget> targets) {
|
public void sendTargetUpdatedEvents(final DistributionSet set, final List<JpaTarget> targets) {
|
||||||
targets.forEach(target -> {
|
targets.forEach(target -> {
|
||||||
target.setUpdateStatus(TargetUpdateStatus.IN_SYNC);
|
target.setUpdateStatus(TargetUpdateStatus.IN_SYNC);
|
||||||
sendTargetUpdatedEvent(target);
|
sendTargetUpdatedEvent(target);
|
||||||
@@ -78,19 +78,19 @@ public class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void closeActiveActions(final List<List<Long>> targetIds) {
|
public void closeActiveActions(final List<List<Long>> targetIds) {
|
||||||
// Not supported by offline case
|
// Not supported by offline case
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void setAssignedDistributionSetAndTargetStatus(final JpaDistributionSet set, final List<List<Long>> targetIds,
|
public void setAssignedDistributionSetAndTargetStatus(final JpaDistributionSet set, final List<List<Long>> targetIds,
|
||||||
final String currentUser) {
|
final String currentUser) {
|
||||||
targetIds.forEach(tIds -> targetRepository.setAssignedAndInstalledDistributionSetAndUpdateStatus(
|
targetIds.forEach(tIds -> targetRepository.setAssignedAndInstalledDistributionSetAndUpdateStatus(
|
||||||
TargetUpdateStatus.IN_SYNC, set, System.currentTimeMillis(), currentUser, tIds));
|
TargetUpdateStatus.IN_SYNC, set, System.currentTimeMillis(), currentUser, tIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JpaAction createTargetAction(final String initiatedBy, final TargetWithActionType targetWithActionType,
|
public JpaAction createTargetAction(final String initiatedBy, final TargetWithActionType targetWithActionType,
|
||||||
final List<JpaTarget> targets, final JpaDistributionSet set) {
|
final List<JpaTarget> targets, final JpaDistributionSet set) {
|
||||||
final JpaAction result = super.createTargetAction(initiatedBy, targetWithActionType, targets, set);
|
final JpaAction result = super.createTargetAction(initiatedBy, targetWithActionType, targets, set);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@@ -101,7 +101,7 @@ public class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JpaActionStatus createActionStatus(final JpaAction action, final String actionMessage) {
|
public JpaActionStatus createActionStatus(final JpaAction action, final String actionMessage) {
|
||||||
final JpaActionStatus result = super.createActionStatus(action, actionMessage);
|
final JpaActionStatus result = super.createActionStatus(action, actionMessage);
|
||||||
result.setStatus(Status.FINISHED);
|
result.setStatus(Status.FINISHED);
|
||||||
result.addMessage(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Action reported as offline deployment");
|
result.addMessage(RepositoryConstants.SERVER_MESSAGE_PREFIX + "Action reported as offline deployment");
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void sendTargetUpdatedEvents(final DistributionSet set, final List<JpaTarget> targets) {
|
public void sendTargetUpdatedEvents(final DistributionSet set, final List<JpaTarget> targets) {
|
||||||
targets.forEach(target -> {
|
targets.forEach(target -> {
|
||||||
target.setUpdateStatus(TargetUpdateStatus.PENDING);
|
target.setUpdateStatus(TargetUpdateStatus.PENDING);
|
||||||
sendTargetUpdatedEvent(target);
|
sendTargetUpdatedEvent(target);
|
||||||
@@ -62,7 +62,7 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void sendDeploymentEvents(final DistributionSetAssignmentResult assignmentResult) {
|
public void sendDeploymentEvents(final DistributionSetAssignmentResult assignmentResult) {
|
||||||
if (isMultiAssignmentsEnabled()) {
|
if (isMultiAssignmentsEnabled()) {
|
||||||
sendDeploymentEvents(Collections.singletonList(assignmentResult));
|
sendDeploymentEvents(Collections.singletonList(assignmentResult));
|
||||||
} else {
|
} else {
|
||||||
@@ -71,7 +71,7 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void sendDeploymentEvents(final List<DistributionSetAssignmentResult> assignmentResults) {
|
public void sendDeploymentEvents(final List<DistributionSetAssignmentResult> assignmentResults) {
|
||||||
if (isMultiAssignmentsEnabled()) {
|
if (isMultiAssignmentsEnabled()) {
|
||||||
sendDeploymentEvent(assignmentResults.stream().flatMap(result -> result.getAssignedEntity().stream())
|
sendDeploymentEvent(assignmentResults.stream().flatMap(result -> result.getAssignedEntity().stream())
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
@@ -80,7 +80,7 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendDeploymentEvents(final long distributionSetId, final List<Action> actions) {
|
public void sendDeploymentEvents(final long distributionSetId, final List<Action> actions) {
|
||||||
if (isMultiAssignmentsEnabled()) {
|
if (isMultiAssignmentsEnabled()) {
|
||||||
sendDeploymentEvent(actions);
|
sendDeploymentEvent(actions);
|
||||||
return;
|
return;
|
||||||
@@ -94,7 +94,7 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
List<JpaTarget> findTargetsForAssignment(final List<String> controllerIDs, final long setId) {
|
public List<JpaTarget> findTargetsForAssignment(final List<String> controllerIDs, final long setId) {
|
||||||
final Function<List<String>, List<JpaTarget>> mapper;
|
final Function<List<String>, List<JpaTarget>> mapper;
|
||||||
if (isMultiAssignmentsEnabled()) {
|
if (isMultiAssignmentsEnabled()) {
|
||||||
mapper = ids -> targetRepository.findAll(TargetSpecifications.hasControllerIdIn(ids));
|
mapper = ids -> targetRepository.findAll(TargetSpecifications.hasControllerIdIn(ids));
|
||||||
@@ -107,18 +107,18 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Set<Long> cancelActiveActions(final List<List<Long>> targetIds) {
|
public Set<Long> cancelActiveActions(final List<List<Long>> targetIds) {
|
||||||
return targetIds.stream().map(this::overrideObsoleteUpdateActions).flatMap(Collection::stream)
|
return targetIds.stream().map(this::overrideObsoleteUpdateActions).flatMap(Collection::stream)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void closeActiveActions(final List<List<Long>> targetIds) {
|
public void closeActiveActions(final List<List<Long>> targetIds) {
|
||||||
targetIds.forEach(this::closeObsoleteUpdateActions);
|
targetIds.forEach(this::closeObsoleteUpdateActions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void setAssignedDistributionSetAndTargetStatus(final JpaDistributionSet set, final List<List<Long>> targetIds,
|
public void setAssignedDistributionSetAndTargetStatus(final JpaDistributionSet set, final List<List<Long>> targetIds,
|
||||||
final String currentUser) {
|
final String currentUser) {
|
||||||
targetIds.forEach(tIds -> targetRepository.setAssignedDistributionSetAndUpdateStatus(TargetUpdateStatus.PENDING,
|
targetIds.forEach(tIds -> targetRepository.setAssignedDistributionSetAndUpdateStatus(TargetUpdateStatus.PENDING,
|
||||||
set, System.currentTimeMillis(), currentUser, tIds));
|
set, System.currentTimeMillis(), currentUser, tIds));
|
||||||
@@ -126,7 +126,7 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
JpaAction createTargetAction(final String initiatedBy, final TargetWithActionType targetWithActionType,
|
public JpaAction createTargetAction(final String initiatedBy, final TargetWithActionType targetWithActionType,
|
||||||
final List<JpaTarget> targets, final JpaDistributionSet set) {
|
final List<JpaTarget> targets, final JpaDistributionSet set) {
|
||||||
final JpaAction result = super.createTargetAction(initiatedBy, targetWithActionType, targets, set);
|
final JpaAction result = super.createTargetAction(initiatedBy, targetWithActionType, targets, set);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@@ -136,7 +136,7 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
JpaActionStatus createActionStatus(final JpaAction action, final String actionMessage) {
|
public JpaActionStatus createActionStatus(final JpaAction action, final String actionMessage) {
|
||||||
final JpaActionStatus result = super.createActionStatus(action, actionMessage);
|
final JpaActionStatus result = super.createActionStatus(action, actionMessage);
|
||||||
result.setStatus(Status.RUNNING);
|
result.setStatus(Status.RUNNING);
|
||||||
return result;
|
return result;
|
||||||
@@ -146,7 +146,7 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
|||||||
if (isMultiAssignmentsEnabled()) {
|
if (isMultiAssignmentsEnabled()) {
|
||||||
sendMultiActionCancelEvent(action);
|
sendMultiActionCancelEvent(action);
|
||||||
} else {
|
} else {
|
||||||
cancelAssignDistributionSetEvent(action.getTarget(), action.getId());
|
cancelAssignDistributionSetEvent(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -119,6 +119,31 @@ public class RemoteTenantAwareEventTest extends AbstractRemoteEventTest {
|
|||||||
assertTargetAssignDistributionSetEvent(action, remoteEventJackson);
|
assertTargetAssignDistributionSetEvent(action, remoteEventJackson);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Verifies that a TargetAssignDistributionSetEvent can be properly serialized and deserialized")
|
||||||
|
public void testCancelTargetAssignmentEvent() {
|
||||||
|
|
||||||
|
final DistributionSet dsA = testdataFactory.createDistributionSet("");
|
||||||
|
|
||||||
|
final JpaAction generateAction = new JpaAction();
|
||||||
|
generateAction.setActionType(ActionType.FORCED);
|
||||||
|
generateAction.setTarget(testdataFactory.createTarget("Test"));
|
||||||
|
generateAction.setDistributionSet(dsA);
|
||||||
|
generateAction.setStatus(Status.RUNNING);
|
||||||
|
generateAction.setInitiatedBy(tenantAware.getCurrentUsername());
|
||||||
|
|
||||||
|
final Action action = actionRepository.save(generateAction);
|
||||||
|
|
||||||
|
final CancelTargetAssignmentEvent cancelEvent = new CancelTargetAssignmentEvent(action,
|
||||||
|
serviceMatcher.getServiceId());
|
||||||
|
|
||||||
|
final CancelTargetAssignmentEvent remoteEventProtoStuff = createProtoStuffEvent(cancelEvent);
|
||||||
|
assertCancelTargetAssignmentEvent(action, remoteEventProtoStuff);
|
||||||
|
|
||||||
|
final CancelTargetAssignmentEvent remoteEventJackson = createJacksonEvent(cancelEvent);
|
||||||
|
assertCancelTargetAssignmentEvent(action, remoteEventJackson);
|
||||||
|
}
|
||||||
|
|
||||||
private void assertTargetAssignDistributionSetEvent(final Action action,
|
private void assertTargetAssignDistributionSetEvent(final Action action,
|
||||||
final TargetAssignDistributionSetEvent underTest) {
|
final TargetAssignDistributionSetEvent underTest) {
|
||||||
|
|
||||||
@@ -128,4 +153,12 @@ public class RemoteTenantAwareEventTest extends AbstractRemoteEventTest {
|
|||||||
assertThat(actionProperties).isEqualToComparingFieldByField(new ActionProperties(action));
|
assertThat(actionProperties).isEqualToComparingFieldByField(new ActionProperties(action));
|
||||||
assertThat(underTest.getDistributionSetId()).isEqualTo(action.getDistributionSet().getId());
|
assertThat(underTest.getDistributionSetId()).isEqualTo(action.getDistributionSet().getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertCancelTargetAssignmentEvent(final Action action, final CancelTargetAssignmentEvent underTest) {
|
||||||
|
assertThat(underTest.getActions().size()).isEqualTo(1);
|
||||||
|
final ActionProperties actionProperties = underTest.getActions().get(action.getTarget().getControllerId());
|
||||||
|
assertThat(actionProperties).isNotNull();
|
||||||
|
assertThat(actionProperties).isEqualToComparingFieldByField(new ActionProperties(action));
|
||||||
|
assertThat(underTest.getActionPropertiesForController(action.getTarget().getControllerId())).isPresent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,17 +36,6 @@ public class TargetEventTest extends AbstractRemoteEntityEventTest<Target> {
|
|||||||
assertAndCreateRemoteEvent(TargetUpdatedEvent.class);
|
assertAndCreateRemoteEvent(TargetUpdatedEvent.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@Description("Verifies that cancel target assignment event works")
|
|
||||||
public void testCancelTargetAssignmentEvent() {
|
|
||||||
final Target target = createEntity();
|
|
||||||
final CancelTargetAssignmentEvent assignmentEvent = new CancelTargetAssignmentEvent(target, 1L, "node");
|
|
||||||
final CancelTargetAssignmentEvent underTest = (CancelTargetAssignmentEvent) assertEntity(target,
|
|
||||||
assignmentEvent);
|
|
||||||
|
|
||||||
assertThat(underTest.getActionId()).isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Target createEntity() {
|
protected Target createEntity() {
|
||||||
return testdataFactory.createTarget("12345");
|
return testdataFactory.createTarget("12345");
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
|
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedEvent;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
|
|||||||
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
|
import org.eclipse.hawkbit.repository.event.remote.CancelTargetAssignmentEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdatedEvent;
|
||||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||||
@@ -265,7 +265,7 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
@Expect(type = TargetUpdatedEvent.class, count = 40),
|
@Expect(type = TargetUpdatedEvent.class, count = 40),
|
||||||
@Expect(type = TargetAssignDistributionSetEvent.class, count = 2),
|
@Expect(type = TargetAssignDistributionSetEvent.class, count = 2),
|
||||||
@Expect(type = ActionCreatedEvent.class, count = 40),
|
@Expect(type = ActionCreatedEvent.class, count = 40),
|
||||||
@Expect(type = CancelTargetAssignmentEvent.class, count = 20),
|
@Expect(type = CancelTargetAssignmentEvent.class, count = 1),
|
||||||
@Expect(type = ActionUpdatedEvent.class, count = 20),
|
@Expect(type = ActionUpdatedEvent.class, count = 20),
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
|
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6) })
|
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6) })
|
||||||
@@ -945,11 +945,11 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
|||||||
@Expect(type = TargetUpdatedEvent.class, count = 3 * 4),
|
@Expect(type = TargetUpdatedEvent.class, count = 3 * 4),
|
||||||
@Expect(type = ActionCreatedEvent.class, count = 3 * 4),
|
@Expect(type = ActionCreatedEvent.class, count = 3 * 4),
|
||||||
@Expect(type = ActionUpdatedEvent.class, count = 4 * 2),
|
@Expect(type = ActionUpdatedEvent.class, count = 4 * 2),
|
||||||
@Expect(type = CancelTargetAssignmentEvent.class, count = 4 * 2),
|
@Expect(type = CancelTargetAssignmentEvent.class, count = 2),
|
||||||
@Expect(type = DistributionSetCreatedEvent.class, count = 3),
|
@Expect(type = DistributionSetCreatedEvent.class, count = 3),
|
||||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 9),
|
@Expect(type = SoftwareModuleCreatedEvent.class, count = 9),
|
||||||
@Expect(type = TargetAssignDistributionSetEvent.class, count = 3) })
|
@Expect(type = TargetAssignDistributionSetEvent.class, count = 3) })
|
||||||
void multipleDeployments() throws InterruptedException {
|
void multipleDeployments() {
|
||||||
final String undeployedTargetPrefix = "undep-T";
|
final String undeployedTargetPrefix = "undep-T";
|
||||||
final int noOfUndeployedTargets = 5;
|
final int noOfUndeployedTargets = 5;
|
||||||
|
|
||||||
|
|||||||
@@ -131,7 +131,8 @@ final class DdiApiModelProperties {
|
|||||||
|
|
||||||
static final String ACTION_HISTORY_RESP_STATUS = "Status of the deployment based on previous feedback by the device.";
|
static final String ACTION_HISTORY_RESP_STATUS = "Status of the deployment based on previous feedback by the device.";
|
||||||
|
|
||||||
static final String ACTION_HISTORY_RESP_MESSAGES = "Messages are previously sent to the feedback channel in LIFO order by the device.";
|
static final String ACTION_HISTORY_RESP_MESSAGES = "Messages are previously sent to the feedback channel in LIFO order by the device. "
|
||||||
|
+ "Note: The first status message is set by the system and describes the trigger of the deployment";
|
||||||
|
|
||||||
static final String UPDATE_MODE = "Optional parameter to specify the update mode that should be applied when updating target attributes. "
|
static final String UPDATE_MODE = "Optional parameter to specify the update mode that should be applied when updating target attributes. "
|
||||||
+ "Valid values are 'merge', 'replace', and 'remove'. Defaults to 'merge'.";
|
+ "Valid values are 'merge', 'replace', and 'remove'. Defaults to 'merge'.";
|
||||||
|
|||||||
@@ -382,7 +382,11 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
|
|||||||
fieldWithPath("deployment.chunks[].part").description(DdiApiModelProperties.CHUNK_TYPE),
|
fieldWithPath("deployment.chunks[].part").description(DdiApiModelProperties.CHUNK_TYPE),
|
||||||
fieldWithPath("deployment.chunks[].name").description(DdiApiModelProperties.CHUNK_NAME),
|
fieldWithPath("deployment.chunks[].name").description(DdiApiModelProperties.CHUNK_NAME),
|
||||||
fieldWithPath("deployment.chunks[].version")
|
fieldWithPath("deployment.chunks[].version")
|
||||||
.description(DdiApiModelProperties.CHUNK_VERSION))));
|
.description(DdiApiModelProperties.CHUNK_VERSION),
|
||||||
|
fieldWithPath("actionHistory.status")
|
||||||
|
.description(DdiApiModelProperties.ACTION_HISTORY_RESP_STATUS),
|
||||||
|
fieldWithPath("actionHistory.messages")
|
||||||
|
.description(DdiApiModelProperties.ACTION_HISTORY_RESP_MESSAGES))));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user