private static ScopeData?ValidateScope(SemanticModel semanticModel, LogInvalidScopeDiagnostic logInvalidScopeFunc, ResourceScope supportedScopes, SyntaxBase bodySyntax, SyntaxBase?scopeValue) { if (scopeValue is null) { // no scope provided - use the target scope for the file if (!supportedScopes.HasFlag(semanticModel.TargetScope)) { logInvalidScopeFunc(bodySyntax, semanticModel.TargetScope, supportedScopes); return(null); } return(null); } var(scopeSymbol, indexExpression) = scopeValue switch { // scope indexing can only happen with references to module or resource collections ArrayAccessSyntax { BaseExpression : VariableAccessSyntax baseVariableAccess } arrayAccess => (semanticModel.GetSymbolInfo(baseVariableAccess), arrayAccess.IndexExpression), ArrayAccessSyntax { BaseExpression : ResourceAccessSyntax baseVariableAccess } arrayAccess => (semanticModel.GetSymbolInfo(baseVariableAccess), arrayAccess.IndexExpression), // all other scope expressions _ => (semanticModel.GetSymbolInfo(scopeValue), null) }; var scopeType = semanticModel.GetTypeInfo(scopeValue); switch (scopeType) { case TenantScopeType type: if (!supportedScopes.HasFlag(ResourceScope.Tenant)) { logInvalidScopeFunc(scopeValue, ResourceScope.Tenant, supportedScopes); return(null); } return(new ScopeData { RequestedScope = ResourceScope.Tenant, IndexExpression = indexExpression }); case ManagementGroupScopeType type: if (!supportedScopes.HasFlag(ResourceScope.ManagementGroup)) { logInvalidScopeFunc(scopeValue, ResourceScope.ManagementGroup, supportedScopes); return(null); } return(type.Arguments.Length switch { 0 => new ScopeData { RequestedScope = ResourceScope.ManagementGroup, IndexExpression = indexExpression }, _ => new ScopeData { RequestedScope = ResourceScope.ManagementGroup, ManagementGroupNameProperty = type.Arguments[0].Expression, IndexExpression = indexExpression }, });
private static ObjectType GetDeploymentReturnType(ResourceScope targetScope) { // Note: there are other properties which could be included here, but they allow you to break out of the bicep world. // We're going to omit them and only include what is truly necessary. If we get feature requests to expose more properties, we should discuss this further. // Properties such as 'template', 'templateHash', 'parameters' depend on the codegen, and feel like they could be fragile. IEnumerable <TypeProperty> properties = new[] { new TypeProperty("name", LanguageConstants.String), new TypeProperty("properties", new ObjectType("properties", TypeSymbolValidationFlags.Default, new [] { new TypeProperty("templateLink", new ObjectType("properties", TypeSymbolValidationFlags.Default, new [] { new TypeProperty("id", LanguageConstants.String), new TypeProperty("uri", LanguageConstants.String), }, null)) }, null)), }; if (!targetScope.HasFlag(ResourceScope.ResourceGroup)) { // deployments in the 'resourcegroup' scope do not have the 'location' property. All other scopes do. var locationProperty = new TypeProperty("location", LanguageConstants.String); properties = properties.Concat(locationProperty.AsEnumerable()); } return(new ObjectType("deployment", TypeSymbolValidationFlags.Default, properties, null)); }
private static ScopeData?ValidateScope(SemanticModel semanticModel, LogInvalidScopeDiagnostic logInvalidScopeFunc, ResourceScope supportedScopes, SyntaxBase bodySyntax, ObjectPropertySyntax?scopeProperty) { if (scopeProperty is null) { // no scope provided - use the target scope for the file if (!supportedScopes.HasFlag(semanticModel.TargetScope)) { logInvalidScopeFunc(bodySyntax, semanticModel.TargetScope, supportedScopes); return(null); } return(null); } var scopeSymbol = semanticModel.GetSymbolInfo(scopeProperty.Value); var scopeType = semanticModel.GetTypeInfo(scopeProperty.Value); switch (scopeType) { case TenantScopeType type: if (!supportedScopes.HasFlag(ResourceScope.Tenant)) { logInvalidScopeFunc(scopeProperty.Value, ResourceScope.Tenant, supportedScopes); return(null); } return(new ScopeData { RequestedScope = ResourceScope.Tenant }); case ManagementGroupScopeType type: if (!supportedScopes.HasFlag(ResourceScope.ManagementGroup)) { logInvalidScopeFunc(scopeProperty.Value, ResourceScope.ManagementGroup, supportedScopes); return(null); } return(type.Arguments.Length switch { 0 => new ScopeData { RequestedScope = ResourceScope.ManagementGroup }, _ => new ScopeData { RequestedScope = ResourceScope.ManagementGroup, ManagementGroupNameProperty = type.Arguments[0].Expression }, });
private static string GetSchema(ResourceScope targetScope) { if (targetScope.HasFlag(ResourceScope.Tenant)) { return("https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#"); } if (targetScope.HasFlag(ResourceScope.ManagementGroup)) { return("https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#"); } if (targetScope.HasFlag(ResourceScope.Subscription)) { return("https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#"); } return("https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#"); }
private static ObjectType SetBicepResourceProperties(ObjectType objectType, ResourceScope validParentScopes, ResourceTypeReference typeReference, bool isExistingResource) { var properties = objectType.Properties; var scopePropertyFlags = TypePropertyFlags.WriteOnly | TypePropertyFlags.DeployTimeConstant; if (validParentScopes == ResourceScope.Resource) { // resource can only be deployed as an extension resource - scope should be required scopePropertyFlags |= TypePropertyFlags.Required; } if (isExistingResource) { // we can refer to a resource at any scope if it is an existing resource not being deployed by this file var scopeReference = LanguageConstants.CreateResourceScopeReference(validParentScopes); properties = properties.SetItem(LanguageConstants.ResourceScopePropertyName, new TypeProperty(LanguageConstants.ResourceScopePropertyName, scopeReference, scopePropertyFlags)); } else { // TODO: remove 'dependsOn' from the type library properties = properties.SetItem(LanguageConstants.ResourceDependsOnPropertyName, new TypeProperty(LanguageConstants.ResourceDependsOnPropertyName, LanguageConstants.ResourceOrResourceCollectionRefArray, TypePropertyFlags.WriteOnly)); // we only support scope for extension resources (or resources where the scope is unknown and thus may be an extension resource) if (validParentScopes.HasFlag(ResourceScope.Resource)) { var scopeReference = LanguageConstants.CreateResourceScopeReference(ResourceScope.Resource); properties = properties.SetItem(LanguageConstants.ResourceScopePropertyName, new TypeProperty(LanguageConstants.ResourceScopePropertyName, scopeReference, scopePropertyFlags)); } } // add the 'parent' property for child resource types if (!typeReference.IsRootType) { var parentType = LanguageConstants.CreateResourceScopeReference(ResourceScope.Resource); var parentFlags = TypePropertyFlags.WriteOnly | TypePropertyFlags.DeployTimeConstant; properties = properties.SetItem(LanguageConstants.ResourceParentPropertyName, new TypeProperty(LanguageConstants.ResourceParentPropertyName, parentType, parentFlags)); } // Deployments RP if (StringComparer.OrdinalIgnoreCase.Equals(objectType.Name, ResourceTypeDeployments)) { properties = properties.SetItem("resourceGroup", new TypeProperty("resourceGroup", LanguageConstants.String, TypePropertyFlags.DeployTimeConstant)); properties = properties.SetItem("subscriptionId", new TypeProperty("subscriptionId", LanguageConstants.String, TypePropertyFlags.DeployTimeConstant)); } return(new NamedObjectType( objectType.Name, objectType.ValidationFlags, isExistingResource ? ConvertToReadOnly(properties.Values) : properties.Values, objectType.AdditionalPropertiesType, isExistingResource ? ConvertToReadOnly(objectType.AdditionalPropertiesFlags) : objectType.AdditionalPropertiesFlags)); }
public static IEnumerable <string> GetResourceScopeDescriptions(ResourceScope resourceScope) { if (resourceScope == ResourceScope.None) { yield return("none"); } if (resourceScope.HasFlag(ResourceScope.Resource)) { yield return("resource"); } if (resourceScope.HasFlag(ResourceScope.Module)) { yield return("module"); } if (resourceScope.HasFlag(ResourceScope.Tenant)) { yield return("tenant"); } if (resourceScope.HasFlag(ResourceScope.ManagementGroup)) { yield return("managementGroup"); } if (resourceScope.HasFlag(ResourceScope.Subscription)) { yield return("subscription"); } if (resourceScope.HasFlag(ResourceScope.ResourceGroup)) { yield return("resourceGroup"); } }
private static ObjectType SetBicepResourceProperties(ObjectType objectType, ResourceScope validParentScopes, bool isExistingResource) { var properties = objectType.Properties; var scopeRequiredFlag = TypePropertyFlags.WriteOnly; if (validParentScopes == ResourceScope.Resource) { // resource can only be deployed as an extension resource - scope should be required scopeRequiredFlag |= TypePropertyFlags.Required; } if (isExistingResource) { // we can refer to a resource at any scope if it is an existing resource not being deployed by this file var scopeReference = LanguageConstants.CreateResourceScopeReference(validParentScopes); properties = properties.SetItem(LanguageConstants.ResourceScopePropertyName, new TypeProperty(LanguageConstants.ResourceScopePropertyName, scopeReference, scopeRequiredFlag)); return(new NamedObjectType( objectType.Name, objectType.ValidationFlags, ConvertToReadOnly(properties.Values), objectType.AdditionalPropertiesType, ConvertToReadOnly(objectType.AdditionalPropertiesFlags))); } else { // we only support scope for extension resources (or resources where the scope is unknown and thus may be an extension resource) if (validParentScopes.HasFlag(ResourceScope.Resource)) { var scopeReference = LanguageConstants.CreateResourceScopeReference(ResourceScope.Resource); properties = properties.SetItem(LanguageConstants.ResourceScopePropertyName, new TypeProperty(LanguageConstants.ResourceScopePropertyName, scopeReference, scopeRequiredFlag)); } // TODO: remove 'dependsOn' from the type library properties = properties.SetItem(LanguageConstants.ResourceDependsOnPropertyName, new TypeProperty(LanguageConstants.ResourceDependsOnPropertyName, LanguageConstants.ResourceRefArray, TypePropertyFlags.WriteOnly)); return(new NamedObjectType( objectType.Name, objectType.ValidationFlags, properties.Values, objectType.AdditionalPropertiesType, objectType.AdditionalPropertiesFlags)); } }
private static ScopeData?ValidateScope(SemanticModel semanticModel, LogInvalidScopeDiagnostic logInvalidScopeFunc, ResourceScope supportedScopes, SyntaxBase bodySyntax, ObjectPropertySyntax?scopeProperty) { if (scopeProperty is null) { // no scope provided - use the target scope for the file if (!supportedScopes.HasFlag(semanticModel.TargetScope)) { logInvalidScopeFunc(bodySyntax, semanticModel.TargetScope, supportedScopes); return(null); } return(null); } var scopeSymbol = scopeProperty.Value switch { // scope indexing can only happen with references to module or resource collections ArrayAccessSyntax { BaseExpression : VariableAccessSyntax baseVariableAccess } => semanticModel.GetSymbolInfo(baseVariableAccess),