Support for action cancellation in ddi controller sdk (#2846)
* Support for action cancellation in ddi controller sdk Signed-off-by: strailov <Stanislav.Trailov@bosch.io> * minor refactor Signed-off-by: strailov <Stanislav.Trailov@bosch.io> * add comment for cancel action Signed-off-by: strailov <Stanislav.Trailov@bosch.io> * minor refactor Signed-off-by: strailov <Stanislav.Trailov@bosch.io> --------- Signed-off-by: strailov <Stanislav.Trailov@bosch.io>
This commit is contained in:
committed by
GitHub
parent
556bad652f
commit
bfc0e7e550
@@ -24,12 +24,16 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.ddi.json.model.DdiActionFeedback;
|
||||
import org.eclipse.hawkbit.ddi.json.model.DdiChunk;
|
||||
import org.eclipse.hawkbit.ddi.json.model.DdiConfigData;
|
||||
import org.eclipse.hawkbit.ddi.json.model.DdiConfirmationFeedback;
|
||||
import org.eclipse.hawkbit.ddi.json.model.DdiControllerBase;
|
||||
import org.eclipse.hawkbit.ddi.json.model.DdiDeployment;
|
||||
import org.eclipse.hawkbit.ddi.json.model.DdiDeploymentBase;
|
||||
import org.eclipse.hawkbit.ddi.json.model.DdiProgress;
|
||||
import org.eclipse.hawkbit.ddi.json.model.DdiResult;
|
||||
import org.eclipse.hawkbit.ddi.json.model.DdiStatus;
|
||||
import org.eclipse.hawkbit.ddi.json.model.DdiUpdateMode;
|
||||
import org.eclipse.hawkbit.ddi.rest.api.DdiRootControllerRestApi;
|
||||
import org.eclipse.hawkbit.sdk.Certificate;
|
||||
@@ -55,6 +59,7 @@ public class DdiController {
|
||||
|
||||
private static final String DEPLOYMENT_BASE_LINK = "deploymentBase";
|
||||
private static final String CONFIRMATION_BASE_LINK = "confirmationBase";
|
||||
private static final String CANCEL_ACTION_LINK = "cancelAction";
|
||||
|
||||
private final Tenant tenant;
|
||||
private final Controller controller;
|
||||
@@ -147,6 +152,19 @@ public class DdiController {
|
||||
}
|
||||
}
|
||||
|
||||
public void sendCancelFeedback(long actionId) {
|
||||
try {
|
||||
log.info(LOG_PREFIX + "Sending cancelation feedback for action with id : {}", getTenantId(), getControllerId(), actionId);
|
||||
getDdiApi().postCancelActionFeedback(new DdiActionFeedback(
|
||||
new DdiStatus(DdiStatus.ExecutionStatus.CLOSED, new DdiResult(DdiResult.FinalResult.SUCCESS,
|
||||
new DdiProgress(100, 100)), 200, List.of("Successfully cancelled by the controller."))
|
||||
), getTenantId(), getControllerId(), actionId);
|
||||
} catch (Exception ex) {
|
||||
log.error(LOG_PREFIX + "Failed to send cancelation feedback {}", getTenantId(), getControllerId(),
|
||||
actionId, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void poll() {
|
||||
log.debug(LOG_PREFIX + " Polling ...", getTenantId(), getControllerId());
|
||||
Optional.ofNullable(executorService).ifPresent(executor ->
|
||||
@@ -165,31 +183,21 @@ public class DdiController {
|
||||
.ifPresentOrElse(actionWithDeployment -> {
|
||||
final long actionId = actionWithDeployment.getKey();
|
||||
if (currentActionId == null) {
|
||||
if (lastActionId != null && lastActionId == actionId) {
|
||||
log.info(LOG_PREFIX + "Still receive the last action {}",
|
||||
getTenantId(), getControllerId(), actionId);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(LOG_PREFIX + "Process action {}", getTenantId(), getControllerId(),
|
||||
actionId);
|
||||
final DdiDeployment deployment = actionWithDeployment.getValue().getDeployment();
|
||||
final DdiDeployment.HandlingType updateType = deployment.getUpdate();
|
||||
final List<DdiChunk> modules = deployment.getChunks();
|
||||
|
||||
currentActionId = actionId;
|
||||
executor.submit(updateHandler.getUpdateProcessor(this, updateType, modules));
|
||||
processAction(actionId, actionWithDeployment, executor);
|
||||
} else if (currentActionId != actionId) {
|
||||
// TODO - cancel and start new one?
|
||||
// currentActionId had failed to be processed and new one had been initiated
|
||||
// try cancel current and process new one
|
||||
log.info(LOG_PREFIX + "Action {} is canceled while in process (new {})!", getTenantId(),
|
||||
getControllerId(), currentActionId, actionId);
|
||||
cancelActionByCancellationLink(controllerBase, currentActionId);
|
||||
currentActionId = null;
|
||||
// then process the new one
|
||||
poll();
|
||||
} // else same action - already processing
|
||||
}, () -> {
|
||||
if (currentActionId != null) {
|
||||
// TODO - cancel current?
|
||||
log.info(LOG_PREFIX + "Action {} is canceled while in process (not returned)!", getTenantId(),
|
||||
getControllerId(), getCurrentActionId());
|
||||
}
|
||||
cancelActionByCancellationLink(controllerBase, -1);
|
||||
// reset current action id - on next poll should be available deploymentBase
|
||||
currentActionId = null;
|
||||
});
|
||||
executor.schedule(this::poll, getPollMillis(controllerBase), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
@@ -198,6 +206,23 @@ public class DdiController {
|
||||
executor.schedule(this::poll, DEFAULT_POLL_MS, TimeUnit.MILLISECONDS)));
|
||||
}
|
||||
|
||||
private void processAction(final long actionId, final Map.Entry<Long,DdiDeploymentBase> actionWithDeployment, final ScheduledExecutorService executor) {
|
||||
if (lastActionId != null && lastActionId == actionId) {
|
||||
log.info(LOG_PREFIX + "Still receive the last action {}",
|
||||
getTenantId(), getControllerId(), actionId);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(LOG_PREFIX + "Process action {}", getTenantId(), getControllerId(),
|
||||
actionId);
|
||||
final DdiDeployment deployment = actionWithDeployment.getValue().getDeployment();
|
||||
final DdiDeployment.HandlingType updateType = deployment.getUpdate();
|
||||
final List<DdiChunk> modules = deployment.getChunks();
|
||||
|
||||
currentActionId = actionId;
|
||||
executor.submit(updateHandler.getUpdateProcessor(this, updateType, modules));
|
||||
}
|
||||
|
||||
private Optional<DdiControllerBase> getControllerBase() {
|
||||
log.trace(LOG_PREFIX + "Polling ...", getTenantId(), getControllerId());
|
||||
final ResponseEntity<DdiControllerBase> poll;
|
||||
@@ -216,6 +241,16 @@ public class DdiController {
|
||||
return Optional.ofNullable(poll.getBody());
|
||||
}
|
||||
|
||||
private void cancelActionByCancellationLink(DdiControllerBase controllerBase, long actionToBeCanceled) {
|
||||
getRequiredLink(controllerBase, CANCEL_ACTION_LINK).ifPresentOrElse(link -> {
|
||||
// action is in CANCELING state - send cancel feedback
|
||||
final long actionId = actionToBeCanceled == -1 ? getActionIdFromCancellationLink(link) : actionToBeCanceled;
|
||||
log.info(LOG_PREFIX + "Cancelling current action {}", getTenantId(), getControllerId(), actionId);
|
||||
sendCancelFeedback(actionId);
|
||||
}, () -> log.info(LOG_PREFIX + "Action {} is canceled while in process (not returned)!", getTenantId(), getControllerId(), getCurrentActionId())
|
||||
);
|
||||
}
|
||||
|
||||
private Optional<Link> getRequiredLink(final DdiControllerBase controllerBase, final String nameOfTheLink) {
|
||||
final Optional<Link> link = controllerBase != null ? controllerBase.getLink(nameOfTheLink) : Optional.empty();
|
||||
link.ifPresentOrElse(
|
||||
@@ -262,4 +297,10 @@ public class DdiController {
|
||||
final String href = link.getHref();
|
||||
return Long.parseLong(href.substring(href.lastIndexOf('/') + 1, href.indexOf('?')));
|
||||
}
|
||||
|
||||
private long getActionIdFromCancellationLink(final Link link) {
|
||||
final String href = link.getHref();
|
||||
final String[] split = href.split("/");
|
||||
return Long.parseLong(split[split.length - 1]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user