configmanager.go 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package config
  2. import (
  3. "os"
  4. "sync"
  5. "github.com/opencost/opencost/core/pkg/log"
  6. "github.com/opencost/opencost/core/pkg/storage"
  7. )
  8. //--------------------------------------------------------------------------
  9. // ConfigFileManagerOpts
  10. //--------------------------------------------------------------------------
  11. // ConfigFileManagerOpts describes how to configure the ConfigFileManager for
  12. // serving configuration files
  13. type ConfigFileManagerOpts struct {
  14. // BucketStoreConfig is the local file location for the configuration used to
  15. // write and read configuration data to/from the bucket. The format of this
  16. // configuration file should be compatible with storage.NewBucketStorage
  17. BucketStoreConfig string
  18. // LocalConfigPath provides a backup location for storing the configuration
  19. // files
  20. LocalConfigPath string
  21. }
  22. // IsBucketStorageEnabled returns true if bucket storage is enabled.
  23. func (cfmo *ConfigFileManagerOpts) IsBucketStorageEnabled() bool {
  24. return cfmo.BucketStoreConfig != ""
  25. }
  26. // DefaultConfigFileManagerOpts returns the default configuration options for the
  27. // config file manager
  28. func DefaultConfigFileManagerOpts() *ConfigFileManagerOpts {
  29. return &ConfigFileManagerOpts{
  30. BucketStoreConfig: "",
  31. LocalConfigPath: "/",
  32. }
  33. }
  34. //--------------------------------------------------------------------------
  35. // ConfigFileManager
  36. //--------------------------------------------------------------------------
  37. // ConfigFileManager is a fascade for a central API used to create and watch
  38. // config files.
  39. type ConfigFileManager struct {
  40. lock sync.Mutex
  41. store storage.Storage
  42. files map[string]*ConfigFile
  43. }
  44. // NewConfigFileManager creates a new backing storage and configuration file manager
  45. func NewConfigFileManager(opts *ConfigFileManagerOpts) *ConfigFileManager {
  46. if opts == nil {
  47. opts = DefaultConfigFileManagerOpts()
  48. }
  49. var configStore storage.Storage
  50. if opts.IsBucketStorageEnabled() {
  51. bucketConfig, err := os.ReadFile(opts.BucketStoreConfig)
  52. if err != nil {
  53. log.Warnf("Failed to initialize config bucket storage: %s", err)
  54. } else {
  55. bucketStore, err := storage.NewBucketStorage(bucketConfig)
  56. if err != nil {
  57. log.Warnf("Failed to create config bucket storage: %s", err)
  58. } else {
  59. configStore = bucketStore
  60. }
  61. }
  62. } else {
  63. configStore = storage.NewFileStorage(opts.LocalConfigPath)
  64. }
  65. return &ConfigFileManager{
  66. store: configStore,
  67. files: make(map[string]*ConfigFile),
  68. }
  69. }
  70. // ConfigFileAt returns an existing configuration file for the provided path if it exists. Otherwise,
  71. // a new instance is created and returned. Note that the path does not have to exist in order for the
  72. // instance to be created. It can exist as a potential file path on the storage, and be written to
  73. // later
  74. func (cfm *ConfigFileManager) ConfigFileAt(path string) *ConfigFile {
  75. cfm.lock.Lock()
  76. defer cfm.lock.Unlock()
  77. if cf, ok := cfm.files[path]; ok {
  78. return cf
  79. }
  80. cf := NewConfigFile(cfm.store, path)
  81. cfm.files[path] = cf
  82. return cf
  83. }