Преглед изворни кода

Fix Issue where ClusterMap would omit local cluster (self-emission dependence)

Matt Bolt пре 4 година
родитељ
комит
645ca9bf04
3 измењених фајлова са 92 додато и 11 уклоњено
  1. 22 0
      pkg/costmodel/clusterinfo.go
  2. 67 9
      pkg/costmodel/clusters/clustermap.go
  3. 3 2
      pkg/costmodel/router.go

+ 22 - 0
pkg/costmodel/clusterinfo.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 
 	cloudProvider "github.com/kubecost/cost-model/pkg/cloud"
+	"github.com/kubecost/cost-model/pkg/costmodel/clusters"
 	"github.com/kubecost/cost-model/pkg/env"
 	"github.com/kubecost/cost-model/pkg/thanos"
 
@@ -40,6 +41,27 @@ func writeThanosFlags(clusterInfo map[string]string) {
 	}
 }
 
+// default local cluster info provider implementation which provides an instanced object for
+// getting the local cluster info
+type defaultLocalClusterInfoProvider struct {
+	k8s      kubernetes.Interface
+	provider cloudProvider.Provider
+}
+
+// GetClusterInfo returns a string map containing the local cluster info
+func (dlcip *defaultLocalClusterInfoProvider) GetClusterInfo() map[string]string {
+	return GetClusterInfo(dlcip.k8s, dlcip.provider)
+}
+
+// NewLocalClusterInfoProvider creates a new clusters.LocalClusterInfoProvider implementation for providing local
+// cluster information
+func NewLocalClusterInfoProvider(k8s kubernetes.Interface, cloud cloudProvider.Provider) clusters.LocalClusterInfoProvider {
+	return &defaultLocalClusterInfoProvider{
+		k8s:      k8s,
+		provider: cloud,
+	}
+}
+
 // GetClusterInfo provides specific information about the cluster cloud provider as well as
 // generic configuration values.
 func GetClusterInfo(kubeClient kubernetes.Interface, cloud cloudProvider.Provider) map[string]string {

+ 67 - 9
pkg/costmodel/clusters/clustermap.go

@@ -68,23 +68,31 @@ type ClusterMap interface {
 	StopRefresh()
 }
 
+// LocalClusterInfoProvider is a contract which is capable of performing local cluster info lookups.
+type LocalClusterInfoProvider interface {
+	// GetClusterInfo returns a string map containing the local cluster info
+	GetClusterInfo() map[string]string
+}
+
 // ClusterMap keeps records of all known cost-model clusters.
 type PrometheusClusterMap struct {
-	lock     *sync.RWMutex
-	client   prometheus.Client
-	clusters map[string]*ClusterInfo
-	stop     chan struct{}
+	lock         *sync.RWMutex
+	client       prometheus.Client
+	clusters     map[string]*ClusterInfo
+	localCluster LocalClusterInfoProvider
+	stop         chan struct{}
 }
 
 // NewClusterMap creates a new ClusterMap implementation using a prometheus or thanos client
-func NewClusterMap(client prometheus.Client, refresh time.Duration) ClusterMap {
+func NewClusterMap(client prometheus.Client, lcip LocalClusterInfoProvider, refresh time.Duration) ClusterMap {
 	stop := make(chan struct{})
 
 	cm := &PrometheusClusterMap{
-		lock:     new(sync.RWMutex),
-		client:   client,
-		clusters: make(map[string]*ClusterInfo),
-		stop:     stop,
+		lock:         new(sync.RWMutex),
+		client:       client,
+		clusters:     make(map[string]*ClusterInfo),
+		localCluster: lcip,
+		stop:         stop,
 	}
 
 	// Run an updater to ensure cluster data stays relevant over time
@@ -175,9 +183,59 @@ func (pcm *PrometheusClusterMap) loadClusters() (map[string]*ClusterInfo, error)
 		}
 	}
 
+	if len(clusters) == 0 {
+		localInfo, err := pcm.getLocalClusterInfo()
+		if err != nil {
+			log.Warningf("Failed to load local cluster info: %s", err)
+		} else {
+			clusters[localInfo.ID] = localInfo
+		}
+	}
+
 	return clusters, nil
 }
 
+// getLocalClusterInfo returns the local cluster info in the event there does not exist a metric available.
+func (pcm *PrometheusClusterMap) getLocalClusterInfo() (*ClusterInfo, error) {
+	info := pcm.localCluster.GetClusterInfo()
+
+	var id string
+	var name string
+
+	if i, ok := info["id"]; ok {
+		id = i
+	} else {
+		return nil, fmt.Errorf("Local Cluster Info Missing ID")
+	}
+	if n, ok := info["name"]; ok {
+		name = n
+	} else {
+		return nil, fmt.Errorf("Local Cluster Info Missing Name")
+	}
+
+	var clusterProfile string
+	var provider string
+	var provisioner string
+
+	if cp, ok := info["clusterProfile"]; ok {
+		clusterProfile = cp
+	}
+	if pvdr, ok := info["provider"]; ok {
+		provider = pvdr
+	}
+	if pvsr, ok := info["provisioner"]; ok {
+		provisioner = pvsr
+	}
+
+	return &ClusterInfo{
+		ID:          id,
+		Name:        name,
+		Profile:     clusterProfile,
+		Provider:    provider,
+		Provisioner: provisioner,
+	}, nil
+}
+
 // refreshClusters loads the clusters and updates the internal map
 func (pcm *PrometheusClusterMap) refreshClusters() {
 	updated, err := pcm.loadClusters()

+ 3 - 2
pkg/costmodel/router.go

@@ -1167,10 +1167,11 @@ func Initialize(additionalConfigWatchers ...ConfigWatchers) *Accesses {
 
 	// Initialize ClusterMap for maintaining ClusterInfo by ClusterID
 	var clusterMap clusters.ClusterMap
+	localCIProvider := NewLocalClusterInfoProvider(kubeClientset, cloudProvider)
 	if thanosClient != nil {
-		clusterMap = clusters.NewClusterMap(thanosClient, 10*time.Minute)
+		clusterMap = clusters.NewClusterMap(thanosClient, localCIProvider, 10*time.Minute)
 	} else {
-		clusterMap = clusters.NewClusterMap(promCli, 5*time.Minute)
+		clusterMap = clusters.NewClusterMap(promCli, localCIProvider, 5*time.Minute)
 	}
 
 	// cache responses from model and aggregation for a default of 10 minutes;