diff --git a/go.mod b/go.mod index abba789..bd657cd 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,15 @@ module github.com/kapetacom/sdk-go-config go 1.21.6 require ( - github.com/kapetacom/schemas/packages/go v0.0.0-20240209083259-f5ce079d8abc - github.com/stretchr/testify v1.8.4 + github.com/kapetacom/schemas/packages/go v0.0.0-20240626154923-8b19e1b1396e + github.com/stretchr/testify v1.9.0 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect ) diff --git a/go.sum b/go.sum index 215b005..d3b9bc1 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,24 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/kapetacom/schemas/packages/go v0.0.0-20240209083259-f5ce079d8abc h1:ghhXNScFqGXUP7uywvPF/dyYBcS7czmirlLcgtc0cEg= github.com/kapetacom/schemas/packages/go v0.0.0-20240209083259-f5ce079d8abc/go.mod h1:dWvKSUqSQRHiqFFnGPnJofgci1dvRT1PPNJLtffVukk= +github.com/kapetacom/schemas/packages/go v0.0.0-20240626154923-8b19e1b1396e h1:k46OcPxyVVsPS2Fe0vU5NSMraJOzsUI1I+qvBTVgBuM= +github.com/kapetacom/schemas/packages/go v0.0.0-20240626154923-8b19e1b1396e/go.mod h1:dWvKSUqSQRHiqFFnGPnJofgci1dvRT1PPNJLtffVukk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/provider.go b/provider.go index 07765b1..9b0f102 100644 --- a/provider.go +++ b/provider.go @@ -21,12 +21,15 @@ type InstanceValue struct { } type Config struct { - provider providers.ConfigProvider + mu sync.Mutex + provider providers.ConfigProvider + callbacks []func(providers.ConfigProvider) once sync.Once } // TODO: See if we can remove this global variable +var muConfig sync.Mutex var CONFIG Config const ( @@ -42,6 +45,8 @@ const ( // GetProvider returns the configured provider or panics if it's not initialized func GetProvider() providers.ConfigProvider { + muConfig.Lock() + defer muConfig.Unlock() if CONFIG.provider == nil { panic("Configuration not yet initialized, call Init('path to kapeta.yml') first") } @@ -56,6 +61,8 @@ func getEnvOrDefault(envVarName, defaultValue string) string { } func (c *Config) OnReady(callback func(providers.ConfigProvider)) { + c.mu.Lock() + defer c.mu.Unlock() c.once.Do(func() { if c.provider != nil { callback(c.provider) @@ -66,10 +73,15 @@ func (c *Config) OnReady(callback func(providers.ConfigProvider)) { } func (c *Config) IsReady() bool { + c.mu.Lock() + defer c.mu.Unlock() return c.provider != nil } func (c *Config) GetProvider() providers.ConfigProvider { + c.mu.Lock() + defer c.mu.Unlock() + if c.provider == nil { panic("Configuration not yet initialized") } @@ -98,6 +110,9 @@ func (c *Config) getInstanceHost(instanceID string) (string, error) { // Init initializes the configuration provider based on the kapeta.yml file in the given block directory func Init(blockDir string) (providers.ConfigProvider, error) { + muConfig.Lock() + defer muConfig.Unlock() + if CONFIG.provider != nil { return CONFIG.provider, nil } diff --git a/providers/kubernetes.go b/providers/kubernetes.go index 05fa12c..4d4a3f7 100644 --- a/providers/kubernetes.go +++ b/providers/kubernetes.go @@ -7,8 +7,10 @@ import ( "encoding/json" "errors" "fmt" - cfg "github.com/kapetacom/sdk-go-config/config" "strings" + "sync" + + cfg "github.com/kapetacom/sdk-go-config/config" ) const DEFAULT_SERVER_PORT_TYPE = "rest" @@ -27,7 +29,9 @@ func toEnvName(name string) string { // KubernetesConfigProvider implements the ConfigProvider interface type KubernetesConfigProvider struct { AbstractConfigProvider + muConfig sync.Mutex configuration map[string]interface{} + muHosts sync.Mutex instanceHosts map[string]string } @@ -103,6 +107,8 @@ func (k *KubernetesConfigProvider) GetProviderId() string { // getConfiguration is a private method to get the configuration value from the environment variable func (k *KubernetesConfigProvider) getConfiguration(path string, defaultValue interface{}) interface{} { + k.muConfig.Lock() + defer k.muConfig.Unlock() if k.configuration == nil { envVar := "KAPETA_INSTANCE_CONFIG" if value, exists := k.LookupEnv(envVar); exists { @@ -140,6 +146,8 @@ func (k *KubernetesConfigProvider) GetOrDefault(path string, defaultValue interf // GetInstanceHost returns the hostname for the given instance ID func (k *KubernetesConfigProvider) GetInstanceHost(instanceID string) (string, error) { + k.muHosts.Lock() + defer k.muHosts.Unlock() if k.instanceHosts == nil { if blockHosts, exists := k.LookupEnv("KAPETA_BLOCK_HOSTS"); exists { err := json.Unmarshal([]byte(blockHosts), &k.instanceHosts) diff --git a/providers/local.go b/providers/local.go index db5874c..ba47fed 100644 --- a/providers/local.go +++ b/providers/local.go @@ -13,6 +13,7 @@ import ( "os" "os/signal" "strings" + "sync" "syscall" "github.com/kapetacom/schemas/packages/go/model" @@ -35,6 +36,7 @@ type AssetWrapper[T any] struct { // LocalConfigProvider struct represents the local config provider type LocalConfigProvider struct { AbstractConfigProvider + mu sync.Mutex configuration map[string]interface{} cfg *cfg.ClusterConfig GetPlan func() (*model.Plan, error) @@ -218,11 +220,15 @@ func (l *LocalConfigProvider) GetInstanceHost(instanceID string) (string, error) // GetConfig gets the configuration value for the specified path func (l *LocalConfigProvider) GetConfig(path string) interface{} { + l.mu.Lock() + defer l.mu.Unlock() return l.configuration[path] } // GetOrDefault gets the configuration value for the specified path, or a default value if not found func (l *LocalConfigProvider) GetOrDefault(path string, defaultValue interface{}) interface{} { + l.mu.Lock() + defer l.mu.Unlock() if value, ok := l.configuration[path]; ok { return value }