diff --git a/Directory.Packages.props b/Directory.Packages.props index ddc8a6da1d..fd10aed0c1 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,15 +7,15 @@ true true 3.10.0 - 1.0.0-beta.1 + 1.0.0 - - - - + + + + @@ -31,11 +31,11 @@ - + - + @@ -106,14 +106,14 @@ - + - + - + @@ -125,22 +125,22 @@ - - + + - - + + - + - + @@ -157,7 +157,7 @@ - + @@ -165,7 +165,7 @@ - + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e9c5d338e2..6dd577b99d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -49,25 +49,25 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime eddf880ac57b7f2c79a77592e3e6d24d1d02f112 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5 + 81cabf2857a01351e5ab578947c7403a5b128ad1 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5 + 81cabf2857a01351e5ab578947c7403a5b128ad1 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5 + 81cabf2857a01351e5ab578947c7403a5b128ad1 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5 + 81cabf2857a01351e5ab578947c7403a5b128ad1 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5 + 81cabf2857a01351e5ab578947c7403a5b128ad1 https://dev.azure.com/dnceng/internal/_git/dotnet-runtime diff --git a/eng/Versions.props b/eng/Versions.props index a54512be38..d4fdee3964 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -67,7 +67,7 @@ 8.0.11 8.0.11 9.0.0-preview.5.24272.3 - 8.0.8 + 8.0.10 9.0.0 diff --git a/playground/AzureContainerApps/AzureContainerApps.AppHost/Program.cs b/playground/AzureContainerApps/AzureContainerApps.AppHost/Program.cs index f955d65df0..b8d590e650 100644 --- a/playground/AzureContainerApps/AzureContainerApps.AppHost/Program.cs +++ b/playground/AzureContainerApps/AzureContainerApps.AppHost/Program.cs @@ -42,7 +42,7 @@ app.ConfigureCustomDomain(customDomain, certificateName); // Scale to 0 - app.Template.Value!.Scale.Value!.MinReplicas = 0; + app.Template.Scale.MinReplicas = 0; }); #if !SKIP_DASHBOARD_REFERENCE diff --git a/playground/bicep/BicepSample.AppHost/redis.module.bicep b/playground/bicep/BicepSample.AppHost/redis.module.bicep index 969e501807..e4b434c67a 100644 --- a/playground/bicep/BicepSample.AppHost/redis.module.bicep +++ b/playground/bicep/BicepSample.AppHost/redis.module.bicep @@ -15,11 +15,11 @@ resource redis 'Microsoft.Cache/redis@2024-03-01' = { capacity: 1 } enableNonSslPort: false + disableAccessKeyAuthentication: true minimumTlsVersion: '1.2' redisConfiguration: { 'aad-enabled': 'true' } - disableAccessKeyAuthentication: 'true' } tags: { 'aspire-resource-name': 'redis' diff --git a/playground/cdk/CdkSample.AppHost/Program.cs b/playground/cdk/CdkSample.AppHost/Program.cs index c63e19b819..db6bc49993 100644 --- a/playground/cdk/CdkSample.AppHost/Program.cs +++ b/playground/cdk/CdkSample.AppHost/Program.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using Azure.Provisioning.ApplicationInsights; -using Azure.Provisioning.Expressions; using Azure.Provisioning.KeyVault; using Azure.Provisioning.OperationalInsights; using Azure.Provisioning.ServiceBus; @@ -17,7 +16,7 @@ var storage = builder.AddAzureStorage("storage") .ConfigureInfrastructure(infrastructure => { - var account = infrastructure.GetResources().OfType().Single(); + var account = infrastructure.GetProvisionableResources().OfType().Single(); account.Sku = new StorageSku() { Name = sku.AsProvisioningParameter(infrastructure) }; account.Location = locationOverride.AsProvisioningParameter(infrastructure); }); @@ -30,7 +29,7 @@ var keyvault = builder.AddAzureKeyVault("mykv") .ConfigureInfrastructure(infrastructure => { - var keyVault = infrastructure.GetResources().OfType().Single(); + var keyVault = infrastructure.GetProvisionableResources().OfType().Single(); var secret = new KeyVaultSecret("mysecret") { Parent = keyVault, @@ -55,26 +54,22 @@ .AddQueue("queue1") .ConfigureInfrastructure(infrastructure => { - var queue = infrastructure.GetResources().OfType().Single(q => q.IdentifierName == "queue1"); + var queue = infrastructure.GetProvisionableResources().OfType().Single(q => q.BicepIdentifier == "queue1"); queue.MaxDeliveryCount = 5; - queue.LockDuration = new StringLiteral("PT5M"); - // TODO: this should be - // queue.LockDuration = TimeSpan.FromMinutes(5); + queue.LockDuration = TimeSpan.FromMinutes(5); }) .AddTopic("topic1") .ConfigureInfrastructure(infrastructure => { - var topic = infrastructure.GetResources().OfType().Single(q => q.IdentifierName == "topic1"); + var topic = infrastructure.GetProvisionableResources().OfType().Single(q => q.BicepIdentifier == "topic1"); topic.EnablePartitioning = true; }) .AddTopic("topic2") .AddSubscription("topic1", "subscription1") .ConfigureInfrastructure(infrastructure => { - var subscription = infrastructure.GetResources().OfType().Single(q => q.IdentifierName == "subscription1"); - subscription.LockDuration = new StringLiteral("PT5M"); - // TODO: this should be - //subscription.LockDuration = TimeSpan.FromMinutes(5); + var subscription = infrastructure.GetProvisionableResources().OfType().Single(q => q.BicepIdentifier == "subscription1"); + subscription.LockDuration = TimeSpan.FromMinutes(5); subscription.RequiresSession = true; }) .AddSubscription("topic1", "subscription2") @@ -89,7 +84,7 @@ var logAnalyticsWorkspace = builder.AddAzureLogAnalyticsWorkspace("logAnalyticsWorkspace") .ConfigureInfrastructure(infrastructure => { - var logAnalyticsWorkspace = infrastructure.GetResources().OfType().Single(); + var logAnalyticsWorkspace = infrastructure.GetProvisionableResources().OfType().Single(); logAnalyticsWorkspace.Sku = new OperationalInsightsWorkspaceSku() { Name = OperationalInsightsWorkspaceSkuName.PerNode @@ -99,7 +94,7 @@ var appInsights = builder.AddAzureApplicationInsights("appInsights", logAnalyticsWorkspace) .ConfigureInfrastructure(infrastructure => { - var appInsights = infrastructure.GetResources().OfType().Single(); + var appInsights = infrastructure.GetProvisionableResources().OfType().Single(); appInsights.IngestionMode = ComponentIngestionMode.LogAnalytics; }); diff --git a/playground/cdk/CdkSample.AppHost/cache.module.bicep b/playground/cdk/CdkSample.AppHost/cache.module.bicep index 83b2ee2c22..ab540b7b74 100644 --- a/playground/cdk/CdkSample.AppHost/cache.module.bicep +++ b/playground/cdk/CdkSample.AppHost/cache.module.bicep @@ -15,11 +15,11 @@ resource cache 'Microsoft.Cache/redis@2024-03-01' = { capacity: 1 } enableNonSslPort: false + disableAccessKeyAuthentication: true minimumTlsVersion: '1.2' redisConfiguration: { 'aad-enabled': 'true' } - disableAccessKeyAuthentication: 'true' } tags: { 'aspire-resource-name': 'cache' diff --git a/playground/python/Python.AppHost/Program.cs b/playground/python/Python.AppHost/Program.cs index ea51d15981..3449eba1b0 100644 --- a/playground/python/Python.AppHost/Program.cs +++ b/playground/python/Python.AppHost/Program.cs @@ -1,6 +1,8 @@ // 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 ASPIREHOSTINGPYTHON001 // Test for experimental feature + var builder = DistributedApplication.CreateBuilder(args); builder.AddPythonApp("script-only", "../script_only", "main.py"); diff --git a/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppsInfrastructure.cs b/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppsInfrastructure.cs index 7d4426ada9..243b1d561d 100644 --- a/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppsInfrastructure.cs +++ b/src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppsInfrastructure.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Globalization; -using System.Text; using System.Text.RegularExpressions; using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Lifecycle; @@ -12,6 +11,7 @@ using Azure.Provisioning.KeyVault; using Azure.Provisioning.Resources; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; namespace Aspire.Hosting.Azure; @@ -19,7 +19,10 @@ namespace Aspire.Hosting.Azure; /// Represents the infrastructure for Azure Container Apps within the Aspire Hosting environment. /// Implements the interface to provide lifecycle hooks for distributed applications. /// -internal sealed class AzureContainerAppsInfrastructure(ILogger logger, DistributedApplicationExecutionContext executionContext) : IDistributedApplicationLifecycleHook +internal sealed class AzureContainerAppsInfrastructure( + ILogger logger, + IOptions provisioningOptions, + DistributedApplicationExecutionContext executionContext) : IDistributedApplicationLifecycleHook { public async Task BeforeStartAsync(DistributedApplicationModel appModel, CancellationToken cancellationToken = default) { @@ -49,7 +52,7 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell continue; } - var containerApp = await containerAppEnvironmentContext.CreateContainerAppAsync(r, executionContext, cancellationToken).ConfigureAwait(false); + var containerApp = await containerAppEnvironmentContext.CreateContainerAppAsync(r, provisioningOptions.Value, executionContext, cancellationToken).ConfigureAwait(false); r.Annotations.Add(new DeploymentTargetAnnotation(containerApp)); } @@ -75,11 +78,12 @@ IManifestExpressionProvider clientId private readonly Dictionary _containerApps = []; - public async Task CreateContainerAppAsync(IResource resource, DistributedApplicationExecutionContext executionContext, CancellationToken cancellationToken) + public async Task CreateContainerAppAsync(IResource resource, AzureProvisioningOptions provisioningOptions, DistributedApplicationExecutionContext executionContext, CancellationToken cancellationToken) { var context = await ProcessResourceAsync(resource, executionContext, cancellationToken).ConfigureAwait(false); var provisioningResource = new AzureProvisioningResource(resource.Name, context.BuildContainerApp); + provisioningResource.ProvisioningBuildOptions = provisioningOptions.ProvisioningBuildOptions; provisioningResource.Annotations.Add(new ManifestPublishingCallbackAnnotation(provisioningResource.WriteToManifest)); @@ -143,7 +147,7 @@ public void BuildContainerApp(AzureResourceInfrastructure c) containerImageParam = AllocateContainerImageParameter(); } - var containerAppResource = new ContainerApp(Infrastructure.NormalizeIdentifierName(resource.Name)) + var containerAppResource = new ContainerApp(Infrastructure.NormalizeBicepIdentifier(resource.Name)) { Name = resource.Name.ToLowerInvariant() }; @@ -180,7 +184,7 @@ public void BuildContainerApp(AzureResourceInfrastructure c) var containerAppContainer = new ContainerAppContainer(); template.Containers = [containerAppContainer]; - containerAppContainer.Image = containerImageParam is null ? containerImageName : containerImageParam; + containerAppContainer.Image = containerImageParam is null ? containerImageName! : containerImageParam; containerAppContainer.Name = resource.Name; AddEnvironmentVariablesAndCommandLineArgs(containerAppContainer); @@ -497,7 +501,8 @@ private async Task ProcessEnvironmentAsync(DistributedApplicationExecutionContex { var managedIdentityParameter = AllocateManagedIdentityIdParameter(); secret.Identity = managedIdentityParameter; - secret.KeyVaultUri = new BicepValue(argValue.Expression!); + // TODO: this should be able to use ToUri(), but it hit an issue + secret.KeyVaultUri = new BicepValue(((BicepExpression?)argValue)!); } else { @@ -531,7 +536,6 @@ private static BicepValue ResolveValue(object val) { BicepValue s => s, string s => s, - BicepValueFormattableString fs => Interpolate(fs), ProvisioningParameter p => p, _ => throw new NotSupportedException("Unsupported value type " + val.GetType()) }; @@ -698,7 +702,7 @@ BicepValue GetHostValue(string? prefix = null, string? suffix = null) args[index++] = val; } - return (new BicepValueFormattableString(expr.Format, args), finalSecretType); + return (Interpolate(expr.Format, args), finalSecretType); } @@ -714,7 +718,7 @@ private BicepValue AllocateKeyVaultSecretUriReference(BicepSecretOutputR { // We resolve the keyvault that represents the storage for secret outputs var parameter = AllocateParameter(SecretOutputExpression.GetSecretOutputKeyVault(secretOutputReference.Resource)); - kv = KeyVaultService.FromExisting($"{parameter.IdentifierName}_kv"); + kv = KeyVaultService.FromExisting($"{parameter.BicepIdentifier}_kv"); kv.Name = parameter; KeyVaultRefs[secretOutputReference.Resource.Name] = kv; @@ -723,19 +727,15 @@ private BicepValue AllocateKeyVaultSecretUriReference(BicepSecretOutputR if (!KeyVaultSecretRefs.TryGetValue(secretOutputReference.ValueExpression, out var secret)) { // Now we resolve the secret - var secretIdentifierName = Infrastructure.NormalizeIdentifierName($"{kv.IdentifierName}_{secretOutputReference.Name}"); - secret = KeyVaultSecret.FromExisting(secretIdentifierName); + var secretBicepIdentifier = Infrastructure.NormalizeBicepIdentifier($"{kv.BicepIdentifier}_{secretOutputReference.Name}"); + secret = KeyVaultSecret.FromExisting(secretBicepIdentifier); secret.Name = secretOutputReference.Name; secret.Parent = kv; KeyVaultSecretRefs[secretOutputReference.ValueExpression] = secret; } - // TODO: There should be a better way to do this? - return new MemberExpression( - new MemberExpression( - new IdentifierExpression(secret.IdentifierName), "properties"), - "secretUri"); + return secret.Properties.SecretUri; } private ProvisioningParameter AllocateContainerImageParameter() @@ -895,81 +895,45 @@ private void AddContainerRegistryParameters(ContainerAppConfiguration app) } } - // REVIEW: BicepFunction.Interpolate is buggy and doesn't handle nested formattable strings correctly - // This is a workaround to handle nested formattable strings until the bug is fixed. - private static BicepValue Interpolate(BicepValueFormattableString text) + private static BicepValue Interpolate(string format, object[] args) { - var formatStringBuilder = new StringBuilder(); - var arguments = new List>(); + var bicepStringBuilder = new BicepStringBuilder(); - void ProcessFormattableString(BicepValueFormattableString formattableString, int argumentIndex) - { - var span = formattableString.Format.AsSpan(); - var skip = 0; - - foreach (var match in Regex.EnumerateMatches(span, @"{\d+}")) - { - formatStringBuilder.Append(span[..(match.Index - skip)]); + var span = format.AsSpan(); + var skip = 0; + var argumentIndex = 0; - var argument = formattableString.GetArgument(argumentIndex); + foreach (var match in Regex.EnumerateMatches(span, @"{\d+}")) + { + bicepStringBuilder.Append(span[..(match.Index - skip)].ToString()); - if (argument is BicepValueFormattableString nested) - { - // Inline the nested formattable string - ProcessFormattableString(nested, 0); - } - else - { - formatStringBuilder.Append(CultureInfo.InvariantCulture, $"{{{arguments.Count}}}"); - if (argument is BicepValue bicepValue) - { - arguments.Add(bicepValue); - } - else if (argument is string s) - { - arguments.Add(s); - } - else if (argument is ProvisioningParameter provisioningParameter) - { - arguments.Add(provisioningParameter); - } - else - { - throw new NotSupportedException($"{argument} is not supported"); - } - } + var argument = args[argumentIndex]; - argumentIndex++; - span = span[(match.Index + match.Length - skip)..]; - skip = match.Index + match.Length; + if (argument is BicepValue bicepValue) + { + bicepStringBuilder.Append($"{bicepValue}"); + } + else if (argument is string s) + { + bicepStringBuilder.Append(s); + } + else if (argument is ProvisioningParameter provisioningParameter) + { + bicepStringBuilder.Append($"{provisioningParameter}"); + } + else + { + throw new NotSupportedException($"{argument} is not supported"); } - formatStringBuilder.Append(span); - } - - ProcessFormattableString(text, 0); - - var formatString = formatStringBuilder.ToString(); - - if (formatString == "{0}") - { - return arguments[0]; + argumentIndex++; + span = span[(match.Index + match.Length - skip)..]; + skip = match.Index + match.Length; } - return BicepFunction.Interpolate(new BicepValueFormattableString(formatString, [.. arguments])); - } + bicepStringBuilder.Append(span.ToString()); - /// - /// A custom FormattableString implementation that allows us to inline nested formattable strings. - /// - private sealed class BicepValueFormattableString(string formatString, object[] values) : FormattableString - { - public override int ArgumentCount => values.Length; - public override string Format => formatString; - public override object? GetArgument(int index) => values[index]; - public override object?[] GetArguments() => values; - public override string ToString(IFormatProvider? formatProvider) => Format; - public override string ToString() => formatString; + return bicepStringBuilder.Build(); } /// diff --git a/src/Aspire.Hosting.Azure.AppContainers/ContainerAppExtensions.cs b/src/Aspire.Hosting.Azure.AppContainers/ContainerAppExtensions.cs index f1f004d121..bce9c2ba7c 100644 --- a/src/Aspire.Hosting.Azure.AppContainers/ContainerAppExtensions.cs +++ b/src/Aspire.Hosting.Azure.AppContainers/ContainerAppExtensions.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; using Aspire.Hosting.ApplicationModel; +using Aspire.Hosting.Azure; +using Azure.Provisioning; using Azure.Provisioning.AppContainers; using Azure.Provisioning.Expressions; -using Azure.Provisioning; -using System.Diagnostics.CodeAnalysis; -using Aspire.Hosting.Azure; namespace Aspire.Hosting; @@ -62,40 +62,40 @@ public static void ConfigureCustomDomain(this ContainerApp app, IResourceBuilder throw new ArgumentException("Cannot configure custom domain when resource is not parented by ResourceModuleConstruct.", nameof(app)); } - var containerAppManagedEnvironmentIdParameter = module.GetResources().OfType().Single( - p => p.IdentifierName == "outputs_azure_container_apps_environment_id"); - var certificatNameParameter = certificateName.AsProvisioningParameter(module); + var containerAppManagedEnvironmentIdParameter = module.GetProvisionableResources().OfType().Single( + p => p.BicepIdentifier == "outputs_azure_container_apps_environment_id"); + var certificateNameParameter = certificateName.AsProvisioningParameter(module); var customDomainParameter = customDomain.AsProvisioningParameter(module); var bindingTypeConditional = new ConditionalExpression( new BinaryExpression( - new IdentifierExpression(certificatNameParameter.IdentifierName), - BinaryOperator.NotEqual, - new StringLiteral(string.Empty)), - new StringLiteral("SniEnabled"), - new StringLiteral("Disabled") + new IdentifierExpression(certificateNameParameter.BicepIdentifier), + BinaryBicepOperator.NotEqual, + new StringLiteralExpression(string.Empty)), + new StringLiteralExpression("SniEnabled"), + new StringLiteralExpression("Disabled") ); var certificateOrEmpty = new ConditionalExpression( new BinaryExpression( - new IdentifierExpression(certificatNameParameter.IdentifierName), - BinaryOperator.NotEqual, - new StringLiteral(string.Empty)), - new InterpolatedString( - "{0}/managedCertificates/{1}", + new IdentifierExpression(certificateNameParameter.BicepIdentifier), + BinaryBicepOperator.NotEqual, + new StringLiteralExpression(string.Empty)), + new InterpolatedStringExpression( [ - new IdentifierExpression(containerAppManagedEnvironmentIdParameter.IdentifierName), - new IdentifierExpression(certificatNameParameter.IdentifierName) + new IdentifierExpression(containerAppManagedEnvironmentIdParameter.BicepIdentifier), + new StringLiteralExpression("/managedCertificates/"), + new IdentifierExpression(certificateNameParameter.BicepIdentifier) ]), - new NullLiteral() + new NullLiteralExpression() ); - app.Configuration.Value!.Ingress!.Value!.CustomDomains = new BicepList() + app.Configuration.Ingress.CustomDomains = new BicepList() { new ContainerAppCustomDomain() { BindingType = bindingTypeConditional, - Name = new IdentifierExpression(customDomainParameter.IdentifierName), + Name = customDomainParameter, CertificateId = certificateOrEmpty } }; diff --git a/src/Aspire.Hosting.Azure.ApplicationInsights/AzureApplicationInsightsExtensions.cs b/src/Aspire.Hosting.Azure.ApplicationInsights/AzureApplicationInsightsExtensions.cs index 04c06574ef..06d7d191be 100644 --- a/src/Aspire.Hosting.Azure.ApplicationInsights/AzureApplicationInsightsExtensions.cs +++ b/src/Aspire.Hosting.Azure.ApplicationInsights/AzureApplicationInsightsExtensions.cs @@ -5,7 +5,6 @@ using Aspire.Hosting.Azure; using Azure.Provisioning; using Azure.Provisioning.ApplicationInsights; -using Azure.Provisioning.Expressions; using Azure.Provisioning.OperationalInsights; namespace Aspire.Hosting; @@ -41,13 +40,13 @@ public static IResourceBuilder AddAzureApplica { var appTypeParameter = new ProvisioningParameter("applicationType", typeof(string)) { - Value = new StringLiteral("web") + Value = "web" }; infrastructure.Add(appTypeParameter); var kindParameter = new ProvisioningParameter("kind", typeof(string)) { - Value = new StringLiteral("web") + Value = "web" }; infrastructure.Add(kindParameter); @@ -67,7 +66,7 @@ public static IResourceBuilder AddAzureApplica else if (builder.ExecutionContext.IsRunMode) { // ... otherwise if we are in run mode, the provisioner expects us to create one ourselves. - var autoInjectedLogAnalyticsWorkspaceName = $"law_{appInsights.IdentifierName}"; + var autoInjectedLogAnalyticsWorkspaceName = $"law_{appInsights.BicepIdentifier}"; var autoInjectedLogAnalyticsWorkspace = new OperationalInsightsWorkspace(autoInjectedLogAnalyticsWorkspaceName) { Sku = new OperationalInsightsWorkspaceSku() @@ -89,7 +88,7 @@ public static IResourceBuilder AddAzureApplica infrastructure.AspireResource.Parameters.TryAdd(AzureBicepResource.KnownParameters.LogAnalyticsWorkspaceId, null); var logAnalyticsWorkspaceParameter = new ProvisioningParameter(AzureBicepResource.KnownParameters.LogAnalyticsWorkspaceId, typeof(string)) { - Value = new StringLiteral("web") + Value = "web" }; infrastructure.Add(kindParameter); appInsights.WorkspaceResourceId = logAnalyticsWorkspaceParameter; diff --git a/src/Aspire.Hosting.Azure.CognitiveServices/AzureOpenAIExtensions.cs b/src/Aspire.Hosting.Azure.CognitiveServices/AzureOpenAIExtensions.cs index e9e3b85b69..27b98ffda8 100644 --- a/src/Aspire.Hosting.Azure.CognitiveServices/AzureOpenAIExtensions.cs +++ b/src/Aspire.Hosting.Azure.CognitiveServices/AzureOpenAIExtensions.cs @@ -5,7 +5,6 @@ using Aspire.Hosting.Azure; using Azure.Provisioning; using Azure.Provisioning.CognitiveServices; -using Azure.Provisioning.Expressions; using static Azure.Provisioning.Expressions.BicepFunction; namespace Aspire.Hosting; @@ -47,17 +46,7 @@ public static IResourceBuilder AddAzureOpenAI(this IDistrib infrastructure.Add(new ProvisioningOutput("connectionString", typeof(string)) { - Value = new InterpolatedString( - "Endpoint={0}", - [ - new MemberExpression( - new MemberExpression( - new IdentifierExpression(cogServicesAccount.IdentifierName), - "properties"), - "endpoint") - ]) - // TODO This should be - // Value = BicepFunction.Interpolate($"Endpoint={cogServicesAccount.Endpoint}") + Value = Interpolate($"Endpoint={cogServicesAccount.Properties.Endpoint}") }); var principalTypeParameter = new ProvisioningParameter(AzureBicepResource.KnownParameters.PrincipalType, typeof(string)); @@ -71,7 +60,7 @@ public static IResourceBuilder AddAzureOpenAI(this IDistrib var cdkDeployments = new List(); foreach (var deployment in resource.Deployments) { - var cdkDeployment = new CognitiveServicesAccountDeployment(Infrastructure.NormalizeIdentifierName(deployment.Name)) + var cdkDeployment = new CognitiveServicesAccountDeployment(Infrastructure.NormalizeBicepIdentifier(deployment.Name)) { Name = deployment.Name, Parent = cogServicesAccount, diff --git a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBExtensions.cs b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBExtensions.cs index 2f75161e4f..6fbb1067b3 100644 --- a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBExtensions.cs +++ b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBExtensions.cs @@ -65,7 +65,7 @@ public static IResourceBuilder AddAzureCosmosDB(this IDis List cosmosSqlDatabases = new List(); foreach (var databaseName in azureResource.Databases) { - var cosmosSqlDatabase = new CosmosDBSqlDatabase(Infrastructure.NormalizeIdentifierName(databaseName)) + var cosmosSqlDatabase = new CosmosDBSqlDatabase(Infrastructure.NormalizeBicepIdentifier(databaseName)) { Parent = cosmosAccount, Name = databaseName, diff --git a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsExtensions.cs b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsExtensions.cs index 2074fcb0d1..8cb4934eb1 100644 --- a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsExtensions.cs +++ b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsExtensions.cs @@ -9,7 +9,6 @@ using Azure.Messaging.EventHubs.Producer; using Azure.Provisioning; using Azure.Provisioning.EventHubs; -using Azure.Provisioning.Expressions; using Microsoft.Extensions.DependencyInjection; namespace Aspire.Hosting; @@ -34,7 +33,7 @@ public static IResourceBuilder AddAzureEventHubs( { var skuParameter = new ProvisioningParameter("sku", typeof(string)) { - Value = new StringLiteral("Standard") + Value = "Standard" }; infrastructure.Add(skuParameter); @@ -58,7 +57,7 @@ public static IResourceBuilder AddAzureEventHubs( foreach (var hub in azureResource.Hubs) { - var hubResource = new EventHub(Infrastructure.NormalizeIdentifierName(hub)) + var hubResource = new EventHub(Infrastructure.NormalizeBicepIdentifier(hub)) { Parent = eventHubsNamespace, Name = hub diff --git a/src/Aspire.Hosting.Azure.Functions/AzureFunctionsProjectResourceExtensions.cs b/src/Aspire.Hosting.Azure.Functions/AzureFunctionsProjectResourceExtensions.cs index 7030369bc9..7d07dd878a 100644 --- a/src/Aspire.Hosting.Azure.Functions/AzureFunctionsProjectResourceExtensions.cs +++ b/src/Aspire.Hosting.Azure.Functions/AzureFunctionsProjectResourceExtensions.cs @@ -54,7 +54,7 @@ public static class AzureFunctionsProjectResourceExtensions var principalTypeParameter = new ProvisioningParameter(AzureBicepResource.KnownParameters.PrincipalType, typeof(string)); var principalIdParameter = new ProvisioningParameter(AzureBicepResource.KnownParameters.PrincipalId, typeof(string)); - var storageAccount = infrastructure.GetResources().OfType().FirstOrDefault(r => r.IdentifierName == storageResourceName) + var storageAccount = infrastructure.GetProvisionableResources().OfType().FirstOrDefault(r => r.BicepIdentifier == storageResourceName) ?? throw new InvalidOperationException($"Could not find storage account with '{storageResourceName}' name."); infrastructure.Add(storageAccount.CreateRoleAssignment(StorageBuiltInRole.StorageAccountContributor, principalTypeParameter, principalIdParameter)); }; diff --git a/src/Aspire.Hosting.Azure.KeyVault/AzureKeyVaultResourceExtensions.cs b/src/Aspire.Hosting.Azure.KeyVault/AzureKeyVaultResourceExtensions.cs index 36346cd269..ae3f5eb949 100644 --- a/src/Aspire.Hosting.Azure.KeyVault/AzureKeyVaultResourceExtensions.cs +++ b/src/Aspire.Hosting.Azure.KeyVault/AzureKeyVaultResourceExtensions.cs @@ -43,14 +43,7 @@ public static IResourceBuilder AddAzureKeyVault(this IDis infrastructure.Add(new ProvisioningOutput("vaultUri", typeof(string)) { - Value = - new MemberExpression( - new MemberExpression( - new IdentifierExpression(keyVault.IdentifierName), - "properties"), - "vaultUri") - // TODO: this should be - //Value = keyVault.VaultUri + Value = keyVault.Properties.VaultUri }); keyVault.Tags["aspire-resource-name"] = infrastructure.AspireResource.Name; diff --git a/src/Aspire.Hosting.Azure.PostgreSQL/AzurePostgresExtensions.cs b/src/Aspire.Hosting.Azure.PostgreSQL/AzurePostgresExtensions.cs index 961cc36b41..f8d4b4f996 100644 --- a/src/Aspire.Hosting.Azure.PostgreSQL/AzurePostgresExtensions.cs +++ b/src/Aspire.Hosting.Azure.PostgreSQL/AzurePostgresExtensions.cs @@ -157,7 +157,7 @@ public static IResourceBuilder AddAzurePost var principalTypeParameter = new ProvisioningParameter(AzureBicepResource.KnownParameters.PrincipalType, typeof(string)); var principalNameParameter = new ProvisioningParameter(AzureBicepResource.KnownParameters.PrincipalName, typeof(string)); - var admin = new PostgreSqlFlexibleServerActiveDirectoryAdministrator($"{postgres.IdentifierName}_admin") + var admin = new PostgreSqlFlexibleServerActiveDirectoryAdministrator($"{postgres.BicepIdentifier}_admin") { Parent = postgres, Name = principalIdParameter, @@ -167,7 +167,7 @@ public static IResourceBuilder AddAzurePost // This is a workaround for a bug in the API that requires the parent to be fully resolved admin.DependsOn.Add(postgres); - foreach (var firewall in infrastructure.GetResources().OfType()) + foreach (var firewall in infrastructure.GetProvisionableResources().OfType()) { admin.DependsOn.Add(firewall); } @@ -355,7 +355,7 @@ public static IResourceBuilder WithPassword RemoveActiveDirectoryAuthResources(infrastructure); - var postgres = infrastructure.GetResources().OfType().FirstOrDefault(r => r.IdentifierName == azureResource.GetBicepIdentifier()) + var postgres = infrastructure.GetProvisionableResources().OfType().FirstOrDefault(r => r.BicepIdentifier == azureResource.GetBicepIdentifier()) ?? throw new InvalidOperationException($"Could not find a PostgreSqlFlexibleServer with name {azureResource.Name}."); var administratorLogin = new ProvisioningParameter("administratorLogin", typeof(string)); @@ -393,7 +393,7 @@ public static IResourceBuilder WithPassword foreach (var database in azureResource.Databases) { - var dbSecret = new KeyVaultSecret(Infrastructure.NormalizeIdentifierName(database.Key + "_connectionString")) + var dbSecret = new KeyVaultSecret(Infrastructure.NormalizeBicepIdentifier(database.Key + "_connectionString")) { Parent = keyVault, Name = AzurePostgresFlexibleServerResource.GetDatabaseKeyVaultSecretName(database.Key), @@ -417,7 +417,7 @@ private static PostgreSqlFlexibleServer CreatePostgreSqlFlexibleServer(AzureReso Name = "Standard_B1ms", Tier = PostgreSqlFlexibleServerSkuTier.Burstable }, - Version = new StringLiteral("16"), + Version = new StringLiteralExpression("16"), HighAvailability = new PostgreSqlFlexibleServerHighAvailability() { Mode = PostgreSqlFlexibleServerHighAvailabilityMode.Disabled @@ -455,9 +455,9 @@ private static PostgreSqlFlexibleServer CreatePostgreSqlFlexibleServer(AzureReso foreach (var databaseNames in databases) { - var identifierName = Infrastructure.NormalizeIdentifierName(databaseNames.Key); + var bicepIdentifier = Infrastructure.NormalizeBicepIdentifier(databaseNames.Key); var databaseName = databaseNames.Value; - var pgsqlDatabase = new PostgreSqlFlexibleServerDatabase(identifierName) + var pgsqlDatabase = new PostgreSqlFlexibleServerDatabase(bicepIdentifier) { Parent = postgres, Name = databaseName @@ -480,13 +480,13 @@ private static IResourceBuilder RemoveActiv private static void RemoveActiveDirectoryAuthResources(AzureResourceInfrastructure infrastructure) { var resourcesToRemove = new List(); - foreach (var resource in infrastructure.GetResources()) + foreach (var resource in infrastructure.GetProvisionableResources()) { if (resource is PostgreSqlFlexibleServerActiveDirectoryAdministrator) { resourcesToRemove.Add(resource); } - else if (resource is ProvisioningOutput output && output.IdentifierName == "connectionString") + else if (resource is ProvisioningOutput output && output.BicepIdentifier == "connectionString") { resourcesToRemove.Add(resource); } diff --git a/src/Aspire.Hosting.Azure.Redis/AzureRedisExtensions.cs b/src/Aspire.Hosting.Azure.Redis/AzureRedisExtensions.cs index 97f76c422e..3b2a0c20d8 100644 --- a/src/Aspire.Hosting.Azure.Redis/AzureRedisExtensions.cs +++ b/src/Aspire.Hosting.Azure.Redis/AzureRedisExtensions.cs @@ -129,14 +129,11 @@ public static IResourceBuilder AddAzureRedis( { IsAadEnabled = "true" }; - - // TODO: This property should be available from the CDK in the latest version. - var disableAccessKeys = BicepValue.DefineProperty(redis, "DisableAccessKeyAuthentication", ["properties", "disableAccessKeyAuthentication"], isOutput: false, isRequired: false); - disableAccessKeys.Assign("true"); + redis.IsAccessKeyAuthenticationDisabled = true; var principalIdParameter = new ProvisioningParameter(AzureBicepResource.KnownParameters.PrincipalId, typeof(string)); var principalNameParameter = new ProvisioningParameter(AzureBicepResource.KnownParameters.PrincipalName, typeof(string)); - infrastructure.Add(new RedisCacheAccessPolicyAssignment($"{redis.IdentifierName}_contributor") + infrastructure.Add(new RedisCacheAccessPolicyAssignment($"{redis.BicepIdentifier}_contributor") { Parent = redis, AccessPolicyName = "Data Contributor", @@ -233,7 +230,7 @@ public static IResourceBuilder WithAccessKeyAuthenticat { RemoveActiveDirectoryAuthResources(infrastructure); - var redis = infrastructure.GetResources().OfType().FirstOrDefault(r => r.IdentifierName == builder.Resource.GetBicepIdentifier()) + var redis = infrastructure.GetProvisionableResources().OfType().FirstOrDefault(r => r.BicepIdentifier == builder.Resource.GetBicepIdentifier()) ?? throw new InvalidOperationException($"Could not find a RedisResource with name {builder.Resource.Name}."); var kvNameParam = new ProvisioningParameter("keyVaultName", typeof(string)); @@ -243,11 +240,8 @@ public static IResourceBuilder WithAccessKeyAuthenticat keyVault.Name = kvNameParam; infrastructure.Add(keyVault); - redis.RedisConfiguration.Value!.IsAadEnabled.Kind = BicepValueKind.Unset; - - // TODO: This property should be available from the CDK in the latest version. - var disableAccessKeys = BicepValue.DefineProperty(redis, "DisableAccessKeyAuthentication", ["properties", "disableAccessKeyAuthentication"], isOutput: false, isRequired: false); - disableAccessKeys.Kind = BicepValueKind.Unset; + redis.RedisConfiguration.IsAadEnabled.ClearValue(); + redis.IsAccessKeyAuthenticationDisabled.ClearValue(); var secret = new KeyVaultSecret("connectionString") { @@ -292,14 +286,14 @@ private static IResourceBuilder RemoveActiveDirectoryPa private static void RemoveActiveDirectoryAuthResources(AzureResourceInfrastructure infrastructure) { var resourcesToRemove = new List(); - foreach (var resource in infrastructure.GetResources()) + foreach (var resource in infrastructure.GetProvisionableResources()) { if (resource is RedisCacheAccessPolicyAssignment accessPolicy && - accessPolicy.IdentifierName == $"{infrastructure.AspireResource.GetBicepIdentifier()}_contributor") + accessPolicy.BicepIdentifier == $"{infrastructure.AspireResource.GetBicepIdentifier()}_contributor") { resourcesToRemove.Add(resource); } - else if (resource is ProvisioningOutput output && output.IdentifierName == "connectionString") + else if (resource is ProvisioningOutput output && output.BicepIdentifier == "connectionString") { resourcesToRemove.Add(resource); } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs index ec7c4b7720..92c19b6575 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs @@ -4,7 +4,6 @@ using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Azure; using Azure.Provisioning; -using Azure.Provisioning.Expressions; using Azure.Provisioning.ServiceBus; namespace Aspire.Hosting; @@ -28,7 +27,7 @@ public static IResourceBuilder AddAzureServiceBus(this { var skuParameter = new ProvisioningParameter("sku", typeof(string)) { - Value = new StringLiteral("Standard") + Value = "Standard" }; infrastructure.Add(skuParameter); @@ -53,7 +52,7 @@ public static IResourceBuilder AddAzureServiceBus(this foreach (var queue in azureResource.Queues) { - var queueResource = new ServiceBusQueue(Infrastructure.NormalizeIdentifierName(queue)) + var queueResource = new ServiceBusQueue(Infrastructure.NormalizeBicepIdentifier(queue)) { Parent = serviceBusNamespace, Name = queue @@ -63,7 +62,7 @@ public static IResourceBuilder AddAzureServiceBus(this var topicDictionary = new Dictionary(); foreach (var topic in azureResource.Topics) { - var topicResource = new ServiceBusTopic(Infrastructure.NormalizeIdentifierName(topic)) + var topicResource = new ServiceBusTopic(Infrastructure.NormalizeBicepIdentifier(topic)) { Parent = serviceBusNamespace, Name = topic @@ -74,7 +73,7 @@ public static IResourceBuilder AddAzureServiceBus(this foreach (var subscription in azureResource.Subscriptions) { var topic = topicDictionary[subscription.TopicName]; - var subscriptionResource = new ServiceBusSubscription(Infrastructure.NormalizeIdentifierName(subscription.Name)) + var subscriptionResource = new ServiceBusSubscription(Infrastructure.NormalizeBicepIdentifier(subscription.Name)) { Parent = topic, Name = subscription.Name diff --git a/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs b/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs index 5ee8df25f9..99a2880ec9 100644 --- a/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs +++ b/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs @@ -243,7 +243,7 @@ private static void CreateSqlServer( // When in run mode we inject the users identity and we need to specify // the principalType. var principalTypeParameter = new ProvisioningParameter(AzureBicepResource.KnownParameters.PrincipalType, typeof(string)); - sqlServer.Administrators.Value!.PrincipalType = principalTypeParameter; + sqlServer.Administrators.PrincipalType = principalTypeParameter; infrastructure.Add(new SqlFirewallRule("sqlFirewallRule_AllowAllIps") { @@ -256,9 +256,9 @@ private static void CreateSqlServer( foreach (var databaseNames in databases) { - var identifierName = Infrastructure.NormalizeIdentifierName(databaseNames.Key); + var bicepIdentifier = Infrastructure.NormalizeBicepIdentifier(databaseNames.Key); var databaseName = databaseNames.Value; - var sqlDatabase = new SqlDatabase(identifierName) + var sqlDatabase = new SqlDatabase(bicepIdentifier) { Parent = sqlServer, Name = databaseName diff --git a/src/Aspire.Hosting.Azure.Storage/AzureStorageExtensions.cs b/src/Aspire.Hosting.Azure.Storage/AzureStorageExtensions.cs index 347822fb0e..d34f2f466b 100644 --- a/src/Aspire.Hosting.Azure.Storage/AzureStorageExtensions.cs +++ b/src/Aspire.Hosting.Azure.Storage/AzureStorageExtensions.cs @@ -65,9 +65,9 @@ public static IResourceBuilder AddAzureStorage(this IDistr infrastructure.Add(storageAccount.CreateRoleAssignment(StorageBuiltInRole.StorageTableDataContributor, principalTypeParameter, principalIdParameter)); infrastructure.Add(storageAccount.CreateRoleAssignment(StorageBuiltInRole.StorageQueueDataContributor, principalTypeParameter, principalIdParameter)); - infrastructure.Add(new ProvisioningOutput("blobEndpoint", typeof(string)) { Value = storageAccount.PrimaryEndpoints.Value!.BlobUri }); - infrastructure.Add(new ProvisioningOutput("queueEndpoint", typeof(string)) { Value = storageAccount.PrimaryEndpoints.Value!.QueueUri }); - infrastructure.Add(new ProvisioningOutput("tableEndpoint", typeof(string)) { Value = storageAccount.PrimaryEndpoints.Value!.TableUri }); + infrastructure.Add(new ProvisioningOutput("blobEndpoint", typeof(string)) { Value = storageAccount.PrimaryEndpoints.BlobUri }); + infrastructure.Add(new ProvisioningOutput("queueEndpoint", typeof(string)) { Value = storageAccount.PrimaryEndpoints.QueueUri }); + infrastructure.Add(new ProvisioningOutput("tableEndpoint", typeof(string)) { Value = storageAccount.PrimaryEndpoints.TableUri }); }; var resource = new AzureStorageResource(name, configureInfrastructure); diff --git a/src/Aspire.Hosting.Azure.WebPubSub/AzureWebPubSubExtensions.cs b/src/Aspire.Hosting.Azure.WebPubSub/AzureWebPubSubExtensions.cs index fc2e5a7ccd..a4237f5705 100644 --- a/src/Aspire.Hosting.Azure.WebPubSub/AzureWebPubSubExtensions.cs +++ b/src/Aspire.Hosting.Azure.WebPubSub/AzureWebPubSubExtensions.cs @@ -31,7 +31,7 @@ public static IResourceBuilder AddAzureWebPubSub(this ID // Supported values are Free_F1 Standard_S1 Premium_P1 var skuParameter = new ProvisioningParameter("sku", typeof(string)) { - Value = new StringLiteral("Free_F1") + Value = "Free_F1" }; infrastructure.Add(skuParameter); @@ -66,14 +66,14 @@ public static IResourceBuilder AddAzureWebPubSub(this ID var hubBuilder = setting.Value; var hubResource = hubBuilder; - var hub = new WebPubSubHub(Infrastructure.NormalizeIdentifierName(hubResource.Name)) + var hub = new WebPubSubHub(Infrastructure.NormalizeBicepIdentifier(hubResource.Name)) { Name = setting.Key, Parent = service, Properties = new WebPubSubHubProperties() }; - var hubProperties = hub.Properties.Value!; + var hubProperties = hub.Properties; // invoke the configure from AddEventHandler for (var i = 0; i < hubResource.EventHandlers.Count; i++) @@ -92,7 +92,7 @@ public static IResourceBuilder AddAzureWebPubSub(this ID // otherwise add parameter to the construct var parameter = new ProvisioningParameter($"{hubName}_url_{i}", typeof(string)); infrastructure.Add(parameter); - resource.Parameters[parameter.IdentifierName] = urlExpression; + resource.Parameters[parameter.BicepIdentifier] = urlExpression; urlParameter = parameter; } @@ -183,7 +183,7 @@ private static WebPubSubEventHandler GetWebPubSubEventHandler(BicepValue if (authSettings != null) { - handler.Auth = new BicepValue(authSettings); + handler.Auth = authSettings; } return handler; } diff --git a/src/Aspire.Hosting.Azure/AspireV8ResourceNamePropertyResolver.cs b/src/Aspire.Hosting.Azure/AspireV8ResourceNamePropertyResolver.cs index a2c7f776dc..05488e39af 100644 --- a/src/Aspire.Hosting.Azure/AspireV8ResourceNamePropertyResolver.cs +++ b/src/Aspire.Hosting.Azure/AspireV8ResourceNamePropertyResolver.cs @@ -16,9 +16,29 @@ namespace Aspire.Hosting.Azure; public sealed class AspireV8ResourceNamePropertyResolver : DynamicResourceNamePropertyResolver { /// - public override BicepValue? ResolveName(ProvisioningContext context, Resource resource, ResourceNameRequirements requirements) + public override BicepValue? ResolveName(ProvisioningBuildOptions options, ProvisionableResource resource, ResourceNameRequirements requirements) { - var suffix = GetUniqueSuffix(context, resource); - return BicepFunction.ToLower(BicepFunction.Take(BicepFunction.Interpolate($"{resource.IdentifierName}{suffix}"), 24)); + var suffix = GetUniqueSuffix(options, resource); + var prefix = GetNamePrefix(resource); + + return BicepFunction.ToLower(BicepFunction.Take(BicepFunction.Interpolate($"{prefix}{suffix}"), 24)); + } + + /// + /// Use the 'aspire-resource-name' tag to get the prefix for the resource name, if available. + /// + /// + /// The BicepIdentifier has already had any dashes changed to underscores, which we don't want to use since .NET Aspire 8.x used the dashes. + /// + private static string GetNamePrefix(ProvisionableResource resource) + { + BicepValue? aspireResourceName = null; + if (resource.ProvisionableProperties.TryGetValue("Tags", out var tags) && + tags is BicepDictionary tagDictionary) + { + tagDictionary.TryGetValue("aspire-resource-name", out aspireResourceName); + } + + return aspireResourceName?.Value ?? resource.BicepIdentifier; } } diff --git a/src/Aspire.Hosting.Azure/AzureProvisioningOptions.cs b/src/Aspire.Hosting.Azure/AzureProvisioningOptions.cs index 8084b6e4ed..ea778c7bf1 100644 --- a/src/Aspire.Hosting.Azure/AzureProvisioningOptions.cs +++ b/src/Aspire.Hosting.Azure/AzureProvisioningOptions.cs @@ -15,8 +15,8 @@ namespace Aspire.Hosting.Azure; public sealed class AzureProvisioningOptions { /// - /// Gets the which contains common settings and + /// Gets the which contains common settings and /// functionality for building Azure resources. /// - public ProvisioningContext ProvisioningContext { get; } = new ProvisioningContext(); + public ProvisioningBuildOptions ProvisioningBuildOptions { get; } = new ProvisioningBuildOptions(); } diff --git a/src/Aspire.Hosting.Azure/AzureProvisioningResource.cs b/src/Aspire.Hosting.Azure/AzureProvisioningResource.cs index 8122c30a54..c5c18228be 100644 --- a/src/Aspire.Hosting.Azure/AzureProvisioningResource.cs +++ b/src/Aspire.Hosting.Azure/AzureProvisioningResource.cs @@ -20,10 +20,10 @@ public class AzureProvisioningResource(string name, Action ConfigureInfrastructure { get; internal set; } = configureInfrastructure; /// - /// Gets or sets the which contains common settings and + /// Gets or sets the which contains common settings and /// functionality for building Azure resources. /// - public ProvisioningContext? ProvisioningContext { get; set; } + public ProvisioningBuildOptions? ProvisioningBuildOptions { get; set; } /// public override BicepTemplateFile GetBicepTemplateFile(string? directory = null, bool deleteTemporaryFileOnDispose = true) @@ -38,8 +38,8 @@ public override BicepTemplateFile GetBicepTemplateFile(string? directory = null, // put them into a dictionary for quick lookup so we don't need to scan // through the parameter enumerable each time. var infrastructureParameters = infrastructure.GetParameters(); - var distinctInfrastructureParameters = infrastructureParameters.DistinctBy(p => p.IdentifierName); - var distinctInfrastructureParametersLookup = distinctInfrastructureParameters.ToDictionary(p => p.IdentifierName); + var distinctInfrastructureParameters = infrastructureParameters.DistinctBy(p => p.BicepIdentifier); + var distinctInfrastructureParametersLookup = distinctInfrastructureParameters.ToDictionary(p => p.BicepIdentifier); foreach (var aspireParameter in this.Parameters) { @@ -56,7 +56,7 @@ public override BicepTemplateFile GetBicepTemplateFile(string? directory = null, var generationPath = Directory.CreateTempSubdirectory("aspire").FullName; var moduleSourcePath = Path.Combine(generationPath, "main.bicep"); - var plan = infrastructure.Build(ProvisioningContext); + var plan = infrastructure.Build(ProvisioningBuildOptions); var compilation = plan.Compile(); Debug.Assert(compilation.Count == 1); var compiledBicep = compilation.First(); diff --git a/src/Aspire.Hosting.Azure/AzureProvisioningResourceExtensions.cs b/src/Aspire.Hosting.Azure/AzureProvisioningResourceExtensions.cs index d6c0472d5b..33b8d27f00 100644 --- a/src/Aspire.Hosting.Azure/AzureProvisioningResourceExtensions.cs +++ b/src/Aspire.Hosting.Azure/AzureProvisioningResourceExtensions.cs @@ -69,11 +69,11 @@ public static ProvisioningParameter AsProvisioningParameter(this IResourceBuilde ArgumentNullException.ThrowIfNull(parameterResourceBuilder); ArgumentNullException.ThrowIfNull(infrastructure); - parameterName ??= Infrastructure.NormalizeIdentifierName(parameterResourceBuilder.Resource.Name); + parameterName ??= Infrastructure.NormalizeBicepIdentifier(parameterResourceBuilder.Resource.Name); infrastructure.AspireResource.Parameters[parameterName] = parameterResourceBuilder.Resource; - var parameter = infrastructure.GetParameters().FirstOrDefault(p => p.IdentifierName == parameterName); + var parameter = infrastructure.GetParameters().FirstOrDefault(p => p.BicepIdentifier == parameterName); if (parameter is null) { parameter = new ProvisioningParameter(parameterName, typeof(string)) @@ -112,7 +112,7 @@ public static ProvisioningParameter AsProvisioningParameter(this BicepOutputRefe infrastructure.AspireResource.Parameters[parameterName] = outputReference; - var parameter = infrastructure.GetParameters().FirstOrDefault(p => p.IdentifierName == parameterName); + var parameter = infrastructure.GetParameters().FirstOrDefault(p => p.BicepIdentifier == parameterName); if (parameter is null) { parameter = new ProvisioningParameter(parameterName, typeof(string)); diff --git a/src/Aspire.Hosting.Azure/AzureResourceExtensions.cs b/src/Aspire.Hosting.Azure/AzureResourceExtensions.cs index 1d8b2fc2c5..ac9a3b73b9 100644 --- a/src/Aspire.Hosting.Azure/AzureResourceExtensions.cs +++ b/src/Aspire.Hosting.Azure/AzureResourceExtensions.cs @@ -30,5 +30,5 @@ public static IResourceBuilder PublishAsConnectionString(this IResourceBui /// The Azure resource. /// A valid Bicep identifier. public static string GetBicepIdentifier(this IAzureResource resource) => - Infrastructure.NormalizeIdentifierName(resource.Name); + Infrastructure.NormalizeBicepIdentifier(resource.Name); } diff --git a/src/Aspire.Hosting.Azure/AzureResourceInfrastructure.cs b/src/Aspire.Hosting.Azure/AzureResourceInfrastructure.cs index bb8e480848..5396171d0c 100644 --- a/src/Aspire.Hosting.Azure/AzureResourceInfrastructure.cs +++ b/src/Aspire.Hosting.Azure/AzureResourceInfrastructure.cs @@ -30,5 +30,5 @@ internal AzureResourceInfrastructure(AzureProvisioningResource resource, string /// public AzureProvisioningResource AspireResource { get; } - internal IEnumerable GetParameters() => GetResources().OfType(); + internal IEnumerable GetParameters() => GetProvisionableResources().OfType(); } diff --git a/src/Aspire.Hosting.Azure/Provisioning/Provisioners/AzureProvisioner.cs b/src/Aspire.Hosting.Azure/Provisioning/Provisioners/AzureProvisioner.cs index 8e1aaf1c36..ee690f8cee 100644 --- a/src/Aspire.Hosting.Azure/Provisioning/Provisioners/AzureProvisioner.cs +++ b/src/Aspire.Hosting.Azure/Provisioning/Provisioners/AzureProvisioner.cs @@ -83,12 +83,12 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell return; } - // set the ProvisioningContext on the resource, if necessary + // set the ProvisioningBuildOptions on the resource, if necessary foreach (var r in azureResources) { if (r.AzureResource is AzureProvisioningResource provisioningResource) { - provisioningResource.ProvisioningContext = provisioningOptions.Value.ProvisioningContext; + provisioningResource.ProvisioningBuildOptions = provisioningOptions.Value.ProvisioningBuildOptions; } } diff --git a/src/Aspire.Hosting.Azure/PublicAPI.Unshipped.txt b/src/Aspire.Hosting.Azure/PublicAPI.Unshipped.txt index 005fda52ce..830233db18 100644 --- a/src/Aspire.Hosting.Azure/PublicAPI.Unshipped.txt +++ b/src/Aspire.Hosting.Azure/PublicAPI.Unshipped.txt @@ -17,18 +17,18 @@ Aspire.Hosting.Azure.AspireV8ResourceNamePropertyResolver Aspire.Hosting.Azure.AspireV8ResourceNamePropertyResolver.AspireV8ResourceNamePropertyResolver() -> void Aspire.Hosting.Azure.AzureProvisioningOptions Aspire.Hosting.Azure.AzureProvisioningOptions.AzureProvisioningOptions() -> void -Aspire.Hosting.Azure.AzureProvisioningOptions.ProvisioningContext.get -> Azure.Provisioning.ProvisioningContext! +Aspire.Hosting.Azure.AzureProvisioningOptions.ProvisioningBuildOptions.get -> Azure.Provisioning.ProvisioningBuildOptions! Aspire.Hosting.Azure.AzureProvisioningResource.AzureProvisioningResource(string! name, System.Action! configureInfrastructure) -> void Aspire.Hosting.Azure.AzureProvisioningResource.ConfigureInfrastructure.get -> System.Action! Aspire.Hosting.Azure.AzureProvisioningResource -Aspire.Hosting.Azure.AzureProvisioningResource.ProvisioningContext.get -> Azure.Provisioning.ProvisioningContext? -Aspire.Hosting.Azure.AzureProvisioningResource.ProvisioningContext.set -> void +Aspire.Hosting.Azure.AzureProvisioningResource.ProvisioningBuildOptions.get -> Azure.Provisioning.ProvisioningBuildOptions? +Aspire.Hosting.Azure.AzureProvisioningResource.ProvisioningBuildOptions.set -> void Aspire.Hosting.Azure.AzureResourceInfrastructure Aspire.Hosting.Azure.AzureResourceInfrastructure.AspireResource.get -> Aspire.Hosting.Azure.AzureProvisioningResource! Aspire.Hosting.Azure.IResourceWithAzureFunctionsConfig Aspire.Hosting.Azure.IResourceWithAzureFunctionsConfig.ApplyAzureFunctionsConfiguration(System.Collections.Generic.IDictionary! target, string! connectionName) -> void Aspire.Hosting.AzureProvisioningResourceExtensions -override Aspire.Hosting.Azure.AspireV8ResourceNamePropertyResolver.ResolveName(Azure.Provisioning.ProvisioningContext! context, Azure.Provisioning.Primitives.Resource! resource, Azure.Provisioning.Primitives.ResourceNameRequirements requirements) -> Azure.Provisioning.BicepValue? +override Aspire.Hosting.Azure.AspireV8ResourceNamePropertyResolver.ResolveName(Azure.Provisioning.ProvisioningBuildOptions! options, Azure.Provisioning.Primitives.ProvisionableResource! resource, Azure.Provisioning.Primitives.ResourceNameRequirements requirements) -> Azure.Provisioning.BicepValue? override Aspire.Hosting.Azure.AzureProvisioningResource.GetBicepTemplateFile(string? directory = null, bool deleteTemporaryFileOnDispose = true) -> Aspire.Hosting.Azure.BicepTemplateFile override Aspire.Hosting.Azure.AzureProvisioningResource.GetBicepTemplateString() -> string! static Aspire.Hosting.AzureBicepResourceExtensions.WithParameter(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, Aspire.Hosting.ApplicationModel.EndpointReference! value) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! diff --git a/src/Aspire.Hosting.Azure/Utils/BicepIdentifierHelpers.cs b/src/Aspire.Hosting.Azure/Utils/BicepIdentifierHelpers.cs index af38d6a69b..20c83ee8b1 100644 --- a/src/Aspire.Hosting.Azure/Utils/BicepIdentifierHelpers.cs +++ b/src/Aspire.Hosting.Azure/Utils/BicepIdentifierHelpers.cs @@ -10,7 +10,7 @@ internal static class BicepIdentifierHelpers { internal static string ThrowIfInvalid(string name, [CallerArgumentExpression(nameof(name))] string? paramName = null) { - Infrastructure.ValidateIdentifierName(name, paramName); + Infrastructure.ValidateBicepIdentifier(name, paramName); return name; } } diff --git a/src/Aspire.Hosting.Elasticsearch/ElasticsearchContainerImageTags.cs b/src/Aspire.Hosting.Elasticsearch/ElasticsearchContainerImageTags.cs index 87cc7d0734..bf48e60541 100644 --- a/src/Aspire.Hosting.Elasticsearch/ElasticsearchContainerImageTags.cs +++ b/src/Aspire.Hosting.Elasticsearch/ElasticsearchContainerImageTags.cs @@ -11,7 +11,7 @@ internal static class ElasticsearchContainerImageTags /// library/elasticsearch public const string Image = "library/elasticsearch"; - /// 8.15.2 - public const string Tag = "8.15.2"; + /// 8.15.3 + public const string Tag = "8.15.3"; } diff --git a/src/Aspire.Hosting.Keycloak/KeycloakContainerImageTags.cs b/src/Aspire.Hosting.Keycloak/KeycloakContainerImageTags.cs index 493161891c..e336945470 100644 --- a/src/Aspire.Hosting.Keycloak/KeycloakContainerImageTags.cs +++ b/src/Aspire.Hosting.Keycloak/KeycloakContainerImageTags.cs @@ -11,6 +11,6 @@ internal static class KeycloakContainerImageTags /// keycloak/keycloak public const string Image = "keycloak/keycloak"; - /// 25.0 - public const string Tag = "25.0"; + /// 26.0 + public const string Tag = "26.0"; } diff --git a/src/Aspire.Hosting.Milvus/Aspire.Hosting.Milvus.csproj b/src/Aspire.Hosting.Milvus/Aspire.Hosting.Milvus.csproj index df6c5cfee7..81e5c37030 100644 --- a/src/Aspire.Hosting.Milvus/Aspire.Hosting.Milvus.csproj +++ b/src/Aspire.Hosting.Milvus/Aspire.Hosting.Milvus.csproj @@ -10,8 +10,6 @@ false - - true @@ -21,7 +19,6 @@ - @@ -31,8 +28,4 @@ - - - - diff --git a/src/Aspire.Hosting.Milvus/MilvusBuilderExtensions.cs b/src/Aspire.Hosting.Milvus/MilvusBuilderExtensions.cs index e6261e0bee..5a02375604 100644 --- a/src/Aspire.Hosting.Milvus/MilvusBuilderExtensions.cs +++ b/src/Aspire.Hosting.Milvus/MilvusBuilderExtensions.cs @@ -1,15 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Data.Common; using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Milvus; using Aspire.Hosting.Utils; -using Aspire.Milvus.Client; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Diagnostics.HealthChecks; -using Microsoft.Extensions.Logging; -using Milvus.Client; namespace Aspire.Hosting; @@ -56,27 +50,6 @@ public static IResourceBuilder AddMilvus(this IDistributed ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(builder, $"{name}-key"); var milvus = new MilvusServerResource(name, apiKeyParameter); - - MilvusClient? milvusClient = null; - - builder.Eventing.Subscribe(milvus, async (@event, ct) => - { - var connectionString = await milvus.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false) - ?? throw new DistributedApplicationException($"ConnectionStringAvailableEvent was published for the '{milvus.Name}' resource but the connection string was null."); - milvusClient = CreateMilvusClient(@event.Services, connectionString); - }); - - var healthCheckKey = $"{name}_check"; - // TODO: Use health check from AspNetCore.Diagnostics.HealthChecks once it's implemented via this issue: - // https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks/issues/2214 - builder.Services.AddHealthChecks() - .Add(new HealthCheckRegistration( - healthCheckKey, - sp => new MilvusHealthCheck(milvusClient!), - failureStatus: default, - tags: default, - timeout: default)); - return builder.AddResource(milvus) .WithImage(MilvusContainerImageTags.Image, MilvusContainerImageTags.Tag) .WithImageRegistry(MilvusContainerImageTags.Registry) @@ -93,8 +66,7 @@ public static IResourceBuilder AddMilvus(this IDistributed { ctx.EnvironmentVariables["COMMON_SECURITY_DEFAULTROOTPASSWORD"] = milvus.ApiKeyParameter; }) - .WithArgs("milvus", "run", "standalone") - .WithHealthCheck(healthCheckKey); + .WithArgs("milvus", "run", "standalone"); } /// @@ -220,44 +192,4 @@ private static void ConfigureAttuContainer(EnvironmentCallbackContext context, M // This will need to be refactored once updated service discovery APIs are available context.EnvironmentVariables.Add("MILVUS_URL", $"{resource.PrimaryEndpoint.Scheme}://{resource.Name}:{resource.PrimaryEndpoint.TargetPort}"); } - internal static MilvusClient CreateMilvusClient(IServiceProvider sp, string? connectionString) - { - if (connectionString is null) - { - throw new InvalidOperationException("Connection string is unavailable"); - } - - Uri? endpoint = null; - string? key = null; - string? database = null; - - if (Uri.TryCreate(connectionString, UriKind.Absolute, out var uri)) - { - endpoint = uri; - } - else - { - var connectionBuilder = new DbConnectionStringBuilder - { - ConnectionString = connectionString - }; - - if (connectionBuilder.ContainsKey("Endpoint") && Uri.TryCreate(connectionBuilder["Endpoint"].ToString(), UriKind.Absolute, out var serviceUri)) - { - endpoint = serviceUri; - } - - if (connectionBuilder.ContainsKey("Key")) - { - key = connectionBuilder["Key"].ToString(); - } - - if (connectionBuilder.ContainsKey("Database")) - { - database = connectionBuilder["Database"].ToString(); - } - } - - return new MilvusClient(endpoint!, apiKey: key!, database: database, loggerFactory: sp.GetRequiredService()); - } } diff --git a/src/Aspire.Hosting.Milvus/MilvusContainerImageTags.cs b/src/Aspire.Hosting.Milvus/MilvusContainerImageTags.cs index 5dd329274f..029b714160 100644 --- a/src/Aspire.Hosting.Milvus/MilvusContainerImageTags.cs +++ b/src/Aspire.Hosting.Milvus/MilvusContainerImageTags.cs @@ -11,8 +11,8 @@ internal static class MilvusContainerImageTags /// milvusdb/milvus public const string Image = "milvusdb/milvus"; - /// v2.4.12 - public const string Tag = "v2.4.12"; + /// v2.4.13 + public const string Tag = "v2.4.13"; /// zilliz/attu public const string AttuImage = "zilliz/attu"; diff --git a/src/Aspire.Hosting.MySql/MySqlContainerImageTags.cs b/src/Aspire.Hosting.MySql/MySqlContainerImageTags.cs index e251f95558..52b4f2747c 100644 --- a/src/Aspire.Hosting.MySql/MySqlContainerImageTags.cs +++ b/src/Aspire.Hosting.MySql/MySqlContainerImageTags.cs @@ -11,8 +11,8 @@ internal static class MySqlContainerImageTags /// library/mysql public const string Image = "library/mysql"; - /// 9.0 - public const string Tag = "9.0"; + /// 9.1 + public const string Tag = "9.1"; /// library/phpmyadmin public const string PhpMyAdminImage = "library/phpmyadmin"; diff --git a/src/Aspire.Hosting.Python/Aspire.Hosting.Python.csproj b/src/Aspire.Hosting.Python/Aspire.Hosting.Python.csproj index 3af727c7e2..86a216c7fb 100644 --- a/src/Aspire.Hosting.Python/Aspire.Hosting.Python.csproj +++ b/src/Aspire.Hosting.Python/Aspire.Hosting.Python.csproj @@ -6,8 +6,6 @@ aspire integration hosting python Python support for .NET Aspire. 80 - - true diff --git a/src/Aspire.Hosting.Python/AssemblyInfo.cs b/src/Aspire.Hosting.Python/AssemblyInfo.cs new file mode 100644 index 0000000000..d866cbca5d --- /dev/null +++ b/src/Aspire.Hosting.Python/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; + +[assembly: Experimental("ASPIREHOSTINGPYTHON001", UrlFormat = "https://aka.ms/dotnet/aspire/diagnostics#{0}")] diff --git a/src/Aspire.Hosting.Qdrant/QdrantContainerImageTags.cs b/src/Aspire.Hosting.Qdrant/QdrantContainerImageTags.cs index 322e3a70cc..3ce5c10508 100644 --- a/src/Aspire.Hosting.Qdrant/QdrantContainerImageTags.cs +++ b/src/Aspire.Hosting.Qdrant/QdrantContainerImageTags.cs @@ -11,6 +11,6 @@ internal static class QdrantContainerImageTags /// qdrant/qdrant public const string Image = "qdrant/qdrant"; - /// v1.11.5 - public const string Tag = "v1.11.5"; + /// v1.12.1 + public const string Tag = "v1.12.1"; } diff --git a/src/Aspire.ProjectTemplates/templates/aspire-apphost/8.2/Aspire.AppHost1.csproj b/src/Aspire.ProjectTemplates/templates/aspire-apphost/8.2/Aspire.AppHost1.csproj index b752836509..2722db5811 100644 --- a/src/Aspire.ProjectTemplates/templates/aspire-apphost/8.2/Aspire.AppHost1.csproj +++ b/src/Aspire.ProjectTemplates/templates/aspire-apphost/8.2/Aspire.AppHost1.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Aspire.ProjectTemplates/templates/aspire-empty/8.2/AspireApplication.1.AppHost/AspireApplication.1.AppHost.csproj b/src/Aspire.ProjectTemplates/templates/aspire-empty/8.2/AspireApplication.1.AppHost/AspireApplication.1.AppHost.csproj index b752836509..2722db5811 100644 --- a/src/Aspire.ProjectTemplates/templates/aspire-empty/8.2/AspireApplication.1.AppHost/AspireApplication.1.AppHost.csproj +++ b/src/Aspire.ProjectTemplates/templates/aspire-empty/8.2/AspireApplication.1.AppHost/AspireApplication.1.AppHost.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Aspire.ProjectTemplates/templates/aspire-empty/8.2/AspireApplication.1.ServiceDefaults/AspireApplication.1.ServiceDefaults.csproj b/src/Aspire.ProjectTemplates/templates/aspire-empty/8.2/AspireApplication.1.ServiceDefaults/AspireApplication.1.ServiceDefaults.csproj index 14aae3f847..90b4c84258 100644 --- a/src/Aspire.ProjectTemplates/templates/aspire-empty/8.2/AspireApplication.1.ServiceDefaults/AspireApplication.1.ServiceDefaults.csproj +++ b/src/Aspire.ProjectTemplates/templates/aspire-empty/8.2/AspireApplication.1.ServiceDefaults/AspireApplication.1.ServiceDefaults.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Aspire.ProjectTemplates/templates/aspire-mstest/8.2/Aspire.Tests.1.csproj b/src/Aspire.ProjectTemplates/templates/aspire-mstest/8.2/Aspire.Tests.1.csproj index ebb5cd33d2..fb4402ec2d 100644 --- a/src/Aspire.ProjectTemplates/templates/aspire-mstest/8.2/Aspire.Tests.1.csproj +++ b/src/Aspire.ProjectTemplates/templates/aspire-mstest/8.2/Aspire.Tests.1.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Aspire.ProjectTemplates/templates/aspire-nunit/8.2/Aspire.Tests.1.csproj b/src/Aspire.ProjectTemplates/templates/aspire-nunit/8.2/Aspire.Tests.1.csproj index 9e9cac158d..792ace28a9 100644 --- a/src/Aspire.ProjectTemplates/templates/aspire-nunit/8.2/Aspire.Tests.1.csproj +++ b/src/Aspire.ProjectTemplates/templates/aspire-nunit/8.2/Aspire.Tests.1.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Aspire.ProjectTemplates/templates/aspire-servicedefaults/8.2/Aspire.ServiceDefaults1.csproj b/src/Aspire.ProjectTemplates/templates/aspire-servicedefaults/8.2/Aspire.ServiceDefaults1.csproj index 14aae3f847..90b4c84258 100644 --- a/src/Aspire.ProjectTemplates/templates/aspire-servicedefaults/8.2/Aspire.ServiceDefaults1.csproj +++ b/src/Aspire.ProjectTemplates/templates/aspire-servicedefaults/8.2/Aspire.ServiceDefaults1.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.AppHost/Aspire-StarterApplication.1.AppHost.csproj b/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.AppHost/Aspire-StarterApplication.1.AppHost.csproj index dcc952bdcf..8ce8916f91 100644 --- a/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.AppHost/Aspire-StarterApplication.1.AppHost.csproj +++ b/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.AppHost/Aspire-StarterApplication.1.AppHost.csproj @@ -15,9 +15,9 @@ - + - + diff --git a/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.ServiceDefaults/Aspire-StarterApplication.1.ServiceDefaults.csproj b/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.ServiceDefaults/Aspire-StarterApplication.1.ServiceDefaults.csproj index 14aae3f847..90b4c84258 100644 --- a/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.ServiceDefaults/Aspire-StarterApplication.1.ServiceDefaults.csproj +++ b/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.ServiceDefaults/Aspire-StarterApplication.1.ServiceDefaults.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.Tests/Aspire-StarterApplication.1.Tests.csproj b/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.Tests/Aspire-StarterApplication.1.Tests.csproj index 19d2924d3a..80388e5af5 100644 --- a/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.Tests/Aspire-StarterApplication.1.Tests.csproj +++ b/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.Tests/Aspire-StarterApplication.1.Tests.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.Web/Aspire-StarterApplication.1.Web.csproj b/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.Web/Aspire-StarterApplication.1.Web.csproj index 64a3a657fa..122c8ce8ac 100644 --- a/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.Web/Aspire-StarterApplication.1.Web.csproj +++ b/src/Aspire.ProjectTemplates/templates/aspire-starter/8.2/Aspire-StarterApplication.1.Web/Aspire-StarterApplication.1.Web.csproj @@ -12,7 +12,7 @@ - + diff --git a/src/Aspire.ProjectTemplates/templates/aspire-xunit/8.2/Aspire.Tests.1.csproj b/src/Aspire.ProjectTemplates/templates/aspire-xunit/8.2/Aspire.Tests.1.csproj index 951d965216..dfef69351a 100644 --- a/src/Aspire.ProjectTemplates/templates/aspire-xunit/8.2/Aspire.Tests.1.csproj +++ b/src/Aspire.ProjectTemplates/templates/aspire-xunit/8.2/Aspire.Tests.1.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index ad4ebd71a8..cb7f324feb 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -5,8 +5,6 @@ true true $(BaselineVersionForPackageValidation) - - true diff --git a/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs b/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs index 27a42ae5fa..fef6e8b8a8 100644 --- a/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs +++ b/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs @@ -246,7 +246,7 @@ public async Task AddAzureCosmosDBViaRunMode() var cosmos = builder.AddAzureCosmosDB("cosmos") .ConfigureInfrastructure(infrastructure => { - callbackDatabases = infrastructure.GetResources().OfType(); + callbackDatabases = infrastructure.GetProvisionableResources().OfType(); }); cosmos.AddDatabase("mydatabase"); @@ -340,7 +340,7 @@ public async Task AddAzureCosmosDBViaPublishMode() var cosmos = builder.AddAzureCosmosDB("cosmos") .ConfigureInfrastructure(infrastructure => { - callbackDatabases = infrastructure.GetResources().OfType(); + callbackDatabases = infrastructure.GetProvisionableResources().OfType(); }); cosmos.AddDatabase("mydatabase"); @@ -774,8 +774,8 @@ public async Task AssignParameterPopulatesParametersEverywhere() var manifest = await ManifestUtils.GetManifest(infrastructure1.Resource); Assert.NotNull(moduleInfrastructure); - var infrastructureParameters = moduleInfrastructure.GetParameters().DistinctBy(x => x.IdentifierName); - var infrastructureParametersLookup = infrastructureParameters.ToDictionary(p => p.IdentifierName); + var infrastructureParameters = moduleInfrastructure.GetParameters().DistinctBy(x => x.BicepIdentifier); + var infrastructureParametersLookup = infrastructureParameters.ToDictionary(p => p.BicepIdentifier); Assert.True(infrastructureParametersLookup.ContainsKey("skuName")); var expectedManifest = """ @@ -813,8 +813,8 @@ public async Task AssignParameterWithSpecifiedNamePopulatesParametersEverywhere( var manifest = await ManifestUtils.GetManifest(infrastructure1.Resource); Assert.NotNull(moduleInfrastructure); - var infrastructureParameters = moduleInfrastructure.GetParameters().DistinctBy(x => x.IdentifierName); - var infrastructureParametersLookup = infrastructureParameters.ToDictionary(p => p.IdentifierName); + var infrastructureParameters = moduleInfrastructure.GetParameters().DistinctBy(x => x.BicepIdentifier); + var infrastructureParametersLookup = infrastructureParameters.ToDictionary(p => p.BicepIdentifier); Assert.True(infrastructureParametersLookup.ContainsKey("sku")); var expectedManifest = """ @@ -1879,7 +1879,7 @@ public async Task AddAzureStorageViaRunMode() var storage = builder.AddAzureStorage("storage") .ConfigureInfrastructure(infrastructure => { - var sa = infrastructure.GetResources().OfType().Single(); + var sa = infrastructure.GetProvisionableResources().OfType().Single(); sa.Sku = new StorageSku() { Name = storagesku.AsProvisioningParameter(infrastructure) @@ -2037,7 +2037,7 @@ public async Task AddAzureStorageViaRunModeAllowSharedKeyAccessOverridesDefaultF var storage = builder.AddAzureStorage("storage") .ConfigureInfrastructure(infrastructure => { - var sa = infrastructure.GetResources().OfType().Single(); + var sa = infrastructure.GetProvisionableResources().OfType().Single(); sa.Sku = new StorageSku() { Name = storagesku.AsProvisioningParameter(infrastructure) @@ -2196,7 +2196,7 @@ public async Task AddAzureStorageViaPublishMode() var storage = builder.AddAzureStorage("storage") .ConfigureInfrastructure(infrastructure => { - var sa = infrastructure.GetResources().OfType().Single(); + var sa = infrastructure.GetProvisionableResources().OfType().Single(); sa.Sku = new StorageSku() { Name = storagesku.AsProvisioningParameter(infrastructure) @@ -2354,7 +2354,7 @@ public async Task AddAzureStorageViaPublishModeEnableAllowSharedKeyAccessOverrid var storage = builder.AddAzureStorage("storage") .ConfigureInfrastructure(infrastructure => { - var sa = infrastructure.GetResources().OfType().Single(); + var sa = infrastructure.GetProvisionableResources().OfType().Single(); sa.Sku = new StorageSku() { Name = storagesku.AsProvisioningParameter(infrastructure) @@ -2514,7 +2514,7 @@ public async Task AddAzureSearch() var search = builder.AddAzureSearch("search") .ConfigureInfrastructure(infrastructure => { - var search = infrastructure.GetResources().OfType().Single(); + var search = infrastructure.GetProvisionableResources().OfType().Single(); search.SearchSkuName = sku.AsProvisioningParameter(infrastructure); }); @@ -2636,12 +2636,12 @@ public async Task AddAzureOpenAI(bool overrideLocalAuthDefault) var openai = builder.AddAzureOpenAI("openai") .ConfigureInfrastructure(infrastructure => { - aiDeployments = infrastructure.GetResources().OfType(); + aiDeployments = infrastructure.GetProvisionableResources().OfType(); if (overrideLocalAuthDefault) { - var account = infrastructure.GetResources().OfType().Single(); - account.Properties.Value!.DisableLocalAuth = false; + var account = infrastructure.GetProvisionableResources().OfType().Single(); + account.Properties.DisableLocalAuth = false; } }) .AddDeployment(new("mymodel", "gpt-35-turbo", "0613", "Basic", 4)) @@ -2781,24 +2781,17 @@ public async Task InfrastructureCanBeMutatedAfterCreation() }) .ConfigureInfrastructure(r => { - var vault = r.GetResources().OfType().Single(); + var vault = r.GetProvisionableResources().OfType().Single(); Assert.NotNull(vault); r.Add(new ProvisioningOutput("vaultUri", typeof(string)) { - Value = - new MemberExpression( - new MemberExpression( - new IdentifierExpression(vault.IdentifierName), - "properties"), - "vaultUri") - // TODO: this should be - //Value = keyVault.VaultUri + Value = vault.Properties.VaultUri }); }) .ConfigureInfrastructure(r => { - var vault = r.GetResources().OfType().Single(); + var vault = r.GetProvisionableResources().OfType().Single(); Assert.NotNull(vault); r.Add(new KeyVaultSecret("secret") diff --git a/tests/Aspire.Hosting.Azure.Tests/AzureContainerAppsTests.cs b/tests/Aspire.Hosting.Azure.Tests/AzureContainerAppsTests.cs index e149a94011..62d651204b 100644 --- a/tests/Aspire.Hosting.Azure.Tests/AzureContainerAppsTests.cs +++ b/tests/Aspire.Hosting.Azure.Tests/AzureContainerAppsTests.cs @@ -6,7 +6,9 @@ using System.Runtime.CompilerServices; using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Utils; +using Azure.Provisioning; using Azure.Provisioning.AppContainers; +using Azure.Provisioning.Primitives; using Microsoft.Extensions.DependencyInjection; using Xunit; using Xunit.Abstractions; @@ -365,8 +367,8 @@ public async Task AddContainerAppsInfrastructureWithParameterReference() Value = value.AsProvisioningParameter(module) }; - c.Template.Value!.Containers[0].Value!.Env.Add(val); - c.Template.Value!.Scale.Value!.MinReplicas = minReplicas.AsProvisioningParameter(module); + c.Template.Containers[0].Value!.Env.Add(val); + c.Template.Scale.MinReplicas = minReplicas.AsProvisioningParameter(module); }); using var app = builder.Build(); @@ -759,9 +761,9 @@ public async Task PublishAsContainerAppInfluencesContainerAppDefinition() builder.AddContainer("api", "myimage") .PublishAsAzureContainerApp((module, c) => { - Assert.Contains(c, module.GetResources()); + Assert.Contains(c, module.GetProvisionableResources()); - c.Template.Value!.Scale.Value!.MinReplicas = 0; + c.Template.Scale.MinReplicas = 0; }); using var app = builder.Build(); @@ -1273,6 +1275,94 @@ param outputs_azure_container_apps_environment_id string Assert.Equal(expectedBicep, bicep); } + [Fact] + public async Task CanCustomizeWithProvisioningBuildOptions() + { + var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish); + + builder.Services.Configure(options => options.ProvisioningBuildOptions.InfrastructureResolvers.Insert(0, new MyResourceNamePropertyResolver())); + builder.AddAzureContainerAppsInfrastructure(); + + builder.AddContainer("api1", "myimage"); + + using var app = builder.Build(); + + await ExecuteBeforeStartHooksAsync(app, default); + + var model = app.Services.GetRequiredService(); + + var container = Assert.Single(model.GetContainerResources()); + + container.TryGetLastAnnotation(out var target); + + var resource = target?.DeploymentTarget as AzureProvisioningResource; + + Assert.NotNull(resource); + + var (_, bicep) = await ManifestUtils.GetManifestWithBicep(resource); + + var expectedBicep = + """ + @description('The location for the resource(s) to be deployed.') + param location string = resourceGroup().location + + param outputs_azure_container_registry_managed_identity_id string + + param outputs_managed_identity_client_id string + + param outputs_azure_container_apps_environment_id string + + resource api1 'Microsoft.App/containerApps@2024-03-01' = { + name: 'api1-my' + location: location + properties: { + configuration: { + activeRevisionsMode: 'Single' + } + environmentId: outputs_azure_container_apps_environment_id + template: { + containers: [ + { + image: 'myimage:latest' + name: 'api1' + env: [ + { + name: 'AZURE_CLIENT_ID' + value: outputs_managed_identity_client_id + } + ] + } + ] + scale: { + minReplicas: 1 + } + } + } + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${outputs_azure_container_registry_managed_identity_id}': { } + } + } + } + """; + output.WriteLine(bicep); + Assert.Equal(expectedBicep, bicep); + } + + private sealed class MyResourceNamePropertyResolver : DynamicResourceNamePropertyResolver + { + public override void ResolveProperties(ProvisionableConstruct construct, ProvisioningBuildOptions options) + { + if (construct is ContainerApp app) + { + app.Name = app.Name.Value + "-my"; + } + + base.ResolveProperties(construct, options); + } + } + [Fact] public async Task ExternalEndpointBecomesIngress() { diff --git a/tests/Aspire.Hosting.Azure.Tests/AzureRedisExtensionsTests.cs b/tests/Aspire.Hosting.Azure.Tests/AzureRedisExtensionsTests.cs index e195bcc160..9ec3483820 100644 --- a/tests/Aspire.Hosting.Azure.Tests/AzureRedisExtensionsTests.cs +++ b/tests/Aspire.Hosting.Azure.Tests/AzureRedisExtensionsTests.cs @@ -50,11 +50,11 @@ param principalName string capacity: 1 } enableNonSslPort: false + disableAccessKeyAuthentication: true minimumTlsVersion: '1.2' redisConfiguration: { 'aad-enabled': 'true' } - disableAccessKeyAuthentication: 'true' } tags: { 'aspire-resource-name': 'redis-cache' @@ -116,7 +116,6 @@ param keyVaultName string } enableNonSslPort: false minimumTlsVersion: '1.2' - redisConfiguration: { } } tags: { 'aspire-resource-name': 'redis-cache' diff --git a/tests/Aspire.Hosting.Azure.Tests/AzureResourceOptionsTests.cs b/tests/Aspire.Hosting.Azure.Tests/AzureResourceOptionsTests.cs index e5ec91abf7..f532f93081 100644 --- a/tests/Aspire.Hosting.Azure.Tests/AzureResourceOptionsTests.cs +++ b/tests/Aspire.Hosting.Azure.Tests/AzureResourceOptionsTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Utils; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -11,7 +12,7 @@ namespace Aspire.Hosting.Azure.Tests; public class AzureResourceOptionsTests(ITestOutputHelper output) { /// - /// Ensures that an AzureProvisioningOptions can be configured to modify the ProvisioningContext + /// Ensures that an AzureProvisioningOptions can be configured to modify the ProvisioningBuildOptions /// used when building the bicep for an Azure resource. /// /// This uses the .NET Aspire v8.x naming policy, which always calls toLower, appends a unique string with no separator, @@ -27,11 +28,16 @@ public async Task AzureResourceOptionsCanBeConfigured() { builder.Services.Configure(options => { - options.ProvisioningContext.PropertyResolvers.Insert(0, new AspireV8ResourceNamePropertyResolver()); + options.ProvisioningBuildOptions.InfrastructureResolvers.Insert(0, new AspireV8ResourceNamePropertyResolver()); }); var serviceBus = builder.AddAzureServiceBus("sb"); + // ensure that resources with a hyphen still have a hyphen in the bicep name + var sqlDatabase = builder.AddAzureSqlServer("sql-server") + .RunAsContainer(x => x.WithLifetime(ContainerLifetime.Persistent)) + .AddDatabase("evadexdb"); + using var app = builder.Build(); await app.StartAsync(); @@ -76,6 +82,56 @@ param principalType string output.WriteLine(actualBicep); Assert.Equal(expectedBicep, actualBicep); + actualBicep = await File.ReadAllTextAsync(Path.Combine(tempDir.FullName, "sql-server.module.bicep")); + + expectedBicep = """ + @description('The location for the resource(s) to be deployed.') + param location string = resourceGroup().location + + param principalId string + + param principalName string + + resource sql_server 'Microsoft.Sql/servers@2021-11-01' = { + name: toLower(take('sql-server${uniqueString(resourceGroup().id)}', 24)) + location: location + properties: { + administrators: { + administratorType: 'ActiveDirectory' + login: principalName + sid: principalId + tenantId: subscription().tenantId + azureADOnlyAuthentication: true + } + minimalTlsVersion: '1.2' + publicNetworkAccess: 'Enabled' + version: '12.0' + } + tags: { + 'aspire-resource-name': 'sql-server' + } + } + + resource sqlFirewallRule_AllowAllAzureIps 'Microsoft.Sql/servers/firewallRules@2021-11-01' = { + name: 'AllowAllAzureIps' + properties: { + endIpAddress: '0.0.0.0' + startIpAddress: '0.0.0.0' + } + parent: sql_server + } + + resource evadexdb 'Microsoft.Sql/servers/databases@2021-11-01' = { + name: 'evadexdb' + location: location + parent: sql_server + } + + output sqlServerFqdn string = sql_server.properties.fullyQualifiedDomainName + """; + output.WriteLine(actualBicep); + Assert.Equal(expectedBicep, actualBicep); + await app.StopAsync(); } diff --git a/tests/Aspire.Hosting.Azure.Tests/AzureWebPubSubExtensionsTests.cs b/tests/Aspire.Hosting.Azure.Tests/AzureWebPubSubExtensionsTests.cs index 2b43b5c002..d975977834 100644 --- a/tests/Aspire.Hosting.Azure.Tests/AzureWebPubSubExtensionsTests.cs +++ b/tests/Aspire.Hosting.Azure.Tests/AzureWebPubSubExtensionsTests.cs @@ -29,7 +29,7 @@ public async Task AddWebPubSubHubNameWithSpecialChars() WebPubSubHub? realHub = null; var wps = builder.AddAzureWebPubSub("wps1").ConfigureInfrastructure(infrastructure => { - realHub = infrastructure.GetResources().OfType().Single(); + realHub = infrastructure.GetProvisionableResources().OfType().Single(); }); var hubName = "a-b-c"; var hub = wps.AddHub(hubName); @@ -38,7 +38,7 @@ public async Task AddWebPubSubHubNameWithSpecialChars() var manifest = await ManifestUtils.GetManifestWithBicep(wps.Resource); Assert.NotNull(realHub); Assert.Equal(hubName, realHub.Name.Value); - Assert.Equal("a_b_c", realHub.IdentifierName); + Assert.Equal("a_b_c", realHub.BicepIdentifier); } [Fact] @@ -74,9 +74,9 @@ public async Task AddAzureWebPubSubHubWorks() param sku string = 'Free_F1' param capacity int = 1 - + param principalId string - + param principalType string resource wps1 'Microsoft.SignalRService/webPubSub@2024-03-01' = { @@ -103,7 +103,6 @@ param principalType string resource abc 'Microsoft.SignalRService/webPubSub/hubs@2024-03-01' = { name: 'abc' - properties: { } parent: wps1 } @@ -119,8 +118,8 @@ public async Task AddWebPubSubWithHubConfigure() var hubName = "abc"; var wps = builder.AddAzureWebPubSub("wps1").ConfigureInfrastructure(infrastructure => { - var hub = infrastructure.GetResources().OfType().First(i => i.IdentifierName == hubName); - hub.Properties.Value!.AnonymousConnectPolicy = "allow"; + var hub = infrastructure.GetProvisionableResources().OfType().First(i => i.BicepIdentifier == hubName); + hub.Properties.AnonymousConnectPolicy = "allow"; }); wps.AddHub(hubName); @@ -150,9 +149,9 @@ public async Task AddWebPubSubWithHubConfigure() param sku string = 'Free_F1' param capacity int = 1 - + param principalId string - + param principalType string resource wps1 'Microsoft.SignalRService/webPubSub@2024-03-01' = { @@ -280,8 +279,8 @@ public async Task ConfigureConstructOverridesAddEventHandler() var serviceA = builder.AddProject("serviceA", o => o.ExcludeLaunchProfile = true).WithHttpsEndpoint(); var wps = builder.AddAzureWebPubSub("wps1").ConfigureInfrastructure(infrastructure => { - var hub = infrastructure.GetResources().OfType().First(i => string.Equals(i.IdentifierName, "abc", StringComparison.OrdinalIgnoreCase)); - hub.Properties.Value!.EventHandlers.Add(new WebPubSubEventHandler() { UrlTemplate = "http://fake.com" }); + var hub = infrastructure.GetProvisionableResources().OfType().First(i => string.Equals(i.BicepIdentifier, "abc", StringComparison.OrdinalIgnoreCase)); + hub.Properties.EventHandlers.Add(new WebPubSubEventHandler() { UrlTemplate = "http://fake.com" }); }); wps.AddHub("ABC").AddEventHandler($"http://fake1.com"); // Hub name is case insensitive @@ -358,10 +357,10 @@ public async Task AddAzureWebPubSubHubSettings() var url1 = "fake3.com"; var wps = builder.AddAzureWebPubSub("wps1").ConfigureInfrastructure(infrastructure => { - var hub = infrastructure.GetResources().OfType().First(i => i.IdentifierName == "hub1"); - hub.Properties.Value!.AnonymousConnectPolicy = "allow"; + var hub = infrastructure.GetProvisionableResources().OfType().First(i => i.BicepIdentifier == "hub1"); + hub.Properties.AnonymousConnectPolicy = "allow"; // allow directly event handler set - hub.Properties.Value!.EventHandlers.Add(new WebPubSubEventHandler() { UrlTemplate = "http://fake1.com" }); + hub.Properties.EventHandlers.Add(new WebPubSubEventHandler() { UrlTemplate = "http://fake1.com" }); }); // allow event handler set using a separate call // allow mulitple calls, and order matters @@ -448,7 +447,6 @@ param principalType string { urlTemplate: 'http://fake2.com' userEventPattern: 'event1' - auth: { } } { urlTemplate: 'http://fake3.com' diff --git a/tests/Aspire.Hosting.Milvus.Tests/MilvusFunctionalTests.cs b/tests/Aspire.Hosting.Milvus.Tests/MilvusFunctionalTests.cs index 1267839260..fb404a8023 100644 --- a/tests/Aspire.Hosting.Milvus.Tests/MilvusFunctionalTests.cs +++ b/tests/Aspire.Hosting.Milvus.Tests/MilvusFunctionalTests.cs @@ -2,11 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Components.Common.Tests; -using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Tests.Utils; using Aspire.Hosting.Utils; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Hosting; using Milvus.Client; using Xunit; @@ -201,44 +199,4 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume) } } } - - [Fact] - [RequiresDocker] - public async Task VerifyWaitForOnMilvusBlocksDependentResources() - { - var cts = new CancellationTokenSource(TimeSpan.FromMinutes(3)); - using var builder = TestDistributedApplicationBuilder.CreateWithTestContainerRegistry(testOutputHelper); - - var healthCheckTcs = new TaskCompletionSource(); - builder.Services.AddHealthChecks().AddAsyncCheck("blocking_check", () => - { - return healthCheckTcs.Task; - }); - - var resource = builder.AddMilvus("resource") - .WithHealthCheck("blocking_check"); - - var dependentResource = builder.AddMilvus("dependentresource") - .WaitFor(resource); - - using var app = builder.Build(); - - var pendingStart = app.StartAsync(cts.Token); - - var rns = app.Services.GetRequiredService(); - - await rns.WaitForResourceAsync(resource.Resource.Name, KnownResourceStates.Running, cts.Token); - - await rns.WaitForResourceAsync(dependentResource.Resource.Name, KnownResourceStates.Waiting, cts.Token); - - healthCheckTcs.SetResult(HealthCheckResult.Healthy()); - - await rns.WaitForResourceHealthyAsync(resource.Resource.Name, cts.Token); - - await rns.WaitForResourceAsync(dependentResource.Resource.Name, KnownResourceStates.Running, cts.Token); - - await pendingStart; - - await app.StopAsync(); - } } diff --git a/tests/Aspire.Hosting.Python.Tests/Aspire.Hosting.Python.Tests.csproj b/tests/Aspire.Hosting.Python.Tests/Aspire.Hosting.Python.Tests.csproj index 5ed2b6ca69..669ac12ec3 100644 --- a/tests/Aspire.Hosting.Python.Tests/Aspire.Hosting.Python.Tests.csproj +++ b/tests/Aspire.Hosting.Python.Tests/Aspire.Hosting.Python.Tests.csproj @@ -2,6 +2,10 @@ $(DefaultTargetFramework) + + $(NoWarn); + ASPIREHOSTINGPYTHON001; + diff --git a/tests/Aspire.Hosting.Tests/Schema/SchemaTests.cs b/tests/Aspire.Hosting.Tests/Schema/SchemaTests.cs index 12ed03647b..01d3d7fb29 100644 --- a/tests/Aspire.Hosting.Tests/Schema/SchemaTests.cs +++ b/tests/Aspire.Hosting.Tests/Schema/SchemaTests.cs @@ -146,7 +146,7 @@ public static TheoryData> Applica builder.AddProject("project") .PublishAsAzureContainerApp((infrastructure, app) => { - app.Template.Value!.Scale.Value!.MinReplicas = minReplicas.AsProvisioningParameter(infrastructure); + app.Template.Scale.MinReplicas = minReplicas.AsProvisioningParameter(infrastructure); }); } @@ -167,7 +167,7 @@ public static TheoryData> Applica builder.AddContainer("mycontainer", "myimage") .PublishAsAzureContainerApp((infrastructure, app) => { - app.Template.Value!.Scale.Value!.MinReplicas = minReplicas.AsProvisioningParameter(infrastructure); + app.Template.Scale.MinReplicas = minReplicas.AsProvisioningParameter(infrastructure); }); }