6
6
using System . Net . Http . Headers ;
7
7
using System . Text . RegularExpressions ;
8
8
using System . Threading . Tasks ;
9
+ using ARMExplorer . Model ;
9
10
using Newtonsoft . Json ;
10
11
using Newtonsoft . Json . Linq ;
11
12
@@ -14,6 +15,7 @@ namespace ARMExplorer.Controllers
14
15
public class ArmRepository : IArmRepository
15
16
{
16
17
private readonly IHttpClientWrapper _clientWrapper ;
18
+ private readonly int _maxNextLinkDepth = 5 ;
17
19
18
20
public ArmRepository ( IHttpClientWrapper clientWrapper )
19
21
{
@@ -40,17 +42,63 @@ public async Task<IList<string>> GetSubscriptionIdsAsync(HttpRequestMessage requ
40
42
return subscriptionIds ;
41
43
}
42
44
45
+ private static bool AddResourceToList ( IEnumerable < ArmResource > resources , ISet < ArmResource > allResources )
46
+ {
47
+ var initalCount = allResources . Count ;
48
+
49
+ foreach ( var resource in resources )
50
+ {
51
+ allResources . Add ( resource ) ;
52
+ }
53
+
54
+ var updatedCount = allResources . Count ;
55
+
56
+ return updatedCount > initalCount ;
57
+ }
58
+
59
+ private async Task < HashSet < ArmResource > > GetResources ( HttpRequestMessage requestMessage , string getResourcesUrl )
60
+ {
61
+ var allResources = new HashSet < ArmResource > ( ) ;
62
+ var currentNextLinkDepth = 0 ;
63
+
64
+ while ( ! string . IsNullOrEmpty ( getResourcesUrl ) )
65
+ {
66
+ var response = await GetAsync ( requestMessage , getResourcesUrl ) ;
67
+ response . EnsureSuccessStatusCode ( ) ;
68
+ var armResourceListResult = await response . Content . ReadAsAsync < ArmResourceListResult > ( ) ;
69
+
70
+ var newResourceFound = AddResourceToList ( armResourceListResult . Value , allResources ) ;
71
+
72
+ // ARM API returns the same skiptoken and resources repeatedly when there are no more resources. To avoid infinite cycle break when
73
+ // 1. No new resource was found in the current response or
74
+ // 2. Limit the max number of links to follow to _maxNextLinkDepth or
75
+ // 3. When nextLink is empty
76
+
77
+ if ( ! newResourceFound )
78
+ {
79
+ break ;
80
+ }
81
+
82
+ if ( currentNextLinkDepth ++ > _maxNextLinkDepth )
83
+ {
84
+ break ;
85
+ }
86
+
87
+ getResourcesUrl = armResourceListResult . NextLink ;
88
+ }
89
+
90
+ return allResources ;
91
+ }
92
+
43
93
public async Task < HashSet < string > > GetProviderNamesFor ( HttpRequestMessage requestMessage , string subscriptionId )
44
94
{
45
- var response = await GetResourcesForAsync ( requestMessage , subscriptionId ) ;
46
- response . EnsureSuccessStatusCode ( ) ;
47
- dynamic resources = await response . Content . ReadAsAsync < JObject > ( ) ;
48
- JArray values = resources . value ;
95
+ var initialGetResourcesUrl = string . Format ( Utils . ResourcesTemplate , HyakUtils . CSMUrl , subscriptionId , Utils . CSMApiVersion ) ;
96
+ var resources = await GetResources ( requestMessage , initialGetResourcesUrl ) ;
49
97
var uniqueProviders = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
50
- foreach ( dynamic value in values )
98
+
99
+ foreach ( var resource in resources )
51
100
{
52
- string id = value . id ;
53
- var match = Regex . Match ( id , "/subscriptions/.*?/resourceGroups/(.*?)/providers/(.*?)/(.*?)/" ) ;
101
+ var match = Regex . Match ( resource . Id , "/subscriptions/.*?/resourceGroups/(.*?)/providers/(.*?)/(.*?)/" ) ;
54
102
if ( match . Success )
55
103
{
56
104
var provider = match . Groups [ 2 ] . Value . ToUpperInvariant ( ) ;
@@ -63,15 +111,13 @@ public async Task<HashSet<string>> GetProviderNamesFor(HttpRequestMessage reques
63
111
64
112
public async Task < Dictionary < string , Dictionary < string , HashSet < string > > > > GetProvidersFor ( HttpRequestMessage requestMessage , string subscriptionId )
65
113
{
66
- var response = await GetResourcesForAsync ( requestMessage , subscriptionId ) ;
67
- response . EnsureSuccessStatusCode ( ) ;
68
-
69
- dynamic resources = await response . Content . ReadAsAsync < JObject > ( ) ;
70
- JArray values = resources . value ;
114
+ var initialGetResourcesUrl = string . Format ( Utils . ResourcesTemplate , HyakUtils . CSMUrl , subscriptionId , Utils . CSMApiVersion ) ;
115
+ var resources = await GetResources ( requestMessage , initialGetResourcesUrl ) ;
71
116
var result = new Dictionary < string , Dictionary < string , HashSet < string > > > ( ) ;
72
- foreach ( dynamic value in values )
117
+
118
+ foreach ( var resource in resources )
73
119
{
74
- string id = value . id ;
120
+ string id = resource . Id ;
75
121
var match = Regex . Match ( id , "/subscriptions/.*?/resourceGroups/(.*?)/providers/(.*?)/(.*?)/" ) ;
76
122
if ( match . Success )
77
123
{
@@ -116,10 +162,10 @@ private async Task<HttpResponseMessage> GetSubscriptionsAsync(HttpRequestMessage
116
162
return await _clientWrapper . SendAsync ( requestMessage , sendRequest ) ;
117
163
}
118
164
119
- private async Task < HttpResponseMessage > GetResourcesForAsync ( HttpRequestMessage requestMessage , string subscriptionId )
165
+ private async Task < HttpResponseMessage > GetAsync ( HttpRequestMessage requestMessage , string url )
120
166
{
121
- var sendRequest = new HttpRequestMessage ( HttpMethod . Get , string . Format ( Utils . ResourcesTemplate , HyakUtils . CSMUrl , subscriptionId , Utils . CSMApiVersion ) ) ;
122
- return await _clientWrapper . SendAsync ( requestMessage , sendRequest ) ;
167
+ var sendRequest = new HttpRequestMessage ( HttpMethod . Get , url ) ;
168
+ return await _clientWrapper . ExecuteAsync ( requestMessage , sendRequest ) ;
123
169
}
124
170
}
125
171
}
0 commit comments