Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show the deployment url when provisioning #2591

Merged
merged 1 commit into from
Mar 3, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Dcp.Process;
using Azure;
using Azure.ResourceManager;
using Azure.Core;
using Azure.ResourceManager.KeyVault;
using Azure.ResourceManager.KeyVault.Models;
using Azure.ResourceManager.Resources;
Expand Down Expand Up @@ -77,18 +77,14 @@ public override async Task<bool> ConfigureResourceAsync(IConfiguration configura
}

var portalUrls = new List<(string, string)>();
foreach (var pair in resourceIds.GetChildren())

if (section["Id"] is string deploymentId &&
ResourceIdentifier.TryParse(deploymentId, out var id) &&
id is not null)
{
portalUrls.Add((pair.Key, $"https://portal.azure.com/#@{configuration["Azure:Tenant"]}/resource{pair.Value}/overview"));
portalUrls.Add(("deployment", GetDeploymentUrl(id)));
}

// TODO: Figure out how to show the deployment in the portal
//var deploymentId = section["Id"];
//if (deploymentId is not null)
//{
// portalUrls.Add(("deployment", $"https://portal.azure.com/#view/HubsExtension/DeploymentDetailsBlade/~/overview/id/resource{Uri.EscapeDataString(deploymentId)}"));
//}

await notificationService.PublishUpdateAsync(resource, state =>
{
ImmutableArray<(string, string)> props = [
Expand Down Expand Up @@ -211,16 +207,30 @@ await notificationService.PublishUpdateAsync(resource, state => state with

var sw = Stopwatch.StartNew();

ArmOperation<ArmDeploymentResource> operation;

operation = await deployments.CreateOrUpdateAsync(WaitUntil.Completed, resource.Name, new ArmDeploymentContent(new(ArmDeploymentMode.Incremental)
var operation = await deployments.CreateOrUpdateAsync(WaitUntil.Started, resource.Name, new ArmDeploymentContent(new(ArmDeploymentMode.Incremental)
{
Template = BinaryData.FromString(armTemplateContents.ToString()),
Parameters = BinaryData.FromObjectAsJson(parameters),
DebugSettingDetailLevel = "RequestContent, ResponseContent",
}),
cancellationToken).ConfigureAwait(false);

// Resolve the deployment URL before waiting for the operation to complete
var url = GetDeploymentUrl(context, resource.Name);

resourceLogger.LogInformation("Deployment started: {Url}", url);

await notificationService.PublishUpdateAsync(resource, state =>
{
return state with
{
Urls = [.. state.Urls, ("deployment", url)],
};
})
.ConfigureAwait(false);

await operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false);

sw.Stop();
resourceLogger.LogInformation("Deployment of {Name} to {ResourceGroup} took {Elapsed}", resource.Name, context.ResourceGroup.Data.Name, sw.Elapsed);

Expand Down Expand Up @@ -249,7 +259,8 @@ await notificationService.PublishUpdateAsync(resource, state => state with
.Prop("Deployments")
.Prop(resource.Name);

// TODO: Clear the entire section if the deployment
// Clear the entire section
resourceConfig.AsObject().Clear();

// Save the deployment id to the configuration
resourceConfig["Id"] = deployment.Id.ToString();
Expand All @@ -266,19 +277,6 @@ await notificationService.PublishUpdateAsync(resource, state => state with
// Save the checksum to the configuration
resourceConfig["CheckSum"] = GetChecksum(resource, parameters);

// Save the resource ids created
var resourceIdConfig = resourceConfig.Prop("ResourceIds");
var portalUrls = new List<(string, string)>();

foreach (var item in deployment.Data.Properties.OutputResources)
{
resourceIdConfig[item.Id.Name] = item.Id.ToString();
portalUrls.Add((item.Id.Name, $"https://portal.azure.com/#@{context.Tenant.Data.DefaultDomain}/resource{item.Id}/overview"));
}

// TODO: Figure out how to show the deployment in the portal
// portalUrls.Add(("deployment", $"https://portal.azure.com/#view/HubsExtension/DeploymentDetailsBlade/~/overview/id/resource{deployment.Id}"));

if (outputObj is not null)
{
foreach (var item in outputObj.AsObject())
Expand Down Expand Up @@ -321,8 +319,7 @@ await notificationService.PublishUpdateAsync(resource, state =>
{
State = "Running",
CreationTimeStamp = DateTime.UtcNow,
Properties = properties,
Urls = [.. portalUrls]
Properties = properties
};
})
.ConfigureAwait(false);
Expand Down Expand Up @@ -486,4 +483,25 @@ internal static void SetParameters(JsonObject parameters, AzureBicepResource res
};
}
}

private const string PortalDeploymentOverviewUrl = "https://portal.azure.com/#view/HubsExtension/DeploymentDetailsBlade/~/overview/id";

private static string GetDeploymentUrl(ProvisioningContext provisioningContext, string deploymentName)
{
var prefix = PortalDeploymentOverviewUrl;

var subId = provisioningContext.Subscription.Data.Id.ToString();
var rgName = provisioningContext.ResourceGroup.Data.Name;
var subAndRg = $"{subId}/resourceGroups/{rgName}";

var deployId = deploymentName;

var path = $"{subAndRg}/providers/Microsoft.Resources/deployments/{deployId}";
var encodedPath = Uri.EscapeDataString(path);

return $"{prefix}/{encodedPath}";
}

public static string GetDeploymentUrl(ResourceIdentifier deploymentId) =>
$"{PortalDeploymentOverviewUrl}/{Uri.EscapeDataString(deploymentId.ToString())}";
}