internal sealed class CloudFormationStackResourceProvisioner()

in src/Aspire.Hosting.AWS/Provisioning/CloudFormationStackResourceProvisioner.cs [11:57]


internal sealed class CloudFormationStackResourceProvisioner(
    ResourceLoggerService loggerService,
    ResourceNotificationService notificationService)
    : CloudFormationResourceProvisioner<CloudFormationStackResource>(loggerService, notificationService)
{
    protected override async Task GetOrCreateResourceAsync(CloudFormationStackResource resource, CancellationToken cancellationToken)
    {
        var logger = LoggerService.GetLogger(resource);
        try
        {
            using var cfClient = GetCloudFormationClient(resource);

            var request = new DescribeStacksRequest { StackName = resource.StackName };
            var response = await cfClient.DescribeStacksAsync(request, cancellationToken).ConfigureAwait(false);

            // If the stack didn't exist then a StackNotFoundException would have been thrown.
            var stack = response.Stacks[0];

            // Capture the CloudFormation stack output parameters on to the Aspire CloudFormation resource. This
            // allows projects that have a reference to the stack have the output parameters applied to the
            // projects IConfiguration.
            resource.Outputs = stack!.Outputs ?? new List<Output>();
            logger.LogInformation("CloudFormation stack has {Count} output parameters", resource.Outputs.Count);
            if (logger.IsEnabled(LogLevel.Information))
            {
                foreach (var output in resource.Outputs)
                {
                    logger.LogInformation("Output Name: {Name}, Value {Value}", output.OutputKey, output.OutputValue);
                }
            }

            await PublishCloudFormationUpdatePropertiesAsync(resource, ConvertOutputToProperties(stack)).ConfigureAwait(false);
        }
        catch (Exception e)
        {
            if (e is AmazonCloudFormationException ce && string.Equals(ce.ErrorCode, "ValidationError"))
            {
                logger.LogError("Stack {StackName} does not exists to add as a resource", resource.Name);
            }
            else
            {
                logger.LogError(e, "Error reading {StackName}", resource.Name);
            }
            throw;
        }
    }
}