|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#pragma warning disable ASPIREPIPELINES001
#pragma warning disable ASPIREAZURE001
#pragma warning disable ASPIREPIPELINES003
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Pipelines;
using Aspire.Hosting.Publishing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Aspire.Hosting.Azure;
/// <summary>
/// Represents an Azure App Service Web Site resource.
/// </summary>
public class AzureAppServiceWebSiteResource : AzureProvisioningResource
{
/// <summary>
/// Initializes a new instance of the <see cref="AzureAppServiceWebSiteResource"/> class.
/// </summary>
/// <param name="name">The name of the resource in the Aspire application model.</param>
/// <param name="configureInfrastructure">Callback to configure the Azure resources.</param>
/// <param name="targetResource">The target resource that this Azure Web Site is being created for.</param>
public AzureAppServiceWebSiteResource(string name, Action<AzureResourceInfrastructure> configureInfrastructure, IResource targetResource)
: base(name, configureInfrastructure)
{
TargetResource = targetResource;
// Add pipeline step annotation for push
Annotations.Add(new PipelineStepAnnotation((factoryContext) =>
{
// Get the registry from the target resource's deployment target annotation
var deploymentTargetAnnotation = targetResource.GetDeploymentTargetAnnotation();
if (deploymentTargetAnnotation?.ContainerRegistry is not IContainerRegistry registry)
{
// No registry available, skip push
return [];
}
var steps = new List<PipelineStep>();
if (targetResource.RequiresImageBuildAndPush())
{
// Create push step for this deployment target
var pushStep = new PipelineStep
{
Name = $"push-{targetResource.Name}",
Action = async ctx =>
{
var containerImageBuilder = ctx.Services.GetRequiredService<IResourceContainerImageBuilder>();
await AzureEnvironmentResourceHelpers.PushImageToRegistryAsync(
registry,
targetResource,
ctx,
containerImageBuilder).ConfigureAwait(false);
},
Tags = [WellKnownPipelineTags.PushContainerImage]
};
steps.Add(pushStep);
}
if (!targetResource.TryGetEndpoints(out var endpoints))
{
endpoints = [];
}
var printResourceSummary = new PipelineStep
{
Name = $"print-{targetResource.Name}-summary",
Action = async ctx =>
{
var computerEnv = (AzureAppServiceEnvironmentResource)deploymentTargetAnnotation.ComputeEnvironment!;
var websiteSuffix = await computerEnv.WebSiteSuffix.GetValueAsync(ctx.CancellationToken).ConfigureAwait(false);
var hostName = $"{targetResource.Name.ToLowerInvariant()}-{websiteSuffix}";
if (hostName.Length > 60)
{
hostName = hostName.Substring(0, 60);
}
var endpoint = $"https://{hostName}.azurewebsites.net";
ctx.ReportingStep.Log(LogLevel.Information, $"Successfully deployed **{targetResource.Name}** to [{endpoint}]({endpoint})", enableMarkdown: true);
},
Tags = ["print-summary"]
};
var deployStep = new PipelineStep
{
Name = $"deploy-{targetResource.Name}",
Action = _ => Task.CompletedTask,
Tags = [WellKnownPipelineTags.DeployCompute]
};
deployStep.DependsOn(printResourceSummary);
steps.Add(deployStep);
steps.Add(printResourceSummary);
return steps;
}));
// Add pipeline configuration annotation to wire up dependencies
Annotations.Add(new PipelineConfigurationAnnotation((context) =>
{
// Find the push step for this resource
var pushSteps = context.GetSteps(this, WellKnownPipelineTags.PushContainerImage);
var provisionSteps = context.GetSteps(this, WellKnownPipelineTags.ProvisionInfrastructure);
// Make push step depend on build steps of the target resource
var buildSteps = context.GetSteps(targetResource, WellKnownPipelineTags.BuildCompute);
pushSteps.DependsOn(buildSteps);
// Make push step depend on the registry being provisioned
var deploymentTargetAnnotation = targetResource.GetDeploymentTargetAnnotation();
if (deploymentTargetAnnotation?.ContainerRegistry is IResource registryResource)
{
var registryProvisionSteps = context.GetSteps(registryResource, WellKnownPipelineTags.ProvisionInfrastructure);
pushSteps.DependsOn(registryProvisionSteps);
}
// The app deployment should depend on the push step
provisionSteps.DependsOn(pushSteps);
// Ensure summary step runs after provision
context.GetSteps(this, "print-summary").DependsOn(provisionSteps);
}));
}
/// <summary>
/// Gets the target resource that this Azure Web Site is being created for.
/// </summary>
public IResource TargetResource { get; }
}
|