From 2240b39296b30451904ec73b4eb5290c4bc8c975 Mon Sep 17 00:00:00 2001 From: ish Date: Wed, 7 Feb 2024 17:42:37 +0900 Subject: [PATCH 1/2] Azure: Make filtering to work --- .../azure/resources/PriceInfoHandler.go | 116 ++++++++++++++++-- 1 file changed, 104 insertions(+), 12 deletions(-) diff --git a/cloud-control-manager/cloud-driver/drivers/azure/resources/PriceInfoHandler.go b/cloud-control-manager/cloud-driver/drivers/azure/resources/PriceInfoHandler.go index 7e6345434..fe25f0a8b 100644 --- a/cloud-control-manager/cloud-driver/drivers/azure/resources/PriceInfoHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/azure/resources/PriceInfoHandler.go @@ -12,6 +12,7 @@ import ( "io" "net/http" "net/url" + "reflect" "strconv" "strings" "time" @@ -90,6 +91,76 @@ func getAzurePriceInfo(filterOption string) ([]byte, error) { return responseBody, nil } +func isFieldToFilterExist(structVal any, filterList []irs.KeyValue) (exist bool, fields []string) { + var val reflect.Value + + if len(filterList) == 0 { + return false, fields + } + + if _, ok := structVal.(irs.ProductInfo); ok { + data := structVal.(irs.ProductInfo) + val = reflect.ValueOf(&data).Elem() + } else if _, ok := structVal.(irs.PricingPolicies); ok { + data := structVal.(irs.PricingPolicies) + val = reflect.ValueOf(&data).Elem() + } else { + return false, fields + } + + for i := 0; i < val.NumField(); i++ { + field := val.Type().Field(i).Name + fields = append(fields, field) + } + + for _, filter := range filterList { + for _, field := range fields { + fieldToLower := strings.ToLower(field) + keyToLower := strings.ToLower(filter.Key) + if keyToLower == fieldToLower { + return true, fields + } + } + } + + return false, fields +} + +func isPicked(structVal any, fields []string, filterList []irs.KeyValue) bool { + var val reflect.Value + + if _, ok := structVal.(irs.ProductInfo); ok { + data := structVal.(irs.ProductInfo) + val = reflect.ValueOf(&data).Elem() + } else if _, ok := structVal.(irs.PricingPolicies); ok { + data := structVal.(irs.PricingPolicies) + val = reflect.ValueOf(&data).Elem() + } else { + return false + } + + if len(filterList) == 0 { + return true + } + + for _, filter := range filterList { + for _, field := range fields { + fieldToLower := strings.ToLower(field) + keyToLower := strings.ToLower(filter.Key) + if keyToLower == fieldToLower { + fieldValue := reflect.Indirect(val).FieldByName(field).String() + fieldValueToLower := strings.ToLower(fieldValue) + valueToLower := strings.ToLower(filter.Value) + if strings.Contains(fieldValueToLower, valueToLower) { + return true + } + } + } + } + + return false +} + func (priceInfoHandler *AzurePriceInfoHandler) ListProductFamily(regionName string) ([]string, error) { hiscallInfo := GetCallLogScheme(priceInfoHandler.Region, call.PRICEINFO, "PriceInfo", "ListProductFamily()") start := call.Start() @@ -127,9 +198,6 @@ func (priceInfoHandler *AzurePriceInfoHandler) GetPriceInfo(productFamily string start := call.Start() filterOption := "serviceFamily eq '" + productFamily + "' and armRegionName eq '" + regionName + "'" - for _, filter := range filterList { - filterOption += " and " + filter.Key + " eq '" + filter.Value + "'" - } result, err := getAzurePriceInfo(filterOption) if err != nil { @@ -223,8 +291,11 @@ func (priceInfoHandler *AzurePriceInfoHandler) GetPriceInfo(productFamily string } var pricingPolicies []irs.PricingPolicies + var isPickedByPricingPolicies bool + isPricingPoliciesFilterExist, fields := isFieldToFilterExist(irs.PricingPolicies{}, filterList) + for _, item := range value { - pricingPolicies = append(pricingPolicies, irs.PricingPolicies{ + pricingPolicy := irs.PricingPolicies{ PricingId: item.SkuID, PricingPolicy: item.Type, Unit: item.UnitOfMeasure, @@ -232,16 +303,37 @@ func (priceInfoHandler *AzurePriceInfoHandler) GetPriceInfo(productFamily string Price: strconv.FormatFloat(item.RetailPrice, 'f', -1, 64), Description: "NA", PricingPolicyInfo: nil, - }) + } + + picked := true + if isPricingPoliciesFilterExist { + picked = isPicked(pricingPolicy, fields, filterList) + if picked { + isPickedByPricingPolicies = true + } + } + if picked { + pricingPolicies = append(pricingPolicies, pricingPolicy) + } } - priceList = append(priceList, irs.Price{ - ProductInfo: productInfo, - PriceInfo: irs.PriceInfo{ - PricingPolicies: pricingPolicies, - CSPPriceInfo: value, - }, - }) + picked := true + isProductInfoFilterExist, fields := isFieldToFilterExist(irs.ProductInfo{}, filterList) + if isProductInfoFilterExist { + picked = isPicked(productInfo, fields, filterList) + } + if picked { + if isPricingPoliciesFilterExist && !isPickedByPricingPolicies { + continue + } + priceList = append(priceList, irs.Price{ + ProductInfo: productInfo, + PriceInfo: irs.PriceInfo{ + PricingPolicies: pricingPolicies, + CSPPriceInfo: value, + }, + }) + } } cloudPriceData := irs.CloudPriceData{ From b662ed835fd826a251bde386887cfd2ca57c27af Mon Sep 17 00:00:00 2001 From: ish Date: Thu, 8 Feb 2024 12:43:22 +0900 Subject: [PATCH 2/2] IBM: Make filtering to work --- .../ibmcloud-vpc/main/Test_Resources.go | 62 +++++----- .../resources/PriceInfoHandler.go | 113 ++++++++++++++++-- 2 files changed, 134 insertions(+), 41 deletions(-) diff --git a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/main/Test_Resources.go b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/main/Test_Resources.go index 587065af3..ecf1aea16 100644 --- a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/main/Test_Resources.go +++ b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/main/Test_Resources.go @@ -1500,38 +1500,36 @@ Loop: cblogger.Error(err) } - // filter not supported in IBM Cloud - - //var addFilterList string - //var filterList []irs.KeyValue - //for { - // fmt.Print("Add filter list? (y/N): ") - // _, err := fmt.Scanln(&addFilterList) - // if err != nil || strings.ToLower(addFilterList) == "n" { - // break - // } - // - // fmt.Println("=== Enter key to filter ===") - // in = bufio.NewReader(os.Stdin) - // key, err := in.ReadString('\n') - // if err != nil { - // cblogger.Error(err) - // } - // key = strings.TrimSpace(key) - // - // fmt.Println("=== Enter value to filter ===") - // in = bufio.NewReader(os.Stdin) - // value, err := in.ReadString('\n') - // if err != nil { - // cblogger.Error(err) - // } - // value = strings.TrimSpace(value) - // - // filterList = append(filterList, irs.KeyValue{ - // Key: key, - // Value: value, - // }) - //} + var addFilterList string + var filterList []irs.KeyValue + for { + fmt.Print("Add filter list? (y/N): ") + _, err := fmt.Scanln(&addFilterList) + if err != nil || strings.ToLower(addFilterList) == "n" { + break + } + + fmt.Println("=== Enter key to filter ===") + in = bufio.NewReader(os.Stdin) + key, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + key = strings.TrimSpace(key) + + fmt.Println("=== Enter value to filter ===") + in = bufio.NewReader(os.Stdin) + value, err := in.ReadString('\n') + if err != nil { + cblogger.Error(err) + } + value = strings.TrimSpace(value) + + filterList = append(filterList, irs.KeyValue{ + Key: key, + Value: value, + }) + } if priceInfo, err := priceInfoHandler.GetPriceInfo(productFamiliy, region, []irs.KeyValue{} /*filterList*/); err != nil { cblogger.Error(err) diff --git a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/PriceInfoHandler.go b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/PriceInfoHandler.go index 379d6e25f..f31a65769 100644 --- a/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/PriceInfoHandler.go +++ b/cloud-control-manager/cloud-driver/drivers/ibmcloud-vpc/resources/PriceInfoHandler.go @@ -10,6 +10,7 @@ import ( "io" "k8s.io/apimachinery/pkg/util/json" "net/http" + "reflect" "sort" "strconv" "strings" @@ -192,6 +193,76 @@ func removeDuplicateStr(array []string) []string { return array[:prev] } +func isFieldToFilterExist(structVal any, filterList []irs.KeyValue) (exist bool, fields []string) { + var val reflect.Value + + if len(filterList) == 0 { + return false, fields + } + + if _, ok := structVal.(irs.ProductInfo); ok { + data := structVal.(irs.ProductInfo) + val = reflect.ValueOf(&data).Elem() + } else if _, ok := structVal.(irs.PricingPolicies); ok { + data := structVal.(irs.PricingPolicies) + val = reflect.ValueOf(&data).Elem() + } else { + return false, fields + } + + for i := 0; i < val.NumField(); i++ { + field := val.Type().Field(i).Name + fields = append(fields, field) + } + + for _, filter := range filterList { + for _, field := range fields { + fieldToLower := strings.ToLower(field) + keyToLower := strings.ToLower(filter.Key) + if keyToLower == fieldToLower { + return true, fields + } + } + } + + return false, fields +} + +func isPicked(structVal any, fields []string, filterList []irs.KeyValue) bool { + var val reflect.Value + + if _, ok := structVal.(irs.ProductInfo); ok { + data := structVal.(irs.ProductInfo) + val = reflect.ValueOf(&data).Elem() + } else if _, ok := structVal.(irs.PricingPolicies); ok { + data := structVal.(irs.PricingPolicies) + val = reflect.ValueOf(&data).Elem() + } else { + return false + } + + if len(filterList) == 0 { + return true + } + + for _, filter := range filterList { + for _, field := range fields { + fieldToLower := strings.ToLower(field) + keyToLower := strings.ToLower(filter.Key) + if keyToLower == fieldToLower { + fieldValue := reflect.Indirect(val).FieldByName(field).String() + fieldValueToLower := strings.ToLower(fieldValue) + valueToLower := strings.ToLower(filter.Value) + if strings.Contains(fieldValueToLower, valueToLower) { + return true + } + } + } + } + + return false +} + func (priceInfoHandler *IbmPriceInfoHandler) ListProductFamily(regionName string) ([]string, error) { hiscallInfo := GetCallLogScheme(priceInfoHandler.Region, call.PRICEINFO, "PriceInfo", "ListProductFamily()") start := call.Start() @@ -506,13 +577,16 @@ func (priceInfoHandler *IbmPriceInfoHandler) GetPriceInfo(productFamily string, } var pricingPolicies []irs.PricingPolicies + var isPickedByPricingPolicies bool + isPricingPoliciesFilterExist, fields := isFieldToFilterExist(irs.PricingPolicies{}, filterList) + for _, metric := range priceInfo.Metrics { for _, amount := range metric.Amounts { if amount.Country == "USA" { currency := amount.Currency for _, price := range amount.Prices { - pricingPolicies = append(pricingPolicies, irs.PricingPolicies{ + pricingPolicy := irs.PricingPolicies{ PricingId: metric.MetricID, PricingPolicy: "quantity_tier=" + strconv.Itoa(price.QuantityTier), Unit: metric.ChargeUnit, @@ -520,19 +594,40 @@ func (priceInfoHandler *IbmPriceInfoHandler) GetPriceInfo(productFamily string, Price: strconv.FormatFloat(price.Price, 'f', -1, 64), Description: metric.ChargeUnitDisplayName, PricingPolicyInfo: nil, - }) + } + + picked := true + if isPricingPoliciesFilterExist { + picked = isPicked(pricingPolicy, fields, filterList) + if picked { + isPickedByPricingPolicies = true + } + } + if picked { + pricingPolicies = append(pricingPolicies, pricingPolicy) + } } } } } - priceList = append(priceList, irs.Price{ - ProductInfo: productInfo, - PriceInfo: irs.PriceInfo{ - PricingPolicies: pricingPolicies, - CSPPriceInfo: priceInfo.Metrics, - }, - }) + picked := true + isProductInfoFilterExist, fields := isFieldToFilterExist(irs.ProductInfo{}, filterList) + if isProductInfoFilterExist { + picked = isPicked(productInfo, fields, filterList) + } + if picked { + if isPricingPoliciesFilterExist && !isPickedByPricingPolicies { + continue + } + priceList = append(priceList, irs.Price{ + ProductInfo: productInfo, + PriceInfo: irs.PriceInfo{ + PricingPolicies: pricingPolicies, + CSPPriceInfo: priceInfo.Metrics, + }, + }) + } } cloudPriceData := irs.CloudPriceData{