mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-09 23:24:05 -08:00
update Consul vendor code so that catalog.ServiceMultipleTags can be (#5151)
Signed-off-by: Callum Styan <callumstyan@gmail.com>
This commit is contained in:
parent
04ce817c49
commit
83c46fd549
|
@ -294,7 +294,7 @@ var expectedConf = &Config{
|
|||
Server: "localhost:1234",
|
||||
Token: "mysecret",
|
||||
Services: []string{"nginx", "cache", "mysql"},
|
||||
ServiceTag: "canary",
|
||||
ServiceTags: []string{"canary", "v1"},
|
||||
NodeMeta: map[string]string{"rack": "123"},
|
||||
TagSeparator: consul.DefaultSDConfig.TagSeparator,
|
||||
Scheme: "https",
|
||||
|
|
2
config/testdata/conf.good.yml
vendored
2
config/testdata/conf.good.yml
vendored
|
@ -128,7 +128,7 @@ scrape_configs:
|
|||
- server: 'localhost:1234'
|
||||
token: mysecret
|
||||
services: ['nginx', 'cache', 'mysql']
|
||||
tag: "canary"
|
||||
tags: ["canary", "v1"]
|
||||
node_meta:
|
||||
rack: "123"
|
||||
allow_stale: true
|
||||
|
|
|
@ -113,9 +113,8 @@ type SDConfig struct {
|
|||
// The list of services for which targets are discovered.
|
||||
// Defaults to all services if empty.
|
||||
Services []string `yaml:"services,omitempty"`
|
||||
// An optional tag used to filter instances inside a service. A single tag is supported
|
||||
// here to match the Consul API.
|
||||
ServiceTag string `yaml:"tag,omitempty"`
|
||||
// A list of tags used to filter instances inside a service. Services must contain all tags in the list.
|
||||
ServiceTags []string `yaml:"tags,omitempty"`
|
||||
// Desired node metadata.
|
||||
NodeMeta map[string]string `yaml:"node_meta,omitempty"`
|
||||
|
||||
|
@ -152,7 +151,7 @@ type Discovery struct {
|
|||
clientDatacenter string
|
||||
tagSeparator string
|
||||
watchedServices []string // Set of services which will be discovered.
|
||||
watchedTag string // A tag used to filter instances of a service.
|
||||
watchedTags []string // Tags used to filter instances of a service.
|
||||
watchedNodeMeta map[string]string
|
||||
allowStale bool
|
||||
refreshInterval time.Duration
|
||||
|
@ -202,7 +201,7 @@ func NewDiscovery(conf *SDConfig, logger log.Logger) (*Discovery, error) {
|
|||
client: client,
|
||||
tagSeparator: conf.TagSeparator,
|
||||
watchedServices: conf.Services,
|
||||
watchedTag: conf.ServiceTag,
|
||||
watchedTags: conf.ServiceTags,
|
||||
watchedNodeMeta: conf.NodeMeta,
|
||||
allowStale: conf.AllowStale,
|
||||
refreshInterval: time.Duration(conf.RefreshInterval),
|
||||
|
@ -238,16 +237,20 @@ func (d *Discovery) shouldWatchFromName(name string) bool {
|
|||
// *all* services. Details in https://github.com/prometheus/prometheus/pull/3814
|
||||
func (d *Discovery) shouldWatchFromTags(tags []string) bool {
|
||||
// If there's no fixed set of watched tags, we watch everything.
|
||||
if d.watchedTag == "" {
|
||||
if len(d.watchedTags) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, tag := range tags {
|
||||
if d.watchedTag == tag {
|
||||
return true
|
||||
tagOuter:
|
||||
for _, wtag := range d.watchedTags {
|
||||
for _, tag := range tags {
|
||||
if wtag == tag {
|
||||
continue tagOuter
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
// Get the local datacenter if not specified.
|
||||
|
@ -306,7 +309,7 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) {
|
|||
}
|
||||
d.initialize(ctx)
|
||||
|
||||
if len(d.watchedServices) == 0 || d.watchedTag != "" {
|
||||
if len(d.watchedServices) == 0 || len(d.watchedTags) != 0 {
|
||||
// We need to watch the catalog.
|
||||
ticker := time.NewTicker(d.refreshInterval)
|
||||
|
||||
|
@ -339,7 +342,7 @@ func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) {
|
|||
// entire list of services.
|
||||
func (d *Discovery) watchServices(ctx context.Context, ch chan<- []*targetgroup.Group, lastIndex *uint64, services map[string]func()) error {
|
||||
catalog := d.client.Catalog()
|
||||
level.Debug(d.logger).Log("msg", "Watching services", "tag", d.watchedTag)
|
||||
level.Debug(d.logger).Log("msg", "Watching services", "tags", d.watchedTags)
|
||||
|
||||
t0 := time.Now()
|
||||
opts := &consul.QueryOptions{
|
||||
|
@ -403,7 +406,7 @@ func (d *Discovery) watchServices(ctx context.Context, ch chan<- []*targetgroup.
|
|||
// consulService contains data belonging to the same service.
|
||||
type consulService struct {
|
||||
name string
|
||||
tag string
|
||||
tags []string
|
||||
labels model.LabelSet
|
||||
discovery *Discovery
|
||||
client *consul.Client
|
||||
|
@ -417,7 +420,7 @@ func (d *Discovery) watchService(ctx context.Context, ch chan<- []*targetgroup.G
|
|||
discovery: d,
|
||||
client: d.client,
|
||||
name: name,
|
||||
tag: d.watchedTag,
|
||||
tags: d.watchedTags,
|
||||
labels: model.LabelSet{
|
||||
serviceLabel: model.LabelValue(name),
|
||||
datacenterLabel: model.LabelValue(d.clientDatacenter),
|
||||
|
@ -445,7 +448,7 @@ func (d *Discovery) watchService(ctx context.Context, ch chan<- []*targetgroup.G
|
|||
|
||||
// Get updates for a service.
|
||||
func (srv *consulService) watch(ctx context.Context, ch chan<- []*targetgroup.Group, catalog *consul.Catalog, lastIndex *uint64) error {
|
||||
level.Debug(srv.logger).Log("msg", "Watching service", "service", srv.name, "tag", srv.tag)
|
||||
level.Debug(srv.logger).Log("msg", "Watching service", "service", srv.name, "tags", srv.tags)
|
||||
|
||||
t0 := time.Now()
|
||||
opts := &consul.QueryOptions{
|
||||
|
@ -454,7 +457,7 @@ func (srv *consulService) watch(ctx context.Context, ch chan<- []*targetgroup.Gr
|
|||
AllowStale: srv.discovery.allowStale,
|
||||
NodeMeta: srv.discovery.watchedNodeMeta,
|
||||
}
|
||||
nodes, meta, err := catalog.Service(srv.name, srv.tag, opts.WithContext(ctx))
|
||||
nodes, meta, err := catalog.ServiceMultipleTags(srv.name, srv.tags, opts.WithContext(ctx))
|
||||
elapsed := time.Since(t0)
|
||||
rpcDuration.WithLabelValues("catalog", "service").Observe(elapsed.Seconds())
|
||||
|
||||
|
@ -467,7 +470,7 @@ func (srv *consulService) watch(ctx context.Context, ch chan<- []*targetgroup.Gr
|
|||
}
|
||||
|
||||
if err != nil {
|
||||
level.Error(srv.logger).Log("msg", "Error refreshing service", "service", srv.name, "tag", srv.tag, "err", err)
|
||||
level.Error(srv.logger).Log("msg", "Error refreshing service", "service", srv.name, "tags", srv.tags, "err", err)
|
||||
rpcFailuresCount.Inc()
|
||||
time.Sleep(retryInterval)
|
||||
return err
|
||||
|
|
|
@ -46,8 +46,8 @@ func TestConfiguredService(t *testing.T) {
|
|||
|
||||
func TestConfiguredServiceWithTag(t *testing.T) {
|
||||
conf := &SDConfig{
|
||||
Services: []string{"configuredServiceName"},
|
||||
ServiceTag: "http",
|
||||
Services: []string{"configuredServiceName"},
|
||||
ServiceTags: []string{"http"},
|
||||
}
|
||||
consulDiscovery, err := NewDiscovery(conf, nil)
|
||||
|
||||
|
@ -68,6 +68,96 @@ func TestConfiguredServiceWithTag(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestConfiguredServiceWithTags(t *testing.T) {
|
||||
type testcase struct {
|
||||
// What we've configured to watch.
|
||||
conf *SDConfig
|
||||
// The service we're checking if we should watch or not.
|
||||
serviceName string
|
||||
serviceTags []string
|
||||
shouldWatch bool
|
||||
}
|
||||
|
||||
cases := []testcase{
|
||||
testcase{
|
||||
conf: &SDConfig{
|
||||
Services: []string{"configuredServiceName"},
|
||||
ServiceTags: []string{"http", "v1"},
|
||||
},
|
||||
serviceName: "configuredServiceName",
|
||||
serviceTags: []string{""},
|
||||
shouldWatch: false,
|
||||
},
|
||||
testcase{
|
||||
conf: &SDConfig{
|
||||
Services: []string{"configuredServiceName"},
|
||||
ServiceTags: []string{"http", "v1"},
|
||||
},
|
||||
serviceName: "configuredServiceName",
|
||||
serviceTags: []string{"http", "v1"},
|
||||
shouldWatch: true,
|
||||
},
|
||||
testcase{
|
||||
conf: &SDConfig{
|
||||
Services: []string{"configuredServiceName"},
|
||||
ServiceTags: []string{"http", "v1"},
|
||||
},
|
||||
serviceName: "nonConfiguredServiceName",
|
||||
serviceTags: []string{""},
|
||||
shouldWatch: false,
|
||||
},
|
||||
testcase{
|
||||
conf: &SDConfig{
|
||||
Services: []string{"configuredServiceName"},
|
||||
ServiceTags: []string{"http", "v1"},
|
||||
},
|
||||
serviceName: "nonConfiguredServiceName",
|
||||
serviceTags: []string{"http, v1"},
|
||||
shouldWatch: false,
|
||||
},
|
||||
testcase{
|
||||
conf: &SDConfig{
|
||||
Services: []string{"configuredServiceName"},
|
||||
ServiceTags: []string{"http", "v1"},
|
||||
},
|
||||
serviceName: "configuredServiceName",
|
||||
serviceTags: []string{"http", "v1", "foo"},
|
||||
shouldWatch: true,
|
||||
},
|
||||
testcase{
|
||||
conf: &SDConfig{
|
||||
Services: []string{"configuredServiceName"},
|
||||
ServiceTags: []string{"http", "v1", "foo"},
|
||||
},
|
||||
serviceName: "configuredServiceName",
|
||||
serviceTags: []string{"http", "v1", "foo"},
|
||||
shouldWatch: true,
|
||||
},
|
||||
testcase{
|
||||
conf: &SDConfig{
|
||||
Services: []string{"configuredServiceName"},
|
||||
ServiceTags: []string{"http", "v1"},
|
||||
},
|
||||
serviceName: "configuredServiceName",
|
||||
serviceTags: []string{"http", "v1", "v1"},
|
||||
shouldWatch: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
consulDiscovery, err := NewDiscovery(tc.conf, nil)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error when initializing discovery %v", err)
|
||||
}
|
||||
ret := consulDiscovery.shouldWatch(tc.serviceName, tc.serviceTags)
|
||||
if ret != tc.shouldWatch {
|
||||
t.Errorf("Expected should watch? %t, got %t. Watched serivce and tags: %s %+v, input was %s %+v", tc.shouldWatch, ret, tc.conf.Services, tc.conf.ServiceTags, tc.serviceName, tc.serviceTags)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonConfiguredService(t *testing.T) {
|
||||
conf := &SDConfig{}
|
||||
consulDiscovery, err := NewDiscovery(conf, nil)
|
||||
|
@ -195,7 +285,7 @@ func TestAllOptions(t *testing.T) {
|
|||
|
||||
config.Services = []string{"test"}
|
||||
config.NodeMeta = map[string]string{"rack_name": "2304"}
|
||||
config.ServiceTag = "tag1"
|
||||
config.ServiceTags = []string{"tag1"}
|
||||
config.AllowStale = true
|
||||
config.Token = "fake-token"
|
||||
|
||||
|
|
|
@ -337,8 +337,9 @@ services:
|
|||
# See https://www.consul.io/api/catalog.html#list-nodes-for-service to know more
|
||||
# about the possible filters that can be used.
|
||||
|
||||
# An optional tag used to filter nodes for a given service.
|
||||
[ tag: <string> ]
|
||||
# An optional list of tags used to filter nodes for a given service. Services must contain all tags in the list.
|
||||
tags:
|
||||
[ - <string> ]
|
||||
|
||||
# Node metadata used to filter nodes for a given service.
|
||||
[ node_meta:
|
||||
|
|
9
go.mod
9
go.mod
|
@ -4,6 +4,7 @@ require (
|
|||
contrib.go.opencensus.io/exporter/ocagent v0.4.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v23.2.0+incompatible
|
||||
github.com/Azure/go-autorest v11.2.8+incompatible
|
||||
github.com/DataDog/datadog-go v0.0.0-20180822151419-281ae9f2d895 // indirect
|
||||
github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f // indirect
|
||||
github.com/VividCortex/ewma v1.1.1 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf
|
||||
|
@ -13,6 +14,8 @@ require (
|
|||
github.com/cenk/backoff v2.0.0+incompatible // indirect
|
||||
github.com/certifi/gocertifi v0.0.0-20180905225744-ee1a9a0726d2 // indirect
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/circonus-labs/circonus-gometrics v2.2.6+incompatible // indirect
|
||||
github.com/circonus-labs/circonusllhist v0.1.3 // indirect
|
||||
github.com/cockroachdb/apd v1.1.0 // indirect
|
||||
github.com/cockroachdb/cmux v0.0.0-20170110192607-30d10be49292
|
||||
github.com/cockroachdb/cockroach v0.0.0-20170608034007-84bc9597164f
|
||||
|
@ -44,11 +47,11 @@ require (
|
|||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.6.3
|
||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
|
||||
github.com/hashicorp/consul v0.0.0-20180615161029-bed22a81e9fd
|
||||
github.com/hashicorp/go-cleanhttp v0.0.0-20160407174126-ad28ea4487f0 // indirect
|
||||
github.com/hashicorp/consul v1.4.2
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect
|
||||
github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c // indirect
|
||||
github.com/hashicorp/go-multierror v1.0.0 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90 // indirect
|
||||
github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86 // indirect
|
||||
github.com/hashicorp/memberlist v0.1.0 // indirect
|
||||
|
@ -70,6 +73,7 @@ require (
|
|||
github.com/miekg/dns v1.1.4
|
||||
github.com/mitchellh/go-homedir v0.0.0-20180523094522-3864e76763d9 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.1.2 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
|
||||
|
@ -105,6 +109,7 @@ require (
|
|||
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect
|
||||
github.com/spf13/pflag v1.0.3 // indirect
|
||||
github.com/stretchr/testify v1.2.2
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 // indirect
|
||||
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8 // indirect
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be
|
||||
|
|
20
go.sum
20
go.sum
|
@ -7,6 +7,8 @@ github.com/Azure/azure-sdk-for-go v23.2.0+incompatible h1:bch1RS060vGpHpY3zvQDV4
|
|||
github.com/Azure/azure-sdk-for-go v23.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/go-autorest v11.2.8+incompatible h1:Q2feRPMlcfVcqz3pF87PJzkm5lZrL+x6BDtzhODzNJM=
|
||||
github.com/Azure/go-autorest v11.2.8+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/DataDog/datadog-go v0.0.0-20180822151419-281ae9f2d895 h1:dmc/C8bpE5VkQn65PNbbyACDC8xw8Hpp/NEurdPmQDQ=
|
||||
github.com/DataDog/datadog-go v0.0.0-20180822151419-281ae9f2d895/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f h1:5ZfJxyXo8KyX8DgGXC5B7ILL8y51fci/qYz2B4j8iLY=
|
||||
|
@ -33,6 +35,10 @@ github.com/certifi/gocertifi v0.0.0-20180905225744-ee1a9a0726d2 h1:MmeatFT1pTPSV
|
|||
github.com/certifi/gocertifi v0.0.0-20180905225744-ee1a9a0726d2/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/circonus-labs/circonus-gometrics v2.2.6+incompatible h1:NoaznmtBvXxBwKGS+lQBGJSNqJQAtCTPE5ekztSSQfs=
|
||||
github.com/circonus-labs/circonus-gometrics v2.2.6+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
|
@ -114,18 +120,20 @@ github.com/grpc-ecosystem/grpc-gateway v1.6.3 h1:oQ+8y59SMDn8Ita1Sh4f94XCUVp8AB8
|
|||
github.com/grpc-ecosystem/grpc-gateway v1.6.3/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=
|
||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
|
||||
github.com/hashicorp/consul v0.0.0-20180615161029-bed22a81e9fd h1:auIpcMc3+//R94n6tzTN+sJDiNvL3k5+Rus62AtvO4M=
|
||||
github.com/hashicorp/consul v0.0.0-20180615161029-bed22a81e9fd/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI=
|
||||
github.com/hashicorp/consul v1.4.2 h1:D9iJoJb8Ehe/Zmr+UEE3U3FjOLZ4LUxqFMl4O43BM1U=
|
||||
github.com/hashicorp/consul v1.4.2/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.0.0-20160407174126-ad28ea4487f0 h1:2l0haPDqCzZEO160UR5DSrrl8RWptFCoxFsSbRLJBaI=
|
||||
github.com/hashicorp/go-cleanhttp v0.0.0-20160407174126-ad28ea4487f0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c h1:BTAbnbegUIMB6xmQCwWE8yRzbA4XSpnZY5hvRJC188I=
|
||||
github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-retryablehttp v0.5.2 h1:AoISa4P4IsW0/m4T6St8Yw38gTl5GtBAgfkhYh1xAz4=
|
||||
github.com/hashicorp/go-retryablehttp v0.5.2/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||
github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90 h1:VBj0QYQ0u2MCJzBfeYXGexnAl17GsH1yidnoxCqqD9E=
|
||||
github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90/go.mod h1:o4zcYY1e0GEZI6eSEr+43QDYmuGglw1qSO6qdHUHCgg=
|
||||
github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86 h1:7YOlAIO2YWnJZkQp7B5eFykaIY7C9JndqAFQyVV5BhM=
|
||||
|
@ -180,6 +188,8 @@ github.com/mitchellh/go-homedir v0.0.0-20180523094522-3864e76763d9 h1:Y94YB7jrsi
|
|||
github.com/mitchellh/go-homedir v0.0.0-20180523094522-3864e76763d9/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
|
@ -265,6 +275,8 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
|||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
go.opencensus.io v0.18.1-0.20181204023538-aab39bd6a98b h1:6ayHMBPtdP3jNuk+Sfhso+PTB7ZJQ5E1FBo403m2H8w=
|
||||
go.opencensus.io v0.18.1-0.20181204023538-aab39bd6a98b/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8 h1:h7zdf0RiEvWbYBKIx4b+q41xoUVnMmvsGZnIVE5syG8=
|
||||
|
|
3
vendor/github.com/hashicorp/consul/NOTICE.md
generated
vendored
Normal file
3
vendor/github.com/hashicorp/consul/NOTICE.md
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
Copyright © 2014-2018 HashiCorp, Inc.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this project, you can obtain one at http://mozilla.org/MPL/2.0/.
|
68
vendor/github.com/hashicorp/consul/api/README.md
generated
vendored
68
vendor/github.com/hashicorp/consul/api/README.md
generated
vendored
|
@ -17,27 +17,51 @@ Usage
|
|||
Below is an example of using the Consul client:
|
||||
|
||||
```go
|
||||
// Get a new client
|
||||
client, err := api.NewClient(api.DefaultConfig())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
package main
|
||||
|
||||
import "github.com/hashicorp/consul/api"
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
// Get a new client
|
||||
client, err := api.NewClient(api.DefaultConfig())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Get a handle to the KV API
|
||||
kv := client.KV()
|
||||
|
||||
// PUT a new KV pair
|
||||
p := &api.KVPair{Key: "REDIS_MAXCLIENTS", Value: []byte("1000")}
|
||||
_, err = kv.Put(p, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Lookup the pair
|
||||
pair, _, err := kv.Get("REDIS_MAXCLIENTS", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("KV: %v %s\n", pair.Key, pair.Value)
|
||||
}
|
||||
|
||||
// Get a handle to the KV API
|
||||
kv := client.KV()
|
||||
|
||||
// PUT a new KV pair
|
||||
p := &api.KVPair{Key: "foo", Value: []byte("test")}
|
||||
_, err = kv.Put(p, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Lookup the pair
|
||||
pair, _, err := kv.Get("foo", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("KV: %v", pair)
|
||||
|
||||
```
|
||||
|
||||
To run this example, start a Consul server:
|
||||
|
||||
```bash
|
||||
consul agent -dev
|
||||
```
|
||||
|
||||
Copy the code above into a file such as `main.go`.
|
||||
|
||||
Install and run. You'll see a key (`REDIS_MAXCLIENTS`) and value (`1000`) printed.
|
||||
|
||||
```bash
|
||||
$ go get
|
||||
$ go run main.go
|
||||
KV: REDIS_MAXCLIENTS 1000
|
||||
```
|
||||
|
||||
After running the code, you can also view the values in the Consul UI on your local machine at http://localhost:8500/ui/dc1/kv
|
||||
|
|
419
vendor/github.com/hashicorp/consul/api/acl.go
generated
vendored
419
vendor/github.com/hashicorp/consul/api/acl.go
generated
vendored
|
@ -1,6 +1,9 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -12,7 +15,42 @@ const (
|
|||
ACLManagementType = "management"
|
||||
)
|
||||
|
||||
// ACLEntry is used to represent an ACL entry
|
||||
type ACLTokenPolicyLink struct {
|
||||
ID string
|
||||
Name string
|
||||
}
|
||||
|
||||
// ACLToken represents an ACL Token
|
||||
type ACLToken struct {
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
AccessorID string
|
||||
SecretID string
|
||||
Description string
|
||||
Policies []*ACLTokenPolicyLink
|
||||
Local bool
|
||||
CreateTime time.Time `json:",omitempty"`
|
||||
Hash []byte `json:",omitempty"`
|
||||
|
||||
// DEPRECATED (ACL-Legacy-Compat)
|
||||
// Rules will only be present for legacy tokens returned via the new APIs
|
||||
Rules string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type ACLTokenListEntry struct {
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
AccessorID string
|
||||
Description string
|
||||
Policies []*ACLTokenPolicyLink
|
||||
Local bool
|
||||
CreateTime time.Time
|
||||
Hash []byte
|
||||
Legacy bool
|
||||
}
|
||||
|
||||
// ACLEntry is used to represent a legacy ACL token
|
||||
// The legacy tokens are deprecated.
|
||||
type ACLEntry struct {
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
|
@ -24,12 +62,36 @@ type ACLEntry struct {
|
|||
|
||||
// ACLReplicationStatus is used to represent the status of ACL replication.
|
||||
type ACLReplicationStatus struct {
|
||||
Enabled bool
|
||||
Running bool
|
||||
SourceDatacenter string
|
||||
ReplicatedIndex uint64
|
||||
LastSuccess time.Time
|
||||
LastError time.Time
|
||||
Enabled bool
|
||||
Running bool
|
||||
SourceDatacenter string
|
||||
ReplicationType string
|
||||
ReplicatedIndex uint64
|
||||
ReplicatedTokenIndex uint64
|
||||
LastSuccess time.Time
|
||||
LastError time.Time
|
||||
}
|
||||
|
||||
// ACLPolicy represents an ACL Policy.
|
||||
type ACLPolicy struct {
|
||||
ID string
|
||||
Name string
|
||||
Description string
|
||||
Rules string
|
||||
Datacenters []string
|
||||
Hash []byte
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
type ACLPolicyListEntry struct {
|
||||
ID string
|
||||
Name string
|
||||
Description string
|
||||
Datacenters []string
|
||||
Hash []byte
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
// ACL can be used to query the ACL endpoints
|
||||
|
@ -44,23 +106,25 @@ func (c *Client) ACL() *ACL {
|
|||
|
||||
// Bootstrap is used to perform a one-time ACL bootstrap operation on a cluster
|
||||
// to get the first management token.
|
||||
func (a *ACL) Bootstrap() (string, *WriteMeta, error) {
|
||||
func (a *ACL) Bootstrap() (*ACLToken, *WriteMeta, error) {
|
||||
r := a.c.newRequest("PUT", "/v1/acl/bootstrap")
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
wm := &WriteMeta{RequestTime: rtt}
|
||||
var out struct{ ID string }
|
||||
var out ACLToken
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return "", nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
return out.ID, wm, nil
|
||||
return &out, wm, nil
|
||||
}
|
||||
|
||||
// Create is used to generate a new token with the given parameters
|
||||
//
|
||||
// Deprecated: Use TokenCreate instead.
|
||||
func (a *ACL) Create(acl *ACLEntry, q *WriteOptions) (string, *WriteMeta, error) {
|
||||
r := a.c.newRequest("PUT", "/v1/acl/create")
|
||||
r.setWriteOptions(q)
|
||||
|
@ -80,6 +144,8 @@ func (a *ACL) Create(acl *ACLEntry, q *WriteOptions) (string, *WriteMeta, error)
|
|||
}
|
||||
|
||||
// Update is used to update the rules of an existing token
|
||||
//
|
||||
// Deprecated: Use TokenUpdate instead.
|
||||
func (a *ACL) Update(acl *ACLEntry, q *WriteOptions) (*WriteMeta, error) {
|
||||
r := a.c.newRequest("PUT", "/v1/acl/update")
|
||||
r.setWriteOptions(q)
|
||||
|
@ -95,6 +161,8 @@ func (a *ACL) Update(acl *ACLEntry, q *WriteOptions) (*WriteMeta, error) {
|
|||
}
|
||||
|
||||
// Destroy is used to destroy a given ACL token ID
|
||||
//
|
||||
// Deprecated: Use TokenDelete instead.
|
||||
func (a *ACL) Destroy(id string, q *WriteOptions) (*WriteMeta, error) {
|
||||
r := a.c.newRequest("PUT", "/v1/acl/destroy/"+id)
|
||||
r.setWriteOptions(q)
|
||||
|
@ -109,6 +177,8 @@ func (a *ACL) Destroy(id string, q *WriteOptions) (*WriteMeta, error) {
|
|||
}
|
||||
|
||||
// Clone is used to return a new token cloned from an existing one
|
||||
//
|
||||
// Deprecated: Use TokenClone instead.
|
||||
func (a *ACL) Clone(id string, q *WriteOptions) (string, *WriteMeta, error) {
|
||||
r := a.c.newRequest("PUT", "/v1/acl/clone/"+id)
|
||||
r.setWriteOptions(q)
|
||||
|
@ -127,6 +197,8 @@ func (a *ACL) Clone(id string, q *WriteOptions) (string, *WriteMeta, error) {
|
|||
}
|
||||
|
||||
// Info is used to query for information about an ACL token
|
||||
//
|
||||
// Deprecated: Use TokenRead instead.
|
||||
func (a *ACL) Info(id string, q *QueryOptions) (*ACLEntry, *QueryMeta, error) {
|
||||
r := a.c.newRequest("GET", "/v1/acl/info/"+id)
|
||||
r.setQueryOptions(q)
|
||||
|
@ -151,6 +223,8 @@ func (a *ACL) Info(id string, q *QueryOptions) (*ACLEntry, *QueryMeta, error) {
|
|||
}
|
||||
|
||||
// List is used to get all the ACL tokens
|
||||
//
|
||||
// Deprecated: Use TokenList instead.
|
||||
func (a *ACL) List(q *QueryOptions) ([]*ACLEntry, *QueryMeta, error) {
|
||||
r := a.c.newRequest("GET", "/v1/acl/list")
|
||||
r.setQueryOptions(q)
|
||||
|
@ -191,3 +265,324 @@ func (a *ACL) Replication(q *QueryOptions) (*ACLReplicationStatus, *QueryMeta, e
|
|||
}
|
||||
return entries, qm, nil
|
||||
}
|
||||
|
||||
// TokenCreate creates a new ACL token. It requires that the AccessorID and SecretID fields
|
||||
// of the ACLToken structure to be empty as these will be filled in by Consul.
|
||||
func (a *ACL) TokenCreate(token *ACLToken, q *WriteOptions) (*ACLToken, *WriteMeta, error) {
|
||||
if token.AccessorID != "" {
|
||||
return nil, nil, fmt.Errorf("Cannot specify an AccessorID in Token Creation")
|
||||
}
|
||||
|
||||
if token.SecretID != "" {
|
||||
return nil, nil, fmt.Errorf("Cannot specify a SecretID in Token Creation")
|
||||
}
|
||||
|
||||
r := a.c.newRequest("PUT", "/v1/acl/token")
|
||||
r.setWriteOptions(q)
|
||||
r.obj = token
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
wm := &WriteMeta{RequestTime: rtt}
|
||||
var out ACLToken
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &out, wm, nil
|
||||
}
|
||||
|
||||
// TokenUpdate updates a token in place without modifying its AccessorID or SecretID. A valid
|
||||
// AccessorID must be set in the ACLToken structure passed to this function but the SecretID may
|
||||
// be omitted and will be filled in by Consul with its existing value.
|
||||
func (a *ACL) TokenUpdate(token *ACLToken, q *WriteOptions) (*ACLToken, *WriteMeta, error) {
|
||||
if token.AccessorID == "" {
|
||||
return nil, nil, fmt.Errorf("Must specify an AccessorID for Token Updating")
|
||||
}
|
||||
r := a.c.newRequest("PUT", "/v1/acl/token/"+token.AccessorID)
|
||||
r.setWriteOptions(q)
|
||||
r.obj = token
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
wm := &WriteMeta{RequestTime: rtt}
|
||||
var out ACLToken
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &out, wm, nil
|
||||
}
|
||||
|
||||
// TokenClone will create a new token with the same policies and locality as the original
|
||||
// token but will have its own auto-generated AccessorID and SecretID as well having the
|
||||
// description passed to this function. The tokenID parameter must be a valid Accessor ID
|
||||
// of an existing token.
|
||||
func (a *ACL) TokenClone(tokenID string, description string, q *WriteOptions) (*ACLToken, *WriteMeta, error) {
|
||||
if tokenID == "" {
|
||||
return nil, nil, fmt.Errorf("Must specify a tokenID for Token Cloning")
|
||||
}
|
||||
|
||||
r := a.c.newRequest("PUT", "/v1/acl/token/"+tokenID+"/clone")
|
||||
r.setWriteOptions(q)
|
||||
r.obj = struct{ Description string }{description}
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
wm := &WriteMeta{RequestTime: rtt}
|
||||
var out ACLToken
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &out, wm, nil
|
||||
}
|
||||
|
||||
// TokenDelete removes a single ACL token. The tokenID parameter must be a valid
|
||||
// Accessor ID of an existing token.
|
||||
func (a *ACL) TokenDelete(tokenID string, q *WriteOptions) (*WriteMeta, error) {
|
||||
r := a.c.newRequest("DELETE", "/v1/acl/token/"+tokenID)
|
||||
r.setWriteOptions(q)
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
wm := &WriteMeta{RequestTime: rtt}
|
||||
return wm, nil
|
||||
}
|
||||
|
||||
// TokenRead retrieves the full token details. The tokenID parameter must be a valid
|
||||
// Accessor ID of an existing token.
|
||||
func (a *ACL) TokenRead(tokenID string, q *QueryOptions) (*ACLToken, *QueryMeta, error) {
|
||||
r := a.c.newRequest("GET", "/v1/acl/token/"+tokenID)
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out ACLToken
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &out, qm, nil
|
||||
}
|
||||
|
||||
// TokenReadSelf retrieves the full token details of the token currently
|
||||
// assigned to the API Client. In this manner its possible to read a token
|
||||
// by its Secret ID.
|
||||
func (a *ACL) TokenReadSelf(q *QueryOptions) (*ACLToken, *QueryMeta, error) {
|
||||
r := a.c.newRequest("GET", "/v1/acl/token/self")
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out ACLToken
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &out, qm, nil
|
||||
}
|
||||
|
||||
// TokenList lists all tokens. The listing does not contain any SecretIDs as those
|
||||
// may only be retrieved by a call to TokenRead.
|
||||
func (a *ACL) TokenList(q *QueryOptions) ([]*ACLTokenListEntry, *QueryMeta, error) {
|
||||
r := a.c.newRequest("GET", "/v1/acl/tokens")
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var entries []*ACLTokenListEntry
|
||||
if err := decodeBody(resp, &entries); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return entries, qm, nil
|
||||
}
|
||||
|
||||
// PolicyCreate will create a new policy. It is not allowed for the policy parameters
|
||||
// ID field to be set as this will be generated by Consul while processing the request.
|
||||
func (a *ACL) PolicyCreate(policy *ACLPolicy, q *WriteOptions) (*ACLPolicy, *WriteMeta, error) {
|
||||
if policy.ID != "" {
|
||||
return nil, nil, fmt.Errorf("Cannot specify an ID in Policy Creation")
|
||||
}
|
||||
|
||||
r := a.c.newRequest("PUT", "/v1/acl/policy")
|
||||
r.setWriteOptions(q)
|
||||
r.obj = policy
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
wm := &WriteMeta{RequestTime: rtt}
|
||||
var out ACLPolicy
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &out, wm, nil
|
||||
}
|
||||
|
||||
// PolicyUpdate updates a policy. The ID field of the policy parameter must be set to an
|
||||
// existing policy ID
|
||||
func (a *ACL) PolicyUpdate(policy *ACLPolicy, q *WriteOptions) (*ACLPolicy, *WriteMeta, error) {
|
||||
if policy.ID == "" {
|
||||
return nil, nil, fmt.Errorf("Must specify an ID in Policy Creation")
|
||||
}
|
||||
|
||||
r := a.c.newRequest("PUT", "/v1/acl/policy/"+policy.ID)
|
||||
r.setWriteOptions(q)
|
||||
r.obj = policy
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
wm := &WriteMeta{RequestTime: rtt}
|
||||
var out ACLPolicy
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &out, wm, nil
|
||||
}
|
||||
|
||||
// PolicyDelete deletes a policy given its ID.
|
||||
func (a *ACL) PolicyDelete(policyID string, q *WriteOptions) (*WriteMeta, error) {
|
||||
r := a.c.newRequest("DELETE", "/v1/acl/policy/"+policyID)
|
||||
r.setWriteOptions(q)
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
wm := &WriteMeta{RequestTime: rtt}
|
||||
return wm, nil
|
||||
}
|
||||
|
||||
// PolicyRead retrieves the policy details including the rule set.
|
||||
func (a *ACL) PolicyRead(policyID string, q *QueryOptions) (*ACLPolicy, *QueryMeta, error) {
|
||||
r := a.c.newRequest("GET", "/v1/acl/policy/"+policyID)
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out ACLPolicy
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &out, qm, nil
|
||||
}
|
||||
|
||||
// PolicyList retrieves a listing of all policies. The listing does not include the
|
||||
// rules for any policy as those should be retrieved by subsequent calls to PolicyRead.
|
||||
func (a *ACL) PolicyList(q *QueryOptions) ([]*ACLPolicyListEntry, *QueryMeta, error) {
|
||||
r := a.c.newRequest("GET", "/v1/acl/policies")
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var entries []*ACLPolicyListEntry
|
||||
if err := decodeBody(resp, &entries); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return entries, qm, nil
|
||||
}
|
||||
|
||||
// RulesTranslate translates the legacy rule syntax into the current syntax.
|
||||
//
|
||||
// Deprecated: Support for the legacy syntax translation will be removed
|
||||
// when legacy ACL support is removed.
|
||||
func (a *ACL) RulesTranslate(rules io.Reader) (string, error) {
|
||||
r := a.c.newRequest("POST", "/v1/acl/rules/translate")
|
||||
r.body = rules
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
ruleBytes, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Failed to read translated rule body: %v", err)
|
||||
}
|
||||
|
||||
return string(ruleBytes), nil
|
||||
}
|
||||
|
||||
// RulesTranslateToken translates the rules associated with the legacy syntax
|
||||
// into the current syntax and returns the results.
|
||||
//
|
||||
// Deprecated: Support for the legacy syntax translation will be removed
|
||||
// when legacy ACL support is removed.
|
||||
func (a *ACL) RulesTranslateToken(tokenID string) (string, error) {
|
||||
r := a.c.newRequest("GET", "/v1/acl/rules/translate/"+tokenID)
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
ruleBytes, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Failed to read translated rule body: %v", err)
|
||||
}
|
||||
|
||||
return string(ruleBytes), nil
|
||||
}
|
||||
|
|
343
vendor/github.com/hashicorp/consul/api/agent.go
generated
vendored
343
vendor/github.com/hashicorp/consul/api/agent.go
generated
vendored
|
@ -3,6 +3,53 @@ package api
|
|||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// ServiceKind is the kind of service being registered.
|
||||
type ServiceKind string
|
||||
|
||||
const (
|
||||
// ServiceKindTypical is a typical, classic Consul service. This is
|
||||
// represented by the absence of a value. This was chosen for ease of
|
||||
// backwards compatibility: existing services in the catalog would
|
||||
// default to the typical service.
|
||||
ServiceKindTypical ServiceKind = ""
|
||||
|
||||
// ServiceKindConnectProxy is a proxy for the Connect feature. This
|
||||
// service proxies another service within Consul and speaks the connect
|
||||
// protocol.
|
||||
ServiceKindConnectProxy ServiceKind = "connect-proxy"
|
||||
)
|
||||
|
||||
// ProxyExecMode is the execution mode for a managed Connect proxy.
|
||||
type ProxyExecMode string
|
||||
|
||||
const (
|
||||
// ProxyExecModeDaemon indicates that the proxy command should be long-running
|
||||
// and should be started and supervised by the agent until it's target service
|
||||
// is deregistered.
|
||||
ProxyExecModeDaemon ProxyExecMode = "daemon"
|
||||
|
||||
// ProxyExecModeScript indicates that the proxy command should be invoke to
|
||||
// completion on each change to the configuration of lifecycle event. The
|
||||
// script typically fetches the config and certificates from the agent API and
|
||||
// then configures an externally managed daemon, perhaps starting and stopping
|
||||
// it if necessary.
|
||||
ProxyExecModeScript ProxyExecMode = "script"
|
||||
)
|
||||
|
||||
// UpstreamDestType is the type of upstream discovery mechanism.
|
||||
type UpstreamDestType string
|
||||
|
||||
const (
|
||||
// UpstreamDestTypeService discovers instances via healthy service lookup.
|
||||
UpstreamDestTypeService UpstreamDestType = "service"
|
||||
|
||||
// UpstreamDestTypePreparedQuery discovers instances via prepared query
|
||||
// execution.
|
||||
UpstreamDestTypePreparedQuery UpstreamDestType = "prepared_query"
|
||||
)
|
||||
|
||||
// AgentCheck represents a check known to the agent
|
||||
|
@ -18,17 +65,64 @@ type AgentCheck struct {
|
|||
Definition HealthCheckDefinition
|
||||
}
|
||||
|
||||
// AgentWeights represent optional weights for a service
|
||||
type AgentWeights struct {
|
||||
Passing int
|
||||
Warning int
|
||||
}
|
||||
|
||||
// AgentService represents a service known to the agent
|
||||
type AgentService struct {
|
||||
Kind ServiceKind `json:",omitempty"`
|
||||
ID string
|
||||
Service string
|
||||
Tags []string
|
||||
Meta map[string]string
|
||||
Port int
|
||||
Address string
|
||||
Weights AgentWeights
|
||||
EnableTagOverride bool
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
CreateIndex uint64 `json:",omitempty"`
|
||||
ModifyIndex uint64 `json:",omitempty"`
|
||||
ContentHash string `json:",omitempty"`
|
||||
// DEPRECATED (ProxyDestination) - remove this field
|
||||
ProxyDestination string `json:",omitempty"`
|
||||
Proxy *AgentServiceConnectProxyConfig `json:",omitempty"`
|
||||
Connect *AgentServiceConnect `json:",omitempty"`
|
||||
}
|
||||
|
||||
// AgentServiceChecksInfo returns information about a Service and its checks
|
||||
type AgentServiceChecksInfo struct {
|
||||
AggregatedStatus string
|
||||
Service *AgentService
|
||||
Checks HealthChecks
|
||||
}
|
||||
|
||||
// AgentServiceConnect represents the Connect configuration of a service.
|
||||
type AgentServiceConnect struct {
|
||||
Native bool `json:",omitempty"`
|
||||
Proxy *AgentServiceConnectProxy `json:",omitempty"`
|
||||
SidecarService *AgentServiceRegistration `json:",omitempty"`
|
||||
}
|
||||
|
||||
// AgentServiceConnectProxy represents the Connect Proxy configuration of a
|
||||
// service.
|
||||
type AgentServiceConnectProxy struct {
|
||||
ExecMode ProxyExecMode `json:",omitempty"`
|
||||
Command []string `json:",omitempty"`
|
||||
Config map[string]interface{} `json:",omitempty"`
|
||||
Upstreams []Upstream `json:",omitempty"`
|
||||
}
|
||||
|
||||
// AgentServiceConnectProxyConfig is the proxy configuration in a connect-proxy
|
||||
// ServiceDefinition or response.
|
||||
type AgentServiceConnectProxyConfig struct {
|
||||
DestinationServiceName string
|
||||
DestinationServiceID string `json:",omitempty"`
|
||||
LocalServiceAddress string `json:",omitempty"`
|
||||
LocalServicePort int `json:",omitempty"`
|
||||
Config map[string]interface{} `json:",omitempty"`
|
||||
Upstreams []Upstream
|
||||
}
|
||||
|
||||
// AgentMember represents a cluster member known to the agent
|
||||
|
@ -61,6 +155,7 @@ type MembersOpts struct {
|
|||
|
||||
// AgentServiceRegistration is used to register a new service
|
||||
type AgentServiceRegistration struct {
|
||||
Kind ServiceKind `json:",omitempty"`
|
||||
ID string `json:",omitempty"`
|
||||
Name string `json:",omitempty"`
|
||||
Tags []string `json:",omitempty"`
|
||||
|
@ -68,8 +163,13 @@ type AgentServiceRegistration struct {
|
|||
Address string `json:",omitempty"`
|
||||
EnableTagOverride bool `json:",omitempty"`
|
||||
Meta map[string]string `json:",omitempty"`
|
||||
Weights *AgentWeights `json:",omitempty"`
|
||||
Check *AgentServiceCheck
|
||||
Checks AgentServiceChecks
|
||||
// DEPRECATED (ProxyDestination) - remove this field
|
||||
ProxyDestination string `json:",omitempty"`
|
||||
Proxy *AgentServiceConnectProxyConfig `json:",omitempty"`
|
||||
Connect *AgentServiceConnect `json:",omitempty"`
|
||||
}
|
||||
|
||||
// AgentCheckRegistration is used to register a new check
|
||||
|
@ -100,6 +200,8 @@ type AgentServiceCheck struct {
|
|||
TLSSkipVerify bool `json:",omitempty"`
|
||||
GRPC string `json:",omitempty"`
|
||||
GRPCUseTLS bool `json:",omitempty"`
|
||||
AliasNode string `json:",omitempty"`
|
||||
AliasService string `json:",omitempty"`
|
||||
|
||||
// In Consul 0.7 and later, checks that are associated with a service
|
||||
// may also contain this optional DeregisterCriticalServiceAfter field,
|
||||
|
@ -152,6 +254,45 @@ type SampledValue struct {
|
|||
Labels map[string]string
|
||||
}
|
||||
|
||||
// AgentAuthorizeParams are the request parameters for authorizing a request.
|
||||
type AgentAuthorizeParams struct {
|
||||
Target string
|
||||
ClientCertURI string
|
||||
ClientCertSerial string
|
||||
}
|
||||
|
||||
// AgentAuthorize is the response structure for Connect authorization.
|
||||
type AgentAuthorize struct {
|
||||
Authorized bool
|
||||
Reason string
|
||||
}
|
||||
|
||||
// ConnectProxyConfig is the response structure for agent-local proxy
|
||||
// configuration.
|
||||
type ConnectProxyConfig struct {
|
||||
ProxyServiceID string
|
||||
TargetServiceID string
|
||||
TargetServiceName string
|
||||
ContentHash string
|
||||
// DEPRECATED(managed-proxies) - this struct is re-used for sidecar configs
|
||||
// but they don't need ExecMode or Command
|
||||
ExecMode ProxyExecMode `json:",omitempty"`
|
||||
Command []string `json:",omitempty"`
|
||||
Config map[string]interface{}
|
||||
Upstreams []Upstream
|
||||
}
|
||||
|
||||
// Upstream is the response structure for a proxy upstream configuration.
|
||||
type Upstream struct {
|
||||
DestinationType UpstreamDestType `json:",omitempty"`
|
||||
DestinationNamespace string `json:",omitempty"`
|
||||
DestinationName string
|
||||
Datacenter string `json:",omitempty"`
|
||||
LocalBindAddress string `json:",omitempty"`
|
||||
LocalBindPort int `json:",omitempty"`
|
||||
Config map[string]interface{} `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Agent can be used to query the Agent endpoints
|
||||
type Agent struct {
|
||||
c *Client
|
||||
|
@ -182,6 +323,24 @@ func (a *Agent) Self() (map[string]map[string]interface{}, error) {
|
|||
return out, nil
|
||||
}
|
||||
|
||||
// Host is used to retrieve information about the host the
|
||||
// agent is running on such as CPU, memory, and disk. Requires
|
||||
// a operator:read ACL token.
|
||||
func (a *Agent) Host() (map[string]interface{}, error) {
|
||||
r := a.c.newRequest("GET", "/v1/agent/host")
|
||||
_, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var out map[string]interface{}
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Metrics is used to query the agent we are speaking to for
|
||||
// its current internal metric data
|
||||
func (a *Agent) Metrics() (*MetricsInfo, error) {
|
||||
|
@ -253,9 +412,104 @@ func (a *Agent) Services() (map[string]*AgentService, error) {
|
|||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// AgentHealthServiceByID returns for a given serviceID: the aggregated health status, the service definition or an error if any
|
||||
// - If the service is not found, will return status (critical, nil, nil)
|
||||
// - If the service is found, will return (critical|passing|warning), AgentServiceChecksInfo, nil)
|
||||
// - In all other cases, will return an error
|
||||
func (a *Agent) AgentHealthServiceByID(serviceID string) (string, *AgentServiceChecksInfo, error) {
|
||||
path := fmt.Sprintf("/v1/agent/health/service/id/%v", url.PathEscape(serviceID))
|
||||
r := a.c.newRequest("GET", path)
|
||||
r.params.Add("format", "json")
|
||||
r.header.Set("Accept", "application/json")
|
||||
_, resp, err := a.c.doRequest(r)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
// Service not Found
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
return HealthCritical, nil, nil
|
||||
}
|
||||
var out *AgentServiceChecksInfo
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return HealthCritical, out, err
|
||||
}
|
||||
switch resp.StatusCode {
|
||||
case http.StatusOK:
|
||||
return HealthPassing, out, nil
|
||||
case http.StatusTooManyRequests:
|
||||
return HealthWarning, out, nil
|
||||
case http.StatusServiceUnavailable:
|
||||
return HealthCritical, out, nil
|
||||
}
|
||||
return HealthCritical, out, fmt.Errorf("Unexpected Error Code %v for %s", resp.StatusCode, path)
|
||||
}
|
||||
|
||||
// AgentHealthServiceByName returns for a given service name: the aggregated health status for all services
|
||||
// having the specified name.
|
||||
// - If no service is not found, will return status (critical, [], nil)
|
||||
// - If the service is found, will return (critical|passing|warning), []api.AgentServiceChecksInfo, nil)
|
||||
// - In all other cases, will return an error
|
||||
func (a *Agent) AgentHealthServiceByName(service string) (string, []AgentServiceChecksInfo, error) {
|
||||
path := fmt.Sprintf("/v1/agent/health/service/name/%v", url.PathEscape(service))
|
||||
r := a.c.newRequest("GET", path)
|
||||
r.params.Add("format", "json")
|
||||
r.header.Set("Accept", "application/json")
|
||||
_, resp, err := a.c.doRequest(r)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
// Service not Found
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
return HealthCritical, nil, nil
|
||||
}
|
||||
var out []AgentServiceChecksInfo
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return HealthCritical, out, err
|
||||
}
|
||||
switch resp.StatusCode {
|
||||
case http.StatusOK:
|
||||
return HealthPassing, out, nil
|
||||
case http.StatusTooManyRequests:
|
||||
return HealthWarning, out, nil
|
||||
case http.StatusServiceUnavailable:
|
||||
return HealthCritical, out, nil
|
||||
}
|
||||
return HealthCritical, out, fmt.Errorf("Unexpected Error Code %v for %s", resp.StatusCode, path)
|
||||
}
|
||||
|
||||
// Service returns a locally registered service instance and allows for
|
||||
// hash-based blocking.
|
||||
//
|
||||
// Note that this uses an unconventional blocking mechanism since it's
|
||||
// agent-local state. That means there is no persistent raft index so we block
|
||||
// based on object hash instead.
|
||||
func (a *Agent) Service(serviceID string, q *QueryOptions) (*AgentService, *QueryMeta, error) {
|
||||
r := a.c.newRequest("GET", "/v1/agent/service/"+serviceID)
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out *AgentService
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return out, qm, nil
|
||||
}
|
||||
|
||||
// Members returns the known gossip members. The WAN
|
||||
// flag can be used to query a server for WAN members.
|
||||
func (a *Agent) Members(wan bool) ([]*AgentMember, error) {
|
||||
|
@ -485,6 +739,91 @@ func (a *Agent) ForceLeave(node string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ConnectAuthorize is used to authorize an incoming connection
|
||||
// to a natively integrated Connect service.
|
||||
func (a *Agent) ConnectAuthorize(auth *AgentAuthorizeParams) (*AgentAuthorize, error) {
|
||||
r := a.c.newRequest("POST", "/v1/agent/connect/authorize")
|
||||
r.obj = auth
|
||||
_, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var out AgentAuthorize
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
// ConnectCARoots returns the list of roots.
|
||||
func (a *Agent) ConnectCARoots(q *QueryOptions) (*CARootList, *QueryMeta, error) {
|
||||
r := a.c.newRequest("GET", "/v1/agent/connect/ca/roots")
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out CARootList
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &out, qm, nil
|
||||
}
|
||||
|
||||
// ConnectCALeaf gets the leaf certificate for the given service ID.
|
||||
func (a *Agent) ConnectCALeaf(serviceID string, q *QueryOptions) (*LeafCert, *QueryMeta, error) {
|
||||
r := a.c.newRequest("GET", "/v1/agent/connect/ca/leaf/"+serviceID)
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out LeafCert
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &out, qm, nil
|
||||
}
|
||||
|
||||
// ConnectProxyConfig gets the configuration for a local managed proxy instance.
|
||||
//
|
||||
// Note that this uses an unconventional blocking mechanism since it's
|
||||
// agent-local state. That means there is no persistent raft index so we block
|
||||
// based on object hash instead.
|
||||
func (a *Agent) ConnectProxyConfig(proxyServiceID string, q *QueryOptions) (*ConnectProxyConfig, *QueryMeta, error) {
|
||||
r := a.c.newRequest("GET", "/v1/agent/connect/proxy/"+proxyServiceID)
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(a.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out ConnectProxyConfig
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &out, qm, nil
|
||||
}
|
||||
|
||||
// EnableServiceMaintenance toggles service maintenance mode on
|
||||
// for the given service ID.
|
||||
func (a *Agent) EnableServiceMaintenance(serviceID, reason string) error {
|
||||
|
|
122
vendor/github.com/hashicorp/consul/api/api.go
generated
vendored
122
vendor/github.com/hashicorp/consul/api/api.go
generated
vendored
|
@ -61,6 +61,12 @@ const (
|
|||
// HTTPSSLVerifyEnvName defines an environment variable name which sets
|
||||
// whether or not to disable certificate checking.
|
||||
HTTPSSLVerifyEnvName = "CONSUL_HTTP_SSL_VERIFY"
|
||||
|
||||
// GRPCAddrEnvName defines an environment variable name which sets the gRPC
|
||||
// address for consul connect envoy. Note this isn't actually used by the api
|
||||
// client in this package but is defined here for consistency with all the
|
||||
// other ENV names we use.
|
||||
GRPCAddrEnvName = "CONSUL_GRPC_ADDR"
|
||||
)
|
||||
|
||||
// QueryOptions are used to parameterize a query
|
||||
|
@ -78,10 +84,37 @@ type QueryOptions struct {
|
|||
// read.
|
||||
RequireConsistent bool
|
||||
|
||||
// UseCache requests that the agent cache results locally. See
|
||||
// https://www.consul.io/api/index.html#agent-caching for more details on the
|
||||
// semantics.
|
||||
UseCache bool
|
||||
|
||||
// MaxAge limits how old a cached value will be returned if UseCache is true.
|
||||
// If there is a cached response that is older than the MaxAge, it is treated
|
||||
// as a cache miss and a new fetch invoked. If the fetch fails, the error is
|
||||
// returned. Clients that wish to allow for stale results on error can set
|
||||
// StaleIfError to a longer duration to change this behaviour. It is ignored
|
||||
// if the endpoint supports background refresh caching. See
|
||||
// https://www.consul.io/api/index.html#agent-caching for more details.
|
||||
MaxAge time.Duration
|
||||
|
||||
// StaleIfError specifies how stale the client will accept a cached response
|
||||
// if the servers are unavailable to fetch a fresh one. Only makes sense when
|
||||
// UseCache is true and MaxAge is set to a lower, non-zero value. It is
|
||||
// ignored if the endpoint supports background refresh caching. See
|
||||
// https://www.consul.io/api/index.html#agent-caching for more details.
|
||||
StaleIfError time.Duration
|
||||
|
||||
// WaitIndex is used to enable a blocking query. Waits
|
||||
// until the timeout or the next index is reached
|
||||
WaitIndex uint64
|
||||
|
||||
// WaitHash is used by some endpoints instead of WaitIndex to perform blocking
|
||||
// on state based on a hash of the response rather than a monotonic index.
|
||||
// This is required when the state being blocked on is not stored in Raft, for
|
||||
// example agent-local proxy configuration.
|
||||
WaitHash string
|
||||
|
||||
// WaitTime is used to bound the duration of a wait.
|
||||
// Defaults to that of the Config, but can be overridden.
|
||||
WaitTime time.Duration
|
||||
|
@ -106,6 +139,10 @@ type QueryOptions struct {
|
|||
// a value from 0 to 5 (inclusive).
|
||||
RelayFactor uint8
|
||||
|
||||
// Connect filters prepared query execution to only include Connect-capable
|
||||
// services. This currently affects prepared query execution.
|
||||
Connect bool
|
||||
|
||||
// ctx is an optional context pass through to the underlying HTTP
|
||||
// request layer. Use Context() and WithContext() to manage this.
|
||||
ctx context.Context
|
||||
|
@ -169,6 +206,11 @@ type QueryMeta struct {
|
|||
// a blocking query
|
||||
LastIndex uint64
|
||||
|
||||
// LastContentHash. This can be used as a WaitHash to perform a blocking query
|
||||
// for endpoints that support hash-based blocking. Endpoints that do not
|
||||
// support it will return an empty hash.
|
||||
LastContentHash string
|
||||
|
||||
// Time of last contact from the leader for the
|
||||
// server servicing the request
|
||||
LastContact time.Duration
|
||||
|
@ -181,6 +223,13 @@ type QueryMeta struct {
|
|||
|
||||
// Is address translation enabled for HTTP responses on this agent
|
||||
AddressTranslationEnabled bool
|
||||
|
||||
// CacheHit is true if the result was served from agent-local cache.
|
||||
CacheHit bool
|
||||
|
||||
// CacheAge is set if request was ?cached and indicates how stale the cached
|
||||
// response is.
|
||||
CacheAge time.Duration
|
||||
}
|
||||
|
||||
// WriteMeta is used to return meta data about a write
|
||||
|
@ -261,7 +310,7 @@ type TLSConfig struct {
|
|||
// DefaultConfig returns a default configuration for the client. By default this
|
||||
// will pool and reuse idle connections to Consul. If you have a long-lived
|
||||
// client object, this is the desired behavior and should make the most efficient
|
||||
// use of the connections to Consul. If you don't reuse a client object , which
|
||||
// use of the connections to Consul. If you don't reuse a client object, which
|
||||
// is not recommended, then you may notice idle connections building up over
|
||||
// time. To avoid this, use the DefaultNonPooledConfig() instead.
|
||||
func DefaultConfig() *Config {
|
||||
|
@ -390,6 +439,29 @@ func SetupTLSConfig(tlsConfig *TLSConfig) (*tls.Config, error) {
|
|||
return tlsClientConfig, nil
|
||||
}
|
||||
|
||||
func (c *Config) GenerateEnv() []string {
|
||||
env := make([]string, 0, 10)
|
||||
|
||||
env = append(env,
|
||||
fmt.Sprintf("%s=%s", HTTPAddrEnvName, c.Address),
|
||||
fmt.Sprintf("%s=%s", HTTPTokenEnvName, c.Token),
|
||||
fmt.Sprintf("%s=%t", HTTPSSLEnvName, c.Scheme == "https"),
|
||||
fmt.Sprintf("%s=%s", HTTPCAFile, c.TLSConfig.CAFile),
|
||||
fmt.Sprintf("%s=%s", HTTPCAPath, c.TLSConfig.CAPath),
|
||||
fmt.Sprintf("%s=%s", HTTPClientCert, c.TLSConfig.CertFile),
|
||||
fmt.Sprintf("%s=%s", HTTPClientKey, c.TLSConfig.KeyFile),
|
||||
fmt.Sprintf("%s=%s", HTTPTLSServerName, c.TLSConfig.Address),
|
||||
fmt.Sprintf("%s=%t", HTTPSSLVerifyEnvName, !c.TLSConfig.InsecureSkipVerify))
|
||||
|
||||
if c.HttpAuth != nil {
|
||||
env = append(env, fmt.Sprintf("%s=%s:%s", HTTPAuthEnvName, c.HttpAuth.Username, c.HttpAuth.Password))
|
||||
} else {
|
||||
env = append(env, fmt.Sprintf("%s=", HTTPAuthEnvName))
|
||||
}
|
||||
|
||||
return env
|
||||
}
|
||||
|
||||
// Client provides a client to the Consul API
|
||||
type Client struct {
|
||||
config Config
|
||||
|
@ -533,6 +605,9 @@ func (r *request) setQueryOptions(q *QueryOptions) {
|
|||
if q.WaitTime != 0 {
|
||||
r.params.Set("wait", durToMsec(q.WaitTime))
|
||||
}
|
||||
if q.WaitHash != "" {
|
||||
r.params.Set("hash", q.WaitHash)
|
||||
}
|
||||
if q.Token != "" {
|
||||
r.header.Set("X-Consul-Token", q.Token)
|
||||
}
|
||||
|
@ -547,6 +622,23 @@ func (r *request) setQueryOptions(q *QueryOptions) {
|
|||
if q.RelayFactor != 0 {
|
||||
r.params.Set("relay-factor", strconv.Itoa(int(q.RelayFactor)))
|
||||
}
|
||||
if q.Connect {
|
||||
r.params.Set("connect", "true")
|
||||
}
|
||||
if q.UseCache && !q.RequireConsistent {
|
||||
r.params.Set("cached", "")
|
||||
|
||||
cc := []string{}
|
||||
if q.MaxAge > 0 {
|
||||
cc = append(cc, fmt.Sprintf("max-age=%.0f", q.MaxAge.Seconds()))
|
||||
}
|
||||
if q.StaleIfError > 0 {
|
||||
cc = append(cc, fmt.Sprintf("stale-if-error=%.0f", q.StaleIfError.Seconds()))
|
||||
}
|
||||
if len(cc) > 0 {
|
||||
r.header.Set("Cache-Control", strings.Join(cc, ", "))
|
||||
}
|
||||
}
|
||||
r.ctx = q.ctx
|
||||
}
|
||||
|
||||
|
@ -681,7 +773,7 @@ func (c *Client) doRequest(r *request) (time.Duration, *http.Response, error) {
|
|||
func (c *Client) query(endpoint string, out interface{}, q *QueryOptions) (*QueryMeta, error) {
|
||||
r := c.newRequest("GET", endpoint)
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(c.doRequest(r))
|
||||
rtt, resp, err := c.doRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -724,12 +816,16 @@ func (c *Client) write(endpoint string, in, out interface{}, q *WriteOptions) (*
|
|||
func parseQueryMeta(resp *http.Response, q *QueryMeta) error {
|
||||
header := resp.Header
|
||||
|
||||
// Parse the X-Consul-Index
|
||||
index, err := strconv.ParseUint(header.Get("X-Consul-Index"), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to parse X-Consul-Index: %v", err)
|
||||
// Parse the X-Consul-Index (if it's set - hash based blocking queries don't
|
||||
// set this)
|
||||
if indexStr := header.Get("X-Consul-Index"); indexStr != "" {
|
||||
index, err := strconv.ParseUint(indexStr, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to parse X-Consul-Index: %v", err)
|
||||
}
|
||||
q.LastIndex = index
|
||||
}
|
||||
q.LastIndex = index
|
||||
q.LastContentHash = header.Get("X-Consul-ContentHash")
|
||||
|
||||
// Parse the X-Consul-LastContact
|
||||
last, err := strconv.ParseUint(header.Get("X-Consul-LastContact"), 10, 64)
|
||||
|
@ -754,6 +850,18 @@ func parseQueryMeta(resp *http.Response, q *QueryMeta) error {
|
|||
q.AddressTranslationEnabled = false
|
||||
}
|
||||
|
||||
// Parse Cache info
|
||||
if cacheStr := header.Get("X-Cache"); cacheStr != "" {
|
||||
q.CacheHit = strings.EqualFold(cacheStr, "HIT")
|
||||
}
|
||||
if ageStr := header.Get("Age"); ageStr != "" {
|
||||
age, err := strconv.ParseUint(ageStr, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to parse Age Header: %v", err)
|
||||
}
|
||||
q.CacheAge = time.Duration(age) * time.Second
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
54
vendor/github.com/hashicorp/consul/api/catalog.go
generated
vendored
54
vendor/github.com/hashicorp/consul/api/catalog.go
generated
vendored
|
@ -1,5 +1,10 @@
|
|||
package api
|
||||
|
||||
type Weights struct {
|
||||
Passing int
|
||||
Warning int
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
ID string
|
||||
Node string
|
||||
|
@ -24,9 +29,14 @@ type CatalogService struct {
|
|||
ServiceTags []string
|
||||
ServiceMeta map[string]string
|
||||
ServicePort int
|
||||
ServiceWeights Weights
|
||||
ServiceEnableTagOverride bool
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
// DEPRECATED (ProxyDestination) - remove the next comment!
|
||||
// We forgot to ever add ServiceProxyDestination here so no need to deprecate!
|
||||
ServiceProxy *AgentServiceConnectProxyConfig
|
||||
CreateIndex uint64
|
||||
Checks HealthChecks
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
type CatalogNode struct {
|
||||
|
@ -43,6 +53,7 @@ type CatalogRegistration struct {
|
|||
Datacenter string
|
||||
Service *AgentService
|
||||
Check *AgentCheck
|
||||
Checks HealthChecks
|
||||
SkipNodeUpdate bool
|
||||
}
|
||||
|
||||
|
@ -156,10 +167,43 @@ func (c *Catalog) Services(q *QueryOptions) (map[string][]string, *QueryMeta, er
|
|||
|
||||
// Service is used to query catalog entries for a given service
|
||||
func (c *Catalog) Service(service, tag string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
|
||||
r := c.c.newRequest("GET", "/v1/catalog/service/"+service)
|
||||
r.setQueryOptions(q)
|
||||
var tags []string
|
||||
if tag != "" {
|
||||
r.params.Set("tag", tag)
|
||||
tags = []string{tag}
|
||||
}
|
||||
return c.service(service, tags, q, false)
|
||||
}
|
||||
|
||||
// Supports multiple tags for filtering
|
||||
func (c *Catalog) ServiceMultipleTags(service string, tags []string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
|
||||
return c.service(service, tags, q, false)
|
||||
}
|
||||
|
||||
// Connect is used to query catalog entries for a given Connect-enabled service
|
||||
func (c *Catalog) Connect(service, tag string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
|
||||
var tags []string
|
||||
if tag != "" {
|
||||
tags = []string{tag}
|
||||
}
|
||||
return c.service(service, tags, q, true)
|
||||
}
|
||||
|
||||
// Supports multiple tags for filtering
|
||||
func (c *Catalog) ConnectMultipleTags(service string, tags []string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
|
||||
return c.service(service, tags, q, true)
|
||||
}
|
||||
|
||||
func (c *Catalog) service(service string, tags []string, q *QueryOptions, connect bool) ([]*CatalogService, *QueryMeta, error) {
|
||||
path := "/v1/catalog/service/" + service
|
||||
if connect {
|
||||
path = "/v1/catalog/connect/" + service
|
||||
}
|
||||
r := c.c.newRequest("GET", path)
|
||||
r.setQueryOptions(q)
|
||||
if len(tags) > 0 {
|
||||
for _, tag := range tags {
|
||||
r.params.Add("tag", tag)
|
||||
}
|
||||
}
|
||||
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||
if err != nil {
|
||||
|
|
12
vendor/github.com/hashicorp/consul/api/connect.go
generated
vendored
Normal file
12
vendor/github.com/hashicorp/consul/api/connect.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
package api
|
||||
|
||||
// Connect can be used to work with endpoints related to Connect, the
|
||||
// feature for securely connecting services within Consul.
|
||||
type Connect struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// Connect returns a handle to the connect-related endpoints
|
||||
func (c *Client) Connect() *Connect {
|
||||
return &Connect{c}
|
||||
}
|
174
vendor/github.com/hashicorp/consul/api/connect_ca.go
generated
vendored
Normal file
174
vendor/github.com/hashicorp/consul/api/connect_ca.go
generated
vendored
Normal file
|
@ -0,0 +1,174 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
// CAConfig is the structure for the Connect CA configuration.
|
||||
type CAConfig struct {
|
||||
// Provider is the CA provider implementation to use.
|
||||
Provider string
|
||||
|
||||
// Configuration is arbitrary configuration for the provider. This
|
||||
// should only contain primitive values and containers (such as lists
|
||||
// and maps).
|
||||
Config map[string]interface{}
|
||||
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
// CommonCAProviderConfig is the common options available to all CA providers.
|
||||
type CommonCAProviderConfig struct {
|
||||
LeafCertTTL time.Duration
|
||||
SkipValidate bool
|
||||
CSRMaxPerSecond float32
|
||||
CSRMaxConcurrent int
|
||||
}
|
||||
|
||||
// ConsulCAProviderConfig is the config for the built-in Consul CA provider.
|
||||
type ConsulCAProviderConfig struct {
|
||||
CommonCAProviderConfig `mapstructure:",squash"`
|
||||
|
||||
PrivateKey string
|
||||
RootCert string
|
||||
RotationPeriod time.Duration
|
||||
}
|
||||
|
||||
// ParseConsulCAConfig takes a raw config map and returns a parsed
|
||||
// ConsulCAProviderConfig.
|
||||
func ParseConsulCAConfig(raw map[string]interface{}) (*ConsulCAProviderConfig, error) {
|
||||
var config ConsulCAProviderConfig
|
||||
decodeConf := &mapstructure.DecoderConfig{
|
||||
DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
|
||||
Result: &config,
|
||||
WeaklyTypedInput: true,
|
||||
}
|
||||
|
||||
decoder, err := mapstructure.NewDecoder(decodeConf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := decoder.Decode(raw); err != nil {
|
||||
return nil, fmt.Errorf("error decoding config: %s", err)
|
||||
}
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// CARootList is the structure for the results of listing roots.
|
||||
type CARootList struct {
|
||||
ActiveRootID string
|
||||
TrustDomain string
|
||||
Roots []*CARoot
|
||||
}
|
||||
|
||||
// CARoot represents a root CA certificate that is trusted.
|
||||
type CARoot struct {
|
||||
// ID is a globally unique ID (UUID) representing this CA root.
|
||||
ID string
|
||||
|
||||
// Name is a human-friendly name for this CA root. This value is
|
||||
// opaque to Consul and is not used for anything internally.
|
||||
Name string
|
||||
|
||||
// RootCertPEM is the PEM-encoded public certificate.
|
||||
RootCertPEM string `json:"RootCert"`
|
||||
|
||||
// Active is true if this is the current active CA. This must only
|
||||
// be true for exactly one CA. For any method that modifies roots in the
|
||||
// state store, tests should be written to verify that multiple roots
|
||||
// cannot be active.
|
||||
Active bool
|
||||
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
// LeafCert is a certificate that has been issued by a Connect CA.
|
||||
type LeafCert struct {
|
||||
// SerialNumber is the unique serial number for this certificate.
|
||||
// This is encoded in standard hex separated by :.
|
||||
SerialNumber string
|
||||
|
||||
// CertPEM and PrivateKeyPEM are the PEM-encoded certificate and private
|
||||
// key for that cert, respectively. This should not be stored in the
|
||||
// state store, but is present in the sign API response.
|
||||
CertPEM string `json:",omitempty"`
|
||||
PrivateKeyPEM string `json:",omitempty"`
|
||||
|
||||
// Service is the name of the service for which the cert was issued.
|
||||
// ServiceURI is the cert URI value.
|
||||
Service string
|
||||
ServiceURI string
|
||||
|
||||
// ValidAfter and ValidBefore are the validity periods for the
|
||||
// certificate.
|
||||
ValidAfter time.Time
|
||||
ValidBefore time.Time
|
||||
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
// CARoots queries the list of available roots.
|
||||
func (h *Connect) CARoots(q *QueryOptions) (*CARootList, *QueryMeta, error) {
|
||||
r := h.c.newRequest("GET", "/v1/connect/ca/roots")
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(h.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out CARootList
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &out, qm, nil
|
||||
}
|
||||
|
||||
// CAGetConfig returns the current CA configuration.
|
||||
func (h *Connect) CAGetConfig(q *QueryOptions) (*CAConfig, *QueryMeta, error) {
|
||||
r := h.c.newRequest("GET", "/v1/connect/ca/configuration")
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(h.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out CAConfig
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &out, qm, nil
|
||||
}
|
||||
|
||||
// CASetConfig sets the current CA configuration.
|
||||
func (h *Connect) CASetConfig(conf *CAConfig, q *WriteOptions) (*WriteMeta, error) {
|
||||
r := h.c.newRequest("PUT", "/v1/connect/ca/configuration")
|
||||
r.setWriteOptions(q)
|
||||
r.obj = conf
|
||||
rtt, resp, err := requireOK(h.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
wm := &WriteMeta{}
|
||||
wm.RequestTime = rtt
|
||||
return wm, nil
|
||||
}
|
302
vendor/github.com/hashicorp/consul/api/connect_intention.go
generated
vendored
Normal file
302
vendor/github.com/hashicorp/consul/api/connect_intention.go
generated
vendored
Normal file
|
@ -0,0 +1,302 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Intention defines an intention for the Connect Service Graph. This defines
|
||||
// the allowed or denied behavior of a connection between two services using
|
||||
// Connect.
|
||||
type Intention struct {
|
||||
// ID is the UUID-based ID for the intention, always generated by Consul.
|
||||
ID string
|
||||
|
||||
// Description is a human-friendly description of this intention.
|
||||
// It is opaque to Consul and is only stored and transferred in API
|
||||
// requests.
|
||||
Description string
|
||||
|
||||
// SourceNS, SourceName are the namespace and name, respectively, of
|
||||
// the source service. Either of these may be the wildcard "*", but only
|
||||
// the full value can be a wildcard. Partial wildcards are not allowed.
|
||||
// The source may also be a non-Consul service, as specified by SourceType.
|
||||
//
|
||||
// DestinationNS, DestinationName is the same, but for the destination
|
||||
// service. The same rules apply. The destination is always a Consul
|
||||
// service.
|
||||
SourceNS, SourceName string
|
||||
DestinationNS, DestinationName string
|
||||
|
||||
// SourceType is the type of the value for the source.
|
||||
SourceType IntentionSourceType
|
||||
|
||||
// Action is whether this is a whitelist or blacklist intention.
|
||||
Action IntentionAction
|
||||
|
||||
// DefaultAddr, DefaultPort of the local listening proxy (if any) to
|
||||
// make this connection.
|
||||
DefaultAddr string
|
||||
DefaultPort int
|
||||
|
||||
// Meta is arbitrary metadata associated with the intention. This is
|
||||
// opaque to Consul but is served in API responses.
|
||||
Meta map[string]string
|
||||
|
||||
// Precedence is the order that the intention will be applied, with
|
||||
// larger numbers being applied first. This is a read-only field, on
|
||||
// any intention update it is updated.
|
||||
Precedence int
|
||||
|
||||
// CreatedAt and UpdatedAt keep track of when this record was created
|
||||
// or modified.
|
||||
CreatedAt, UpdatedAt time.Time
|
||||
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
// String returns human-friendly output describing ths intention.
|
||||
func (i *Intention) String() string {
|
||||
return fmt.Sprintf("%s => %s (%s)",
|
||||
i.SourceString(),
|
||||
i.DestinationString(),
|
||||
i.Action)
|
||||
}
|
||||
|
||||
// SourceString returns the namespace/name format for the source, or
|
||||
// just "name" if the namespace is the default namespace.
|
||||
func (i *Intention) SourceString() string {
|
||||
return i.partString(i.SourceNS, i.SourceName)
|
||||
}
|
||||
|
||||
// DestinationString returns the namespace/name format for the source, or
|
||||
// just "name" if the namespace is the default namespace.
|
||||
func (i *Intention) DestinationString() string {
|
||||
return i.partString(i.DestinationNS, i.DestinationName)
|
||||
}
|
||||
|
||||
func (i *Intention) partString(ns, n string) string {
|
||||
// For now we omit the default namespace from the output. In the future
|
||||
// we might want to look at this and show this in a multi-namespace world.
|
||||
if ns != "" && ns != IntentionDefaultNamespace {
|
||||
n = ns + "/" + n
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// IntentionDefaultNamespace is the default namespace value.
|
||||
const IntentionDefaultNamespace = "default"
|
||||
|
||||
// IntentionAction is the action that the intention represents. This
|
||||
// can be "allow" or "deny" to whitelist or blacklist intentions.
|
||||
type IntentionAction string
|
||||
|
||||
const (
|
||||
IntentionActionAllow IntentionAction = "allow"
|
||||
IntentionActionDeny IntentionAction = "deny"
|
||||
)
|
||||
|
||||
// IntentionSourceType is the type of the source within an intention.
|
||||
type IntentionSourceType string
|
||||
|
||||
const (
|
||||
// IntentionSourceConsul is a service within the Consul catalog.
|
||||
IntentionSourceConsul IntentionSourceType = "consul"
|
||||
)
|
||||
|
||||
// IntentionMatch are the arguments for the intention match API.
|
||||
type IntentionMatch struct {
|
||||
By IntentionMatchType
|
||||
Names []string
|
||||
}
|
||||
|
||||
// IntentionMatchType is the target for a match request. For example,
|
||||
// matching by source will look for all intentions that match the given
|
||||
// source value.
|
||||
type IntentionMatchType string
|
||||
|
||||
const (
|
||||
IntentionMatchSource IntentionMatchType = "source"
|
||||
IntentionMatchDestination IntentionMatchType = "destination"
|
||||
)
|
||||
|
||||
// IntentionCheck are the arguments for the intention check API. For
|
||||
// more documentation see the IntentionCheck function.
|
||||
type IntentionCheck struct {
|
||||
// Source and Destination are the source and destination values to
|
||||
// check. The destination is always a Consul service, but the source
|
||||
// may be other values as defined by the SourceType.
|
||||
Source, Destination string
|
||||
|
||||
// SourceType is the type of the value for the source.
|
||||
SourceType IntentionSourceType
|
||||
}
|
||||
|
||||
// Intentions returns the list of intentions.
|
||||
func (h *Connect) Intentions(q *QueryOptions) ([]*Intention, *QueryMeta, error) {
|
||||
r := h.c.newRequest("GET", "/v1/connect/intentions")
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(h.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out []*Intention
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return out, qm, nil
|
||||
}
|
||||
|
||||
// IntentionGet retrieves a single intention.
|
||||
func (h *Connect) IntentionGet(id string, q *QueryOptions) (*Intention, *QueryMeta, error) {
|
||||
r := h.c.newRequest("GET", "/v1/connect/intentions/"+id)
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := h.c.doRequest(r)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
if resp.StatusCode == 404 {
|
||||
return nil, qm, nil
|
||||
} else if resp.StatusCode != 200 {
|
||||
var buf bytes.Buffer
|
||||
io.Copy(&buf, resp.Body)
|
||||
return nil, nil, fmt.Errorf(
|
||||
"Unexpected response %d: %s", resp.StatusCode, buf.String())
|
||||
}
|
||||
|
||||
var out Intention
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &out, qm, nil
|
||||
}
|
||||
|
||||
// IntentionDelete deletes a single intention.
|
||||
func (h *Connect) IntentionDelete(id string, q *WriteOptions) (*WriteMeta, error) {
|
||||
r := h.c.newRequest("DELETE", "/v1/connect/intentions/"+id)
|
||||
r.setWriteOptions(q)
|
||||
rtt, resp, err := requireOK(h.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &WriteMeta{}
|
||||
qm.RequestTime = rtt
|
||||
|
||||
return qm, nil
|
||||
}
|
||||
|
||||
// IntentionMatch returns the list of intentions that match a given source
|
||||
// or destination. The returned intentions are ordered by precedence where
|
||||
// result[0] is the highest precedence (if that matches, then that rule overrides
|
||||
// all other rules).
|
||||
//
|
||||
// Matching can be done for multiple names at the same time. The resulting
|
||||
// map is keyed by the given names. Casing is preserved.
|
||||
func (h *Connect) IntentionMatch(args *IntentionMatch, q *QueryOptions) (map[string][]*Intention, *QueryMeta, error) {
|
||||
r := h.c.newRequest("GET", "/v1/connect/intentions/match")
|
||||
r.setQueryOptions(q)
|
||||
r.params.Set("by", string(args.By))
|
||||
for _, name := range args.Names {
|
||||
r.params.Add("name", name)
|
||||
}
|
||||
rtt, resp, err := requireOK(h.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out map[string][]*Intention
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return out, qm, nil
|
||||
}
|
||||
|
||||
// IntentionCheck returns whether a given source/destination would be allowed
|
||||
// or not given the current set of intentions and the configuration of Consul.
|
||||
func (h *Connect) IntentionCheck(args *IntentionCheck, q *QueryOptions) (bool, *QueryMeta, error) {
|
||||
r := h.c.newRequest("GET", "/v1/connect/intentions/check")
|
||||
r.setQueryOptions(q)
|
||||
r.params.Set("source", args.Source)
|
||||
r.params.Set("destination", args.Destination)
|
||||
if args.SourceType != "" {
|
||||
r.params.Set("source-type", string(args.SourceType))
|
||||
}
|
||||
rtt, resp, err := requireOK(h.c.doRequest(r))
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out struct{ Allowed bool }
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return out.Allowed, qm, nil
|
||||
}
|
||||
|
||||
// IntentionCreate will create a new intention. The ID in the given
|
||||
// structure must be empty and a generate ID will be returned on
|
||||
// success.
|
||||
func (c *Connect) IntentionCreate(ixn *Intention, q *WriteOptions) (string, *WriteMeta, error) {
|
||||
r := c.c.newRequest("POST", "/v1/connect/intentions")
|
||||
r.setWriteOptions(q)
|
||||
r.obj = ixn
|
||||
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
wm := &WriteMeta{}
|
||||
wm.RequestTime = rtt
|
||||
|
||||
var out struct{ ID string }
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return out.ID, wm, nil
|
||||
}
|
||||
|
||||
// IntentionUpdate will update an existing intention. The ID in the given
|
||||
// structure must be non-empty.
|
||||
func (c *Connect) IntentionUpdate(ixn *Intention, q *WriteOptions) (*WriteMeta, error) {
|
||||
r := c.c.newRequest("PUT", "/v1/connect/intentions/"+ixn.ID)
|
||||
r.setWriteOptions(q)
|
||||
r.obj = ixn
|
||||
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
wm := &WriteMeta{}
|
||||
wm.RequestTime = rtt
|
||||
return wm, nil
|
||||
}
|
106
vendor/github.com/hashicorp/consul/api/debug.go
generated
vendored
Normal file
106
vendor/github.com/hashicorp/consul/api/debug.go
generated
vendored
Normal file
|
@ -0,0 +1,106 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Debug can be used to query the /debug/pprof endpoints to gather
|
||||
// profiling information about the target agent.Debug
|
||||
//
|
||||
// The agent must have enable_debug set to true for profiling to be enabled
|
||||
// and for these endpoints to function.
|
||||
type Debug struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// Debug returns a handle that exposes the internal debug endpoints.
|
||||
func (c *Client) Debug() *Debug {
|
||||
return &Debug{c}
|
||||
}
|
||||
|
||||
// Heap returns a pprof heap dump
|
||||
func (d *Debug) Heap() ([]byte, error) {
|
||||
r := d.c.newRequest("GET", "/debug/pprof/heap")
|
||||
_, resp, err := d.c.doRequest(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error making request: %s", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// We return a raw response because we're just passing through a response
|
||||
// from the pprof handlers
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding body: %s", err)
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// Profile returns a pprof CPU profile for the specified number of seconds
|
||||
func (d *Debug) Profile(seconds int) ([]byte, error) {
|
||||
r := d.c.newRequest("GET", "/debug/pprof/profile")
|
||||
|
||||
// Capture a profile for the specified number of seconds
|
||||
r.params.Set("seconds", strconv.Itoa(seconds))
|
||||
|
||||
_, resp, err := d.c.doRequest(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error making request: %s", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// We return a raw response because we're just passing through a response
|
||||
// from the pprof handlers
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding body: %s", err)
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// Trace returns an execution trace
|
||||
func (d *Debug) Trace(seconds int) ([]byte, error) {
|
||||
r := d.c.newRequest("GET", "/debug/pprof/trace")
|
||||
|
||||
// Capture a trace for the specified number of seconds
|
||||
r.params.Set("seconds", strconv.Itoa(seconds))
|
||||
|
||||
_, resp, err := d.c.doRequest(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error making request: %s", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// We return a raw response because we're just passing through a response
|
||||
// from the pprof handlers
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding body: %s", err)
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// Goroutine returns a pprof goroutine profile
|
||||
func (d *Debug) Goroutine() ([]byte, error) {
|
||||
r := d.c.newRequest("GET", "/debug/pprof/goroutine")
|
||||
|
||||
_, resp, err := d.c.doRequest(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error making request: %s", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// We return a raw response because we're just passing through a response
|
||||
// from the pprof handlers
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding body: %s", err)
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
131
vendor/github.com/hashicorp/consul/api/health.go
generated
vendored
131
vendor/github.com/hashicorp/consul/api/health.go
generated
vendored
|
@ -1,8 +1,10 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -36,21 +38,99 @@ type HealthCheck struct {
|
|||
ServiceTags []string
|
||||
|
||||
Definition HealthCheckDefinition
|
||||
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
// HealthCheckDefinition is used to store the details about
|
||||
// a health check's execution.
|
||||
type HealthCheckDefinition struct {
|
||||
HTTP string
|
||||
Header map[string][]string
|
||||
Method string
|
||||
TLSSkipVerify bool
|
||||
TCP string
|
||||
HTTP string
|
||||
Header map[string][]string
|
||||
Method string
|
||||
TLSSkipVerify bool
|
||||
TCP string
|
||||
IntervalDuration time.Duration `json:"-"`
|
||||
TimeoutDuration time.Duration `json:"-"`
|
||||
DeregisterCriticalServiceAfterDuration time.Duration `json:"-"`
|
||||
|
||||
// DEPRECATED in Consul 1.4.1. Use the above time.Duration fields instead.
|
||||
Interval ReadableDuration
|
||||
Timeout ReadableDuration
|
||||
DeregisterCriticalServiceAfter ReadableDuration
|
||||
}
|
||||
|
||||
func (d *HealthCheckDefinition) MarshalJSON() ([]byte, error) {
|
||||
type Alias HealthCheckDefinition
|
||||
out := &struct {
|
||||
Interval string
|
||||
Timeout string
|
||||
DeregisterCriticalServiceAfter string
|
||||
*Alias
|
||||
}{
|
||||
Interval: d.Interval.String(),
|
||||
Timeout: d.Timeout.String(),
|
||||
DeregisterCriticalServiceAfter: d.DeregisterCriticalServiceAfter.String(),
|
||||
Alias: (*Alias)(d),
|
||||
}
|
||||
|
||||
if d.IntervalDuration != 0 {
|
||||
out.Interval = d.IntervalDuration.String()
|
||||
} else if d.Interval != 0 {
|
||||
out.Interval = d.Interval.String()
|
||||
}
|
||||
if d.TimeoutDuration != 0 {
|
||||
out.Timeout = d.TimeoutDuration.String()
|
||||
} else if d.Timeout != 0 {
|
||||
out.Timeout = d.Timeout.String()
|
||||
}
|
||||
if d.DeregisterCriticalServiceAfterDuration != 0 {
|
||||
out.DeregisterCriticalServiceAfter = d.DeregisterCriticalServiceAfterDuration.String()
|
||||
} else if d.DeregisterCriticalServiceAfter != 0 {
|
||||
out.DeregisterCriticalServiceAfter = d.DeregisterCriticalServiceAfter.String()
|
||||
}
|
||||
|
||||
return json.Marshal(out)
|
||||
}
|
||||
|
||||
func (d *HealthCheckDefinition) UnmarshalJSON(data []byte) error {
|
||||
type Alias HealthCheckDefinition
|
||||
aux := &struct {
|
||||
Interval string
|
||||
Timeout string
|
||||
DeregisterCriticalServiceAfter string
|
||||
*Alias
|
||||
}{
|
||||
Alias: (*Alias)(d),
|
||||
}
|
||||
if err := json.Unmarshal(data, &aux); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse the values into both the time.Duration and old ReadableDuration fields.
|
||||
var err error
|
||||
if aux.Interval != "" {
|
||||
if d.IntervalDuration, err = time.ParseDuration(aux.Interval); err != nil {
|
||||
return err
|
||||
}
|
||||
d.Interval = ReadableDuration(d.IntervalDuration)
|
||||
}
|
||||
if aux.Timeout != "" {
|
||||
if d.TimeoutDuration, err = time.ParseDuration(aux.Timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
d.Timeout = ReadableDuration(d.TimeoutDuration)
|
||||
}
|
||||
if aux.DeregisterCriticalServiceAfter != "" {
|
||||
if d.DeregisterCriticalServiceAfterDuration, err = time.ParseDuration(aux.DeregisterCriticalServiceAfter); err != nil {
|
||||
return err
|
||||
}
|
||||
d.DeregisterCriticalServiceAfter = ReadableDuration(d.DeregisterCriticalServiceAfterDuration)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HealthChecks is a collection of HealthCheck structs.
|
||||
type HealthChecks []*HealthCheck
|
||||
|
||||
|
@ -159,10 +239,45 @@ func (h *Health) Checks(service string, q *QueryOptions) (HealthChecks, *QueryMe
|
|||
// for a given service. It can optionally do server-side filtering on a tag
|
||||
// or nodes with passing health checks only.
|
||||
func (h *Health) Service(service, tag string, passingOnly bool, q *QueryOptions) ([]*ServiceEntry, *QueryMeta, error) {
|
||||
r := h.c.newRequest("GET", "/v1/health/service/"+service)
|
||||
r.setQueryOptions(q)
|
||||
var tags []string
|
||||
if tag != "" {
|
||||
r.params.Set("tag", tag)
|
||||
tags = []string{tag}
|
||||
}
|
||||
return h.service(service, tags, passingOnly, q, false)
|
||||
}
|
||||
|
||||
func (h *Health) ServiceMultipleTags(service string, tags []string, passingOnly bool, q *QueryOptions) ([]*ServiceEntry, *QueryMeta, error) {
|
||||
return h.service(service, tags, passingOnly, q, false)
|
||||
}
|
||||
|
||||
// Connect is equivalent to Service except that it will only return services
|
||||
// which are Connect-enabled and will returns the connection address for Connect
|
||||
// client's to use which may be a proxy in front of the named service. If
|
||||
// passingOnly is true only instances where both the service and any proxy are
|
||||
// healthy will be returned.
|
||||
func (h *Health) Connect(service, tag string, passingOnly bool, q *QueryOptions) ([]*ServiceEntry, *QueryMeta, error) {
|
||||
var tags []string
|
||||
if tag != "" {
|
||||
tags = []string{tag}
|
||||
}
|
||||
return h.service(service, tags, passingOnly, q, true)
|
||||
}
|
||||
|
||||
func (h *Health) ConnectMultipleTags(service string, tags []string, passingOnly bool, q *QueryOptions) ([]*ServiceEntry, *QueryMeta, error) {
|
||||
return h.service(service, tags, passingOnly, q, true)
|
||||
}
|
||||
|
||||
func (h *Health) service(service string, tags []string, passingOnly bool, q *QueryOptions, connect bool) ([]*ServiceEntry, *QueryMeta, error) {
|
||||
path := "/v1/health/service/" + service
|
||||
if connect {
|
||||
path = "/v1/health/connect/" + service
|
||||
}
|
||||
r := h.c.newRequest("GET", path)
|
||||
r.setQueryOptions(q)
|
||||
if len(tags) > 0 {
|
||||
for _, tag := range tags {
|
||||
r.params.Add("tag", tag)
|
||||
}
|
||||
}
|
||||
if passingOnly {
|
||||
r.params.Set(HealthPassing, "1")
|
||||
|
|
160
vendor/github.com/hashicorp/consul/api/kv.go
generated
vendored
160
vendor/github.com/hashicorp/consul/api/kv.go
generated
vendored
|
@ -45,44 +45,6 @@ type KVPair struct {
|
|||
// KVPairs is a list of KVPair objects
|
||||
type KVPairs []*KVPair
|
||||
|
||||
// KVOp constants give possible operations available in a KVTxn.
|
||||
type KVOp string
|
||||
|
||||
const (
|
||||
KVSet KVOp = "set"
|
||||
KVDelete KVOp = "delete"
|
||||
KVDeleteCAS KVOp = "delete-cas"
|
||||
KVDeleteTree KVOp = "delete-tree"
|
||||
KVCAS KVOp = "cas"
|
||||
KVLock KVOp = "lock"
|
||||
KVUnlock KVOp = "unlock"
|
||||
KVGet KVOp = "get"
|
||||
KVGetTree KVOp = "get-tree"
|
||||
KVCheckSession KVOp = "check-session"
|
||||
KVCheckIndex KVOp = "check-index"
|
||||
KVCheckNotExists KVOp = "check-not-exists"
|
||||
)
|
||||
|
||||
// KVTxnOp defines a single operation inside a transaction.
|
||||
type KVTxnOp struct {
|
||||
Verb KVOp
|
||||
Key string
|
||||
Value []byte
|
||||
Flags uint64
|
||||
Index uint64
|
||||
Session string
|
||||
}
|
||||
|
||||
// KVTxnOps defines a set of operations to be performed inside a single
|
||||
// transaction.
|
||||
type KVTxnOps []*KVTxnOp
|
||||
|
||||
// KVTxnResponse has the outcome of a transaction.
|
||||
type KVTxnResponse struct {
|
||||
Results []*KVPair
|
||||
Errors TxnErrors
|
||||
}
|
||||
|
||||
// KV is used to manipulate the K/V API
|
||||
type KV struct {
|
||||
c *Client
|
||||
|
@ -300,121 +262,25 @@ func (k *KV) deleteInternal(key string, params map[string]string, q *WriteOption
|
|||
return res, qm, nil
|
||||
}
|
||||
|
||||
// TxnOp is the internal format we send to Consul. It's not specific to KV,
|
||||
// though currently only KV operations are supported.
|
||||
type TxnOp struct {
|
||||
KV *KVTxnOp
|
||||
}
|
||||
|
||||
// TxnOps is a list of transaction operations.
|
||||
type TxnOps []*TxnOp
|
||||
|
||||
// TxnResult is the internal format we receive from Consul.
|
||||
type TxnResult struct {
|
||||
KV *KVPair
|
||||
}
|
||||
|
||||
// TxnResults is a list of TxnResult objects.
|
||||
type TxnResults []*TxnResult
|
||||
|
||||
// TxnError is used to return information about an operation in a transaction.
|
||||
type TxnError struct {
|
||||
OpIndex int
|
||||
What string
|
||||
}
|
||||
|
||||
// TxnErrors is a list of TxnError objects.
|
||||
type TxnErrors []*TxnError
|
||||
|
||||
// TxnResponse is the internal format we receive from Consul.
|
||||
type TxnResponse struct {
|
||||
Results TxnResults
|
||||
Errors TxnErrors
|
||||
}
|
||||
|
||||
// Txn is used to apply multiple KV operations in a single, atomic transaction.
|
||||
//
|
||||
// Note that Go will perform the required base64 encoding on the values
|
||||
// automatically because the type is a byte slice. Transactions are defined as a
|
||||
// list of operations to perform, using the KVOp constants and KVTxnOp structure
|
||||
// to define operations. If any operation fails, none of the changes are applied
|
||||
// to the state store. Note that this hides the internal raw transaction interface
|
||||
// and munges the input and output types into KV-specific ones for ease of use.
|
||||
// If there are more non-KV operations in the future we may break out a new
|
||||
// transaction API client, but it will be easy to keep this KV-specific variant
|
||||
// supported.
|
||||
//
|
||||
// Even though this is generally a write operation, we take a QueryOptions input
|
||||
// and return a QueryMeta output. If the transaction contains only read ops, then
|
||||
// Consul will fast-path it to a different endpoint internally which supports
|
||||
// consistency controls, but not blocking. If there are write operations then
|
||||
// the request will always be routed through raft and any consistency settings
|
||||
// will be ignored.
|
||||
//
|
||||
// Here's an example:
|
||||
//
|
||||
// ops := KVTxnOps{
|
||||
// &KVTxnOp{
|
||||
// Verb: KVLock,
|
||||
// Key: "test/lock",
|
||||
// Session: "adf4238a-882b-9ddc-4a9d-5b6758e4159e",
|
||||
// Value: []byte("hello"),
|
||||
// },
|
||||
// &KVTxnOp{
|
||||
// Verb: KVGet,
|
||||
// Key: "another/key",
|
||||
// },
|
||||
// }
|
||||
// ok, response, _, err := kv.Txn(&ops, nil)
|
||||
//
|
||||
// If there is a problem making the transaction request then an error will be
|
||||
// returned. Otherwise, the ok value will be true if the transaction succeeded
|
||||
// or false if it was rolled back. The response is a structured return value which
|
||||
// will have the outcome of the transaction. Its Results member will have entries
|
||||
// for each operation. Deleted keys will have a nil entry in the, and to save
|
||||
// space, the Value of each key in the Results will be nil unless the operation
|
||||
// is a KVGet. If the transaction was rolled back, the Errors member will have
|
||||
// entries referencing the index of the operation that failed along with an error
|
||||
// message.
|
||||
// The Txn function has been deprecated from the KV object; please see the Txn
|
||||
// object for more information about Transactions.
|
||||
func (k *KV) Txn(txn KVTxnOps, q *QueryOptions) (bool, *KVTxnResponse, *QueryMeta, error) {
|
||||
r := k.c.newRequest("PUT", "/v1/txn")
|
||||
r.setQueryOptions(q)
|
||||
|
||||
// Convert into the internal format since this is an all-KV txn.
|
||||
ops := make(TxnOps, 0, len(txn))
|
||||
for _, kvOp := range txn {
|
||||
ops = append(ops, &TxnOp{KV: kvOp})
|
||||
var ops TxnOps
|
||||
for _, op := range txn {
|
||||
ops = append(ops, &TxnOp{KV: op})
|
||||
}
|
||||
r.obj = ops
|
||||
rtt, resp, err := k.c.doRequest(r)
|
||||
|
||||
respOk, txnResp, qm, err := k.c.txn(ops, q)
|
||||
if err != nil {
|
||||
return false, nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusConflict {
|
||||
var txnResp TxnResponse
|
||||
if err := decodeBody(resp, &txnResp); err != nil {
|
||||
return false, nil, nil, err
|
||||
}
|
||||
|
||||
// Convert from the internal format.
|
||||
kvResp := KVTxnResponse{
|
||||
Errors: txnResp.Errors,
|
||||
}
|
||||
for _, result := range txnResp.Results {
|
||||
kvResp.Results = append(kvResp.Results, result.KV)
|
||||
}
|
||||
return resp.StatusCode == http.StatusOK, &kvResp, qm, nil
|
||||
// Convert from the internal format.
|
||||
kvResp := KVTxnResponse{
|
||||
Errors: txnResp.Errors,
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if _, err := io.Copy(&buf, resp.Body); err != nil {
|
||||
return false, nil, nil, fmt.Errorf("Failed to read response: %v", err)
|
||||
for _, result := range txnResp.Results {
|
||||
kvResp.Results = append(kvResp.Results, result.KV)
|
||||
}
|
||||
return false, nil, nil, fmt.Errorf("Failed request: %s", buf.String())
|
||||
return respOk, &kvResp, qm, nil
|
||||
}
|
||||
|
|
5
vendor/github.com/hashicorp/consul/api/lock.go
generated
vendored
5
vendor/github.com/hashicorp/consul/api/lock.go
generated
vendored
|
@ -181,11 +181,12 @@ WAIT:
|
|||
// Handle the one-shot mode.
|
||||
if l.opts.LockTryOnce && attempts > 0 {
|
||||
elapsed := time.Since(start)
|
||||
if elapsed > qOpts.WaitTime {
|
||||
if elapsed > l.opts.LockWaitTime {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
qOpts.WaitTime -= elapsed
|
||||
// Query wait time should not exceed the lock wait time
|
||||
qOpts.WaitTime = l.opts.LockWaitTime - elapsed
|
||||
}
|
||||
attempts++
|
||||
|
||||
|
|
3
vendor/github.com/hashicorp/consul/api/operator_area.go
generated
vendored
3
vendor/github.com/hashicorp/consul/api/operator_area.go
generated
vendored
|
@ -1,9 +1,10 @@
|
|||
package api
|
||||
|
||||
// The /v1/operator/area endpoints are available only in Consul Enterprise and
|
||||
// interact with its network area subsystem. Network areas are used to link
|
||||
// together Consul servers in different Consul datacenters. With network areas,
|
||||
// Consul datacenters can be linked together in ways other than a fully-connected
|
||||
// mesh, as is required for Consul's WAN.
|
||||
package api
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
|
3
vendor/github.com/hashicorp/consul/api/operator_keyring.go
generated
vendored
3
vendor/github.com/hashicorp/consul/api/operator_keyring.go
generated
vendored
|
@ -16,6 +16,9 @@ type KeyringResponse struct {
|
|||
// Segment has the network segment this request corresponds to.
|
||||
Segment string
|
||||
|
||||
// Messages has information or errors from serf
|
||||
Messages map[string]string `json:",omitempty"`
|
||||
|
||||
// A map of the encryption keys to the number of nodes they're installed on
|
||||
Keys map[string]int
|
||||
|
||||
|
|
8
vendor/github.com/hashicorp/consul/api/prepared_query.go
generated
vendored
8
vendor/github.com/hashicorp/consul/api/prepared_query.go
generated
vendored
|
@ -54,6 +54,14 @@ type ServiceQuery struct {
|
|||
// pair is in this map it must be present on the node in order for the
|
||||
// service entry to be returned.
|
||||
NodeMeta map[string]string
|
||||
|
||||
// Connect if true will filter the prepared query results to only
|
||||
// include Connect-capable services. These include both native services
|
||||
// and proxies for matching services. Note that if a proxy matches,
|
||||
// the constraints in the query above (Near, OnlyPassing, etc.) apply
|
||||
// to the _proxy_ and not the service being proxied. In practice, proxies
|
||||
// should be directly next to their services so this isn't an issue.
|
||||
Connect bool
|
||||
}
|
||||
|
||||
// QueryTemplate carries the arguments for creating a templated query.
|
||||
|
|
5
vendor/github.com/hashicorp/consul/api/semaphore.go
generated
vendored
5
vendor/github.com/hashicorp/consul/api/semaphore.go
generated
vendored
|
@ -199,11 +199,12 @@ WAIT:
|
|||
// Handle the one-shot mode.
|
||||
if s.opts.SemaphoreTryOnce && attempts > 0 {
|
||||
elapsed := time.Since(start)
|
||||
if elapsed > qOpts.WaitTime {
|
||||
if elapsed > s.opts.SemaphoreWaitTime {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
qOpts.WaitTime -= elapsed
|
||||
// Query wait time should not exceed the semaphore wait time
|
||||
qOpts.WaitTime = s.opts.SemaphoreWaitTime - elapsed
|
||||
}
|
||||
attempts++
|
||||
|
||||
|
|
230
vendor/github.com/hashicorp/consul/api/txn.go
generated
vendored
Normal file
230
vendor/github.com/hashicorp/consul/api/txn.go
generated
vendored
Normal file
|
@ -0,0 +1,230 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Txn is used to manipulate the Txn API
|
||||
type Txn struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// Txn is used to return a handle to the K/V apis
|
||||
func (c *Client) Txn() *Txn {
|
||||
return &Txn{c}
|
||||
}
|
||||
|
||||
// TxnOp is the internal format we send to Consul. Currently only K/V and
|
||||
// check operations are supported.
|
||||
type TxnOp struct {
|
||||
KV *KVTxnOp
|
||||
Node *NodeTxnOp
|
||||
Service *ServiceTxnOp
|
||||
Check *CheckTxnOp
|
||||
}
|
||||
|
||||
// TxnOps is a list of transaction operations.
|
||||
type TxnOps []*TxnOp
|
||||
|
||||
// TxnResult is the internal format we receive from Consul.
|
||||
type TxnResult struct {
|
||||
KV *KVPair
|
||||
Node *Node
|
||||
Service *CatalogService
|
||||
Check *HealthCheck
|
||||
}
|
||||
|
||||
// TxnResults is a list of TxnResult objects.
|
||||
type TxnResults []*TxnResult
|
||||
|
||||
// TxnError is used to return information about an operation in a transaction.
|
||||
type TxnError struct {
|
||||
OpIndex int
|
||||
What string
|
||||
}
|
||||
|
||||
// TxnErrors is a list of TxnError objects.
|
||||
type TxnErrors []*TxnError
|
||||
|
||||
// TxnResponse is the internal format we receive from Consul.
|
||||
type TxnResponse struct {
|
||||
Results TxnResults
|
||||
Errors TxnErrors
|
||||
}
|
||||
|
||||
// KVOp constants give possible operations available in a transaction.
|
||||
type KVOp string
|
||||
|
||||
const (
|
||||
KVSet KVOp = "set"
|
||||
KVDelete KVOp = "delete"
|
||||
KVDeleteCAS KVOp = "delete-cas"
|
||||
KVDeleteTree KVOp = "delete-tree"
|
||||
KVCAS KVOp = "cas"
|
||||
KVLock KVOp = "lock"
|
||||
KVUnlock KVOp = "unlock"
|
||||
KVGet KVOp = "get"
|
||||
KVGetTree KVOp = "get-tree"
|
||||
KVCheckSession KVOp = "check-session"
|
||||
KVCheckIndex KVOp = "check-index"
|
||||
KVCheckNotExists KVOp = "check-not-exists"
|
||||
)
|
||||
|
||||
// KVTxnOp defines a single operation inside a transaction.
|
||||
type KVTxnOp struct {
|
||||
Verb KVOp
|
||||
Key string
|
||||
Value []byte
|
||||
Flags uint64
|
||||
Index uint64
|
||||
Session string
|
||||
}
|
||||
|
||||
// KVTxnOps defines a set of operations to be performed inside a single
|
||||
// transaction.
|
||||
type KVTxnOps []*KVTxnOp
|
||||
|
||||
// KVTxnResponse has the outcome of a transaction.
|
||||
type KVTxnResponse struct {
|
||||
Results []*KVPair
|
||||
Errors TxnErrors
|
||||
}
|
||||
|
||||
// NodeOp constants give possible operations available in a transaction.
|
||||
type NodeOp string
|
||||
|
||||
const (
|
||||
NodeGet NodeOp = "get"
|
||||
NodeSet NodeOp = "set"
|
||||
NodeCAS NodeOp = "cas"
|
||||
NodeDelete NodeOp = "delete"
|
||||
NodeDeleteCAS NodeOp = "delete-cas"
|
||||
)
|
||||
|
||||
// NodeTxnOp defines a single operation inside a transaction.
|
||||
type NodeTxnOp struct {
|
||||
Verb NodeOp
|
||||
Node Node
|
||||
}
|
||||
|
||||
// ServiceOp constants give possible operations available in a transaction.
|
||||
type ServiceOp string
|
||||
|
||||
const (
|
||||
ServiceGet ServiceOp = "get"
|
||||
ServiceSet ServiceOp = "set"
|
||||
ServiceCAS ServiceOp = "cas"
|
||||
ServiceDelete ServiceOp = "delete"
|
||||
ServiceDeleteCAS ServiceOp = "delete-cas"
|
||||
)
|
||||
|
||||
// ServiceTxnOp defines a single operation inside a transaction.
|
||||
type ServiceTxnOp struct {
|
||||
Verb ServiceOp
|
||||
Node string
|
||||
Service AgentService
|
||||
}
|
||||
|
||||
// CheckOp constants give possible operations available in a transaction.
|
||||
type CheckOp string
|
||||
|
||||
const (
|
||||
CheckGet CheckOp = "get"
|
||||
CheckSet CheckOp = "set"
|
||||
CheckCAS CheckOp = "cas"
|
||||
CheckDelete CheckOp = "delete"
|
||||
CheckDeleteCAS CheckOp = "delete-cas"
|
||||
)
|
||||
|
||||
// CheckTxnOp defines a single operation inside a transaction.
|
||||
type CheckTxnOp struct {
|
||||
Verb CheckOp
|
||||
Check HealthCheck
|
||||
}
|
||||
|
||||
// Txn is used to apply multiple Consul operations in a single, atomic transaction.
|
||||
//
|
||||
// Note that Go will perform the required base64 encoding on the values
|
||||
// automatically because the type is a byte slice. Transactions are defined as a
|
||||
// list of operations to perform, using the different fields in the TxnOp structure
|
||||
// to define operations. If any operation fails, none of the changes are applied
|
||||
// to the state store.
|
||||
//
|
||||
// Even though this is generally a write operation, we take a QueryOptions input
|
||||
// and return a QueryMeta output. If the transaction contains only read ops, then
|
||||
// Consul will fast-path it to a different endpoint internally which supports
|
||||
// consistency controls, but not blocking. If there are write operations then
|
||||
// the request will always be routed through raft and any consistency settings
|
||||
// will be ignored.
|
||||
//
|
||||
// Here's an example:
|
||||
//
|
||||
// ops := KVTxnOps{
|
||||
// &KVTxnOp{
|
||||
// Verb: KVLock,
|
||||
// Key: "test/lock",
|
||||
// Session: "adf4238a-882b-9ddc-4a9d-5b6758e4159e",
|
||||
// Value: []byte("hello"),
|
||||
// },
|
||||
// &KVTxnOp{
|
||||
// Verb: KVGet,
|
||||
// Key: "another/key",
|
||||
// },
|
||||
// &CheckTxnOp{
|
||||
// Verb: CheckSet,
|
||||
// HealthCheck: HealthCheck{
|
||||
// Node: "foo",
|
||||
// CheckID: "redis:a",
|
||||
// Name: "Redis Health Check",
|
||||
// Status: "passing",
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// ok, response, _, err := kv.Txn(&ops, nil)
|
||||
//
|
||||
// If there is a problem making the transaction request then an error will be
|
||||
// returned. Otherwise, the ok value will be true if the transaction succeeded
|
||||
// or false if it was rolled back. The response is a structured return value which
|
||||
// will have the outcome of the transaction. Its Results member will have entries
|
||||
// for each operation. For KV operations, Deleted keys will have a nil entry in the
|
||||
// results, and to save space, the Value of each key in the Results will be nil
|
||||
// unless the operation is a KVGet. If the transaction was rolled back, the Errors
|
||||
// member will have entries referencing the index of the operation that failed
|
||||
// along with an error message.
|
||||
func (t *Txn) Txn(txn TxnOps, q *QueryOptions) (bool, *TxnResponse, *QueryMeta, error) {
|
||||
return t.c.txn(txn, q)
|
||||
}
|
||||
|
||||
func (c *Client) txn(txn TxnOps, q *QueryOptions) (bool, *TxnResponse, *QueryMeta, error) {
|
||||
r := c.newRequest("PUT", "/v1/txn")
|
||||
r.setQueryOptions(q)
|
||||
|
||||
r.obj = txn
|
||||
rtt, resp, err := c.doRequest(r)
|
||||
if err != nil {
|
||||
return false, nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusConflict {
|
||||
var txnResp TxnResponse
|
||||
if err := decodeBody(resp, &txnResp); err != nil {
|
||||
return false, nil, nil, err
|
||||
}
|
||||
|
||||
return resp.StatusCode == http.StatusOK, &txnResp, qm, nil
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if _, err := io.Copy(&buf, resp.Body); err != nil {
|
||||
return false, nil, nil, fmt.Errorf("Failed to read response: %v", err)
|
||||
}
|
||||
return false, nil, nil, fmt.Errorf("Failed request: %s", buf.String())
|
||||
}
|
26
vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go
generated
vendored
26
vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go
generated
vendored
|
@ -3,11 +3,12 @@ package cleanhttp
|
|||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DefaultTransport returns a new http.Transport with the same default values
|
||||
// as http.DefaultTransport, but with idle connections and keepalives disabled.
|
||||
// DefaultTransport returns a new http.Transport with similar default values to
|
||||
// http.DefaultTransport, but with idle connections and keepalives disabled.
|
||||
func DefaultTransport() *http.Transport {
|
||||
transport := DefaultPooledTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
|
@ -22,13 +23,16 @@ func DefaultTransport() *http.Transport {
|
|||
func DefaultPooledTransport() *http.Transport {
|
||||
transport := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Dial: (&net.Dialer{
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
DisableKeepAlives: false,
|
||||
MaxIdleConnsPerHost: 1,
|
||||
DualStack: true,
|
||||
}).DialContext,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1,
|
||||
}
|
||||
return transport
|
||||
}
|
||||
|
@ -42,10 +46,10 @@ func DefaultClient() *http.Client {
|
|||
}
|
||||
}
|
||||
|
||||
// DefaultPooledClient returns a new http.Client with the same default values
|
||||
// as http.Client, but with a shared Transport. Do not use this function
|
||||
// for transient clients as it can leak file descriptors over time. Only use
|
||||
// this for clients that will be re-used for the same host(s).
|
||||
// DefaultPooledClient returns a new http.Client with similar default values to
|
||||
// http.Client, but with a shared Transport. Do not use this function for
|
||||
// transient clients as it can leak file descriptors over time. Only use this
|
||||
// for clients that will be re-used for the same host(s).
|
||||
func DefaultPooledClient() *http.Client {
|
||||
return &http.Client{
|
||||
Transport: DefaultPooledTransport(),
|
||||
|
|
1
vendor/github.com/hashicorp/go-cleanhttp/go.mod
generated
vendored
Normal file
1
vendor/github.com/hashicorp/go-cleanhttp/go.mod
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
module github.com/hashicorp/go-cleanhttp
|
43
vendor/github.com/hashicorp/go-cleanhttp/handlers.go
generated
vendored
Normal file
43
vendor/github.com/hashicorp/go-cleanhttp/handlers.go
generated
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
package cleanhttp
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// HandlerInput provides input options to cleanhttp's handlers
|
||||
type HandlerInput struct {
|
||||
ErrStatus int
|
||||
}
|
||||
|
||||
// PrintablePathCheckHandler is a middleware that ensures the request path
|
||||
// contains only printable runes.
|
||||
func PrintablePathCheckHandler(next http.Handler, input *HandlerInput) http.Handler {
|
||||
// Nil-check on input to make it optional
|
||||
if input == nil {
|
||||
input = &HandlerInput{
|
||||
ErrStatus: http.StatusBadRequest,
|
||||
}
|
||||
}
|
||||
|
||||
// Default to http.StatusBadRequest on error
|
||||
if input.ErrStatus == 0 {
|
||||
input.ErrStatus = http.StatusBadRequest
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Check URL path for non-printable characters
|
||||
idx := strings.IndexFunc(r.URL.Path, func(c rune) bool {
|
||||
return !unicode.IsPrint(c)
|
||||
})
|
||||
|
||||
if idx != -1 {
|
||||
w.WriteHeader(input.ErrStatus)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
})
|
||||
}
|
8
vendor/github.com/mitchellh/mapstructure/.travis.yml
generated
vendored
Normal file
8
vendor/github.com/mitchellh/mapstructure/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- "1.11.x"
|
||||
- tip
|
||||
|
||||
script:
|
||||
- go test
|
21
vendor/github.com/mitchellh/mapstructure/CHANGELOG.md
generated
vendored
Normal file
21
vendor/github.com/mitchellh/mapstructure/CHANGELOG.md
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
## 1.1.2
|
||||
|
||||
* Fix error when decode hook decodes interface implementation into interface
|
||||
type. [GH-140]
|
||||
|
||||
## 1.1.1
|
||||
|
||||
* Fix panic that can happen in `decodePtr`
|
||||
|
||||
## 1.1.0
|
||||
|
||||
* Added `StringToIPHookFunc` to convert `string` to `net.IP` and `net.IPNet` [GH-133]
|
||||
* Support struct to struct decoding [GH-137]
|
||||
* If source map value is nil, then destination map value is nil (instead of empty)
|
||||
* If source slice value is nil, then destination slice value is nil (instead of empty)
|
||||
* If source pointer is nil, then destination pointer is set to nil (instead of
|
||||
allocated zero value of type)
|
||||
|
||||
## 1.0.0
|
||||
|
||||
* Initial tagged stable release.
|
21
vendor/github.com/mitchellh/mapstructure/LICENSE
generated
vendored
Normal file
21
vendor/github.com/mitchellh/mapstructure/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Mitchell Hashimoto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
46
vendor/github.com/mitchellh/mapstructure/README.md
generated
vendored
Normal file
46
vendor/github.com/mitchellh/mapstructure/README.md
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
# mapstructure [![Godoc](https://godoc.org/github.com/mitchellh/mapstructure?status.svg)](https://godoc.org/github.com/mitchellh/mapstructure)
|
||||
|
||||
mapstructure is a Go library for decoding generic map values to structures
|
||||
and vice versa, while providing helpful error handling.
|
||||
|
||||
This library is most useful when decoding values from some data stream (JSON,
|
||||
Gob, etc.) where you don't _quite_ know the structure of the underlying data
|
||||
until you read a part of it. You can therefore read a `map[string]interface{}`
|
||||
and use this library to decode it into the proper underlying native Go
|
||||
structure.
|
||||
|
||||
## Installation
|
||||
|
||||
Standard `go get`:
|
||||
|
||||
```
|
||||
$ go get github.com/mitchellh/mapstructure
|
||||
```
|
||||
|
||||
## Usage & Example
|
||||
|
||||
For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/mapstructure).
|
||||
|
||||
The `Decode` function has examples associated with it there.
|
||||
|
||||
## But Why?!
|
||||
|
||||
Go offers fantastic standard libraries for decoding formats such as JSON.
|
||||
The standard method is to have a struct pre-created, and populate that struct
|
||||
from the bytes of the encoded format. This is great, but the problem is if
|
||||
you have configuration or an encoding that changes slightly depending on
|
||||
specific fields. For example, consider this JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "person",
|
||||
"name": "Mitchell"
|
||||
}
|
||||
```
|
||||
|
||||
Perhaps we can't populate a specific structure without first reading
|
||||
the "type" field from the JSON. We could always do two passes over the
|
||||
decoding of the JSON (reading the "type" first, and the rest later).
|
||||
However, it is much simpler to just decode this into a `map[string]interface{}`
|
||||
structure, read the "type" key, then use something like this library
|
||||
to decode it into the proper structure.
|
217
vendor/github.com/mitchellh/mapstructure/decode_hooks.go
generated
vendored
Normal file
217
vendor/github.com/mitchellh/mapstructure/decode_hooks.go
generated
vendored
Normal file
|
@ -0,0 +1,217 @@
|
|||
package mapstructure
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// typedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns
|
||||
// it into the proper DecodeHookFunc type, such as DecodeHookFuncType.
|
||||
func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {
|
||||
// Create variables here so we can reference them with the reflect pkg
|
||||
var f1 DecodeHookFuncType
|
||||
var f2 DecodeHookFuncKind
|
||||
|
||||
// Fill in the variables into this interface and the rest is done
|
||||
// automatically using the reflect package.
|
||||
potential := []interface{}{f1, f2}
|
||||
|
||||
v := reflect.ValueOf(h)
|
||||
vt := v.Type()
|
||||
for _, raw := range potential {
|
||||
pt := reflect.ValueOf(raw).Type()
|
||||
if vt.ConvertibleTo(pt) {
|
||||
return v.Convert(pt).Interface()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeHookExec executes the given decode hook. This should be used
|
||||
// since it'll naturally degrade to the older backwards compatible DecodeHookFunc
|
||||
// that took reflect.Kind instead of reflect.Type.
|
||||
func DecodeHookExec(
|
||||
raw DecodeHookFunc,
|
||||
from reflect.Type, to reflect.Type,
|
||||
data interface{}) (interface{}, error) {
|
||||
switch f := typedDecodeHook(raw).(type) {
|
||||
case DecodeHookFuncType:
|
||||
return f(from, to, data)
|
||||
case DecodeHookFuncKind:
|
||||
return f(from.Kind(), to.Kind(), data)
|
||||
default:
|
||||
return nil, errors.New("invalid decode hook signature")
|
||||
}
|
||||
}
|
||||
|
||||
// ComposeDecodeHookFunc creates a single DecodeHookFunc that
|
||||
// automatically composes multiple DecodeHookFuncs.
|
||||
//
|
||||
// The composed funcs are called in order, with the result of the
|
||||
// previous transformation.
|
||||
func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data interface{}) (interface{}, error) {
|
||||
var err error
|
||||
for _, f1 := range fs {
|
||||
data, err = DecodeHookExec(f1, f, t, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Modify the from kind to be correct with the new data
|
||||
f = nil
|
||||
if val := reflect.ValueOf(data); val.IsValid() {
|
||||
f = val.Type()
|
||||
}
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
}
|
||||
|
||||
// StringToSliceHookFunc returns a DecodeHookFunc that converts
|
||||
// string to []string by splitting on the given sep.
|
||||
func StringToSliceHookFunc(sep string) DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Kind,
|
||||
t reflect.Kind,
|
||||
data interface{}) (interface{}, error) {
|
||||
if f != reflect.String || t != reflect.Slice {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
raw := data.(string)
|
||||
if raw == "" {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
return strings.Split(raw, sep), nil
|
||||
}
|
||||
}
|
||||
|
||||
// StringToTimeDurationHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to time.Duration.
|
||||
func StringToTimeDurationHookFunc() DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data interface{}) (interface{}, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
if t != reflect.TypeOf(time.Duration(5)) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
return time.ParseDuration(data.(string))
|
||||
}
|
||||
}
|
||||
|
||||
// StringToIPHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to net.IP
|
||||
func StringToIPHookFunc() DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data interface{}) (interface{}, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
if t != reflect.TypeOf(net.IP{}) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
ip := net.ParseIP(data.(string))
|
||||
if ip == nil {
|
||||
return net.IP{}, fmt.Errorf("failed parsing ip %v", data)
|
||||
}
|
||||
|
||||
return ip, nil
|
||||
}
|
||||
}
|
||||
|
||||
// StringToIPNetHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to net.IPNet
|
||||
func StringToIPNetHookFunc() DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data interface{}) (interface{}, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
if t != reflect.TypeOf(net.IPNet{}) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
_, net, err := net.ParseCIDR(data.(string))
|
||||
return net, err
|
||||
}
|
||||
}
|
||||
|
||||
// StringToTimeHookFunc returns a DecodeHookFunc that converts
|
||||
// strings to time.Time.
|
||||
func StringToTimeHookFunc(layout string) DecodeHookFunc {
|
||||
return func(
|
||||
f reflect.Type,
|
||||
t reflect.Type,
|
||||
data interface{}) (interface{}, error) {
|
||||
if f.Kind() != reflect.String {
|
||||
return data, nil
|
||||
}
|
||||
if t != reflect.TypeOf(time.Time{}) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Convert it by parsing
|
||||
return time.Parse(layout, data.(string))
|
||||
}
|
||||
}
|
||||
|
||||
// WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to
|
||||
// the decoder.
|
||||
//
|
||||
// Note that this is significantly different from the WeaklyTypedInput option
|
||||
// of the DecoderConfig.
|
||||
func WeaklyTypedHook(
|
||||
f reflect.Kind,
|
||||
t reflect.Kind,
|
||||
data interface{}) (interface{}, error) {
|
||||
dataVal := reflect.ValueOf(data)
|
||||
switch t {
|
||||
case reflect.String:
|
||||
switch f {
|
||||
case reflect.Bool:
|
||||
if dataVal.Bool() {
|
||||
return "1", nil
|
||||
}
|
||||
return "0", nil
|
||||
case reflect.Float32:
|
||||
return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil
|
||||
case reflect.Int:
|
||||
return strconv.FormatInt(dataVal.Int(), 10), nil
|
||||
case reflect.Slice:
|
||||
dataType := dataVal.Type()
|
||||
elemKind := dataType.Elem().Kind()
|
||||
if elemKind == reflect.Uint8 {
|
||||
return string(dataVal.Interface().([]uint8)), nil
|
||||
}
|
||||
case reflect.Uint:
|
||||
return strconv.FormatUint(dataVal.Uint(), 10), nil
|
||||
}
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
50
vendor/github.com/mitchellh/mapstructure/error.go
generated
vendored
Normal file
50
vendor/github.com/mitchellh/mapstructure/error.go
generated
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
package mapstructure
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Error implements the error interface and can represents multiple
|
||||
// errors that occur in the course of a single decode.
|
||||
type Error struct {
|
||||
Errors []string
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
points := make([]string, len(e.Errors))
|
||||
for i, err := range e.Errors {
|
||||
points[i] = fmt.Sprintf("* %s", err)
|
||||
}
|
||||
|
||||
sort.Strings(points)
|
||||
return fmt.Sprintf(
|
||||
"%d error(s) decoding:\n\n%s",
|
||||
len(e.Errors), strings.Join(points, "\n"))
|
||||
}
|
||||
|
||||
// WrappedErrors implements the errwrap.Wrapper interface to make this
|
||||
// return value more useful with the errwrap and go-multierror libraries.
|
||||
func (e *Error) WrappedErrors() []error {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]error, len(e.Errors))
|
||||
for i, e := range e.Errors {
|
||||
result[i] = errors.New(e)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func appendErrors(errors []string, err error) []string {
|
||||
switch e := err.(type) {
|
||||
case *Error:
|
||||
return append(errors, e.Errors...)
|
||||
default:
|
||||
return append(errors, e.Error())
|
||||
}
|
||||
}
|
1
vendor/github.com/mitchellh/mapstructure/go.mod
generated
vendored
Normal file
1
vendor/github.com/mitchellh/mapstructure/go.mod
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
module github.com/mitchellh/mapstructure
|
1149
vendor/github.com/mitchellh/mapstructure/mapstructure.go
generated
vendored
Normal file
1149
vendor/github.com/mitchellh/mapstructure/mapstructure.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
6
vendor/modules.txt
vendored
6
vendor/modules.txt
vendored
|
@ -166,9 +166,9 @@ github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/genswagger
|
|||
github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule
|
||||
github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/generator
|
||||
github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options
|
||||
# github.com/hashicorp/consul v0.0.0-20180615161029-bed22a81e9fd
|
||||
# github.com/hashicorp/consul v1.4.2
|
||||
github.com/hashicorp/consul/api
|
||||
# github.com/hashicorp/go-cleanhttp v0.0.0-20160407174126-ad28ea4487f0
|
||||
# github.com/hashicorp/go-cleanhttp v0.5.0
|
||||
github.com/hashicorp/go-cleanhttp
|
||||
# github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90
|
||||
github.com/hashicorp/go-rootcerts
|
||||
|
@ -195,6 +195,8 @@ github.com/matttproud/golang_protobuf_extensions/pbutil
|
|||
github.com/miekg/dns
|
||||
# github.com/mitchellh/go-homedir v0.0.0-20180523094522-3864e76763d9
|
||||
github.com/mitchellh/go-homedir
|
||||
# github.com/mitchellh/mapstructure v1.1.2
|
||||
github.com/mitchellh/mapstructure
|
||||
# github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
|
||||
github.com/modern-go/concurrent
|
||||
# github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742
|
||||
|
|
Loading…
Reference in a new issue