def _query_cost_native(scope: Union[AzureBillingAccount, AzureSubscriptionHandle], query: QueryDefinition, max_pages: int) -> List[QueryResult]: client = default_sdk_client(CostManagementClient) raw_result: ClientRawResponse = client.query.usage(scope.resource_id(), query, raw=True) result = raw_result.output results = [result] next_link = result.next_link if next_link: pages = 1 headers = raw_result.response.request.headers body = json.loads(raw_result.response.request.body) service_client = client._client while next_link: if pages == max_pages: raise Exception( "More results remain after max pages of cost query.") request = service_client.post(next_link, headers=headers, content=body) response = service_client.send(request, stream=False) if response.status_code != 200: raise Exception("Failed to get next page of cost query.") result = client.query._deserialize('QueryResult', response) next_link = result.next_link results.append(result) pages += 1 return results
def _query_native(subscriptions: Iterable[str], query: str, max_pages) -> List[QueryResponse]: client = default_sdk_client(ResourceGraphClient) query_options = QueryRequestOptions() query_request = QueryRequest(subscriptions=realize_sequence(subscriptions), query=query, options=query_options) query_response: QueryResponse = client.resources(query_request) if query_response.result_truncated is ResultTruncated.true: raise RuntimeError( "results are truncated. project id to enable paging.") if query_response.skip_token: page_size = query_response.count if query_response.total_records > page_size * max_pages: raise RuntimeError("too many results. increase max pages.") responses = [query_response] while query_response.skip_token: query_options = QueryRequestOptions( skip_token=query_response.skip_token) query_request = QueryRequest(subscriptions=subscriptions, query=query, options=query_options) query_response = client.resources(query_request) responses.append(query_response) return responses
def _reservations_native() -> List[ReservationResponse]: api = default_sdk_client(AzureReservationAPI) try: original_url = ReservationOperations.list.metadata['url'] # Monkey Patch the Python SDK. A wrapper for this functionality is missing. ReservationOperations.list.metadata[ 'url'] = '/providers/Microsoft.Capacity/reservations' # list() input is ignored due to patch above. all_results = list(api.reservation.list('*')) finally: ReservationOperations.list.metadata['url'] = original_url return all_results
def get_billing_accounts() -> List[AzureBillingAccount]: billing_client = default_sdk_client(BillingManagementClient) service_client = billing_client._client url = service_client.format_url( "/providers/Microsoft.Billing/billingAccounts") query_parameters = {"api-version": "2019-10-01-preview"} request = service_client.get(url, query_parameters) response = service_client.send(request, stream=False) if response.status_code != 200: raise Exception("Failed to enumerate billing accounts.") raw_accounts = json.loads(response.content)["value"] return [ AzureBillingAccount(a["name"], a["properties"]["displayName"], is_default=True) for a in raw_accounts if a.get("properties", {}).get("agreementType") == "EnterpriseAgreement" ]
def get_billing_periods(limit: int = 12) -> List[BillingPeriod]: billing_client = default_sdk_client(BillingManagementClient) return list( itertools.islice(billing_client.billing_periods.list(top=limit), limit))
def load_compute_specifications(logger: Logger) -> AzureComputeSpecifications: client = default_sdk_client(ComputeManagementClient) sku_pages: Iterable[ResourceSku] = client.resource_skus.list( filter="location eq 'eastus2'") specifications = AzureComputeSpecifications() for sku in sku_pages: if sku.resource_type not in ('virtualMachines', 'disks'): continue capabilities: Mapping[str, str] = { c.name: c.value for c in sku.capabilities } if sku.resource_type == 'virtualMachines': if sku.family == 'standardBSFamily' and 'ACUs' not in capabilities: capabilities['ACUs'] = 160 # Bugs in data if sku.family in ('standardBSFamily', 'standardHBSFamily', 'standardHBrsv2Family', 'standardDCSv2Family', 'standardNCSv2Family', 'standardNCSv3Family', 'standardHCSFamily', 'standardNVSv3Family', 'standardNVSv4Family', 'standardNDSFamily', 'standardMSv2Family'): capabilities['EphemeralOSDiskSupported'] = 'False' elif sku.family in ('standardDSv2PromoFamily', 'standardMSFamily'): capabilities['EphemeralOSDiskSupported'] = 'True' match_constrained = re.search(r'-(\d+)', sku.name) if match_constrained is not None: constraint = float(match_constrained[1]) vcpus = map_if_not_none(capabilities.get('vCPUs'), float) vcpus_available = map_if_not_none( capabilities.get('vCPUsAvailable'), float) if vcpus == vcpus_available or vcpus_available != constraint: logger.warning( f'Auto-corrected likely incorrect data from ARM from SKU {sku.name}. vcpus: {vcpus} avail: {vcpus_available}' ) capabilities['vCPUsAvailable'] = constraint if sku.name == 'Standard_E20_v3': capabilities['HyperVGenerations'] = 'V1,V2' if map_if_not_none(capabilities.get('PremiumIO'), _parse_bool) is False: if 'UncachedDiskBytesPerSecond' not in capabilities: capabilities['UncachedDiskBytesPerSecond'] = 60 * 1024**2 if 'UncachedDiskIOPS' not in capabilities: capabilities['UncachedDiskIOPS'] = 500 vm_capability_tuple = VirtualMachineCapabilities( acus=map_if_not_none(capabilities.get('ACUs'), float), accelerated_networking_enabled=map_if_not_none( capabilities.get('AcceleratedNetworkingEnabled'), _parse_bool), cached_disk_bytes=map_if_not_none( capabilities.get('CachedDiskBytes'), float), combined_temp_disk_and_cached_iops=map_if_not_none( capabilities.get('CombinedTempDiskAndCachedIOPS'), float), combined_temp_disk_and_cached_read_bytes_per_second= map_if_not_none( capabilities.get( 'CombinedTempDiskAndCachedReadBytesPerSecond'), float), combined_temp_disk_and_cached_write_bytes_per_second= map_if_not_none( capabilities.get( 'CombinedTempDiskAndCachedWriteBytesPerSecond'), float), ephemeral_os_disk_supported=map_if_not_none( capabilities.get('EphemeralOSDiskSupported'), _parse_bool), gpus=map_if_not_none(capabilities.get('GPUs'), float), hyperv_generations=capabilities.get( 'HyperVGenerations'), # type: ignore low_priority_capable=map_if_not_none( capabilities.get('LowPriorityCapable'), _parse_bool), max_data_disk_count=map_if_not_none( capabilities.get('MaxDataDiskCount'), float), max_network_interfaces=map_if_not_none( capabilities.get('MaxNetworkInterfaces'), float), max_resource_volume_mb=map_if_not_none( capabilities.get('MaxResourceVolumeMB'), float), max_write_accelerator_disks_allowed=map_if_not_none( capabilities.get('MaxWriteAcceleratorDisksAllowed'), float), memory_gb=map_if_not_none(capabilities.get('MemoryGB'), float), os_vhd_size_mb=map_if_not_none(capabilities.get('OSVhdSizeMB'), float), parent_size=capabilities.get('ParentSize'), # type: ignore premium_io=map_if_not_none(capabilities.get('PremiumIO'), _parse_bool), rdma_enabled=map_if_not_none(capabilities.get('RdmaEnabled'), _parse_bool), uncached_disk_bytes_per_second=map_if_not_none( capabilities.get('UncachedDiskBytesPerSecond'), float), uncached_disk_iops=map_if_not_none( capabilities.get('UncachedDiskIOPS'), float), vcpus=map_if_not_none(capabilities.get('vCPUs'), float), vcpus_available=map_if_not_none( capabilities.get('vCPUsAvailable'), float), vcpus_per_core=map_if_not_none( capabilities.get('vCPUsPerCore'), float)) key = sku.name.lower() existing_vm = specifications._virtual_machine_skus.get(key) if existing_vm is not None: assert existing_vm.capabilities == vm_capability_tuple #if not (existing_vm.capabilities == vm_capability_tuple): # print(f"** OMG: {sku.name} - {sku.family} mistmatch") continue specifications._virtual_machine_skus[key] = VirtualMachineSku( sku.tier, sku.family, sku.name, sku.size, vm_capability_tuple) elif sku.resource_type == 'disks': disk_capability_tuple = ManagedDiskCapabilities( billing_partition_sizes=capabilities.get( 'BillingPartitionSizes'), # type: ignore max_bandwidth_mbps=map_if_not_none( capabilities.get('MaxBandwidthMBps'), float), max_bandwidth_mbps_read_only=map_if_not_none( capabilities.get('MaxBandwidthMBpsReadOnly'), float), max_bandwidth_mbps_read_write=map_if_not_none( capabilities.get('MaxBandwidthMBpsReadWrite'), float), max_io_size_kibps=map_if_not_none( capabilities.get('MaxIOSizeKiBps'), float), max_iops=map_if_not_none(capabilities.get('MaxIOps'), float), max_iops_read_write=map_if_not_none( capabilities.get('MaxIOpsReadWrite'), float), max_iops_per_gib_read_only=map_if_not_none( capabilities.get('MaxIopsPerGiBReadOnly'), float), max_iops_per_gib_read_write=map_if_not_none( capabilities.get('MaxIopsPerGiBReadWrite'), float), max_iops_read_only=map_if_not_none( capabilities.get('MaxIopsReadOnly'), float), max_size_gib=map_if_not_none(capabilities.get('MaxSizeGiB'), float), min_bandwidth_mbps=map_if_not_none( capabilities.get('MinBandwidthMBps'), float), min_bandwidth_mbps_read_only=map_if_not_none( capabilities.get('MinBandwidthMBpsReadOnly'), float), min_bandwidth_mbps_read_write=map_if_not_none( capabilities.get('MinBandwidthMBpsReadWrite'), float), min_io_size_kibps=map_if_not_none( capabilities.get('MinIOSizeKiBps'), float), min_iops=map_if_not_none(capabilities.get('MinIOps'), float), min_iops_read_write=map_if_not_none( capabilities.get('MinIOpsReadWrite'), float), min_iops_per_gib_read_only=map_if_not_none( capabilities.get('MinIopsPerGiBReadOnly'), float), min_iops_per_gib_read_write=map_if_not_none( capabilities.get('MinIopsPerGiBReadWrite'), float), min_iops_read_only=map_if_not_none( capabilities.get('MinIopsReadOnly'), float), min_size_gib=map_if_not_none(capabilities.get('MinSizeGiB'), float)) key = sku.size.lower() existing_disk = specifications._managed_disk_skus.get(key) if existing_disk is not None: if sku.size not in ( 'E4', 'P4' ): # these skus vary in their min size across locations for some reason. assert existing_disk.capabilities == disk_capability_tuple continue specifications._managed_disk_skus[key] = ManagedDiskSku( sku.tier, sku.name, sku.size, disk_capability_tuple) return specifications
def get_iter_for_sub(subscription: str) -> Iterable[ResourceRecommendationBase]: client = default_sdk_client(AdvisorManagementClient, subscription_id=subscription) return client.recommendations.list(filter="Category eq 'Cost'")