1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
// Package discover provides functions to get metadata for different
// cloud environments.
package discover
import (
"fmt"
"log"
"sort"
"strings"
"sync"
"github.com/hashicorp/go-discover/provider/aliyun"
"github.com/hashicorp/go-discover/provider/aws"
"github.com/hashicorp/go-discover/provider/gce"
"github.com/hashicorp/go-discover/provider/mdns"
"github.com/hashicorp/go-discover/provider/os"
"github.com/hashicorp/go-discover/provider/packet"
)
// Provider has lookup functions for meta data in a
// cloud environment.
type Provider interface {
// Addrs looks up addresses in the cloud environment according to the
// configuration provided in args.
Addrs(args map[string]string, l *log.Logger) ([]string, error)
// Help provides the configuration help for the command line client.
Help() string
}
// 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)
}
// Providers contains all available providers.
var Providers = map[string]Provider{
"aliyun": &aliyun.Provider{},
"aws": &aws.Provider{},
"gce": &gce.Provider{},
"mdns": &mdns.Provider{},
"os": &os.Provider{},
"packet": &packet.Provider{},
}
// 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
// userAgent is the string to use for requests, when supported.
userAgent string
// once is used to initialize the actual list of providers.
once sync.Once
}
// 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
}
}
// 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
}
}
// Names returns the names of the configured providers.
func (d *Discover) Names() []string {
d.once.Do(d.initProviders)
var names []string
for n := range d.Providers {
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.
func (d *Discover) Help() string {
d.once.Do(d.initProviders)
h := []string{globalHelp}
for _, name := range d.Names() {
h = append(h, d.Providers[name].Help())
}
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.
func (d *Discover) Addrs(cfg string, l *log.Logger) ([]string, error) {
d.once.Do(d.initProviders)
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")
}
providers := d.Providers
if providers == nil {
providers = Providers
}
p := providers[name]
if p == nil {
return nil, fmt.Errorf("discover: unknown provider " + name)
}
l.Printf("[DEBUG] discover: Using provider %q", name)
if typ, ok := p.(ProviderWithUserAgent); ok {
typ.SetUserAgent(d.userAgent)
return p.Addrs(args, l)
}
return p.Addrs(args, l)
}
|