Procházet zdrojové kódy

Fix resource leak in OTC API pagination by moving resp.Body.Close() (#3668)

Signed-off-by: Claude <claude@anthropic.com>
Signed-off-by: peatey <warwick.peatey@ibm.com>
Co-authored-by: Claude <noreply@anthropic.com>
Warwick před 1 měsícem
rodič
revize
44016ce86a
2 změnil soubory, kde provedl 16 přidání a 2 odebrání
  1. 4 0
      CLAUDE.md
  2. 12 2
      pkg/cloud/otc/pricingapi.go

+ 4 - 0
CLAUDE.md

@@ -2,6 +2,10 @@
 
 
 This document provides guidance for AI assistants working with the OpenCost codebase.
 This document provides guidance for AI assistants working with the OpenCost codebase.
 
 
+## AI Assistant Behaviour
+
+- Never include claude.ai session links or URLs in commit messages or pull request bodies.
+
 ## Project Overview
 ## Project Overview
 
 
 OpenCost is an open source Kubernetes cost monitoring tool maintained by the Cloud Native Computing Foundation (CNCF). It provides real-time cost allocation, asset tracking, and cloud cost monitoring for Kubernetes clusters across multiple cloud providers.
 OpenCost is an open source Kubernetes cost monitoring tool maintained by the Cloud Native Computing Foundation (CNCF). It provides real-time cost allocation, asset tracking, and cloud cost monitoring for Kubernetes clusters across multiple cloud providers.

+ 12 - 2
pkg/cloud/otc/pricingapi.go

@@ -9,6 +9,8 @@ import (
 	"github.com/opencost/opencost/core/pkg/log"
 	"github.com/opencost/opencost/core/pkg/log"
 )
 )
 
 
+var otcHTTPClient = http.DefaultClient
+
 // Fetches and flattens all product entries across multiple services with pagination
 // Fetches and flattens all product entries across multiple services with pagination
 func (otc *OTC) fetchPaginatedProducts(serviceNames []string) ([]Product, error) {
 func (otc *OTC) fetchPaginatedProducts(serviceNames []string) ([]Product, error) {
 	const baseURL = "https://calculator.otc-service.com/de/open-telekom-price-api/"
 	const baseURL = "https://calculator.otc-service.com/de/open-telekom-price-api/"
@@ -20,14 +22,22 @@ func (otc *OTC) fetchPaginatedProducts(serviceNames []string) ([]Product, error)
 	for {
 	for {
 		url := fmt.Sprintf("%s?%s&columns%%5B0%%5D=productIdParameter&columns%%5B1%%5D=opiFlavour&columns%%5B2%%5D=osUnit&columns%%5B3%%5D=vCpu&columns%%5B4%%5D=ram&columns%%5B5%%5D=priceAmount&limitFrom=%d", baseURL, query, limitFrom)
 		url := fmt.Sprintf("%s?%s&columns%%5B0%%5D=productIdParameter&columns%%5B1%%5D=opiFlavour&columns%%5B2%%5D=osUnit&columns%%5B3%%5D=vCpu&columns%%5B4%%5D=ram&columns%%5B5%%5D=priceAmount&limitFrom=%d", baseURL, query, limitFrom)
 
 
-		resp, err := http.Get(url)
+		resp, err := otcHTTPClient.Get(url)
 		if err != nil {
 		if err != nil {
+			if resp != nil {
+				resp.Body.Close()
+			}
 			log.Errorf("Error fetching products from OTC API: %v", err)
 			log.Errorf("Error fetching products from OTC API: %v", err)
 			return nil, err
 			return nil, err
 		}
 		}
-		defer resp.Body.Close()
+		if resp.StatusCode != http.StatusOK {
+			io.Copy(io.Discard, resp.Body)
+			resp.Body.Close()
+			return nil, fmt.Errorf("OTC API returned unexpected status %d", resp.StatusCode)
+		}
 
 
 		pageData, stats, err := otc.loadPaginatedResponse(resp)
 		pageData, stats, err := otc.loadPaginatedResponse(resp)
+		resp.Body.Close()
 		if err != nil {
 		if err != nil {
 			log.Errorf("Error loading paginated response: %v", err)
 			log.Errorf("Error loading paginated response: %v", err)
 			return nil, err
 			return nil, err