@@ -73,8 +73,6 @@ def __init__(
7373 account : BaseAccount ,
7474 credentials : AzureCredentials ,
7575 core_feedback : CoreFeedback ,
76- global_resources : List [Type [MicrosoftResource ]],
77- regional_resources : List [Type [MicrosoftResource ]],
7876 task_data : Optional [Json ] = None ,
7977 max_resources_per_account : Optional [int ] = None ,
8078 ):
@@ -83,15 +81,9 @@ def __init__(
8381 self .account = account
8482 self .credentials = credentials
8583 self .core_feedback = core_feedback
86- self .global_resources = global_resources
87- self .regional_resources = regional_resources
8884 self .graph = Graph (root = account , max_nodes = max_resources_per_account )
8985 self .task_data = task_data
9086
91- @abstractmethod
92- def locations (self , builder : GraphBuilder ) -> Dict [str , BaseRegion ]:
93- pass
94-
9587 def collect (self ) -> None :
9688 with ThreadPoolExecutor (
9789 thread_name_prefix = f"azure_{ self .account .id } " ,
@@ -127,16 +119,15 @@ def get_last_run() -> Optional[datetime]:
127119 config = self .config ,
128120 last_run_started_at = last_run ,
129121 )
122+
130123 # collect all locations
131124 locations = self .locations (builder )
132125 builder .location_lookup = locations
133- # collect all global resources
134- self .collect_resource_list ("subscription" , builder , self .global_resources )
135- # collect all regional resources
136- for location in locations .values ():
137- self .collect_resource_list (location .safe_name , builder .with_location (location ), self .regional_resources )
138- # wait for all work to finish
126+
127+ # collect all resources
128+ self .collect_with (builder , locations )
139129 queue .wait_for_submitted_work ()
130+
140131 # connect nodes
141132 log .info (f"[Azure:{ self .account .safe_name } ] Connect resources and create edges." )
142133 for node , data in list (self .graph .nodes (data = True )):
@@ -146,18 +137,16 @@ def get_last_run() -> Optional[datetime]:
146137 pass
147138 else :
148139 raise Exception (f"Only Azure resources expected, but got { node } " )
149- # wait for all work to finish
150140 queue .wait_for_submitted_work ()
151- # filter nodes
152- self .filter_nodes ()
153141
154- # post process nodes
142+ # post-process nodes
143+ self .remove_unused ()
155144 for node , data in list (self .graph .nodes (data = True )):
156145 if isinstance (node , MicrosoftResource ):
157146 node .after_collect (builder , data .get ("source" , {}))
158147
159148 # delete unnecessary nodes after all work is completed
160- self .after_collect_filter ()
149+ self .after_collect ()
161150 # report all accumulated errors
162151 error_accumulator .report_all (self .core_feedback )
163152 self .core_feedback .progress_done (self .account .id , 1 , 1 , context = [self .cloud .id ])
@@ -183,7 +172,37 @@ def work_done(_: Future[None]) -> None:
183172 all_done .add_done_callback (work_done )
184173 return all_done
185174
186- def filter_nodes (self ) -> None :
175+ @abstractmethod
176+ def collect_with (self , builder : GraphBuilder , locations : Dict [str , BaseRegion ]) -> None :
177+ pass
178+
179+ @abstractmethod
180+ def locations (self , builder : GraphBuilder ) -> Dict [str , BaseRegion ]:
181+ pass
182+
183+ def remove_unused (self ) -> None :
184+ pass
185+
186+ def after_collect (self ) -> None :
187+ pass
188+
189+
190+ class AzureSubscriptionCollector (MicrosoftBaseCollector ):
191+ def locations (self , builder : GraphBuilder ) -> Dict [str , BaseRegion ]:
192+ locations = AzureLocation .collect_resources (builder )
193+ return CaseInsensitiveDict ({loc .safe_name : loc for loc in locations }) # type: ignore
194+
195+ def collect_with (self , builder : GraphBuilder , locations : Dict [str , BaseRegion ]) -> None :
196+ # add deferred edge to organization
197+ builder .submit_work ("azure_all" , MicrosoftGraphOrganization .deferred_edge_to_subscription , builder )
198+ # collect all global and regional resources
199+ regional_resources = [r for r in subscription_resources if resource_with_params (r , "location" )]
200+ global_resources = list (set (subscription_resources ) - set (regional_resources ))
201+ self .collect_resource_list ("subscription" , builder , global_resources )
202+ for location in locations .values ():
203+ self .collect_resource_list (location .safe_name , builder .with_location (location ), regional_resources )
204+
205+ def remove_unused (self ) -> None :
187206 remove_nodes = []
188207
189208 def rm_nodes (cls , ignore_kinds : Optional [Type [Any ]] = None ) -> None : # type: ignore
@@ -216,7 +235,7 @@ def remove_usage_zero_value() -> None:
216235 rm_nodes (AzureStorageSku , AzureLocation )
217236 remove_usage_zero_value ()
218237
219- def after_collect_filter (self ) -> None :
238+ def after_collect (self ) -> None :
220239 # Filter unnecessary nodes such as AzureDiskTypePricing
221240 nodes_to_remove = []
222241 node_types = (AzureDiskTypePricing ,)
@@ -227,70 +246,23 @@ def after_collect_filter(self) -> None:
227246 nodes_to_remove .append (node )
228247 self ._delete_nodes (nodes_to_remove )
229248
230- def _delete_nodes (self , nodes_to_delte : Any ) -> None :
249+ def _delete_nodes (self , nodes_to_delete : Any ) -> None :
231250 removed = set ()
232- for node in nodes_to_delte :
251+ for node in nodes_to_delete :
233252 if node in removed :
234253 continue
235254 removed .add (node )
236255 self .graph .remove_node (node )
237- nodes_to_delte .clear ()
238-
239-
240- class AzureSubscriptionCollector (MicrosoftBaseCollector ):
241- def __init__ (
242- self ,
243- config : AzureConfig ,
244- cloud : Cloud ,
245- subscription : AzureSubscription ,
246- credentials : AzureCredentials ,
247- core_feedback : CoreFeedback ,
248- task_data : Optional [Json ] = None ,
249- max_resources_per_account : Optional [int ] = None ,
250- ):
251- regional_resources = [r for r in subscription_resources if resource_with_params (r , "location" )]
252- global_resources = list (set (subscription_resources ) - set (regional_resources ))
253- super ().__init__ (
254- config ,
255- cloud ,
256- subscription ,
257- credentials ,
258- core_feedback ,
259- global_resources ,
260- regional_resources ,
261- task_data = task_data ,
262- max_resources_per_account = max_resources_per_account ,
263- )
264-
265- def locations (self , builder : GraphBuilder ) -> Dict [str , BaseRegion ]:
266- locations = AzureLocation .collect_resources (builder )
267- return CaseInsensitiveDict ({loc .safe_name : loc for loc in locations }) # type: ignore
256+ nodes_to_delete .clear ()
268257
269258
270259class MicrosoftGraphOrganizationCollector (MicrosoftBaseCollector ):
271- def __init__ (
272- self ,
273- config : AzureConfig ,
274- cloud : Cloud ,
275- organization : MicrosoftGraphOrganization ,
276- credentials : AzureCredentials ,
277- core_feedback : CoreFeedback ,
278- task_data : Optional [Json ] = None ,
279- max_resources_per_account : Optional [int ] = None ,
280- ):
281- super ().__init__ (
282- config ,
283- cloud ,
284- organization ,
285- credentials ,
286- core_feedback ,
287- [],
288- graph_resources , # treat all resources as regional resources, attached to the organization root
289- task_data = task_data ,
290- max_resources_per_account = max_resources_per_account ,
291- )
292260
293261 def locations (self , builder : GraphBuilder ) -> Dict [str , BaseRegion ]:
294262 root = MicrosoftGraphOrganizationRoot (id = "organization_root" )
295263 builder .add_node (root )
296264 return {"organization_root" : root }
265+
266+ def collect_with (self , builder : GraphBuilder , locations : Dict [str , BaseRegion ]) -> None :
267+ for location in locations .values (): # all resources underneath the organization root
268+ self .collect_resource_list (location .safe_name , builder .with_location (location ), graph_resources )
0 commit comments