SDK improvements (#1693)

Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-03-19 17:35:14 +02:00
committed by GitHub
parent 50d34dd81e
commit a37702744c
8 changed files with 90 additions and 108 deletions

View File

@@ -73,11 +73,13 @@ public class DdiController {
private volatile ScheduledExecutorService executorService;
private volatile Long currentActionId;
private volatile Long lastActionId;
/**
* Creates a new device instance.
*
* @param tenant the tenant of the device belongs to
* @param controller the the controller
* @param controller the controller
* @param hawkbitClient a factory for creating to {@link DdiRootControllerRestApi} (and used)
* for communication to hawkBit
*/
@@ -102,6 +104,7 @@ public class DdiController {
public void stop() {
executorService = null;
lastActionId = null;
currentActionId = null;
}
@@ -121,6 +124,12 @@ public class DdiController {
getRequiredLink(controllerBase, DEPLOYMENT_BASE_LINK).flatMap(this::getActionWithDeployment).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();
@@ -132,13 +141,13 @@ public class DdiController {
updateHandler.getUpdateProcessor(this, updateType, modules));
} else if (currentActionId != actionId) {
// TODO - cancel and start new one?
log.info(LOG_PREFIX + "Action {} is canceled while in process!", getTenantId(),
getControllerId(), getCurrentActionId());
log.info(LOG_PREFIX + "Action {} is canceled while in process (new {})!", getTenantId(),
getControllerId(), currentActionId, actionId);
} // else same action - already processing
}, () -> {
if (currentActionId != null) {
// TODO - cancel current?
log.info(LOG_PREFIX + "Action {} is canceled while in process!", getTenantId(),
log.info(LOG_PREFIX + "Action {} is canceled while in process (not returned)!", getTenantId(),
getControllerId(), getCurrentActionId());
}
});
@@ -218,10 +227,17 @@ public class DdiController {
void sendFeedback(final UpdateStatus updateStatus) {
log.debug(LOG_PREFIX + "Send feedback {} -> {}", getTenantId(), getControllerId(), currentActionId, updateStatus);
getDdiApi().postDeploymentBaseActionFeedback(
updateStatus.feedback(), getTenantId(), getControllerId(), currentActionId);
try {
getDdiApi().postDeploymentBaseActionFeedback(updateStatus.feedback(), getTenantId(), getControllerId(),
currentActionId);
} catch (final RuntimeException e) {
log.error(LOG_PREFIX + "Failed to send feedback {} -> {}", getTenantId(), getControllerId(),
currentActionId, updateStatus, e);
}
if (updateStatus.status() == UpdateStatus.Status.SUCCESSFUL ||
updateStatus.status() == UpdateStatus.Status.ERROR) {
updateStatus.status() == UpdateStatus.Status.FAILURE) {
lastActionId = currentActionId;
currentActionId = null;
}
}

View File

@@ -95,25 +95,27 @@ public interface UpdateHandler {
@Override
public void run() {
ddiController.sendFeedback(new UpdateStatus(UpdateStatus.Status.RUNNING, List.of("Update begins!")));
ddiController.sendFeedback(new UpdateStatus(UpdateStatus.Status.PROCEEDING, List.of("Update begin ...")));
if (!CollectionUtils.isEmpty(modules)) {
try {
final UpdateStatus updateStatus = download();
ddiController.sendFeedback(updateStatus);
if (updateStatus.status() == UpdateStatus.Status.ERROR) {
if (updateStatus.status() == UpdateStatus.Status.FAILURE) {
return;
} else {
ddiController.sendFeedback(update());
if (updateType != DdiDeployment.HandlingType.SKIP) {
ddiController.sendFeedback(update());
}
}
} finally {
cleanup();
}
}
if (updateType != DdiDeployment.HandlingType.SKIP) {
if (updateType == DdiDeployment.HandlingType.SKIP) {
ddiController.sendFeedback(
new UpdateStatus(UpdateStatus.Status.SUCCESSFUL, List.of("Update complete!")));
new UpdateStatus(UpdateStatus.Status.SUCCESSFUL, List.of("Update (download-only) completed.")));
}
}
@@ -126,11 +128,11 @@ public interface UpdateHandler {
protected UpdateStatus download() {
ddiController.sendFeedback(
new UpdateStatus(
UpdateStatus.Status.DOWNLOADING,
UpdateStatus.Status.DOWNLOAD,
modules.stream().flatMap(mod -> mod.getArtifacts().stream())
.map(art -> "Download starts for: " + art.getFilename() +
.map(art -> "Download start for: " + art.getFilename() +
" with size " + art.getSize() +
" and hashes " + art.getHashes())
" and hashes " + art.getHashes() + " ...")
.collect(Collectors.toList())));
log.info(LOG_PREFIX + "Start download", ddiController.getTenantId(), ddiController.getControllerId());
@@ -146,28 +148,28 @@ public interface UpdateHandler {
}
}));
log.info(LOG_PREFIX + "Download complete", ddiController.getTenantId(), ddiController.getControllerId());
log.info(LOG_PREFIX + "Download complete.", ddiController.getTenantId(), ddiController.getControllerId());
final List<String> messages = new LinkedList<>();
messages.add("Download complete!");
messages.add("Download complete.");
updateStatusList.forEach(download -> messages.addAll(download.messages()));
return new UpdateStatus(
updateStatusList.stream().anyMatch(status -> status.status() == UpdateStatus.Status.ERROR) ?
UpdateStatus.Status.ERROR : UpdateStatus.Status.DOWNLOADED,
updateStatusList.stream().anyMatch(status -> status.status() == UpdateStatus.Status.FAILURE) ?
UpdateStatus.Status.FAILURE : UpdateStatus.Status.DOWNLOADED,
messages);
}
/**
* Extension point. Called after all artifacts has been successfully downloadec. An overriding implementation
* Extension point. Called after all artifacts has been successfully downloaded. An overriding implementation
* may get the {@link #downloads} map and apply them
*/
protected UpdateStatus update() {
log.info(LOG_PREFIX + "Updated", ddiController.getTenantId(), ddiController.getControllerId());
return new UpdateStatus(UpdateStatus.Status.SUCCESSFUL, List.of("Update applied"));
return new UpdateStatus(UpdateStatus.Status.SUCCESSFUL, List.of("Update complete."));
}
/**
* Extension point. Called after download and update has been finished. By default it deletes all downloaded
* Extension point. Called after download and update has been finished. By default, it deletes all downloaded
* files (if any).
*/
protected void cleanup() {
@@ -189,8 +191,7 @@ public interface UpdateHandler {
artifact.getLink("download").ifPresentOrElse(
// HTTPS
link -> status.add(downloadUrl(link.getHref(), gatewayToken, targetToken,
artifact.getHashes(), artifact.getSize()))
,
artifact.getHashes(), artifact.getSize())),
// HTTP
() -> status.add(downloadUrl(
artifact.getLink("download-http")
@@ -216,7 +217,7 @@ public interface UpdateHandler {
log.error(LOG_PREFIX + "Failed to download {}",
ddiController.getTenantId(), ddiController.getControllerId(), url, e);
return new UpdateStatus(
UpdateStatus.Status.ERROR,
UpdateStatus.Status.FAILURE,
List.of("Failed to download " + url + ": " + e.getMessage()));
}
}
@@ -273,7 +274,7 @@ public interface UpdateHandler {
ddiController.getTenantId(), ddiController.getControllerId());
}
downloadHandler.finished(ArtifactHandler.DownloadHandler.Status.ERROR);
return new UpdateStatus(UpdateStatus.Status.ERROR, List.of(message));
return new UpdateStatus(UpdateStatus.Status.FAILURE, List.of(message));
}
});
}

View File

@@ -23,6 +23,21 @@ public record UpdateStatus(Status status, List<String> messages) {
*/
public enum Status {
/**
* Update is running (intermediate status).
*/
PROCEEDING(DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.NONE, null),
/**
* Device starts to download.
*/
DOWNLOAD(DdiStatus.ExecutionStatus.DOWNLOAD, DdiResult.FinalResult.NONE, null),
/**
* Device is finished with downloading.
*/
DOWNLOADED(DdiStatus.ExecutionStatus.DOWNLOADED, DdiResult.FinalResult.NONE, null),
/**
* Update has been successful and response the successful update.
*/
@@ -31,22 +46,7 @@ public record UpdateStatus(Status status, List<String> messages) {
/**
* Update has been not successful and response the error update.
*/
ERROR(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.FAILURE, null),
/**
* Update is running (intermediate status).
*/
RUNNING(DdiStatus.ExecutionStatus.PROCEEDING, DdiResult.FinalResult.NONE, null),
/**
* Device starts to download.
*/
DOWNLOADING(DdiStatus.ExecutionStatus.DOWNLOAD, DdiResult.FinalResult.NONE, null),
/**
* Device is finished with downloading.
*/
DOWNLOADED(DdiStatus.ExecutionStatus.DOWNLOADED, DdiResult.FinalResult.NONE, null);
FAILURE(DdiStatus.ExecutionStatus.CLOSED, DdiResult.FinalResult.FAILURE, null);
private final DdiStatus.ExecutionStatus executionStatus;
private final DdiResult.FinalResult finalResult;