in src/Analyzer.Core/TemplateAnalyzer.cs [145:244]
private IEnumerable<IEvaluation> AnalyzeAllIncludedTemplates(string populatedTemplate, string parameters, string templateFilePath, TemplateContext parentContext, string pathPrefix)
{
JToken templatejObject;
var armTemplateProcessor = new ArmTemplateProcessor(populatedTemplate, logger: this.logger);
try
{
templatejObject = armTemplateProcessor.ProcessTemplate(parameters);
}
catch (Exception e)
{
throw new TemplateAnalyzerException("Error while processing template.", e);
}
var templateContext = new TemplateContext
{
OriginalTemplate = JObject.Parse(populatedTemplate),
ExpandedTemplate = templatejObject,
IsMainTemplate = parentContext.OriginalTemplate == null, // Even the top level context will have a parent defined, but it won't represent a processed template
ResourceMappings = armTemplateProcessor.ResourceMappings,
TemplateIdentifier = templateFilePath,
IsBicep = parentContext.IsBicep,
BicepMetadata = parentContext.BicepMetadata,
PathPrefix = pathPrefix,
ParentContext = parentContext
};
try
{
IEnumerable<IEvaluation> evaluations = this.jsonRuleEngine.AnalyzeTemplate(templateContext);
if (this.powerShellRuleEngine is not null)
{
evaluations = evaluations.Concat(this.powerShellRuleEngine.AnalyzeTemplate(templateContext));
}
// Recursively handle nested templates
var jsonTemplate = JObject.Parse(populatedTemplate);
var processedTemplateResources = templatejObject.InsensitiveToken("resources");
for (int i = 0; i < processedTemplateResources.Count(); i++)
{
var currentProcessedResource = processedTemplateResources[i];
if (currentProcessedResource.InsensitiveToken("type")?.ToString().Equals("Microsoft.Resources/deployments", StringComparison.OrdinalIgnoreCase) ?? false)
{
var nestedTemplate = currentProcessedResource.InsensitiveToken("properties.template");
if (nestedTemplate == null)
{
this.logger?.LogWarning($"A linked template was found on: {templateFilePath}, linked templates are currently not supported");
continue;
}
var populatedNestedTemplate = nestedTemplate.DeepClone();
// Check whether scope is set to inner or outer
var scope = currentProcessedResource.InsensitiveToken("properties.expressionEvaluationOptions.scope")?.ToString();
if (scope == null || scope.Equals("outer", StringComparison.OrdinalIgnoreCase))
{
// Variables, parameters and functions inherited from parent template
string functionsKey = populatedNestedTemplate.InsensitiveToken("functions")?.Parent.Path ?? "functions";
string variablesKey = populatedNestedTemplate.InsensitiveToken("variables")?.Parent.Path ?? "variables";
string parametersKey = populatedNestedTemplate.InsensitiveToken("parameters")?.Parent.Path ?? "parameters";
populatedNestedTemplate[functionsKey] = jsonTemplate.InsensitiveToken("functions");
populatedNestedTemplate[variablesKey] = jsonTemplate.InsensitiveToken("variables");
populatedNestedTemplate[parametersKey] = jsonTemplate.InsensitiveToken("parameters");
}
else // scope is inner
{
// Pass variables and functions to child template
(populatedNestedTemplate.InsensitiveToken("variables") as JObject)?.Merge(currentProcessedResource.InsensitiveToken("properties.variables"));
(populatedNestedTemplate.InsensitiveToken("functions") as JObject)?.Merge(currentProcessedResource.InsensitiveToken("properties.functions)"));
// Pass parameters to child template as the 'parameters' argument
var parametersToPass = currentProcessedResource.InsensitiveToken("properties.parameters");
if (parametersToPass != null)
{
parametersToPass["parameters"] = parametersToPass;
parametersToPass["$schema"] = "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#";
parametersToPass["contentVersion"] = "1.0.0.0";
parameters = JsonConvert.SerializeObject(parametersToPass);
}
}
string jsonPopulatedNestedTemplate = JsonConvert.SerializeObject(populatedNestedTemplate);
IEnumerable<IEvaluation> result = AnalyzeAllIncludedTemplates(jsonPopulatedNestedTemplate, parameters, templateFilePath, templateContext, nestedTemplate.Path);
evaluations = evaluations.Concat(result);
}
}
return evaluations;
}
catch (Exception e)
{
throw new TemplateAnalyzerException("Error while evaluating rules.", e);
}
}