|
@@ -63,9 +63,7 @@ type Accesses struct {
|
|
|
ServiceSelectorRecorder *prometheus.GaugeVec
|
|
ServiceSelectorRecorder *prometheus.GaugeVec
|
|
|
DeploymentSelectorRecorder *prometheus.GaugeVec
|
|
DeploymentSelectorRecorder *prometheus.GaugeVec
|
|
|
Model *CostModel
|
|
Model *CostModel
|
|
|
- CostDataCache *cache.Cache
|
|
|
|
|
OutOfClusterCache *cache.Cache
|
|
OutOfClusterCache *cache.Cache
|
|
|
- SettingsCache *cache.Cache
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
type DataEnvelope struct {
|
|
type DataEnvelope struct {
|
|
@@ -75,14 +73,24 @@ type DataEnvelope struct {
|
|
|
Message string `json:"message,omitempty"`
|
|
Message string `json:"message,omitempty"`
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// FilterCostData allows through only CostData that matches the given filters for namespace and clusterId
|
|
|
|
|
-func FilterCostData(data map[string]*CostData, namespace, clusterId string) map[string]*CostData {
|
|
|
|
|
|
|
+// FilterFunc is a filter that returns true iff the given CostData should be filtered out
|
|
|
|
|
+type FilterFunc func(*CostData) bool
|
|
|
|
|
+
|
|
|
|
|
+// FilterCostData allows through only CostData that matches all the given filter functions
|
|
|
|
|
+func FilterCostData(data map[string]*CostData, filters ...FilterFunc) map[string]*CostData {
|
|
|
result := make(map[string]*CostData)
|
|
result := make(map[string]*CostData)
|
|
|
|
|
+
|
|
|
|
|
+DataLoop:
|
|
|
for key, datum := range data {
|
|
for key, datum := range data {
|
|
|
- if costDataPassesFilters(datum, namespace, clusterId) {
|
|
|
|
|
- result[key] = datum
|
|
|
|
|
|
|
+ for _, ff := range filters {
|
|
|
|
|
+ if !ff(datum) {
|
|
|
|
|
+ // if any filter function check fails, move on to the next datum
|
|
|
|
|
+ continue DataLoop
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ result[key] = datum
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
return result
|
|
return result
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -312,41 +320,6 @@ func (a *Accesses) ClusterCostsOverTime(w http.ResponseWriter, r *http.Request,
|
|
|
w.Write(WrapData(data, err))
|
|
w.Write(WrapData(data, err))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (a *Accesses) CustomPricingHasChanged() bool {
|
|
|
|
|
- customPricing, err := a.Cloud.GetConfig()
|
|
|
|
|
- if err != nil || customPricing == nil {
|
|
|
|
|
- klog.Errorf("error accessing cloud provider configuration: %s", err)
|
|
|
|
|
- return false
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // describe parameters by which we determine whether or not custom
|
|
|
|
|
- // pricing settings have changed
|
|
|
|
|
- encodeCustomPricing := func(cp *costAnalyzerCloud.CustomPricing) string {
|
|
|
|
|
- return fmt.Sprintf("%s:%s:%s:%s:%s:%s:%s:%s", cp.CustomPricesEnabled, cp.CPU, cp.SpotCPU,
|
|
|
|
|
- cp.RAM, cp.SpotRAM, cp.GPU, cp.Storage, cp.CurrencyCode)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // compare cached custom pricing parameters with current values
|
|
|
|
|
- cpStr := encodeCustomPricing(customPricing)
|
|
|
|
|
- cpStrCached := ""
|
|
|
|
|
- val, found := a.SettingsCache.Get("customPricing")
|
|
|
|
|
- if found {
|
|
|
|
|
- ok := false
|
|
|
|
|
- cpStrCached, ok = val.(string)
|
|
|
|
|
- if !ok {
|
|
|
|
|
- klog.Errorf("caching error: failed to cast custom pricing to string")
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if cpStr == cpStrCached {
|
|
|
|
|
- return false
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // cache new custom pricing settings
|
|
|
|
|
- a.SettingsCache.Set("customPricing", cpStr, cache.DefaultExpiration)
|
|
|
|
|
-
|
|
|
|
|
- return true
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
func (a *Accesses) CostDataModelRange(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
func (a *Accesses) CostDataModelRange(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
@@ -911,9 +884,7 @@ func Initialize() {
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
// cache responses from model for a default of 5 minutes; clear expired responses every 10 minutes
|
|
// cache responses from model for a default of 5 minutes; clear expired responses every 10 minutes
|
|
|
- costDataCache := cache.New(time.Minute*5, time.Minute*10)
|
|
|
|
|
outOfClusterCache := cache.New(time.Minute*5, time.Minute*10)
|
|
outOfClusterCache := cache.New(time.Minute*5, time.Minute*10)
|
|
|
- settingsCache := cache.New(cache.NoExpiration, cache.NoExpiration)
|
|
|
|
|
|
|
|
|
|
A = Accesses{
|
|
A = Accesses{
|
|
|
PrometheusClient: promCli,
|
|
PrometheusClient: promCli,
|
|
@@ -935,7 +906,6 @@ func Initialize() {
|
|
|
Model: NewCostModel(k8sCache),
|
|
Model: NewCostModel(k8sCache),
|
|
|
CostDataCache: costDataCache,
|
|
CostDataCache: costDataCache,
|
|
|
OutOfClusterCache: outOfClusterCache,
|
|
OutOfClusterCache: outOfClusterCache,
|
|
|
- SettingsCache: settingsCache,
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
remoteEnabled := os.Getenv(remoteEnabled)
|
|
remoteEnabled := os.Getenv(remoteEnabled)
|