src/Aspire.Hosting.AWS/Provisioning/CloudFormationTemplateResourceProvisioner.cs (70 lines of code) (raw):

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.AWS.CloudFormation; using Microsoft.Extensions.Logging; namespace Aspire.Hosting.AWS.Provisioning; internal class CloudFormationTemplateResourceProvisioner( ResourceLoggerService loggerService, ResourceNotificationService notificationService) : CloudFormationTemplateResourceProvisioner<CloudFormationTemplateResource>(loggerService, notificationService); internal class CloudFormationTemplateResourceProvisioner<T>( ResourceLoggerService loggerService, ResourceNotificationService notificationService) : CloudFormationResourceProvisioner<T>(loggerService, notificationService) where T : CloudFormationTemplateResource { protected override async Task GetOrCreateResourceAsync(T resource, CancellationToken cancellationToken) { var logger = LoggerService.GetLogger(resource); using var cfClient = GetCloudFormationClient(resource); try { var context = await CreateCloudFormationExecutionContextAsync(resource, cancellationToken) .ConfigureAwait(false); var executor = new CloudFormationStackExecutor(cfClient, context, logger); var stack = await executor.ExecuteTemplateAsync(cancellationToken).ConfigureAwait(false); if (stack != null) { logger.LogInformation("CloudFormation stack has {Count} output parameters", stack.Outputs.Count); if (logger.IsEnabled(LogLevel.Information)) { foreach (var output in stack.Outputs) { logger.LogInformation("Output Name: {Name}, Value {Value}", output.OutputKey, output.OutputValue); } } logger.LogInformation("CloudFormation provisioning complete"); if (resource is CloudFormationResource cloudformationResource) { cloudformationResource.Outputs = stack.Outputs; } var templatePath = resource.TemplatePath; await PublishCloudFormationUpdatePropertiesAsync(resource, ConvertOutputToProperties(stack, templatePath), MapCloudFormationStackUrl(cfClient, stack.StackId)).ConfigureAwait(false); } else { logger.LogError("CloudFormation provisioning failed"); throw new AWSProvisioningException("Failed to apply CloudFormation template"); } } catch (Exception ex) { HandleTemplateProvisioningException(ex, resource, logger); throw; } } private static async Task<CloudFormationStackExecutionContext> CreateCloudFormationExecutionContextAsync(T resource, CancellationToken cancellationToken) { var template = await File.ReadAllTextAsync(resource.TemplatePath, cancellationToken).ConfigureAwait(false); return new CloudFormationStackExecutionContext(resource.StackName, template) { RoleArn = resource.RoleArn, DisableDiffCheck = resource.DisableDiffCheck, StackPollingInterval = resource.StackPollingInterval, DisabledCapabilities = resource.DisabledCapabilities, CloudFormationParameters = resource.CloudFormationParameters }; } protected virtual void HandleTemplateProvisioningException(Exception ex, T resource, ILogger logger) { } }