Example #1
0
        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
                    },
                });
Example #2
0
        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));
        }
Example #3
0
        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
                    },
                });
Example #4
0
        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));
        }
Example #6
0
        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");
            }
        }
Example #7
0
        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));
            }
        }
Example #8
0
        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),