Răsfoiți Sursa

Default Collector Storage (#3323)

Signed-off-by: Matt Bolt <mbolt35@gmail.com>
Matt Bolt 8 luni în urmă
părinte
comite
b576f5595e
3 a modificat fișierele cu 54 adăugiri și 4 ștergeri
  1. 12 1
      core/pkg/storage/storefactory.go
  2. 33 1
      pkg/costmodel/router.go
  3. 9 2
      pkg/env/costmodel.go

+ 12 - 1
core/pkg/storage/storefactory.go

@@ -7,7 +7,8 @@ import (
 	"github.com/opencost/opencost/core/pkg/env"
 )
 
-// GetDefaultStorage initializes the default shared storage which is required for kubecost
+// GetDefaultStorage initializes the default shared storage which is required for kubecost. Panics
+// if the storage cannot be initialized.
 func GetDefaultStorage() Storage {
 	store, err := InitializeStorage(env.GetDefaultStorageConfigFilePath())
 	if err != nil {
@@ -16,6 +17,16 @@ func GetDefaultStorage() Storage {
 	return store
 }
 
+// TryGetDefaultStorage will attempt to load the default bucket configuration, but will not panic
+// if the config file does not exist.
+func TryGetDefaultStorage() (Storage, error) {
+	store, err := InitializeStorage(env.GetDefaultStorageConfigFilePath())
+	if err != nil {
+		return nil, fmt.Errorf("failed to initialize default storage: %w", err)
+	}
+	return store, nil
+}
+
 // InitializeStorage creates a storage from the config file at the given path
 func InitializeStorage(configPath string) (Storage, error) {
 	storageConfig, err := os.ReadFile(configPath)

+ 33 - 1
pkg/costmodel/router.go

@@ -510,7 +510,7 @@ func Initialize(router *httprouter.Router, additionalConfigWatchers ...*watcher.
 	}
 	if env.IsCollectorDataSourceEnabled() {
 		fn = func() (source.OpenCostDataSource, error) {
-			store := storage.GetDefaultStorage()
+			store := GetDefaultCollectorStorage()
 			nodeStatConf, err := NewNodeClientConfigFromEnv()
 			if err != nil {
 				return nil, fmt.Errorf("failed to get node client config: %w", err)
@@ -603,6 +603,38 @@ func Initialize(router *httprouter.Router, additionalConfigWatchers ...*watcher.
 	return a
 }
 
+// GetDefaultStorage retrieves the default shared storage which is required for running an opencost collector.
+func GetDefaultCollectorStorage() storage.Storage {
+	const warningMessage = `Failed to create local collector directory '%s' - %s.
+		Did you mean to enable to collector? For persistent storage, it's recommended to use Prometheus, 
+		or set a storage bucket configuration at %s. 
+
+		%s`
+
+	// Try bucket storage if it exists
+	store, err := storage.TryGetDefaultStorage()
+	if err == nil {
+		return store
+	}
+
+	// Fallback to a local storage bucket
+	dir := env.GetLocalCollectorDirectory()
+	err = os.MkdirAll(dir, os.ModePerm)
+	if err != nil {
+		log.Warnf(
+			warningMessage,
+			dir,
+			err.Error(),
+			sysenv.GetDefaultStorageConfigFilePath(),
+			"Falling back to an in-memory file system for collector, which will lose any persistent storage upon restart.",
+		)
+
+		return storage.NewMemoryStorage()
+	}
+
+	return storage.NewFileStorage(dir)
+}
+
 // InitializeCloudCost Initializes Cloud Cost pipeline and querier and registers endpoints
 func InitializeCloudCost(router *httprouter.Router, providerConfig models.ProviderConfig) {
 	log.Debugf("Cloud Cost config path: %s", env.GetCloudCostConfigPath())

+ 9 - 2
pkg/env/costmodel.go

@@ -8,8 +8,9 @@ import (
 const (
 	ClusterInfoFile = "cluster-info.json"
 	ClusterCacheFile
-	GCPAuthSecretFile = "key.json"
-	MetricConfigFile  = "metrics.json"
+	GCPAuthSecretFile        = "key.json"
+	MetricConfigFile         = "metrics.json"
+	DefaultLocalCollectorDir = "collector"
 )
 
 // Env Variables
@@ -45,6 +46,7 @@ const (
 
 	CloudProviderAPIKeyEnvVar        = "CLOUD_PROVIDER_API_KEY"
 	CollectorDataSourceEnabledEnvVar = "COLLECTOR_DATA_SOURCE_ENABLED"
+	LocalCollectorDirectoryEnvVar    = "LOCAL_COLLECTOR_DIRECTORY"
 
 	EmitPodAnnotationsMetricEnvVar       = "EMIT_POD_ANNOTATIONS_METRIC"
 	EmitNamespaceAnnotationsMetricEnvVar = "EMIT_NAMESPACE_ANNOTATIONS_METRIC"
@@ -366,3 +368,8 @@ func GetCloudProvider() string {
 func GetMetricConfigFile() string {
 	return env.GetPathFromConfig(MetricConfigFile)
 }
+
+func GetLocalCollectorDirectory() string {
+	dir := env.Get(LocalCollectorDirectoryEnvVar, DefaultLocalCollectorDir)
+	return env.GetPathFromConfig(dir)
+}