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

Merge pull request #8 from kubecost/AjayTripathy-export-metrics-ep

add metrics and export to prometheus
Webb Brown 7 лет назад
Родитель
Сommit
39af047942
4 измененных файлов с 78 добавлено и 7 удалено
  1. 1 0
      cloud/provider.go
  2. 1 0
      costmodel/costmodel.go
  3. 5 0
      go.sum
  4. 71 7
      main.go

+ 1 - 0
cloud/provider.go

@@ -22,6 +22,7 @@ type Node struct {
 	VCPU             string `json:"CPU"`
 	VCPUCost         string `json:"CPUHourlyCost"`
 	RAM              string `json:"RAM"`
+	RAMBytes         string `json:"RAMBytes"`
 	RAMCost          string `json:"RAMGBHourlyCost"`
 	Storage          string `json:"storage"`
 	StorageCost      string `json:"storageHourlyCost"`

+ 1 - 0
costmodel/costmodel.go

@@ -281,6 +281,7 @@ func getNodeCost(clientset *kubernetes.Clientset, cloud costAnalyzerCloud.Provid
 
 			cnode.VCPUCost = fmt.Sprintf("%f", cpuPrice)
 			cnode.RAMCost = fmt.Sprintf("%f", ramPrice)
+			cnode.RAMBytes = fmt.Sprintf("%f", ram)
 			log.Printf(cnode.RAMCost)
 		}
 		nodes[name] = cnode

+ 5 - 0
go.sum

@@ -12,6 +12,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
 github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
 github.com/aws/aws-sdk-go v1.19.10 h1:WHIaUrU98WsWIXxlxeMCmbuB5HowxuUnk8eBH4iGl/g=
 github.com/aws/aws-sdk-go v1.19.10/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -64,6 +65,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -87,11 +89,14 @@ github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4
 github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA=
 github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU=
 github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU=
 github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg=
 github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=

+ 71 - 7
main.go

@@ -5,20 +5,28 @@ import (
 	"log"
 	"net/http"
 	"os"
+	"strconv"
+	"time"
 
 	"github.com/julienschmidt/httprouter"
 	costAnalyzerCloud "github.com/kubecost/cost-model/cloud"
 	costModel "github.com/kubecost/cost-model/costmodel"
 	prometheusClient "github.com/prometheus/client_golang/api"
+	"github.com/prometheus/client_golang/prometheus"
+
+	"github.com/prometheus/client_golang/prometheus/promhttp"
 
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/rest"
 )
 
 type Accesses struct {
-	PrometheusClient prometheusClient.Client
-	KubeClientSet    *kubernetes.Clientset
-	Cloud            costAnalyzerCloud.Provider
+	PrometheusClient       prometheusClient.Client
+	KubeClientSet          *kubernetes.Clientset
+	Cloud                  costAnalyzerCloud.Provider
+	CPUPriceRecorder       *prometheus.GaugeVec
+	RAMPriceRecorder       *prometheus.GaugeVec
+	NodeTotalPriceRecorder *prometheus.GaugeVec
 }
 
 type DataEnvelope struct {
@@ -80,7 +88,35 @@ func (a *Accesses) CostDataModelRange(w http.ResponseWriter, r *http.Request, ps
 	w.Write(wrapData(data, err))
 }
 
+func (a *Accesses) recordPrices() {
+	go func() {
+		for {
+			log.Printf("Recording prices...")
+			data, err := costModel.ComputeCostData(a.PrometheusClient, a.KubeClientSet, a.Cloud, "1h")
+			if err != nil {
+				log.Printf("Error in price recording: " + err.Error())
+			}
+			for _, costs := range data {
+				nodeName := costs.NodeName
+				node := costs.NodeData
+				cpuCost, _ := strconv.ParseFloat(node.VCPUCost, 64)
+				cpu, _ := strconv.ParseFloat(node.VCPU, 64)
+				ramCost, _ := strconv.ParseFloat(node.RAMCost, 64)
+				ram, _ := strconv.ParseFloat(node.RAMBytes, 64)
+
+				totalCost := cpu*cpuCost + ramCost*(ram/1024/1024/1024)
+
+				a.CPUPriceRecorder.WithLabelValues(nodeName).Set(cpuCost)
+				a.RAMPriceRecorder.WithLabelValues(nodeName).Set(ramCost)
+				a.NodeTotalPriceRecorder.WithLabelValues(nodeName).Set(totalCost)
+			}
+			time.Sleep(time.Minute)
+		}
+	}()
+}
+
 func main() {
+
 	address := os.Getenv("PROMETHEUS_SERVER_ENDPOINT")
 	if address == "" {
 		log.Fatal("No address for prometheus set. Aborting.")
@@ -106,10 +142,32 @@ func main() {
 		panic(err.Error())
 	}
 
+	cpuGv := prometheus.NewGaugeVec(prometheus.GaugeOpts{
+		Name: "node_cpu_hourly_cost",
+		Help: "node_cpu_hourly_cost cost for each cpu on this node",
+	}, []string{"instance"})
+
+	ramGv := prometheus.NewGaugeVec(prometheus.GaugeOpts{
+		Name: "node_ram_hourly_cost",
+		Help: "node_ram_hourly_cost cost for each gb of ram on this node",
+	}, []string{"instance"})
+
+	totalGv := prometheus.NewGaugeVec(prometheus.GaugeOpts{
+		Name: "node_total_hourly_cost",
+		Help: "node_total_hourly_cost Total node cost per hour",
+	}, []string{"instance"})
+
+	prometheus.MustRegister(cpuGv)
+	prometheus.MustRegister(ramGv)
+	prometheus.MustRegister(totalGv)
+
 	a := Accesses{
-		PrometheusClient: promCli,
-		KubeClientSet:    kubeClientset,
-		Cloud:            cloudProvider,
+		PrometheusClient:       promCli,
+		KubeClientSet:          kubeClientset,
+		Cloud:                  cloudProvider,
+		CPUPriceRecorder:       cpuGv,
+		RAMPriceRecorder:       ramGv,
+		NodeTotalPriceRecorder: totalGv,
 	}
 
 	err = a.Cloud.DownloadPricingData()
@@ -117,10 +175,16 @@ func main() {
 		log.Printf("Failed to download pricing data: " + err.Error())
 	}
 
+	a.recordPrices()
+
 	router := httprouter.New()
 	router.GET("/costDataModel", a.CostDataModel)
 	router.GET("/costDataModelRange", a.CostDataModelRange)
 	router.POST("/refreshPricing", a.RefreshPricingData)
 
-	log.Fatal(http.ListenAndServe(":9003", router))
+	rootMux := http.NewServeMux()
+	rootMux.Handle("/", router)
+	rootMux.Handle("/metrics", promhttp.Handler())
+
+	log.Fatal(http.ListenAndServe(":9003", rootMux))
 }