in internal/graph/graph_scanner.go [230:294]
func (a AprlScanner) graphScan(ctx context.Context, graphClient *GraphQuery, rules []models.AprlRecommendation, subscriptions map[string]string) ([]models.AprlResult, error) {
results := []models.AprlResult{}
subs := make([]*string, 0, len(subscriptions))
for s := range subscriptions {
subs = append(subs, &s)
}
sentQueries := 0
for _, rule := range rules {
if rule.GraphQuery != "" {
result := graphClient.Query(ctx, rule.GraphQuery, subs)
if result.Data != nil {
for _, row := range result.Data {
m := row.(map[string]interface{})
log.Debug().Msg(rule.GraphQuery)
// Check if "id" is present in the map
if _, ok := m["id"]; !ok {
log.Warn().Msgf("Skipping result: 'id' field is missing in the response for recommendation: %s", rule.RecommendationID)
break
}
subscription := models.GetSubscriptionFromResourceID(m["id"].(string))
subscriptionName, ok := subscriptions[subscription]
if !ok {
subscriptionName = ""
}
results = append(results, models.AprlResult{
RecommendationID: rule.RecommendationID,
Category: models.RecommendationCategory(rule.Category),
Recommendation: rule.Recommendation,
ResourceType: rule.ResourceType,
LongDescription: rule.LongDescription,
PotentialBenefits: rule.PotentialBenefits,
Impact: models.RecommendationImpact(rule.Impact),
Name: to.String(m["name"]),
ResourceID: to.String(m["id"]),
SubscriptionID: subscription,
SubscriptionName: subscriptionName,
ResourceGroup: models.GetResourceGroupFromResourceID(m["id"].(string)),
Tags: to.String(m["tags"]),
Param1: to.String(m["param1"]),
Param2: to.String(m["param2"]),
Param3: to.String(m["param3"]),
Param4: to.String(m["param4"]),
Param5: to.String(m["param5"]),
Learn: rule.LearnMoreLink[0].Url,
AutomationAvailable: rule.AutomationAvailable,
Source: rule.Source,
})
}
}
sentQueries++
if sentQueries == 2 {
// Staggering queries to avoid throttling. Max 10 queries each 5 seconds.
// https://learn.microsoft.com/en-us/azure/governance/resource-graph/concepts/guidance-for-throttled-requests#staggering-queries
time.Sleep(1 * time.Second)
}
}
}
return results, nil
}