Jelajahi Sumber

progress on adding new prometheus metric: modified router.go, created new struct for unmarshalling cloud provider data in provider.go. Need to figure out where getLBCost() will get called.

Calvin Wang 5 tahun lalu
induk
melakukan
2b67f4e151
4 mengubah file dengan 60 tambahan dan 1 penghapusan
  1. 1 0
      go.sum
  2. 12 0
      pkg/cloud/provider.go
  3. 39 0
      pkg/costmodel/costmodel.go
  4. 8 1
      pkg/costmodel/router.go

+ 1 - 0
go.sum

@@ -559,6 +559,7 @@ k8s.io/apimachinery v0.0.0-20190913075812-e119e5e154b6 h1:tGU1C/vMoUV2ZakSH6wQq2
 k8s.io/apimachinery v0.0.0-20190913075812-e119e5e154b6/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4=
 k8s.io/apimachinery v0.0.0-20190913075812-e119e5e154b6/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4=
 k8s.io/apimachinery v0.18.6 h1:RtFHnfGNfd1N0LeSrKCUznz5xtUP1elRGvHJbL3Ntag=
 k8s.io/apimachinery v0.18.6 h1:RtFHnfGNfd1N0LeSrKCUznz5xtUP1elRGvHJbL3Ntag=
 k8s.io/apimachinery v0.19.0 h1:gjKnAda/HZp5k4xQYjL0K/Yb66IvNqjthCb03QlKpaQ=
 k8s.io/apimachinery v0.19.0 h1:gjKnAda/HZp5k4xQYjL0K/Yb66IvNqjthCb03QlKpaQ=
+k8s.io/apimachinery v0.19.1 h1:cwsxZazM/LA9aUsBaL4bRS5ygoM6bYp8dFk22DSYQa4=
 k8s.io/client-go v0.0.0-20190404172613-2e1a3ed22ac5 h1:BwY2C//EoWktJi74O6R2REBonrhsfhRI0qfVwOjOPp8=
 k8s.io/client-go v0.0.0-20190404172613-2e1a3ed22ac5 h1:BwY2C//EoWktJi74O6R2REBonrhsfhRI0qfVwOjOPp8=
 k8s.io/client-go v0.0.0-20190404172613-2e1a3ed22ac5/go.mod h1:bIEHXHbykaOlj+pgLllzLJ2RPGdzkjtqdk0Il07KPEM=
 k8s.io/client-go v0.0.0-20190404172613-2e1a3ed22ac5/go.mod h1:bIEHXHbykaOlj+pgLllzLJ2RPGdzkjtqdk0Il07KPEM=
 k8s.io/client-go v0.0.0-20190620085101-78d2af792bab h1:E8Fecph0qbNsAbijJJQryKu4Oi9QTp5cVpjTE+nqg6g=
 k8s.io/client-go v0.0.0-20190620085101-78d2af792bab h1:E8Fecph0qbNsAbijJJQryKu4Oi9QTp5cVpjTE+nqg6g=

+ 12 - 0
pkg/cloud/provider.go

@@ -70,6 +70,18 @@ func (n *Node) IsSpot() bool {
 	}
 	}
 }
 }
 
 
+// LoadBalancer is the interface by which the provider and cost model communicate LoadBalancer prices.
+// The provider will best-effort try to fill out this struct.
+type LoadBalancer struct {
+	IngressIPAddresses           []string `json:"IngressIPAddresses"`
+	Cost                         float64  `json:"hourlyCost"` // TODO: find out if cloud providers return these values as strings or floats
+	FirstFiveForwardingRulesCost float64  `json:"firstFiveForwardingRulesCost"`
+	AdditionalForwardingRuleCost float64  `json:"additionalForwardingRuleCost"`
+	IngressDataCostPerGB         float64  `json:"ingressDataCostPerGB"`
+	// TODO: work in progress. Currently designed for GCP, unsure if other cloud providers price differently (e.g., if Azure prices a flat rate per rule)
+	// TODO: potentially need to make an additional struct to marshal GCP ALB data
+}
+
 // Network is the interface by which the provider and cost model communicate network egress prices.
 // Network is the interface by which the provider and cost model communicate network egress prices.
 // The provider will best-effort try to fill out this struct.
 // The provider will best-effort try to fill out this struct.
 type Network struct {
 type Network struct {

+ 39 - 0
pkg/costmodel/costmodel.go

@@ -1183,6 +1183,45 @@ func (cm *CostModel) GetNodeCost(cp costAnalyzerCloud.Provider) (map[string]*cos
 	return nodes, nil
 	return nodes, nil
 }
 }
 
 
+// TODO: drop some logs
+func (cm *CostModel) getLBCost(cp costAnalyzerCloud.Provider) (map[string]*costAnalyzerCloud.LoadBalancer, error) {
+	// for fetching prices from cloud provider
+	// cfg, err := cp.GetConfig()
+	// if err != nil {
+	// 	return nil, err
+	// }
+
+	servicesList := cm.Cache.GetAllServices()
+	loadBalancerMap := make(map[string]*costAnalyzerCloud.LoadBalancer)
+
+	// 1. need to check whether the service is a loadbalancer /
+	// 2. need to generate a unique key for this loadbalancer --> use name, which is unique across a namespace
+	// 3. need to check if key exists in servicesList and then populate loadBalancers with it
+
+	for _, service := range servicesList {
+		// namespace := service.GetObjectMeta().GetNamespace() // do I need this?
+		name := service.GetObjectMeta().GetName()
+
+		// Does this identify ELB vs. ILB? Need to test the /api/allServices call with an ALB. Current work is on ELBs.
+		if service.Spec.Type == "LoadBalancer" {
+			// TODO: dynamically fetch based on cloud provider and region. Currently using hard-coded GCP us-central1 values.
+			loadBalancer := &costAnalyzerCloud.LoadBalancer{
+				FirstFiveForwardingRulesCost: 0.025,
+				AdditionalForwardingRuleCost: 0.010,
+				IngressDataCostPerGB:         0.008,
+			}
+			newLoadBalancer := *loadBalancer
+			if len(service.Status.LoadBalancer.Ingress) > 0 { // should actually check if LoadBalancer.Ingress exists
+				for _, loadBalancerIngress := range service.Status.LoadBalancer.Ingress {
+					newLoadBalancer.IngressIPAddresses = append(newLoadBalancer.IngressIPAddresses, loadBalancerIngress.IP)
+				}
+			}
+			loadBalancerMap[name] = &newLoadBalancer
+		}
+	}
+	return loadBalancerMap, nil
+}
+
 func getPodServices(cache clustercache.ClusterCache, podList []*v1.Pod, clusterID string) (map[string]map[string][]string, error) {
 func getPodServices(cache clustercache.ClusterCache, podList []*v1.Pod, clusterID string) (map[string]map[string][]string, error) {
 	servicesList := cache.GetAllServices()
 	servicesList := cache.GetAllServices()
 	podServicesMapping := make(map[string]map[string][]string)
 	podServicesMapping := make(map[string]map[string][]string)

+ 8 - 1
pkg/costmodel/router.go

@@ -75,6 +75,7 @@ type Accesses struct {
 	GPUAllocationRecorder         *prometheus.GaugeVec
 	GPUAllocationRecorder         *prometheus.GaugeVec
 	PVAllocationRecorder          *prometheus.GaugeVec
 	PVAllocationRecorder          *prometheus.GaugeVec
 	ClusterManagementCostRecorder *prometheus.GaugeVec
 	ClusterManagementCostRecorder *prometheus.GaugeVec
+	LBCostRecorder                *prometheus.GaugeVec
 	NetworkZoneEgressRecorder     prometheus.Gauge
 	NetworkZoneEgressRecorder     prometheus.Gauge
 	NetworkRegionEgressRecorder   prometheus.Gauge
 	NetworkRegionEgressRecorder   prometheus.Gauge
 	NetworkInternetEgressRecorder prometheus.Gauge
 	NetworkInternetEgressRecorder prometheus.Gauge
@@ -829,7 +830,7 @@ func Initialize(additionalConfigWatchers ...ConfigWatchers) {
 
 
 	// TODO: General Architecture Note: Several passes have been made to modularize a lot of
 	// TODO: General Architecture Note: Several passes have been made to modularize a lot of
 	// TODO: our code, but the router still continues to be the obvious entry point for new \
 	// TODO: our code, but the router still continues to be the obvious entry point for new \
-	// TODO: features. We should look to spliting out the actual "router" functionality and
+	// TODO: features. We should look to split out the actual "router" functionality and
 	// TODO: implement a builder -> controller for stitching new features and other dependencies.
 	// TODO: implement a builder -> controller for stitching new features and other dependencies.
 	clusterManager := newClusterManager()
 	clusterManager := newClusterManager()
 
 
@@ -898,6 +899,10 @@ func Initialize(additionalConfigWatchers ...ConfigWatchers) {
 		Name: "kubecost_cluster_management_cost",
 		Name: "kubecost_cluster_management_cost",
 		Help: "kubecost_cluster_management_cost Hourly cost paid as a cluster management fee.",
 		Help: "kubecost_cluster_management_cost Hourly cost paid as a cluster management fee.",
 	}, []string{"provisioner_name"})
 	}, []string{"provisioner_name"})
+	LBCostRecorder := prometheus.NewGaugeVec(prometheus.GaugeOpts{ // don't know if necessary to differentiate ELB vs. ALB cost
+		Name: "load_balancer_cost",
+		Help: "load_balancer_cost Hourly cost of load balancer",
+	}, []string{"ip_address", "namespace", "service_name"}) // will likely need some adjustments
 
 
 	prometheus.MustRegister(cpuGv)
 	prometheus.MustRegister(cpuGv)
 	prometheus.MustRegister(ramGv)
 	prometheus.MustRegister(ramGv)
@@ -911,6 +916,7 @@ func Initialize(additionalConfigWatchers ...ConfigWatchers) {
 	prometheus.MustRegister(GPUAllocation)
 	prometheus.MustRegister(GPUAllocation)
 	prometheus.MustRegister(NetworkZoneEgressRecorder, NetworkRegionEgressRecorder, NetworkInternetEgressRecorder)
 	prometheus.MustRegister(NetworkZoneEgressRecorder, NetworkRegionEgressRecorder, NetworkInternetEgressRecorder)
 	prometheus.MustRegister(ClusterManagementCostRecorder)
 	prometheus.MustRegister(ClusterManagementCostRecorder)
+	prometheus.MustRegister(LBCostRecorder)
 	prometheus.MustRegister(ServiceCollector{
 	prometheus.MustRegister(ServiceCollector{
 		KubeClientSet: kubeClientset,
 		KubeClientSet: kubeClientset,
 	})
 	})
@@ -947,6 +953,7 @@ func Initialize(additionalConfigWatchers ...ConfigWatchers) {
 		NetworkInternetEgressRecorder: NetworkInternetEgressRecorder,
 		NetworkInternetEgressRecorder: NetworkInternetEgressRecorder,
 		PersistentVolumePriceRecorder: pvGv,
 		PersistentVolumePriceRecorder: pvGv,
 		ClusterManagementCostRecorder: ClusterManagementCostRecorder,
 		ClusterManagementCostRecorder: ClusterManagementCostRecorder,
+		LBCostRecorder:                LBCostRecorder,
 		Model:                         NewCostModel(k8sCache),
 		Model:                         NewCostModel(k8sCache),
 		OutOfClusterCache:             outOfClusterCache,
 		OutOfClusterCache:             outOfClusterCache,
 	}
 	}