2017-07-15 21:33:12 +00:00
|
|
|
// Package discover provides functions to get metadata for different
|
|
|
|
// cloud environments.
|
|
|
|
package discover
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
2017-08-02 15:32:48 +00:00
|
|
|
|
2017-10-31 22:03:54 +00:00
|
|
|
"github.com/hashicorp/go-discover/provider/aliyun"
|
2017-08-02 15:32:48 +00:00
|
|
|
"github.com/hashicorp/go-discover/provider/aws"
|
|
|
|
"github.com/hashicorp/go-discover/provider/azure"
|
2017-10-31 22:03:54 +00:00
|
|
|
"github.com/hashicorp/go-discover/provider/digitalocean"
|
2017-08-02 15:32:48 +00:00
|
|
|
"github.com/hashicorp/go-discover/provider/gce"
|
2017-10-31 22:03:54 +00:00
|
|
|
"github.com/hashicorp/go-discover/provider/os"
|
|
|
|
"github.com/hashicorp/go-discover/provider/scaleway"
|
2017-08-02 15:32:48 +00:00
|
|
|
"github.com/hashicorp/go-discover/provider/softlayer"
|
2018-05-10 22:40:16 +00:00
|
|
|
"github.com/hashicorp/go-discover/provider/triton"
|
2017-07-15 21:33:12 +00:00
|
|
|
)
|
|
|
|
|
2017-08-02 15:32:48 +00:00
|
|
|
// Provider has lookup functions for meta data in a
|
|
|
|
// cloud environment.
|
2017-07-15 21:33:12 +00:00
|
|
|
type Provider interface {
|
2017-08-02 15:32:48 +00:00
|
|
|
// Addrs looks up addresses in the cloud environment according to the
|
|
|
|
// configuration provided in args.
|
2017-07-15 21:33:12 +00:00
|
|
|
Addrs(args map[string]string, l *log.Logger) ([]string, error)
|
2017-08-02 15:32:48 +00:00
|
|
|
|
|
|
|
// Help provides the configuration help for the command line client.
|
|
|
|
Help() string
|
2017-07-15 21:33:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-10 22:40:16 +00:00
|
|
|
// ProviderWithUserAgent is a provider that declares it's user agent. Not all
|
|
|
|
// providers support this.
|
|
|
|
type ProviderWithUserAgent interface {
|
|
|
|
// SetUserAgent sets the user agent on the provider to the provided string.
|
|
|
|
SetUserAgent(s string)
|
|
|
|
}
|
|
|
|
|
2017-08-02 15:32:48 +00:00
|
|
|
// Providers contains all available providers.
|
|
|
|
var Providers = map[string]Provider{
|
2017-10-31 22:03:54 +00:00
|
|
|
"aliyun": &aliyun.Provider{},
|
|
|
|
"aws": &aws.Provider{},
|
|
|
|
"azure": &azure.Provider{},
|
|
|
|
"digitalocean": &digitalocean.Provider{},
|
|
|
|
"gce": &gce.Provider{},
|
|
|
|
"os": &os.Provider{},
|
|
|
|
"scaleway": &scaleway.Provider{},
|
|
|
|
"softlayer": &softlayer.Provider{},
|
2018-05-10 22:40:16 +00:00
|
|
|
"triton": &triton.Provider{},
|
2017-08-02 15:32:48 +00:00
|
|
|
}
|
2017-07-15 21:33:12 +00:00
|
|
|
|
2017-08-02 15:32:48 +00:00
|
|
|
// Discover looks up metadata in different cloud environments.
|
|
|
|
type Discover struct {
|
|
|
|
// Providers is the list of address lookup providers.
|
|
|
|
// If nil, the default list of providers is used.
|
|
|
|
Providers map[string]Provider
|
|
|
|
|
2018-05-10 22:40:16 +00:00
|
|
|
// userAgent is the string to use for requests, when supported.
|
|
|
|
userAgent string
|
|
|
|
|
2017-08-02 15:32:48 +00:00
|
|
|
// once is used to initialize the actual list of providers.
|
|
|
|
once sync.Once
|
|
|
|
}
|
|
|
|
|
2018-05-10 22:40:16 +00:00
|
|
|
// Option is used as an initialization option/
|
|
|
|
type Option func(*Discover) error
|
|
|
|
|
|
|
|
// New creates a new discover client with the given options.
|
|
|
|
func New(opts ...Option) (*Discover, error) {
|
|
|
|
d := new(Discover)
|
|
|
|
|
|
|
|
for _, opt := range opts {
|
|
|
|
if err := opt(d); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d.once.Do(d.initProviders)
|
|
|
|
|
|
|
|
return d, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithUserAgent allows specifying a custom user agent option to send with
|
|
|
|
// requests when the underlying client library supports it.
|
|
|
|
func WithUserAgent(agent string) Option {
|
|
|
|
return func(d *Discover) error {
|
|
|
|
d.userAgent = agent
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithProviders allows specifying your own set of providers.
|
|
|
|
func WithProviders(m map[string]Provider) Option {
|
|
|
|
return func(d *Discover) error {
|
|
|
|
d.Providers = m
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-02 15:32:48 +00:00
|
|
|
// initProviders sets the list of providers to the
|
|
|
|
// default list of providers if none are configured.
|
|
|
|
func (d *Discover) initProviders() {
|
|
|
|
if d.Providers == nil {
|
|
|
|
d.Providers = Providers
|
2017-07-15 21:33:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-02 15:32:48 +00:00
|
|
|
// Names returns the names of the configured providers.
|
|
|
|
func (d *Discover) Names() []string {
|
|
|
|
d.once.Do(d.initProviders)
|
|
|
|
|
2017-07-15 21:33:12 +00:00
|
|
|
var names []string
|
2017-08-02 15:32:48 +00:00
|
|
|
for n := range d.Providers {
|
2017-07-15 21:33:12 +00:00
|
|
|
names = append(names, n)
|
|
|
|
}
|
|
|
|
sort.Strings(names)
|
|
|
|
return names
|
|
|
|
}
|
|
|
|
|
|
|
|
var globalHelp = `The options for discovering ip addresses are provided as a
|
|
|
|
single string value in "key=value key=value ..." format where
|
|
|
|
the values are URL encoded.
|
|
|
|
|
|
|
|
provider=aws region=eu-west-1 ...
|
|
|
|
|
|
|
|
The options are provider specific and are listed below.
|
|
|
|
`
|
|
|
|
|
|
|
|
// Help describes the format of the configuration string for address discovery
|
|
|
|
// and the various provider specific options.
|
2017-08-02 15:32:48 +00:00
|
|
|
func (d *Discover) Help() string {
|
|
|
|
d.once.Do(d.initProviders)
|
|
|
|
|
2017-07-15 21:33:12 +00:00
|
|
|
h := []string{globalHelp}
|
2017-08-02 15:32:48 +00:00
|
|
|
for _, name := range d.Names() {
|
|
|
|
h = append(h, d.Providers[name].Help())
|
2017-07-15 21:33:12 +00:00
|
|
|
}
|
|
|
|
return strings.Join(h, "\n")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Addrs discovers ip addresses of nodes that match the given filter criteria.
|
|
|
|
// The config string must have the format 'provider=xxx key=val key=val ...'
|
|
|
|
// where the keys and values are provider specific. The values are URL encoded.
|
2017-08-02 15:32:48 +00:00
|
|
|
func (d *Discover) Addrs(cfg string, l *log.Logger) ([]string, error) {
|
|
|
|
d.once.Do(d.initProviders)
|
|
|
|
|
2017-07-15 21:33:12 +00:00
|
|
|
args, err := Parse(cfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("discover: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
name := args["provider"]
|
|
|
|
if name == "" {
|
|
|
|
return nil, fmt.Errorf("discover: no provider")
|
|
|
|
}
|
|
|
|
|
2017-08-02 15:32:48 +00:00
|
|
|
providers := d.Providers
|
|
|
|
if providers == nil {
|
|
|
|
providers = Providers
|
|
|
|
}
|
2017-07-15 21:33:12 +00:00
|
|
|
|
2017-08-02 15:32:48 +00:00
|
|
|
p := providers[name]
|
2017-07-15 21:33:12 +00:00
|
|
|
if p == nil {
|
|
|
|
return nil, fmt.Errorf("discover: unknown provider " + name)
|
|
|
|
}
|
2017-08-23 16:15:45 +00:00
|
|
|
l.Printf("[DEBUG] discover: Using provider %q", name)
|
|
|
|
|
2018-05-10 22:40:16 +00:00
|
|
|
if typ, ok := p.(ProviderWithUserAgent); ok {
|
|
|
|
typ.SetUserAgent(d.userAgent)
|
|
|
|
return p.Addrs(args, l)
|
|
|
|
}
|
|
|
|
|
2017-07-15 21:33:12 +00:00
|
|
|
return p.Addrs(args, l)
|
|
|
|
}
|