use of com.aws.greengrass.deployment.exceptions.ServiceUpdateException in project aws-greengrass-nucleus by aws-greengrass.
the class KernelUpdateDeploymentTask method call.
@SuppressWarnings({ "PMD.AvoidDuplicateLiterals" })
@Override
public DeploymentResult call() {
Deployment.DeploymentStage stage = deployment.getDeploymentStage();
try {
List<GreengrassService> servicesToTrack = kernel.orderedDependencies().stream().filter(GreengrassService::shouldAutoStart).filter(o -> !kernel.getMain().equals(o)).collect(Collectors.toList());
long mergeTimestamp = kernel.getConfig().lookup("system", "rootpath").getModtime();
logger.atDebug().kv("serviceToTrack", servicesToTrack).kv("mergeTime", mergeTimestamp).log("Nucleus update workflow waiting for services to complete update");
DeploymentConfigMerger.waitForServicesToStart(servicesToTrack, mergeTimestamp);
DeploymentResult result = null;
if (KERNEL_ACTIVATION.equals(stage)) {
result = new DeploymentResult(DeploymentResult.DeploymentStatus.SUCCESSFUL, null);
} else if (KERNEL_ROLLBACK.equals(stage)) {
result = new DeploymentResult(DeploymentResult.DeploymentStatus.FAILED_ROLLBACK_COMPLETE, getDeploymentStatusDetails());
}
componentManager.cleanupStaleVersions();
return result;
} catch (InterruptedException e) {
logger.atError("deployment-interrupted", e).log();
try {
saveDeploymentStatusDetails(e.getMessage());
} catch (IOException ioException) {
logger.atError().log("Failed to persist deployment error information", ioException);
}
// Interrupted workflow. Shutdown kernel and retry this stage.
kernel.shutdown(30, REQUEST_RESTART);
return null;
} catch (ServiceUpdateException e) {
logger.atError("deployment-errored", e).log();
if (KERNEL_ACTIVATION.equals(stage)) {
try {
deployment.setDeploymentStage(KERNEL_ROLLBACK);
saveDeploymentStatusDetails(e.getMessage());
// Rollback workflow. Flip symlinks and restart kernel
kernel.getContext().get(KernelAlternatives.class).prepareRollback();
kernel.shutdown(30, REQUEST_RESTART);
} catch (IOException ioException) {
logger.atError().log("Failed to set up Nucleus rollback directory", ioException);
return new DeploymentResult(DeploymentResult.DeploymentStatus.FAILED_UNABLE_TO_ROLLBACK, e);
}
return null;
} else if (KERNEL_ROLLBACK.equals(stage)) {
logger.atError().log("Nucleus update workflow failed on rollback", e);
return new DeploymentResult(DeploymentResult.DeploymentStatus.FAILED_UNABLE_TO_ROLLBACK, getDeploymentStatusDetails());
}
return null;
}
}
use of com.aws.greengrass.deployment.exceptions.ServiceUpdateException in project aws-greengrass-nucleus by aws-greengrass.
the class DefaultActivator method activate.
@Override
@SuppressWarnings("PMD.PrematureDeclaration")
public void activate(Map<String, Object> newConfig, Deployment deployment, CompletableFuture<DeploymentResult> totallyCompleteFuture) {
Map<String, Object> serviceConfig;
if (newConfig.containsKey(SERVICES_NAMESPACE_TOPIC)) {
serviceConfig = (Map<String, Object>) newConfig.get(SERVICES_NAMESPACE_TOPIC);
} else {
serviceConfig = new HashMap<>();
}
DeploymentDocument deploymentDocument = deployment.getDeploymentDocumentObj();
if (isAutoRollbackRequested(deploymentDocument) && !takeConfigSnapshot(totallyCompleteFuture)) {
return;
}
DeploymentConfigMerger.AggregateServicesChangeManager servicesChangeManager = new DeploymentConfigMerger.AggregateServicesChangeManager(kernel, serviceConfig);
// Get the timestamp before updateMap(). It will be used to check whether services have started.
long mergeTime = System.currentTimeMillis();
updateConfiguration(deploymentDocument.getTimestamp(), newConfig);
// wait until topic listeners finished processing mergeMap changes.
Throwable setDesiredStateFailureCause = kernel.getContext().runOnPublishQueueAndWait(() -> {
// polling to wait for all services to be started.
servicesChangeManager.startNewServices();
// Close unloadable service instances and initiate with new config
servicesChangeManager.replaceUnloadableService();
// Restart any services that may have been broken before this deployment
// This is added to allow deployments to fix broken services
servicesChangeManager.reinstallBrokenServices();
});
if (setDesiredStateFailureCause != null) {
handleFailure(servicesChangeManager, deploymentDocument, totallyCompleteFuture, setDesiredStateFailureCause);
return;
}
try {
Set<GreengrassService> servicesToTrack = servicesChangeManager.servicesToTrack();
logger.atDebug(MERGE_CONFIG_EVENT_KEY).kv("serviceToTrack", servicesToTrack).kv("mergeTime", mergeTime).log("Applied new service config. Waiting for services to complete update");
waitForServicesToStart(servicesToTrack, mergeTime);
logger.atDebug(MERGE_CONFIG_EVENT_KEY).log("new/updated services are running, will now remove old services");
servicesChangeManager.removeObsoleteServices();
logger.atInfo(MERGE_CONFIG_EVENT_KEY).kv(DEPLOYMENT_ID_LOG_KEY, deploymentDocument.getDeploymentId()).log("All services updated");
totallyCompleteFuture.complete(new DeploymentResult(DeploymentResult.DeploymentStatus.SUCCESSFUL, null));
} catch (InterruptedException | ExecutionException | ServiceUpdateException | ServiceLoadException e) {
handleFailure(servicesChangeManager, deploymentDocument, totallyCompleteFuture, e);
}
}
use of com.aws.greengrass.deployment.exceptions.ServiceUpdateException in project aws-greengrass-nucleus by aws-greengrass.
the class BootstrapManager method executeOneBootstrapTask.
/**
* Execute the given bootstrap task.
*
* @param next BootstrapTaskStatus object
* @return 100 if kernel restart is needed, 101 if device reboot is needed, 0 if no-op.
*/
protected int executeOneBootstrapTask(BootstrapTaskStatus next) throws ServiceUpdateException {
Objects.requireNonNull(next);
try {
int exitCode = kernel.locate(next.getComponentName()).bootstrap();
next.setStatus(DONE);
next.setExitCode(exitCode);
return exitCode;
} catch (InterruptedException | TimeoutException | ServiceLoadException e) {
throw new ServiceUpdateException(e);
}
}
use of com.aws.greengrass.deployment.exceptions.ServiceUpdateException in project aws-greengrass-nucleus by aws-greengrass.
the class DeploymentConfigMerger method mergeInNewConfig.
/**
* Merge in new configuration values and new services.
*
* @param deployment deployment object
* @param newConfig the map of new configuration
* @return future which completes only once the config is merged and all the services in the config are running
*/
public Future<DeploymentResult> mergeInNewConfig(Deployment deployment, Map<String, Object> newConfig) {
CompletableFuture<DeploymentResult> totallyCompleteFuture = new CompletableFuture<>();
DeploymentActivator activator;
try {
activator = kernel.getContext().get(DeploymentActivatorFactory.class).getDeploymentActivator(newConfig);
} catch (ServiceUpdateException | ComponentConfigurationValidationException e) {
// Failed to pre-process new config, no rollback needed
logger.atError().setEventType(MERGE_ERROR_LOG_EVENT_KEY).setCause(e).log("Failed to process new configuration for activation");
totallyCompleteFuture.complete(new DeploymentResult(DeploymentResult.DeploymentStatus.FAILED_NO_STATE_CHANGE, e));
return totallyCompleteFuture;
}
boolean ggcRestart = false;
if (activator instanceof KernelUpdateActivator) {
ggcRestart = true;
}
DeploymentDocument deploymentDocument = deployment.getDeploymentDocumentObj();
if (DeploymentComponentUpdatePolicyAction.NOTIFY_COMPONENTS.equals(deploymentDocument.getComponentUpdatePolicy().getComponentUpdatePolicyAction())) {
kernel.getContext().get(UpdateSystemPolicyService.class).addUpdateAction(deploymentDocument.getDeploymentId(), new UpdateAction(deploymentDocument.getDeploymentId(), ggcRestart, deploymentDocument.getComponentUpdatePolicy().getTimeout(), () -> updateActionForDeployment(newConfig, deployment, activator, totallyCompleteFuture)));
} else {
logger.atInfo().log("Deployment is configured to skip update policy check," + " not waiting for disruptable time to update");
updateActionForDeployment(newConfig, deployment, activator, totallyCompleteFuture);
}
return totallyCompleteFuture;
}
use of com.aws.greengrass.deployment.exceptions.ServiceUpdateException in project aws-greengrass-nucleus by aws-greengrass.
the class DeploymentConfigMerger method waitForServicesToStart.
/**
* Completes the provided future when all of the listed services are running.
*
* @param servicesToTrack services to track
* @param mergeTime time the merge was started, used to check if a service is broken due to the merge
* @throws InterruptedException if the thread is interrupted while waiting here
* @throws ServiceUpdateException if a service could not be updated
*/
public static void waitForServicesToStart(Collection<GreengrassService> servicesToTrack, long mergeTime) throws InterruptedException, ServiceUpdateException {
// assuming this loop will not get stuck waiting forever
while (true) {
boolean allServicesRunning = true;
for (GreengrassService service : servicesToTrack) {
State state = service.getState();
// executes. Therefore we first check the service state has been updated since merge map occurs.
if (service.getStateModTime() > mergeTime && State.BROKEN.equals(state)) {
logger.atWarn(MERGE_CONFIG_EVENT_KEY).kv(SERVICE_NAME_LOG_KEY, service.getName()).log("merge-config-service BROKEN");
throw new ServiceUpdateException(String.format("Service %s in broken state after deployment", service.getName()));
}
if (!service.reachedDesiredState()) {
allServicesRunning = false;
continue;
}
if (State.RUNNING.equals(state) || State.FINISHED.equals(state) || !service.shouldAutoStart() && service.reachedDesiredState()) {
continue;
}
allServicesRunning = false;
}
if (allServicesRunning) {
return;
}
// hardcoded
Thread.sleep(WAIT_SVC_START_POLL_INTERVAL_MILLISEC);
}
}
Aggregations