Parcourir la source

assorted fixes

AjayTripathy il y a 7 ans
Parent
commit
4280b79900
6 fichiers modifiés avec 87 ajouts et 27 suppressions
  1. 1 1
      Dockerfile
  2. 1 0
      cloud/aws.json
  3. 12 0
      cloud/awsprovider.go
  4. 2 0
      cloud/provider.go
  5. 70 26
      costmodel/costmodel.go
  6. 1 0
      main.go

+ 1 - 1
Dockerfile

@@ -27,7 +27,7 @@ RUN set -e ;\
         -ldflags "-X main.gitCommit=${GIT_COMMIT}${GIT_DIRTY}" \
         -o /go/bin/app
 
-FROM alpine:3.4
+FROM alpine:3.9.4
 RUN apk add --update --no-cache ca-certificates
 COPY --from=build-env /go/bin/app /go/bin/app
 ADD ./cloud/default.json /models/default.json

+ 1 - 0
cloud/aws.json

@@ -4,6 +4,7 @@
     "CPU": "0.031611",
     "spotCPU": "0.006655",
     "RAM": "0.004237",
+    "GPU": "0.95",
     "spotRAM": "0.000892",
     "spotLabel": "kops.k8s.io/instancegroup",
     "spotLabelValue": "spotinstance-nodes",

+ 12 - 0
cloud/awsprovider.go

@@ -46,6 +46,8 @@ type AWS struct {
 	ValidPricingKeys        map[string]bool
 	Clientset               *kubernetes.Clientset
 	BaseCPUPrice            string
+	BaseRAMPrice            string
+	BaseGPUPrice            string
 	BaseSpotCPUPrice        string
 	BaseSpotRAMPrice        string
 	SpotLabelName           string
@@ -356,6 +358,8 @@ func (aws *AWS) DownloadPricingData() error {
 		klog.V(1).Infof("Error downloading default pricing data: %s", err.Error())
 	}
 	aws.BaseCPUPrice = c.CPU
+	aws.BaseRAMPrice = c.RAM
+	aws.BaseGPUPrice = c.GPU
 	aws.BaseSpotCPUPrice = c.SpotCPU
 	aws.BaseSpotRAMPrice = c.SpotRAM
 	aws.SpotLabelName = c.SpotLabel
@@ -528,6 +532,8 @@ func (aws *AWS) createNode(terms *AWSProductTerms, usageType string, k Key) (*No
 				GPU:          terms.GPU,
 				Storage:      terms.Storage,
 				BaseCPUPrice: aws.BaseCPUPrice,
+				BaseRAMPrice: aws.BaseRAMPrice,
+				BaseGPUPrice: aws.BaseGPUPrice,
 				UsageType:    usageType,
 			}, nil
 		}
@@ -539,6 +545,8 @@ func (aws *AWS) createNode(terms *AWSProductTerms, usageType string, k Key) (*No
 			RAMCost:      aws.BaseSpotRAMPrice,
 			Storage:      terms.Storage,
 			BaseCPUPrice: aws.BaseCPUPrice,
+			BaseRAMPrice: aws.BaseRAMPrice,
+			BaseGPUPrice: aws.BaseGPUPrice,
 			UsageType:    usageType,
 		}, nil
 	}
@@ -554,6 +562,8 @@ func (aws *AWS) createNode(terms *AWSProductTerms, usageType string, k Key) (*No
 		GPU:          terms.GPU,
 		Storage:      terms.Storage,
 		BaseCPUPrice: aws.BaseCPUPrice,
+		BaseRAMPrice: aws.BaseRAMPrice,
+		BaseGPUPrice: aws.BaseGPUPrice,
 		UsageType:    usageType,
 	}, nil
 }
@@ -589,6 +599,8 @@ func (aws *AWS) NodePricing(k Key) (*Node, error) {
 		return &Node{
 			Cost:             aws.BaseCPUPrice,
 			BaseCPUPrice:     aws.BaseCPUPrice,
+			BaseRAMPrice:     aws.BaseRAMPrice,
+			BaseGPUPrice:     aws.BaseGPUPrice,
 			UsageType:        usageType,
 			UsesBaseCPUPrice: true,
 		}, nil

+ 2 - 0
cloud/provider.go

@@ -34,6 +34,8 @@ type Node struct {
 	StorageCost      string `json:"storageHourlyCost"`
 	UsesBaseCPUPrice bool   `json:"usesDefaultPrice"`
 	BaseCPUPrice     string `json:"baseCPUPrice"` // Used to compute an implicit RAM GB/Hr price when RAM pricing is not provided.
+	BaseRAMPrice     string `json:"baseRAMPrice"` // Used to compute an implicit RAM GB/Hr price when RAM pricing is not provided.
+	BaseGPUPrice     string `json:"baseGPUPrice"`
 	UsageType        string `json:"usageType"`
 	GPU              string `json:"gpu"` // GPU represents the number of GPU on the instance
 	GPUName          string `json:"gpuName"`

+ 70 - 26
costmodel/costmodel.go

@@ -80,9 +80,9 @@ const (
 	) by (namespace,container_name,pod_name,node)`
 	queryRAMUsageStr = `sort_desc(
 		avg(
-			label_replace(count_over_time(container_memory_usage_bytes{container_name!="",container_name!="POD", instance!=""}[%s] %s), "node", "$1", "instance","(.+)") 
+			label_replace(count_over_time(container_memory_working_set_bytes{container_name!="",container_name!="POD", instance!=""}[%s] %s), "node", "$1", "instance","(.+)") 
 			* 
-			label_replace(avg_over_time(container_memory_usage_bytes{container_name!="",container_name!="POD", instance!=""}[%s] %s), "node", "$1", "instance","(.+)") 
+			label_replace(avg_over_time(container_memory_working_set_bytes{container_name!="",container_name!="POD", instance!=""}[%s] %s), "node", "$1", "instance","(.+)") 
 		) by (namespace,container_name,pod_name,node)
 	)`
 	queryCPURequestsStr = `avg(
@@ -247,7 +247,13 @@ func ComputeCostData(cli prometheusClient.Client, clientset kubernetes.Interface
 
 	pvClaimMapping, err := getPVInfoVector(resultPVRequests)
 	if err != nil {
-		return nil, err
+		klog.Infof("Unable to get PV Data: %s", err.Error())
+	}
+	if pvClaimMapping != nil {
+		err = addPVData(clientset, pvClaimMapping, cloud)
+		if err != nil {
+			return nil, err
+		}
 	}
 
 	err = addPVData(clientset, pvClaimMapping, cloud)
@@ -659,6 +665,10 @@ func GetPVCost(pv *costAnalyzerCloud.PV, kpv *v1.PersistentVolume, cloud costAna
 }
 
 func getNodeCost(clientset kubernetes.Interface, cloud costAnalyzerCloud.Provider) (map[string]*costAnalyzerCloud.Node, error) {
+	cfg, err := cloud.GetConfig()
+	if err != nil {
+		return nil, err
+	}
 	nodeList, err := clientset.CoreV1().Nodes().List(metav1.ListOptions{})
 	if err != nil {
 		return nil, err
@@ -689,34 +699,68 @@ func getNodeCost(clientset kubernetes.Interface, cloud costAnalyzerCloud.Provide
 
 		if cnode.GPU != "" && cnode.GPUCost == "" { // We couldn't find a gpu cost, so fix cpu and ram, then accordingly
 			klog.V(3).Infof("GPU without cost found for %s, calculating...", cloud.GetKey(nodeLabels).Features())
-			basePrice, err := strconv.ParseFloat(cnode.BaseCPUPrice, 64)
+			defaultCPU, err := strconv.ParseFloat(cfg.CPU, 64)
+			if err != nil {
+				klog.V(3).Infof("Could not parse default cpu price")
+				return nil, err
+			}
+			defaultRAM, err := strconv.ParseFloat(cfg.RAM, 64)
 			if err != nil {
-				klog.V(3).Infof("Error parsing node base price. Error: " + err.Error())
+				klog.V(3).Infof("Could not parse default ram price")
 				return nil, err
 			}
-			nodePrice, err := strconv.ParseFloat(cnode.Cost, 64)
+			defaultGPU, err := strconv.ParseFloat(cfg.RAM, 64)
 			if err != nil {
-				klog.V(3).Infof("Error parsing node cost. Error: " + err.Error())
+				klog.V(3).Infof("Could not parse default gpu price")
 				return nil, err
 			}
-			totalCPUPrice := basePrice * cpu
-			totalRAMPrice := 0.1 * totalCPUPrice
-			ramPrice := totalRAMPrice / (ram / 1024 / 1024 / 1024)
-			gpuPrice := nodePrice - totalCPUPrice - totalRAMPrice
-			cnode.VCPUCost = fmt.Sprintf("%f", basePrice)
+			cpuToRAMRatio := defaultCPU / defaultRAM
+			gpuToRAMRatio := defaultGPU / defaultRAM
+
+			ramGB := ram / 1024 / 1024 / 1024
+			ramMultiple := gpuToRAMRatio + cpu*cpuToRAMRatio + ramGB
+			var nodePrice float64
+			if cnode.Cost != "" {
+				nodePrice, err = strconv.ParseFloat(cnode.Cost, 64)
+				if err != nil {
+					klog.V(3).Infof("Could not parse total node price")
+					return nil, err
+				}
+			} else {
+				nodePrice, err = strconv.ParseFloat(cnode.VCPUCost, 64) // all the price was allocated the the CPU
+				if err != nil {
+					klog.V(3).Infof("Could not parse node vcpu price")
+					return nil, err
+				}
+			}
+
+			ramPrice := (nodePrice / ramMultiple)
+			cpuPrice := ramPrice * cpuToRAMRatio
+			gpuPrice := ramPrice * gpuToRAMRatio
+			cnode.VCPUCost = fmt.Sprintf("%f", cpuPrice)
 			cnode.RAMCost = fmt.Sprintf("%f", ramPrice)
 			cnode.RAMBytes = fmt.Sprintf("%f", ram)
 			cnode.GPUCost = fmt.Sprintf("%f", gpuPrice)
-			klog.V(2).Infof("Computed \"%s\" GPU Cost := %v", name, cnode.GPUCost)
+
 		} else {
 			if cnode.RAMCost == "" { // We couldn't find a ramcost, so fix cpu and allocate ram accordingly
 				klog.V(3).Infof("No RAM cost found for %s, calculating...", cloud.GetKey(nodeLabels).Features())
-				basePrice, err := strconv.ParseFloat(cnode.BaseCPUPrice, 64)
+				defaultCPU, err := strconv.ParseFloat(cfg.CPU, 64)
+				if err != nil {
+					klog.V(3).Infof("Could not parse default cpu price")
+					return nil, err
+				}
+				defaultRAM, err := strconv.ParseFloat(cfg.RAM, 64)
 				if err != nil {
-					klog.V(3).Infof("Could not find base total node price")
+					klog.V(3).Infof("Could not parse default ram price")
 					return nil, err
 				}
-				totalCPUPrice := basePrice * cpu
+				cpuToRAMRatio := defaultCPU / defaultRAM
+
+				ramGB := ram / 1024 / 1024 / 1024
+
+				ramMultiple := cpu*cpuToRAMRatio + ramGB
+
 				var nodePrice float64
 				if cnode.Cost != "" {
 					nodePrice, err = strconv.ParseFloat(cnode.Cost, 64)
@@ -731,11 +775,9 @@ func getNodeCost(clientset kubernetes.Interface, cloud costAnalyzerCloud.Provide
 						return nil, err
 					}
 				}
-				if totalCPUPrice >= nodePrice {
-					totalCPUPrice = 0.9 * nodePrice // just allocate RAM costs to 10% of the node price here to avoid 0 or negative in the numerator
-				}
-				ramPrice := (nodePrice - totalCPUPrice) / (ram / 1024 / 1024 / 1024)
-				cpuPrice := totalCPUPrice / cpu
+
+				ramPrice := (nodePrice / ramMultiple)
+				cpuPrice := ramPrice * cpuToRAMRatio
 
 				cnode.VCPUCost = fmt.Sprintf("%f", cpuPrice)
 				cnode.RAMCost = fmt.Sprintf("%f", ramPrice)
@@ -894,12 +936,14 @@ func ComputeCostDataRange(cli prometheusClient.Client, clientset kubernetes.Inte
 	}
 	pvClaimMapping, err := getPVInfoVectors(resultPVRequests)
 	if err != nil {
-		return nil, err
+		// Just log for compatibility with KSM less than 1.6
+		klog.Infof("Unable to get PV Data: %s", err.Error())
 	}
-
-	err = addPVData(clientset, pvClaimMapping, cloud)
-	if err != nil {
-		return nil, err
+	if pvClaimMapping != nil {
+		err = addPVData(clientset, pvClaimMapping, cloud)
+		if err != nil {
+			return nil, err
+		}
 	}
 
 	containerNameCost := make(map[string]*CostData)

+ 1 - 0
main.go

@@ -63,6 +63,7 @@ type DataEnvelope struct {
 func wrapData(data interface{}, err error) []byte {
 	var resp []byte
 	if err != nil {
+		klog.V(1).Infof("Error returned to client: %s", err.Error())
 		resp, _ = json.Marshal(&DataEnvelope{
 			Code:    500,
 			Status:  "error",