func()

in pkg/selector/selector.go [262:381]


func (s Selector) prepareFilter(ctx context.Context, filters Filters, instanceTypeInfo instancetypes.Details, availabilityZones []string, locationInstanceOfferings map[ec2types.InstanceType]string) (*instancetypes.Details, error) {
	instanceTypeName := instanceTypeInfo.InstanceType
	isFpga := instanceTypeInfo.FpgaInfo != nil
	var instanceTypeHourlyPriceForFilter float64 // Price used to filter based on usage class
	var instanceTypeHourlyPriceOnDemand, instanceTypeHourlyPriceSpot *float64
	// If prices are fetched, populate the fields irrespective of the price filters
	if s.EC2Pricing.OnDemandCacheCount() > 0 {
		price, err := s.EC2Pricing.GetOnDemandInstanceTypeCost(ctx, instanceTypeName)
		if err != nil {
			s.Logger.Printf("Could not retrieve instantaneous hourly on-demand price for instance type %s - %s\n", instanceTypeName, err)
		} else {
			instanceTypeHourlyPriceOnDemand = &price
			instanceTypeInfo.OndemandPricePerHour = instanceTypeHourlyPriceOnDemand
		}
	}

	isSpotUsageClass := false
	for _, it := range instanceTypeInfo.SupportedUsageClasses {
		if it == ec2types.UsageClassTypeSpot {
			isSpotUsageClass = true
		}
	}

	if s.EC2Pricing.SpotCacheCount() > 0 && isSpotUsageClass {
		price, err := s.EC2Pricing.GetSpotInstanceTypeNDayAvgCost(ctx, instanceTypeName, availabilityZones, 30)
		if err != nil {
			s.Logger.Printf("Could not retrieve 30 day avg hourly spot price for instance type %s\n", instanceTypeName)
		} else {
			instanceTypeHourlyPriceSpot = &price
			instanceTypeInfo.SpotPrice = instanceTypeHourlyPriceSpot
		}
	}
	if filters.PricePerHour != nil {
		// If price filter is present, prices should be already fetched
		// If prices are not fetched, filter should fail and the corresponding error is already printed
		if filters.UsageClass != nil && *filters.UsageClass == ec2types.UsageClassTypeSpot && instanceTypeHourlyPriceSpot != nil {
			instanceTypeHourlyPriceForFilter = *instanceTypeHourlyPriceSpot
		} else if instanceTypeHourlyPriceOnDemand != nil {
			instanceTypeHourlyPriceForFilter = *instanceTypeHourlyPriceOnDemand
		}
	}
	eneaSupport := string(instanceTypeInfo.NetworkInfo.EnaSupport)
	ebsOptimizedSupport := string(instanceTypeInfo.EbsInfo.EbsOptimizedSupport)

	// If an empty slice is passed, treat the filter as nil
	filterInstanceTypes := filters.InstanceTypes
	if filterInstanceTypes != nil && len(*filterInstanceTypes) == 0 {
		filterInstanceTypes = nil
	}

	var cpuManufacturerFilter *string
	if filters.CPUManufacturer != nil {
		cpuManufacturerFilter = aws.String(string(*filters.CPUManufacturer))
	}

	// filterToInstanceSpecMappingPairs is a map of filter name [key] to filter pair [value].
	// A filter pair includes user input filter value and instance spec value retrieved from DescribeInstanceTypes
	filterToInstanceSpecMappingPairs := map[string]filterPair{
		cpuArchitecture:                  {filters.CPUArchitecture, instanceTypeInfo.ProcessorInfo.SupportedArchitectures},
		cpuManufacturer:                  {cpuManufacturerFilter, instanceTypeInfo.ProcessorInfo.Manufacturer},
		usageClass:                       {filters.UsageClass, instanceTypeInfo.SupportedUsageClasses},
		rootDeviceType:                   {filters.RootDeviceType, instanceTypeInfo.SupportedRootDeviceTypes},
		hibernationSupported:             {filters.HibernationSupported, instanceTypeInfo.HibernationSupported},
		vcpusRange:                       {filters.VCpusRange, instanceTypeInfo.VCpuInfo.DefaultVCpus},
		memoryRange:                      {filters.MemoryRange, instanceTypeInfo.MemoryInfo.SizeInMiB},
		gpuMemoryRange:                   {filters.GpuMemoryRange, getTotalGpuMemory(instanceTypeInfo.GpuInfo)},
		gpusRange:                        {filters.GpusRange, getTotalGpusCount(instanceTypeInfo.GpuInfo)},
		inferenceAcceleratorsRange:       {filters.InferenceAcceleratorsRange, getTotalAcceleratorsCount(instanceTypeInfo.InferenceAcceleratorInfo)},
		placementGroupStrategy:           {filters.PlacementGroupStrategy, instanceTypeInfo.PlacementGroupInfo.SupportedStrategies},
		hypervisor:                       {filters.Hypervisor, instanceTypeInfo.Hypervisor},
		baremetal:                        {filters.BareMetal, instanceTypeInfo.BareMetal},
		burstable:                        {filters.Burstable, instanceTypeInfo.BurstablePerformanceSupported},
		fpga:                             {filters.Fpga, &isFpga},
		enaSupport:                       {filters.EnaSupport, supportSyntaxToBool(&eneaSupport)},
		efaSupport:                       {filters.EfaSupport, instanceTypeInfo.NetworkInfo.EfaSupported},
		vcpusToMemoryRatio:               {filters.VCpusToMemoryRatio, calculateVCpusToMemoryRatio(instanceTypeInfo.VCpuInfo.DefaultVCpus, instanceTypeInfo.MemoryInfo.SizeInMiB)},
		currentGeneration:                {filters.CurrentGeneration, instanceTypeInfo.CurrentGeneration},
		networkInterfaces:                {filters.NetworkInterfaces, instanceTypeInfo.NetworkInfo.MaximumNetworkInterfaces},
		networkPerformance:               {filters.NetworkPerformance, getNetworkPerformance(instanceTypeInfo.NetworkInfo.NetworkPerformance)},
		networkEncryption:                {filters.NetworkEncryption, instanceTypeInfo.NetworkInfo.EncryptionInTransitSupported},
		ipv6:                             {filters.IPv6, instanceTypeInfo.NetworkInfo.Ipv6Supported},
		instanceTypes:                    {filterInstanceTypes, aws.String(string(instanceTypeInfo.InstanceType))},
		virtualizationType:               {filters.VirtualizationType, instanceTypeInfo.SupportedVirtualizationTypes},
		pricePerHour:                     {filters.PricePerHour, &instanceTypeHourlyPriceForFilter},
		instanceStorageRange:             {filters.InstanceStorageRange, getInstanceStorage(instanceTypeInfo.InstanceStorageInfo)},
		diskType:                         {filters.DiskType, getDiskType(instanceTypeInfo.InstanceStorageInfo)},
		nvme:                             {filters.NVME, getNVMESupport(instanceTypeInfo.InstanceStorageInfo, instanceTypeInfo.EbsInfo)},
		ebsOptimized:                     {filters.EBSOptimized, supportSyntaxToBool(&ebsOptimizedSupport)},
		diskEncryption:                   {filters.DiskEncryption, getDiskEncryptionSupport(instanceTypeInfo.InstanceStorageInfo, instanceTypeInfo.EbsInfo)},
		ebsOptimizedBaselineBandwidth:    {filters.EBSOptimizedBaselineBandwidth, getEBSOptimizedBaselineBandwidth(instanceTypeInfo.EbsInfo)},
		ebsOptimizedBaselineThroughput:   {filters.EBSOptimizedBaselineThroughput, getEBSOptimizedBaselineThroughput(instanceTypeInfo.EbsInfo)},
		ebsOptimizedBaselineIOPS:         {filters.EBSOptimizedBaselineIOPS, getEBSOptimizedBaselineIOPS(instanceTypeInfo.EbsInfo)},
		freeTier:                         {filters.FreeTier, instanceTypeInfo.FreeTierEligible},
		autoRecovery:                     {filters.AutoRecovery, instanceTypeInfo.AutoRecoverySupported},
		gpuManufacturer:                  {filters.GPUManufacturer, getGPUManufacturers(instanceTypeInfo.GpuInfo)},
		gpuModel:                         {filters.GPUModel, getGPUModels(instanceTypeInfo.GpuInfo)},
		inferenceAcceleratorManufacturer: {filters.InferenceAcceleratorManufacturer, getInferenceAcceleratorManufacturers(instanceTypeInfo.InferenceAcceleratorInfo)},
		inferenceAcceleratorModel:        {filters.InferenceAcceleratorModel, getInferenceAcceleratorModels(instanceTypeInfo.InferenceAcceleratorInfo)},
		dedicatedHosts:                   {filters.DedicatedHosts, instanceTypeInfo.DedicatedHostsSupported},
		generation:                       {filters.Generation, getInstanceTypeGeneration(string(instanceTypeInfo.InstanceType))},
	}

	if isInDenyList(filters.DenyList, instanceTypeName) || !isInAllowList(filters.AllowList, instanceTypeName) {
		return nil, nil
	}

	if !isSupportedInLocation(locationInstanceOfferings, instanceTypeName) {
		return nil, nil
	}

	var isInstanceSupported bool
	isInstanceSupported, err := s.executeFilters(ctx, filterToInstanceSpecMappingPairs, instanceTypeName)
	if err != nil {
		return nil, err
	}
	if !isInstanceSupported {
		return nil, nil
	}
	return &instanceTypeInfo, nil
}