Просмотр исходного кода

fix(oracle): tolerate nil/empty AttributedCost during cloudcost ingestion (#3798)

Signed-off-by: Ahmed Soliman <dev.soliman@gmail.com>
Ahmed Soliman 1 день назад
Родитель
Сommit
85c87a3f3f

+ 13 - 7
pkg/cloud/oracle/usageapiintegration.go

@@ -108,14 +108,9 @@ func (uai *UsageApiIntegration) GetCloudCost(start time.Time, end time.Time) (*o
 			listRate = float64(*item.ListRate)
 		}
 
-		attrCostToParse := ""
-		if item.AttributedCost != nil {
-			attrCostToParse = *item.AttributedCost
-		}
-
-		attrCost, err := strconv.ParseFloat(attrCostToParse, 64)
+		attrCost, err := parseAttributedCost(item.AttributedCost)
 		if err != nil {
-			return nil, fmt.Errorf("unable to parse float '%s': %s", attrCostToParse, err.Error())
+			return nil, err
 		}
 
 		computedAmt := 0.0
@@ -164,6 +159,17 @@ func (uai *UsageApiIntegration) RefreshStatus() cloud.ConnectionStatus {
 	return uai.ConnectionStatus
 }
 
+func parseAttributedCost(s *string) (float64, error) {
+	if s == nil || *s == "" {
+		return 0, nil
+	}
+	f, err := strconv.ParseFloat(*s, 64)
+	if err != nil {
+		return 0, fmt.Errorf("unable to parse float '%s': %s", *s, err.Error())
+	}
+	return f, nil
+}
+
 func SelectOCICategory(service string) string {
 	if service == "Compute" {
 		return opencost.ComputeCategory

+ 28 - 0
pkg/cloud/oracle/usageapiintegration_test.go

@@ -9,6 +9,34 @@ import (
 	"github.com/opencost/opencost/core/pkg/util/timeutil"
 )
 
+func TestParseAttributedCost(t *testing.T) {
+	strPtr := func(s string) *string { return &s }
+
+	cases := map[string]struct {
+		input   *string
+		want    float64
+		wantErr bool
+	}{
+		"nil":        {nil, 0, false},
+		"empty":      {strPtr(""), 0, false},
+		"zero":       {strPtr("0"), 0, false},
+		"valid":      {strPtr("1.23"), 1.23, false},
+		"negative":   {strPtr("-0.5"), -0.5, false},
+		"unparsable": {strPtr("abc"), 0, true},
+	}
+	for name, c := range cases {
+		t.Run(name, func(t *testing.T) {
+			got, err := parseAttributedCost(c.input)
+			if (err != nil) != c.wantErr {
+				t.Fatalf("err = %v, wantErr = %v", err, c.wantErr)
+			}
+			if got != c.want {
+				t.Errorf("got %v, want %v", got, c.want)
+			}
+		})
+	}
+}
+
 func TestUsageAPIIntegration_GetCloudCost(t *testing.T) {
 	usageApiConfigPath := os.Getenv("USAGEAPI_CONFIGURATION")
 	if usageApiConfigPath == "" {