1+ from collections import defaultdict
12import logging
23from datetime import datetime
34from typing import ClassVar , Dict , Optional , List , Any , Type
@@ -899,15 +900,16 @@ def build_custom_disk_size(
899900 return premium_ssd_v2_object
900901
901902 @staticmethod
902- def create_unique_disk_sizes (collected_disks : List [MicrosoftResourceType ], builder : GraphBuilder ) -> None :
903+ def create_unique_disk_sizes (
904+ collected_disks : List [MicrosoftResourceType ], builder : GraphBuilder , location : str
905+ ) -> None :
903906 disk_sizes : List [Json ] = []
904907 seen_hashes = set () # Set to keep track of unique hashes
905908 for disk in collected_disks :
906909 if not isinstance (disk , AzureComputeDisk ):
907910 continue
908911 if (
909912 (volume_type := disk .volume_type )
910- and (location := disk .location )
911913 and (size := disk .volume_size )
912914 and (iops := disk .volume_iops )
913915 and (throughput := disk .volume_throughput )
@@ -1046,15 +1048,22 @@ class AzureComputeDisk(MicrosoftResource, BaseVolume):
10461048 tier_name : Optional [str ] = field (default = None , metadata = {"description" : "The sku tier." })
10471049
10481050 @classmethod
1049- def collect_resources (
1050- cls : Type [MicrosoftResourceType ], builder : GraphBuilder , ** kwargs : Any
1051- ) -> List [MicrosoftResourceType ]:
1051+ def collect_resources (cls , builder : GraphBuilder , ** kwargs : Any ) -> List ["AzureComputeDisk" ]:
10521052 log .debug (f"[Azure:{ builder .account .id } ] Collecting { cls .__name__ } with ({ kwargs } )" )
1053+ if not issubclass (cls , MicrosoftResource ):
1054+ return []
10531055 if spec := cls .api_spec :
10541056 items = builder .client .list (spec , ** kwargs )
10551057 collected = cls .collect (items , builder )
1056- # Create additional custom disk sizes for disks with Ultra SSD or Premium SSD v2 types
1057- AzureComputeDiskType .create_unique_disk_sizes (collected , builder )
1058+ disks_by_location = defaultdict (list )
1059+ for disk in collected :
1060+ if disk_location := getattr (disk , "location" , None ):
1061+ disks_by_location [disk_location ].append (disk )
1062+ for d_loc , disks in disks_by_location .items ():
1063+ # Collect disk types for the disks in this location
1064+ AzureComputeDisk ._collect_disk_types (builder , d_loc )
1065+ # Create additional custom disk sizes for disks with Ultra SSD or Premium SSD v2 types
1066+ AzureComputeDiskType .create_unique_disk_sizes (disks , builder , d_loc )
10581067 if builder .config .collect_usage_metrics :
10591068 try :
10601069 cls .collect_usage_metrics (builder , collected )
@@ -1063,33 +1072,32 @@ def collect_resources(
10631072 return collected
10641073 return []
10651074
1066- def post_process (self , graph_builder : GraphBuilder , source : Json ) -> None :
1067- if location := self .location :
1068-
1069- def collect_disk_types () -> None :
1070- log .debug (f"[Azure:{ graph_builder .account .id } ] Collecting AzureComputeDiskType" )
1071- product_names = {
1072- "Standard SSD Managed Disks" ,
1073- "Premium SSD Managed Disks" ,
1074- "Standard HDD Managed Disks" ,
1075- }
1076- sku_items = []
1077- for product_name in product_names :
1078- api_spec = AzureResourceSpec (
1079- service = "compute" ,
1080- version = "2023-01-01-preview" ,
1081- path = f"https://prices.azure.com/api/retail/prices?$filter=productName eq '{ product_name } ' and armRegionName eq '{ location } ' and unitOfMeasure eq '1/Month' and serviceFamily eq 'Storage' and type eq 'Consumption' and isPrimaryMeterRegion eq true" ,
1082- path_parameters = [],
1083- query_parameters = ["api-version" ],
1084- access_path = "Items" ,
1085- expect_array = True ,
1086- )
1075+ @staticmethod
1076+ def _collect_disk_types (graph_builder : GraphBuilder , location : str ) -> None :
1077+ def collect_disk_types () -> None :
1078+ log .debug (f"[Azure:{ graph_builder .account .id } ] Collecting AzureComputeDiskType" )
1079+ product_names = {
1080+ "Standard SSD Managed Disks" ,
1081+ "Premium SSD Managed Disks" ,
1082+ "Standard HDD Managed Disks" ,
1083+ }
1084+ sku_items = []
1085+ for product_name in product_names :
1086+ api_spec = AzureResourceSpec (
1087+ service = "compute" ,
1088+ version = "2023-01-01-preview" ,
1089+ path = f"https://prices.azure.com/api/retail/prices?$filter=productName eq '{ product_name } ' and armRegionName eq '{ location } ' and unitOfMeasure eq '1/Month' and serviceFamily eq 'Storage' and type eq 'Consumption' and isPrimaryMeterRegion eq true" ,
1090+ path_parameters = [],
1091+ query_parameters = ["api-version" ],
1092+ access_path = "Items" ,
1093+ expect_array = True ,
1094+ )
10871095
1088- items = graph_builder .client .list (api_spec )
1089- sku_items .extend (items )
1090- AzureComputeDiskType .collect (sku_items , graph_builder )
1096+ items = graph_builder .client .list (api_spec )
1097+ sku_items .extend (items )
1098+ AzureComputeDiskType .collect (sku_items , graph_builder )
10911099
1092- graph_builder .submit_work (service_name , collect_disk_types )
1100+ graph_builder .submit_work (service_name , collect_disk_types )
10931101
10941102 @classmethod
10951103 def collect_usage_metrics (
@@ -2954,30 +2962,60 @@ def collect_instance_status() -> None:
29542962 if not instance_status_set :
29552963 self .instance_status = InstanceStatus .UNKNOWN
29562964
2957- if location := self . location :
2965+ graph_builder . submit_work ( service_name , collect_instance_status )
29582966
2959- def collect_vm_sizes () -> None :
2960- api_spec = AzureResourceSpec (
2961- service = "compute" ,
2962- version = "2023-03-01" ,
2963- path = "/subscriptions/{subscriptionId}/providers/Microsoft.Compute/locations/"
2964- + f"{ location } /vmSizes" ,
2965- path_parameters = ["subscriptionId" ],
2966- query_parameters = ["api-version" ],
2967- access_path = "value" ,
2968- expect_array = True ,
2969- )
2970- items = graph_builder .client .list (api_spec )
2971- if not items :
2972- return
2973- # Set location for further connect_in_graph method
2974- for item in items :
2975- item ["location" ] = location
2976- AzureComputeVirtualMachineSize .collect (items , graph_builder )
2967+ @classmethod
2968+ def collect_resources (cls , builder : GraphBuilder , ** kwargs : Any ) -> List ["AzureComputeVirtualMachineBase" ]:
2969+ log .debug (f"[Azure:{ builder .account .id } ] Collecting { cls .__name__ } with ({ kwargs } )" )
29772970
2978- graph_builder .submit_work (service_name , collect_vm_sizes )
2971+ if not issubclass (cls , MicrosoftResource ):
2972+ return []
29792973
2980- graph_builder .submit_work (service_name , collect_instance_status )
2974+ if spec := cls .api_spec :
2975+ items = builder .client .list (spec , ** kwargs )
2976+ collected = cls .collect (items , builder )
2977+
2978+ unique_locations = set (getattr (vm , "location" ) for vm in collected if getattr (vm , "location" ))
2979+
2980+ for location in unique_locations :
2981+ log .debug (f"Processing virtual machines in location: { location } " )
2982+
2983+ # Collect VM sizes for the VM in this location
2984+ AzureComputeVirtualMachineBase ._collect_vm_sizes (builder , location )
2985+
2986+ if builder .config .collect_usage_metrics :
2987+ try :
2988+ cls .collect_usage_metrics (builder , collected )
2989+ except Exception as e :
2990+ log .warning (f"Failed to collect usage metrics for { cls .__name__ } : { e } " )
2991+
2992+ return collected
2993+
2994+ return []
2995+
2996+ @staticmethod
2997+ def _collect_vm_sizes (graph_builder : GraphBuilder , location : str ) -> None :
2998+ def collect_vm_sizes () -> None :
2999+ api_spec = AzureResourceSpec (
3000+ service = "compute" ,
3001+ version = "2023-03-01" ,
3002+ path = f"/subscriptions/{{subscriptionId}}/providers/Microsoft.Compute/locations/{ location } /vmSizes" ,
3003+ path_parameters = ["subscriptionId" ],
3004+ query_parameters = ["api-version" ],
3005+ access_path = "value" ,
3006+ expect_array = True ,
3007+ )
3008+ items = graph_builder .client .list (api_spec )
3009+ if not items :
3010+ return
3011+
3012+ # Set location for further connect_in_graph method
3013+ for item in items :
3014+ item ["location" ] = location
3015+
3016+ AzureComputeVirtualMachineSize .collect (items , graph_builder )
3017+
3018+ graph_builder .submit_work (service_name , collect_vm_sizes )
29813019
29823020 @classmethod
29833021 def collect_usage_metrics (
0 commit comments