-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
# Description Add credentials provider to manages Exoscale secret from different environment and time. ## Checklist (For exoscale contributors) V3 alpha development --------- Signed-off-by: Pierre-Emmanuel Jacquier <15922119+pierre-emmanuelJ@users.noreply.github.com>
- Loading branch information
1 parent
cf4abaf
commit be2da0e
Showing
716 changed files
with
318,723 additions
and
1,267 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package credentials | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
) | ||
|
||
var ( | ||
ErrNoValidCredentialProviders = errors.New("no valid credential providers") | ||
) | ||
|
||
// A ChainProvider will search for a provider which returns credentials | ||
// and cache that provider until Retrieve is called again. | ||
type ChainProvider struct { | ||
Providers []Provider | ||
current Provider | ||
} | ||
|
||
// NewChainCredentials returns a pointer to a new Credentials object | ||
// wrapping a chain of providers. | ||
func NewChainCredentials(providers []Provider) *Credentials { | ||
return NewCredentials(&ChainProvider{ | ||
Providers: append([]Provider{}, providers...), | ||
}) | ||
} | ||
|
||
// Retrieve returns the first provider in the chain that succeeds, | ||
// or error if no provider returned. | ||
// | ||
// If a provider is found it will be cached and any calls to IsExpired() | ||
// will return the expired state of the cached provider. | ||
func (c *ChainProvider) Retrieve() (Value, error) { | ||
var errs = ErrNoValidCredentialProviders | ||
|
||
for _, p := range c.Providers { | ||
creds, err := p.Retrieve() | ||
if err == nil { | ||
c.current = p | ||
return creds, nil | ||
} | ||
|
||
errs = fmt.Errorf("%v: %w", errs, err) | ||
} | ||
c.current = nil | ||
|
||
return Value{}, fmt.Errorf("chain provider: %w", errs) | ||
} | ||
|
||
// IsExpired will returned the expired state of the currently cached provider | ||
// if there is one. If there is no current provider, true will be returned. | ||
func (c *ChainProvider) IsExpired() bool { | ||
if c.current != nil { | ||
return c.current.IsExpired() | ||
} | ||
|
||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package credentials | ||
|
||
import ( | ||
"errors" | ||
"sync" | ||
) | ||
|
||
var ( | ||
ErrMissingIncomplete = errors.New("missing or incomplete API credentials") | ||
) | ||
|
||
type Value struct { | ||
APIKey string | ||
APISecret string | ||
} | ||
|
||
// IsSet returns true if the credentials Value has both APIKey and APISecret. | ||
func (v Value) IsSet() bool { | ||
return v.APIKey != "" && v.APISecret != "" | ||
} | ||
|
||
type Provider interface { | ||
// Retrieve returns nil if it successfully retrieved the value. | ||
// Error is returned if the value were not obtainable, or empty. | ||
Retrieve() (Value, error) | ||
|
||
// IsExpired returns if the credentials are no longer valid, and need | ||
// to be retrieved. | ||
IsExpired() bool | ||
} | ||
|
||
type Credentials struct { | ||
credentials Value | ||
provider Provider | ||
|
||
sync.RWMutex | ||
} | ||
|
||
func NewCredentials(provider Provider) *Credentials { | ||
creds := &Credentials{ | ||
provider: provider, | ||
} | ||
|
||
return creds | ||
} | ||
|
||
func (c *Credentials) Expire() { | ||
c.Lock() | ||
defer c.Unlock() | ||
|
||
c.credentials = Value{} | ||
} | ||
|
||
func (c *Credentials) Get() (Value, error) { | ||
if c.IsExpired() { | ||
if err := c.retrieve(); err != nil { | ||
return Value{}, err | ||
} | ||
} | ||
c.RLock() | ||
defer c.RUnlock() | ||
|
||
if !c.credentials.IsSet() { | ||
return Value{}, ErrMissingIncomplete | ||
} | ||
|
||
return c.credentials, nil | ||
} | ||
|
||
func (c *Credentials) IsExpired() bool { | ||
c.RLock() | ||
defer c.RUnlock() | ||
|
||
return (!c.credentials.IsSet() || c.provider.IsExpired()) | ||
} | ||
|
||
func (c *Credentials) retrieve() error { | ||
c.Lock() | ||
defer c.Unlock() | ||
|
||
v, err := c.provider.Retrieve() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
c.credentials = v | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package credentials | ||
|
||
import "os" | ||
|
||
type EnvProvider struct { | ||
retrieved bool | ||
} | ||
|
||
func NewEnvCredentials() *Credentials { | ||
return NewCredentials(&EnvProvider{}) | ||
} | ||
|
||
// Retrieve retrieves the keys from the environment. | ||
func (e *EnvProvider) Retrieve() (Value, error) { | ||
e.retrieved = false | ||
|
||
v := Value{ | ||
APIKey: os.Getenv("EXOSCALE_API_KEY"), | ||
APISecret: os.Getenv("EXOSCALE_API_SECRET"), | ||
} | ||
|
||
if !v.IsSet() { | ||
return Value{}, ErrMissingIncomplete | ||
} | ||
|
||
e.retrieved = true | ||
|
||
return v, nil | ||
} | ||
|
||
// IsExpired returns if the credentials have been retrieved. | ||
func (e *EnvProvider) IsExpired() bool { | ||
return !e.retrieved | ||
} |
Oops, something went wrong.