use of com.aws.greengrass.deployment.exceptions.DeploymentTaskFailureException in project aws-greengrass-nucleus by aws-greengrass.
the class DeploymentDocumentDownloaderTest method GIVEN_download_content_with_invalid_format_WHEN_download_THEN_throws_with_proper_message.
@Test
void GIVEN_download_content_with_invalid_format_WHEN_download_THEN_throws_with_proper_message() throws Exception {
when(httpClientProvider.getSdkHttpClient()).thenReturn(httpClient);
String inValidDoc = "I'm not even a JSON.";
String expectedDigest = Digest.calculate(inValidDoc);
String url = "https://www.presigned.com/a.json";
// mock gg client
when(greengrassV2DataClient.getDeploymentConfiguration(Mockito.any(GetDeploymentConfigurationRequest.class))).thenReturn(GetDeploymentConfigurationResponse.builder().preSignedUrl(url).integrityCheck(IntegrityCheck.builder().algorithm("SHA-256").digest(expectedDigest).build()).build());
// mock http client to return the test file
when(httpClient.prepareRequest(any())).thenReturn(request);
when(request.call()).thenReturn(HttpExecuteResponse.builder().response(SdkHttpResponse.builder().statusCode(HTTP_OK).build()).responseBody(AbortableInputStream.create(IOUtils.toInputStream(inValidDoc))).build());
DeploymentTaskFailureException exception = assertThrows(DeploymentTaskFailureException.class, () -> downloader.download(DEPLOYMENT_ID));
assertThat(exception.getMessage(), containsString("Failed to deserialize deployment document."));
}
use of com.aws.greengrass.deployment.exceptions.DeploymentTaskFailureException in project aws-greengrass-nucleus by aws-greengrass.
the class DeploymentServiceTest method GIVEN_deployment_job_WHEN_deployment_completes_with_non_retryable_error_THEN_report_failed_job_status.
@Test
void GIVEN_deployment_job_WHEN_deployment_completes_with_non_retryable_error_THEN_report_failed_job_status(ExtensionContext context) throws Exception {
String deploymentDocument = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("TestDeploymentDocument.json"), StandardCharsets.UTF_8)).lines().collect(Collectors.joining("\n"));
deploymentQueue.offer(new Deployment(deploymentDocument, Deployment.DeploymentType.IOT_JOBS, TEST_JOB_ID_1));
CompletableFuture<DeploymentResult> mockFutureWithException = new CompletableFuture<>();
ignoreExceptionUltimateCauseOfType(context, DeploymentTaskFailureException.class);
Throwable t = new DeploymentTaskFailureException("");
mockFutureWithException.completeExceptionally(t);
when(mockExecutorService.submit(any(DefaultDeploymentTask.class))).thenReturn(mockFutureWithException);
startDeploymentServiceInAnotherThread();
verify(mockExecutorService, WAIT_FOUR_SECONDS).submit(any(DefaultDeploymentTask.class));
verify(deploymentStatusKeeper, WAIT_FOUR_SECONDS).persistAndPublishDeploymentStatus(eq(TEST_JOB_ID_1), eq(Deployment.DeploymentType.IOT_JOBS), eq(JobStatus.IN_PROGRESS.toString()), any());
verify(deploymentStatusKeeper, WAIT_FOUR_SECONDS).persistAndPublishDeploymentStatus(eq(TEST_JOB_ID_1), eq(Deployment.DeploymentType.IOT_JOBS), eq(JobStatus.FAILED.toString()), any());
}
use of com.aws.greengrass.deployment.exceptions.DeploymentTaskFailureException in project aws-greengrass-nucleus by aws-greengrass.
the class DefaultDeploymentTask method getNonTargetGroupToRootPackagesMap.
@SuppressWarnings("PMD.AvoidCatchingGenericException")
private Map<String, Set<ComponentRequirementIdentifier>> getNonTargetGroupToRootPackagesMap(DeploymentDocument deploymentDocument) throws DeploymentTaskFailureException, InterruptedException {
// Don't block local deployments due to device being offline by using finite retries for getting the
// hierarchy and fall back to hierarchy stored previously in worst case. For cloud deployment, use infinite
// retries by default similar/to all other cloud interactions.
boolean isLocalDeployment = Deployment.DeploymentType.LOCAL.equals(deployment.getDeploymentType());
// SDK already retries with RetryMode.STANDARD. For local deployment we don't retry on top of that
int retryCount = isLocalDeployment ? 1 : INFINITE_RETRY_COUNT;
Optional<Set<String>> groupsForDeviceOpt;
try {
groupsForDeviceOpt = thingGroupHelper.listThingGroupsForDevice(retryCount);
} catch (GreengrassV2DataException e) {
if (e.statusCode() == HttpStatusCode.FORBIDDEN) {
// Getting group hierarchy requires permission to call the ListThingGroupsForCoreDevice API which
// may not be configured on existing IoT Thing policy in use for current device, log a warning in
// that case and move on.
logger.atWarn().setCause(e).log("Failed to get thing group hierarchy. Deployment will proceed. " + "To automatically clean up unused components, please add " + "greengrass:ListThingGroupsForCoreDevice permission to your IoT Thing policy.");
groupsForDeviceOpt = getPersistedMembershipInfo();
} else {
throw new DeploymentTaskFailureException("Error fetching thing group information", e);
}
} catch (Exception e) {
if (isLocalDeployment && ThingGroupHelper.DEVICE_OFFLINE_INDICATIVE_EXCEPTIONS.contains(e.getClass())) {
logger.atWarn().setCause(e).log("Failed to get thing group hierarchy, local deployment will proceed");
groupsForDeviceOpt = getPersistedMembershipInfo();
} else {
throw new DeploymentTaskFailureException("Error fetching thing group information", e);
}
}
Set<String> groupsForDevice = groupsForDeviceOpt.isPresent() ? groupsForDeviceOpt.get() : Collections.emptySet();
Map<String, Set<ComponentRequirementIdentifier>> nonTargetGroupsToRootPackagesMap = new HashMap<>();
Topics groupsToRootPackages = deploymentServiceConfig.lookupTopics(DeploymentService.GROUP_TO_ROOT_COMPONENTS_TOPICS);
groupsToRootPackages.iterator().forEachRemaining(node -> {
Topics groupTopics = (Topics) node;
// skip root packages if device does not belong to that group anymore
if (!groupTopics.getName().equals(deploymentDocument.getGroupName()) && (groupTopics.getName().startsWith(DEVICE_DEPLOYMENT_GROUP_NAME_PREFIX) || groupTopics.getName().equals(LOCAL_DEPLOYMENT_GROUP_NAME) || groupsForDevice.contains(groupTopics.getName()))) {
groupTopics.forEach(pkgNode -> {
Topics pkgTopics = (Topics) pkgNode;
Requirement versionReq = Requirement.buildNPM(Coerce.toString(pkgTopics.lookup(GROUP_TO_ROOT_COMPONENTS_VERSION_KEY)));
nonTargetGroupsToRootPackagesMap.putIfAbsent(groupTopics.getName(), new HashSet<>());
nonTargetGroupsToRootPackagesMap.get(groupTopics.getName()).add(new ComponentRequirementIdentifier(pkgTopics.getName(), versionReq));
});
}
});
deploymentServiceConfig.lookupTopics(DeploymentService.GROUP_MEMBERSHIP_TOPICS).remove();
Topics groupMembership = deploymentServiceConfig.lookupTopics(DeploymentService.GROUP_MEMBERSHIP_TOPICS);
groupsForDevice.forEach(groupMembership::createLeafChild);
return nonTargetGroupsToRootPackagesMap;
}
use of com.aws.greengrass.deployment.exceptions.DeploymentTaskFailureException in project aws-greengrass-nucleus by aws-greengrass.
the class DefaultDeploymentTask method call.
@Override
@SuppressWarnings({ "PMD.PreserveStackTrace", "PMD.PrematureDeclaration" })
public DeploymentResult call() throws InterruptedException {
Future<List<ComponentIdentifier>> resolveDependenciesFuture = null;
Future<Void> preparePackagesFuture = null;
Future<DeploymentResult> deploymentMergeFuture = null;
DeploymentDocument deploymentDocument = deployment.getDeploymentDocumentObj();
try {
logger.atInfo().setEventType(DEPLOYMENT_TASK_EVENT_TYPE).kv("Deployment service config", deploymentServiceConfig.toPOJO().toString()).log("Starting deployment task");
Map<String, Set<ComponentRequirementIdentifier>> nonTargetGroupsToRootPackagesMap = getNonTargetGroupToRootPackagesMap(deploymentDocument);
// Root packages for the target group is taken from deployment document.
Set<String> rootPackages = new HashSet<>(deploymentDocument.getRootPackages());
// Add root components from non-target groups.
nonTargetGroupsToRootPackagesMap.values().forEach(packages -> {
packages.forEach(p -> rootPackages.add(p.getName()));
});
resolveDependenciesFuture = executorService.submit(() -> dependencyResolver.resolveDependencies(deploymentDocument, nonTargetGroupsToRootPackagesMap));
List<ComponentIdentifier> desiredPackages = resolveDependenciesFuture.get();
// download configuration if large
List<String> requiredCapabilities = deploymentDocument.getRequiredCapabilities();
if (requiredCapabilities != null && requiredCapabilities.contains(DeploymentCapability.LARGE_CONFIGURATION.toString())) {
DeploymentDocument downloadedDeploymentDocument = deploymentDocumentDownloader.download(deploymentDocument.getDeploymentId());
deployment.getDeploymentDocumentObj().setDeploymentPackageConfigurationList(downloadedDeploymentDocument.getDeploymentPackageConfigurationList());
}
// Check that all prerequisites for preparing components are met
componentManager.checkPreparePackagesPrerequisites(desiredPackages);
// Block this without timeout because a device can be offline and it can take quite a long time
// to download a package.
preparePackagesFuture = componentManager.preparePackages(desiredPackages);
preparePackagesFuture.get();
Map<String, Object> newConfig = kernelConfigResolver.resolve(desiredPackages, deploymentDocument, new ArrayList<>(rootPackages));
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException("Deployment task is interrupted");
}
deploymentMergeFuture = deploymentConfigMerger.mergeInNewConfig(deployment, newConfig);
// Block this without timeout because it can take a long time for the device to update the config
// (if it's not in a safe window).
DeploymentResult result = deploymentMergeFuture.get();
logger.atInfo(DEPLOYMENT_TASK_EVENT_TYPE).setEventType(DEPLOYMENT_TASK_EVENT_TYPE).log("Finished deployment task");
componentManager.cleanupStaleVersions();
return result;
} catch (PackageLoadingException | DeploymentTaskFailureException | IOException e) {
logger.atError().setCause(e).log("Error occurred while processing deployment");
return new DeploymentResult(DeploymentResult.DeploymentStatus.FAILED_NO_STATE_CHANGE, e);
} catch (ExecutionException e) {
logger.atError().setCause(e).log("Error occurred while processing deployment");
Throwable t = e.getCause();
if (t instanceof InterruptedException) {
throw (InterruptedException) t;
} else {
return new DeploymentResult(DeploymentResult.DeploymentStatus.FAILED_NO_STATE_CHANGE, t);
}
} catch (InterruptedException e) {
// DeploymentTask got interrupted while performing a blocking step.
cancelDeploymentTask(resolveDependenciesFuture, preparePackagesFuture, deploymentMergeFuture);
// Populate the exception up to the stack
throw e;
}
}
use of com.aws.greengrass.deployment.exceptions.DeploymentTaskFailureException in project aws-greengrass-nucleus by aws-greengrass.
the class DeploymentService method createNewDeployment.
private void createNewDeployment(Deployment deployment) {
logger.atInfo().kv(DEPLOYMENT_ID_LOG_KEY, deployment.getId()).kv("DeploymentType", deployment.getDeploymentType().toString()).log("Received deployment in the queue");
DeploymentTask deploymentTask;
boolean cancellable = true;
if (DEFAULT.equals(deployment.getDeploymentStage())) {
deploymentTask = createDefaultNewDeployment(deployment);
} else {
deploymentTask = createKernelUpdateDeployment(deployment);
cancellable = false;
if (DeploymentType.IOT_JOBS.equals(deployment.getDeploymentType())) {
// Keep track of IoT jobs for de-duplication
IotJobsHelper.getLatestQueuedJobs().addProcessedJob(deployment.getId());
}
}
if (deploymentTask == null) {
return;
}
deploymentStatusKeeper.persistAndPublishDeploymentStatus(deployment.getId(), deployment.getDeploymentType(), JobStatus.IN_PROGRESS.toString(), new HashMap<>());
if (DEFAULT.equals(deployment.getDeploymentStage())) {
try {
context.get(KernelAlternatives.class).cleanupLaunchDirectoryLinks();
deploymentDirectoryManager.createNewDeploymentDirectory(deployment.getDeploymentDocumentObj().getDeploymentId());
deploymentDirectoryManager.writeDeploymentMetadata(deployment);
} catch (IOException ioException) {
logger.atError().log("Unable to create deployment directory", ioException);
updateDeploymentResultAsFailed(deployment, deploymentTask, true, new DeploymentTaskFailureException(ioException));
return;
}
List<String> requiredCapabilities = deployment.getDeploymentDocumentObj().getRequiredCapabilities();
if (requiredCapabilities != null && !requiredCapabilities.isEmpty()) {
List<String> missingCapabilities = requiredCapabilities.stream().filter(reqCapabilities -> !kernel.getSupportedCapabilities().contains(reqCapabilities)).collect(Collectors.toList());
if (!missingCapabilities.isEmpty()) {
updateDeploymentResultAsFailed(deployment, deploymentTask, false, new MissingRequiredCapabilitiesException("The current nucleus version doesn't support one " + "or more capabilities that are required by this deployment: " + String.join(", ", missingCapabilities)));
return;
}
}
if (DeploymentType.LOCAL.equals(deployment.getDeploymentType())) {
try {
copyRecipesAndArtifacts(deployment);
} catch (InvalidRequestException | IOException e) {
logger.atError().log("Error copying recipes and artifacts", e);
updateDeploymentResultAsFailed(deployment, deploymentTask, false, e);
return;
}
}
}
Future<DeploymentResult> process = executorService.submit(deploymentTask);
logger.atInfo().kv("deployment", deployment.getId()).log("Started deployment execution");
currentDeploymentTaskMetadata = new DeploymentTaskMetadata(deploymentTask, process, deployment.getId(), deployment.getDeploymentType(), new AtomicInteger(1), deployment.getDeploymentDocumentObj(), cancellable);
}
Aggregations