public static LanguageExpression FormatLocallyScopedResourceId(SemanticModel.SemanticModel semanticModel, string fullyQualifiedType, IEnumerable <LanguageExpression> nameSegments) { var initialArgs = new JTokenExpression(fullyQualifiedType).AsEnumerable(); switch (semanticModel.TargetScope) { case ResourceScopeType.TenantScope: var tenantArgs = initialArgs.Concat(nameSegments); return(new FunctionExpression("tenantResourceId", tenantArgs.ToArray(), new LanguageExpression[0])); case ResourceScopeType.SubscriptionScope: var subscriptionArgs = initialArgs.Concat(nameSegments); return(new FunctionExpression("subscriptionResourceId", subscriptionArgs.ToArray(), new LanguageExpression[0])); case ResourceScopeType.ResourceGroupScope: var resourceGroupArgs = initialArgs.Concat(nameSegments); return(new FunctionExpression("resourceId", resourceGroupArgs.ToArray(), new LanguageExpression[0])); case ResourceScopeType.ManagementGroupScope: // We need to do things slightly differently for Management Groups, because there is no IL to output for "Give me a fully-qualified resource id at the current scope", // and we don't even have a mechanism for reliably getting the current scope (e.g. something like 'deployment().scope'). There are plans to add a managementGroupResourceId function, // but until we have it, we should generate unqualified resource Ids. There should not be a risk of collision, because we do not allow mixing of resource scopes in a single bicep file. return(ExpressionConverter.GenerateUnqualifiedResourceId(fullyQualifiedType, nameSegments)); default: // this should have already been caught during compilation throw new InvalidOperationException($"Invalid target scope {semanticModel.TargetScope} for module"); } }
public static LanguageExpression FormatCrossScopeResourceId(ExpressionConverter expressionConverter, ScopeData scopeData, string fullyQualifiedType, IEnumerable <LanguageExpression> nameSegments) { var arguments = new List <LanguageExpression>(); switch (scopeData.RequestedScope) { case ResourceScopeType.TenantScope: arguments.Add(new JTokenExpression(fullyQualifiedType)); arguments.AddRange(nameSegments); return(new FunctionExpression("tenantResourceId", arguments.ToArray(), new LanguageExpression[0])); case ResourceScopeType.SubscriptionScope: if (scopeData.SubscriptionIdProperty != null) { arguments.Add(expressionConverter.ConvertExpression(scopeData.SubscriptionIdProperty)); } arguments.Add(new JTokenExpression(fullyQualifiedType)); arguments.AddRange(nameSegments); return(new FunctionExpression("subscriptionResourceId", arguments.ToArray(), new LanguageExpression[0])); case ResourceScopeType.ResourceGroupScope: // We avoid using the 'resourceId' function at all here, because its behavior differs depending on the scope that it is called FROM. LanguageExpression scope; if (scopeData.SubscriptionIdProperty == null) { if (scopeData.ResourceGroupProperty == null) { scope = new FunctionExpression("resourceGroup", new LanguageExpression[0], new LanguageExpression[] { new JTokenExpression("id") }); } else { var subscriptionId = new FunctionExpression("subscription", new LanguageExpression[0], new LanguageExpression[] { new JTokenExpression("subscriptionId") }); var resourceGroup = expressionConverter.ConvertExpression(scopeData.ResourceGroupProperty); scope = ExpressionConverter.GenerateResourceGroupScope(subscriptionId, resourceGroup); } } else { if (scopeData.ResourceGroupProperty == null) { throw new NotImplementedException($"Cannot format resourceId with non-null subscription and null resourceGroup"); } var subscriptionId = expressionConverter.ConvertExpression(scopeData.SubscriptionIdProperty); var resourceGroup = expressionConverter.ConvertExpression(scopeData.ResourceGroupProperty); scope = ExpressionConverter.GenerateResourceGroupScope(subscriptionId, resourceGroup); } // We've got to DIY it, unfortunately. The resourceId() function behaves differently when used at different scopes, so is unsuitable here. return(ExpressionConverter.GenerateScopedResourceId(scope, fullyQualifiedType, nameSegments)); case ResourceScopeType.ManagementGroupScope: if (scopeData.ManagementGroupNameProperty != null) { var managementGroupName = expressionConverter.ConvertExpression(scopeData.ManagementGroupNameProperty); var managementGroupScope = ExpressionConverter.GetManagementGroupScopeExpression(managementGroupName); return(ExpressionConverter.GenerateScopedResourceId(managementGroupScope, fullyQualifiedType, nameSegments)); } // We need to do things slightly differently for Management Groups, because there is no IL to output for "Give me a fully-qualified resource id at the current scope", // and we don't even have a mechanism for reliably getting the current scope (e.g. something like 'deployment().scope'). There are plans to add a managementGroupResourceId function, // but until we have it, we should generate unqualified resource Ids. There should not be a risk of collision, because we do not allow mixing of resource scopes in a single bicep file. return(ExpressionConverter.GenerateUnqualifiedResourceId(fullyQualifiedType, nameSegments)); default: throw new NotImplementedException($"Cannot format resourceId for scope {scopeData.RequestedScope}"); } }