diff --git a/sdk/provisioning/Azure.Provisioning/src/Resource.cs b/sdk/provisioning/Azure.Provisioning/src/Resource.cs index 2116dffad2e0..3358f7b94abd 100644 --- a/sdk/provisioning/Azure.Provisioning/src/Resource.cs +++ b/sdk/provisioning/Azure.Provisioning/src/Resource.cs @@ -160,17 +160,14 @@ private protected void AssignParameter(object instance, string propertyName, Par /// The name of the output. /// The instance which contains the property for the output. /// The property name to output. + /// The expression from the lambda /// Is the output literal. /// Is the output secure. /// The . /// If the is not found on the resources properties. - private protected Output AddOutput(string name, object instance, string propertyName, bool isLiteral = false, bool isSecure = false) + private protected Output AddOutput(string name, object instance, string propertyName, string expression, bool isLiteral = false, bool isSecure = false) { - string? reference = GetReference(instance.GetType(), ResourceData.GetType(), propertyName, Name.ToCamelCase()); - - if (reference is null) - throw new ArgumentException(nameof(propertyName), $"{propertyName} was not found in the property tree for {ResourceData.GetType().Name}"); - var result = new Output(name, reference, Scope, isLiteral, isSecure); + var result = new Output(name, $"{Name}.{expression}", Scope, isLiteral, isSecure); Scope.AddOutput(result); return result; } diff --git a/sdk/provisioning/Azure.Provisioning/src/ResourceOfT.cs b/sdk/provisioning/Azure.Provisioning/src/ResourceOfT.cs index cedfb4a7766d..8890b4037eeb 100644 --- a/sdk/provisioning/Azure.Provisioning/src/ResourceOfT.cs +++ b/sdk/provisioning/Azure.Provisioning/src/ResourceOfT.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Linq; using System.Linq.Expressions; using Azure.Core; @@ -46,7 +47,7 @@ protected Resource(IConstruct scope, Resource? parent, string resourceName, Reso /// public void AssignParameter(Expression> propertySelector, Parameter parameter) { - (object instance, string name) = EvaluateLambda(propertySelector); + (object instance, string name, string expression) = EvaluateLambda(propertySelector); AssignParameter(instance, name, parameter); } @@ -60,47 +61,64 @@ public void AssignParameter(Expression> propertySelector, Param /// The . public Output AddOutput(Expression> propertySelector, string outputName, bool isLiteral = false, bool isSecure = false) { - (object instance, string name) = EvaluateLambda(propertySelector); - return AddOutput(outputName, instance, name, isLiteral, isSecure); + (object instance, string name, string expression) = EvaluateLambda(propertySelector); + + return AddOutput(outputName, instance, name, expression, isLiteral, isSecure); } - private (object Instance, string PropertyName) EvaluateLambda(Expression> propertySelector) + private (object Instance, string PropertyName, string Expression) EvaluateLambda(Expression> propertySelector) { ParameterExpression? root = null; Expression? body = null; string? name = null; + string expression = string.Empty; if (propertySelector is LambdaExpression lambda) { root = lambda.Parameters[0]; if (lambda.Body is MemberExpression member) { + GetBicepExpression(member, ref expression); body = member.Expression; name = member.Member.Name; } else if (lambda.Body is UnaryExpression { NodeType: ExpressionType.Convert, Operand: MemberExpression member2 }) { + GetBicepExpression(member2, ref expression); body = member2.Expression; name = member2.Member.Name; } - else if (lambda.Body is IndexExpression { Arguments.Count: 1 } indexer) - { - body = indexer.Object; - name = Expression.Lambda(indexer.Arguments[0], root).Compile().DynamicInvoke(Properties) as string; - } - else if (lambda.Body is MethodCallExpression { Method.Name: "get_Item", Arguments.Count: 1 } call) + else { - body = call.Object; - name = Expression.Lambda(call.Arguments[0], root).Compile().DynamicInvoke(Properties) as string; + throw new InvalidOperationException("Invalid expression type."); } } - - if (body is null || name is null || root is null) + else { - throw new NotSupportedException(); + throw new InvalidOperationException("Invalid expression type."); } - object instance = Expression.Lambda(body, root).Compile().DynamicInvoke(Properties)!; - return (instance, name); + object instance = Expression.Lambda(body!, root).Compile().DynamicInvoke(Properties)!; + return (instance, name, expression); + } + + private void GetBicepExpression(Expression expression, ref string result) + { + switch (expression) + { + case MemberExpression memberExpression: + var attrib = memberExpression.Member.GetCustomAttributes(false).FirstOrDefault(a => a.GetType().Name == "WirePathAttribute"); + string nodeString = attrib?.ToString() ?? memberExpression.Member.Name.ToCamelCase(); + result = result == string.Empty ? nodeString : $"{nodeString}.{result}"; + if (memberExpression.Expression is not null) + { + GetBicepExpression(memberExpression.Expression, ref result); + } + break; + case ParameterExpression parameterExpression: + return; // we have reached the root + default: + throw new InvalidOperationException($"Unsupported expression type {expression.GetType().Name}"); + } } } } diff --git a/sdk/provisioning/Azure.Provisioning/src/appconfiguration/AppConfigurationStore.cs b/sdk/provisioning/Azure.Provisioning/src/appconfiguration/AppConfigurationStore.cs index c9cc184e744d..b657c4f03902 100644 --- a/sdk/provisioning/Azure.Provisioning/src/appconfiguration/AppConfigurationStore.cs +++ b/sdk/provisioning/Azure.Provisioning/src/appconfiguration/AppConfigurationStore.cs @@ -30,6 +30,7 @@ public AppConfigurationStore(IConstruct scope, string name = "store", string ver location: location ?? Environment.GetEnvironmentVariable("AZURE_LOCATION") ?? AzureLocation.WestUS, skuName: "free")) { + AddOutput(store => store.Endpoint, $"{Name}_endpoint"); } /// diff --git a/sdk/provisioning/Azure.Provisioning/src/storage/StorageAccount.cs b/sdk/provisioning/Azure.Provisioning/src/storage/StorageAccount.cs index 1251924817d2..6a761b031fc0 100644 --- a/sdk/provisioning/Azure.Provisioning/src/storage/StorageAccount.cs +++ b/sdk/provisioning/Azure.Provisioning/src/storage/StorageAccount.cs @@ -58,16 +58,15 @@ protected override string GetAzureName(IConstruct scope, string resourceName) { continue; } - if (char.IsDigit(c) && !char.IsLower(c)) + if (char.IsLetter(c)) { - stringBuilder.Append(char.ToLower(c)); + stringBuilder.Append(char.ToLowerInvariant(c)); } else { stringBuilder.Append(c); } } - stringBuilder.Append('-'); stringBuilder.Append(Guid.NewGuid().ToString("N")); return stringBuilder.ToString(0, Math.Min(stringBuilder.Length, 24)); diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/AppConfiguration/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/AppConfiguration/main.bicep index 48aeda971d69..086bbe72e453 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/AppConfiguration/main.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/AppConfiguration/main.bicep @@ -5,7 +5,7 @@ resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' name: 'rg-TEST' location: 'westus' tags: { - azd-env-name: 'TEST' + 'azd-env-name': 'TEST' } } @@ -19,3 +19,5 @@ resource appConfigurationStore_sgecYnln3 'Microsoft.AppConfiguration/configurati properties: { } } + +output appConfigurationStore_sgecYnln3_endpoint string = appConfigurationStore_sgecYnln3.properties.endpoint diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/ResourceGroupOnly/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/ResourceGroupOnly/main.bicep index 9eb894c2b3ff..c61a4b9e1bfc 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/ResourceGroupOnly/main.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/ResourceGroupOnly/main.bicep @@ -5,6 +5,6 @@ resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' name: 'rg-TEST' location: 'westus' tags: { - azd-env-name: 'TEST' + 'azd-env-name': 'TEST' } } diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDefaults/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDefaults/main.bicep index 0edd84b5ad46..efd8c4f974fd 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDefaults/main.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDefaults/main.bicep @@ -5,13 +5,13 @@ resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' name: 'rg-TEST' location: 'westus' tags: { - azd-env-name: 'TEST' + 'azd-env-name': 'TEST' } } -resource storageAccount_SIHb28RDV 'Microsoft.Storage/storageAccounts@2022-09-01' = { +resource storageAccount_8fTaUIzOg 'Microsoft.Storage/storageAccounts@2022-09-01' = { scope: resourceGroup_I6QNkoPsb - name: 'photoAcct-4f6f922c331347' + name: 'photoacct2af3506bedd4415' location: 'westus' sku: { name: 'Premium_LRS' @@ -21,8 +21,8 @@ resource storageAccount_SIHb28RDV 'Microsoft.Storage/storageAccounts@2022-09-01' } } -resource blobService_lyt6uqODr 'Microsoft.Storage/storageAccounts/blobServices@2022-09-01' = { - parent: storageAccount_SIHb28RDV +resource blobService_1iUqwyvnt 'Microsoft.Storage/storageAccounts/blobServices@2022-09-01' = { + parent: storageAccount_8fTaUIzOg name: 'default' properties: { cors: { diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDropDown/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDropDown/main.bicep index c6b29f0ddf3e..7994d65dcd58 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDropDown/main.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDropDown/main.bicep @@ -5,13 +5,13 @@ resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' name: 'rg-TEST' location: 'westus' tags: { - azd-env-name: 'TEST' + 'azd-env-name': 'TEST' } } -resource storageAccount_bhaja5ROZ 'Microsoft.Storage/storageAccounts@2022-09-01' = { +resource storageAccount_VpeHv8O32 'Microsoft.Storage/storageAccounts@2022-09-01' = { scope: resourceGroup_I6QNkoPsb - name: 'photoAcct-96a1eefb1ac845' + name: 'photoacct414ad12f6b9c4a2' location: 'westus' sku: { name: 'Premium_LRS' @@ -21,8 +21,8 @@ resource storageAccount_bhaja5ROZ 'Microsoft.Storage/storageAccounts@2022-09-01' } } -resource blobService_PQ7aICJK8 'Microsoft.Storage/storageAccounts/blobServices@2022-09-01' = { - parent: storageAccount_bhaja5ROZ +resource blobService_6SRi2s6Pf 'Microsoft.Storage/storageAccounts/blobServices@2022-09-01' = { + parent: storageAccount_VpeHv8O32 name: 'default' properties: { cors: { diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL1/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL1/main.bicep index 962c6bbcbb0f..4ab9eac1108a 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL1/main.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL1/main.bicep @@ -13,8 +13,8 @@ resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' name: 'rg-TEST' location: 'westus' tags: { - azd-env-name: 'TEST' - key: 'value' + 'azd-env-name': 'TEST' + 'key': 'value' } } @@ -232,8 +232,8 @@ resource applicationSettingsResource_vEe46o8Zn 'Microsoft.Web/sites/config@2021- parent: webSite_4pzZqR2OO name: 'appsettings' properties: { - SCM_DO_BUILD_DURING_DEPLOYMENT: 'False' - ENABLE_ORYX_BUILD: 'True' + 'SCM_DO_BUILD_DURING_DEPLOYMENT': 'False' + 'ENABLE_ORYX_BUILD': 'True' } } diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/main.bicep index 6edc46bfa65f..5211bdb4ea9f 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/main.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/main.bicep @@ -13,8 +13,8 @@ resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' name: 'rg-TEST' location: 'westus' tags: { - azd-env-name: 'TEST' - key: 'value' + 'azd-env-name': 'TEST' + 'key': 'value' } } diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/TestBackEndWebSite/TestBackEndWebSite.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/TestBackEndWebSite/TestBackEndWebSite.bicep index f92d15b10452..5bf70fec31e9 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/TestBackEndWebSite/TestBackEndWebSite.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/TestBackEndWebSite/TestBackEndWebSite.bicep @@ -34,7 +34,7 @@ resource applicationSettingsResource_vEe46o8Zn 'Microsoft.Web/sites/config@2021- parent: webSite_4pzZqR2OO name: 'appsettings' properties: { - SCM_DO_BUILD_DURING_DEPLOYMENT: 'False' - ENABLE_ORYX_BUILD: 'True' + 'SCM_DO_BUILD_DURING_DEPLOYMENT': 'False' + 'ENABLE_ORYX_BUILD': 'True' } } diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/main.bicep index ef77e05ab324..a4ee26f64267 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/main.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/main.bicep @@ -13,8 +13,8 @@ resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' name: 'rg-TEST' location: 'westus' tags: { - azd-env-name: 'TEST' - key: 'value' + 'azd-env-name': 'TEST' + 'key': 'value' } } diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestBackEndWebSite/TestBackEndWebSite.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestBackEndWebSite/TestBackEndWebSite.bicep index f92d15b10452..5bf70fec31e9 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestBackEndWebSite/TestBackEndWebSite.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestBackEndWebSite/TestBackEndWebSite.bicep @@ -34,7 +34,7 @@ resource applicationSettingsResource_vEe46o8Zn 'Microsoft.Web/sites/config@2021- parent: webSite_4pzZqR2OO name: 'appsettings' properties: { - SCM_DO_BUILD_DURING_DEPLOYMENT: 'False' - ENABLE_ORYX_BUILD: 'True' + 'SCM_DO_BUILD_DURING_DEPLOYMENT': 'False' + 'ENABLE_ORYX_BUILD': 'True' } } diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestWebSiteWithSqlBackEnd/TestWebSiteWithSqlBackEnd.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestWebSiteWithSqlBackEnd/TestWebSiteWithSqlBackEnd.bicep index 18109bc3e303..5de221b11774 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestWebSiteWithSqlBackEnd/TestWebSiteWithSqlBackEnd.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestWebSiteWithSqlBackEnd/TestWebSiteWithSqlBackEnd.bicep @@ -22,7 +22,7 @@ resource keyVault_CRoMbemLF 'Microsoft.KeyVault/vaults@2023-02-01' = { name: 'kv-TEST' location: 'westus' tags: { - key: 'value' + 'key': 'value' } properties: { tenantId: '00000000-0000-0000-0000-000000000000' diff --git a/sdk/provisioning/Azure.Provisioning/tests/ProvisioningTests.cs b/sdk/provisioning/Azure.Provisioning/tests/ProvisioningTests.cs index a25c56c90093..d8ab7312a499 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/ProvisioningTests.cs +++ b/sdk/provisioning/Azure.Provisioning/tests/ProvisioningTests.cs @@ -37,7 +37,7 @@ public void WebSiteUsingL1() WebSite frontEnd = new WebSite(infra, "frontEnd", appServicePlan, WebSiteRuntime.Node, "18-lts"); var frontEndPrincipalId = frontEnd.AddOutput( - website => website.Identity.PrincipalId, + website => website.Identity.PrincipalId, //Identity.PrincipalId "SERVICE_API_IDENTITY_PRINCIPAL_ID", isSecure: true);