internal/graph/graph.go (82 lines of code) (raw):

// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. package graph import ( "context" "time" "github.com/Azure/azqr/internal/to" "github.com/Azure/azure-sdk-for-go/sdk/azcore" arg "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph" "github.com/rs/zerolog/log" ) type ( GraphQuery struct { client *arg.Client } GraphResult struct { Data []interface{} } ) func NewGraphQuery(cred azcore.TokenCredential) *GraphQuery { client, err := arg.NewClient(cred, nil) if err != nil { log.Fatal().Err(err).Msg("Failed to create Resource Graph client") return nil } return &GraphQuery{ client: client, } } func (q *GraphQuery) Query(ctx context.Context, query string, subscriptions []*string) *GraphResult { result := GraphResult{ Data: make([]interface{}, 0), } // Run the query in batches of 300 subscriptions batchSize := 300 for i := 0; i < len(subscriptions); i += batchSize { j := i + batchSize if j > len(subscriptions) { j = len(subscriptions) } format := arg.ResultFormatObjectArray request := arg.QueryRequest{ Subscriptions: subscriptions[i:j], Query: &query, Options: &arg.QueryRequestOptions{ ResultFormat: &format, Top: to.Ptr(int32(1000)), }, } if q.client == nil { log.Fatal().Msg("Resource Graph client not initialized") } var skipToken *string = nil for ok := true; ok; ok = skipToken != nil { request.Options.SkipToken = skipToken // Run the query and get the results results, err := q.retry(ctx, 3, 10*time.Second, request) if err == nil { result.Data = append(result.Data, results.Data.([]interface{})...) skipToken = results.SkipToken } else { log.Fatal().Err(err).Msgf("Failed to run Resource Graph query: %s", query) return nil } } } return &result } func (q *GraphQuery) retry(ctx context.Context, attempts int, sleep time.Duration, request arg.QueryRequest) (arg.ClientResourcesResponse, error) { var err error for i := 0; ; i++ { res, err := q.client.Resources(ctx, request, nil) if err == nil { return res, nil } // if shouldSkipError(err) { // return []azqr.AzureServiceResult{}, nil // } errAsString := err.Error() if i >= (attempts - 1) { log.Info().Msgf("Retry limit reached. Error: %s", errAsString) break } log.Debug().Msgf("Retrying after error: %s", errAsString) time.Sleep(sleep) sleep *= 2 } return arg.ClientResourcesResponse{}, err }